[Freeswitch-svn] [commit] r3774 - in freeswitch/trunk: libs/sofia-sip libs/sofia-sip/docs libs/sofia-sip/libsofia-sip-ua libs/sofia-sip/libsofia-sip-ua-glib libs/sofia-sip/libsofia-sip-ua-glib/docs libs/sofia-sip/libsofia-sip-ua-glib/su-glib libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip libs/sofia-sip/libsofia-sip-ua/bnf libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip libs/sofia-sip/libsofia-sip-ua/docs libs/sofia-sip/libsofia-sip-ua/docs/pictures libs/sofia-sip/libsofia-sip-ua/features libs/sofia-sip/libsofia-sip-ua/features/sofia-sip libs/sofia-sip/libsofia-sip-ua/http libs/sofia-sip/libsofia-sip-ua/http/sofia-sip libs/sofia-sip/libsofia-sip-ua/ipt libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip libs/sofia-sip/libsofia-sip-ua/iptsec libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip libs/sofia-sip/libsofia-sip-ua/msg libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip libs/sofia-sip/libsofia-sip-ua/nea libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip libs/sofia-sip/libsofia-sip-ua/nta libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip libs/sofia-sip/libsofia-sip-ua/nth libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip libs/sofia-sip/libsofia-sip-ua/nua libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip libs/sofia-sip/libsofia-sip-ua/sdp libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip libs/sofia-sip/libsofia-sip-ua/sdp/tests libs/sofia-sip/libsofia-sip-ua/sip libs/sofia-sip/libsofia-sip-ua/sip/images libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip libs/sofia-sip/libsofia-sip-ua/sip/tests libs/sofia-sip/libsofia-sip-ua/soa libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip libs/sofia-sip/libsofia-sip-ua/sresolv libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip libs/sofia-sip/libsofia-sip-ua/stun libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip libs/sofia-sip/libsofia-sip-ua/su libs/sofia-sip/libsofia-sip-ua/su/sofia-sip libs/sofia-sip/libsofia-sip-ua/tport libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip libs/sofia-sip/libsofia-sip-ua/url libs/sofia-sip/libsofia-sip-ua/url/sofia-sip libs/sofia-sip/m4 libs/sofia-sip/packages libs/sofia-sip/scripts libs/sofia-sip/utils libs/sofia-sip/win32 libs/sofia-sip/win32/libsofia-sip-ua libs/sofia-sip/win32/libsofia-sip-ua-static libs/sofia-sip/win32/sofia-sip libs/sofia-sip/win32/tests libs/sofia-sip/win32/tests/test_htable libs/sofia-sip/win32/tests/test_memmem libs/sofia-sip/win32/tests/test_nta libs/sofia-sip/win32/tests/test_nua libs/sofia-sip/win32/tests/test_su libs/sofia-sip/win32/tests/test_tport libs/sofia-sip/win32/tests/torture_rbtree libs/sofia-sip/win32/tests/torture_su libs/sofia-sip/win32/tests/torture_su_alloc libs/sofia-sip/win32/tests/torture_su_bm libs/sofia-sip/win32/tests/torture_su_port libs/sofia-sip/win32/tests/torture_su_root libs/sofia-sip/win32/tests/torture_su_tag libs/sofia-sip/win32/tests/torture_su_time libs/sofia-sip/win32/tests/torture_su_timer libs/sofia-sip/win32/utils libs/sofia-sip/win32/utils/localinfo libs/sofia-sip/win32/utils/sip_dig libs/sofia-sip/win32/utils/sip_options libs/sofia-sip/win32/utils/sip_options_static libs/sofia-sip/win32/utils/stunc src/mod/endpoints/mod_sofia

Freeswitch SVN mikej at freeswitch.org
Thu Dec 21 01:30:40 EST 2006


Author: mikej
Date: Thu Dec 21 01:30:28 2006
New Revision: 3774

Added:
   freeswitch/trunk/libs/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/AUTHORS
   freeswitch/trunk/libs/sofia-sip/COPYING
   freeswitch/trunk/libs/sofia-sip/COPYRIGHTS
   freeswitch/trunk/libs/sofia-sip/ChangeLog
   freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees
   freeswitch/trunk/libs/sofia-sip/Makefile.am
   freeswitch/trunk/libs/sofia-sip/Makefile.in
   freeswitch/trunk/libs/sofia-sip/README
   freeswitch/trunk/libs/sofia-sip/README.developers
   freeswitch/trunk/libs/sofia-sip/RELEASE
   freeswitch/trunk/libs/sofia-sip/RELEASE.template
   freeswitch/trunk/libs/sofia-sip/TODO
   freeswitch/trunk/libs/sofia-sip/aclocal.m4
   freeswitch/trunk/libs/sofia-sip/autogen.sh
   freeswitch/trunk/libs/sofia-sip/compile   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/config.guess   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/config.h.in
   freeswitch/trunk/libs/sofia-sip/config.sub   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/configure   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/configure.ac
   freeswitch/trunk/libs/sofia-sip/depcomp   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/docs/
   freeswitch/trunk/libs/sofia-sip/docs/build_system.txt
   freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt
   freeswitch/trunk/libs/sofia-sip/docs/release_management.txt
   freeswitch/trunk/libs/sofia-sip/install-sh   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/   (props changed)
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h
   freeswitch/trunk/libs/sofia-sip/ltmain.sh   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/m4/
   freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4
   freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4
   freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4
   freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4
   freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4
   freeswitch/trunk/libs/sofia-sip/missing   (contents, props changed)
   freeswitch/trunk/libs/sofia-sip/packages/   (props changed)
   freeswitch/trunk/libs/sofia-sip/packages/ChangeLog
   freeswitch/trunk/libs/sofia-sip/packages/Makefile.am
   freeswitch/trunk/libs/sofia-sip/packages/Makefile.in
   freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in
   freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in
   freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in
   freeswitch/trunk/libs/sofia-sip/scripts/
   freeswitch/trunk/libs/sofia-sip/scripts/coverage
   freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip
   freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot
   freeswitch/trunk/libs/sofia-sip/utils/   (props changed)
   freeswitch/trunk/libs/sofia-sip/utils/ChangeLog
   freeswitch/trunk/libs/sofia-sip/utils/Doxyfile
   freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in
   freeswitch/trunk/libs/sofia-sip/utils/Makefile.am
   freeswitch/trunk/libs/sofia-sip/utils/Makefile.in
   freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h
   freeswitch/trunk/libs/sofia-sip/utils/sip-date.c
   freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c
   freeswitch/trunk/libs/sofia-sip/utils/sip-options.c
   freeswitch/trunk/libs/sofia-sip/win32/   (props changed)
   freeswitch/trunk/libs/sofia-sip/win32/ChangeLog
   freeswitch/trunk/libs/sofia-sip/win32/Makefile.am
   freeswitch/trunk/libs/sofia-sip/win32/Makefile.in
   freeswitch/trunk/libs/sofia-sip/win32/README.txt
   freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw
   freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd
   freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd
   freeswitch/trunk/libs/sofia-sip/win32/check.cmd
   freeswitch/trunk/libs/sofia-sip/win32/config.h.in
   freeswitch/trunk/libs/sofia-sip/win32/install.cmd
   freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/
   freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/
   freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
   freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp
   freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def
   freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/
   freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h
   freeswitch/trunk/libs/sofia-sip/win32/tests/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp
   freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/
   freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp
   freeswitch/trunk/libs/sofia-sip/win32/unistd.h
   freeswitch/trunk/libs/sofia-sip/win32/utils/
   freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/
   freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/
   freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp
   freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/
   freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp
   freeswitch/trunk/libs/sofia-sip/win32/version.awk
   freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd
Modified:
   freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile

Log:
add sofia-sip 1.12.4 (plus some patches through 12/21/2006) to in tree libs

Added: freeswitch/trunk/libs/sofia-sip/AUTHORS
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/AUTHORS	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+Current development team
+------------------------
+
+Pekka Pessi <pekka.pessi -at nokia -dot com>
+Martti Mela <martti.mela -at nokia -dot com>
+Kai Vehmanen <kai.vehmanen -at nokia -dot com>
+
+Contributors (in alphabetical order)
+------------------------------------
+
+Chan, Tat
+Haataja, Mikko
+Jacobs, Remeres
+Jalava, Teemu
+Jerris, Michael <mike -at jerris -dot com>
+Prado, Dimitri E. <dprado -at e3c -dot com -dot br>
+Puustinen, Ismo
+Rinne-Rahkola, Pasi
+Saari, Mika
+Selin, Jari
+Urpalainen, Jari

Added: freeswitch/trunk/libs/sofia-sip/COPYING
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/COPYING	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+

Added: freeswitch/trunk/libs/sofia-sip/COPYRIGHTS
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/COPYRIGHTS	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,223 @@
+This package contains the Sofia-SIP library.
+
+Copyright (C) 2005-2006 Nokia Corporation and others (see the 
+in individual files for a detailed list of copyright holders).
+
+Contact: Pekka Pessi <Pekka.Pessi at nokia.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License
+as published by the Free Software Foundation; either version 2.1 of
+the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License (LICENSE) for more details.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/inet_ntop.c
+
+The package also contains files licensed by Internet Software Consortium.
+These files are distributed with the following copyright notice:
+
+Copyright (c) 1996 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/inet_pton.c
+
+The package also contains files licensed by Internet Software Consortium and
+Internet Systems Consortium, Inc.. These files are distributed with the
+following copyright notice:
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996,1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
+libsofia-sip-ua/su/su_addrinfo.c
+
+The package also contains files licensed by WIDE Project. These files are
+distributed with the following copyright notice:
+
+Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the project nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/getopt.c
+
+The package also contains files licensed by IBM Corporation. These files are
+distributed with the following copyright notice:
+
+           This module contains code made available by IBM 
+           Corporation on an AS IS basis.  Any one receiving the 
+           module is considered to be licensed under IBM copyrights 
+           to use the IBM-provided source code in any way he or she 
+           deems fit, including copying it, compiling it, modifying 
+           it, and redistributing it, with or without 
+           modifications.  No license under any IBM patents or 
+           patent applications is to be implied from this copyright 
+           license. 
+
+           A user of the module should understand that IBM cannot 
+           provide technical support for the module and will not be 
+           responsible for any consequences of use of the program. 
+
+           Any notices, including this one, are not to be removed 
+           from the module without the prior written consent of 
+           IBM. 
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/su_md5.c
+
+The package also contains files written by Colin Plumb. These files are
+distributed with the following copyright notice:
+
+This code implements the MD5 message-digest algorithm. The algorithm is due
+to Ron Rivest. This code was initially 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.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/strtoull.c
+
+The package also contains files licensed by University of California and Sun
+Microsystems. These files are distributed with the following copyright
+notice:
+
+Copyright (c) 1988 The Regents of the University of California.
+Copyright (c) 1994 Sun Microsystems, Inc.
+
+The following license.terms for information on usage and redistribution
+of this individual file, and for a DISCLAIMER OF ALL WARRANTIES.
+ 
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.  The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license. 
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/ipt/rc4.c
+
+The package also contains files written by Pekka Pessi. These files are
+distributed with the following copyright notice:
+
+Copyright (c) 1996 Pekka Pessi. All rights reserved.
+
+This source code is provided for unrestricted use. Users may copy or
+modify this source code without charge.
+
+THIS SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
+INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
+PRACTICE.
+
+This source code is provided with no support and without any obligation
+on the part of author to assist in its use, correction, modification or
+enhancement.
+
+AUTHOR SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF
+COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE OR ANY PART
+THEREOF.
+
+In no event will author be liable for any lost revenue or profits or
+other special, indirect and consequential damages, even if author has
+been advised of the possibility of such damages.
+
+----------------------------------------------------------------------------

Added: freeswitch/trunk/libs/sofia-sip/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+===============================================================
+ChangeLog / Sofia-SIP - SIP User-Agent library
+===============================================================
+
+Sofia-SIP library ChangeLog files are available in the 
+following places:
+
+- per subdirectory ChangeLog files 
+    - all non-trivial changes to files (unless documented  
+      elsewhere)
+- version control system changelogs
+    - darcs and CVS tree repositories (see README.developers
+      for latest repository location information)
+- RELEASE files
+    - changes for the current version store in top-level
+      RELEASE files of the source tree
+    - old RELEASE files available at:
+      http://sofia-sip.sourceforge.net/relnotes/

Added: freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4578 @@
+2006-05-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Release 1.11.8.
+
+  * Updates for win32.
+  Added SOFIAPUBFUN to few functions in msg_parser().
+  Added new C++ wrappers for C files that need C++ linkage in tport_test.
+  Fixed setlocal braino in build_sources.cmd.
+
+  * Compiling and linking torture_su_bm and torture_su_port as static on win32.
+
+  * Added more warnings to ignore on VC to win32/config.h.in.
+
+  * Added files missing from dist to win32/Makefile.am
+
+  * Added msg_get_address() and msg_set_address() functions to <msg_addr.h>
+  Trying to solve ai_addrlen problem.
+
+  * Put last fixes into RELEASE file.
+
+  * Fixed binding problems in nua and nta.c.
+  Returning more appropriate error code from tport_tbind(), too.
+  This patch fixes tracked bugs 
+  #1485624 (nua not binding to 5060), 
+  #1485625 (nua_create() fails if STUN init fails) and 
+  #1485632 (ncorrect error message for nua bind error).
+  Nua now also binds both to NUTAG_URL and NUTAG_SIPS_URL() URIs, nua_create()
+  fails if binding either of them fails.
+
+  * Fixed msg_addrlen() usage.
+  
+  msg_addrlen() returns a pointer to ai_addrlen field of struct addrinfo
+  inside the msg_t object. ai_addrlen has type size_t. However, system calls
+  taking a return valur pointer to address length, use type socklen_t. 
+  Typically size_t is unsigned long, socklen_t is int, so casting
+  msg_addrlen() return value to (socklen_t *) will break on (high-endian)
+  64-bit platforms. svsp.
+
+  * Re-enable natify in test_nua.c.
+
+  * Updated nua_register() and NUTAG_OUTBOUND() documentation.
+  Taking NUTAG_OUTBOUND() options correctly into account in outbound.c.
+  Improved the contact validation process in outbound.c, too.
+
+  * Silenced warnings caused by mismatching integral types.
+  In nua_session, unsigned v. sip_time_t.
+  In tport.c, size_t v. socklen_t.
+
+  * Fixed socket semantics on test_nat.c for BSD, too.
+
+  * Fixed type of msg_addrlen() to size_t in msg_addr.h/msg.c.
+  POSIX socklen_t is not used in addrinfo. We use addrinfo.
+
+  * Added Changes to RELEASE.
+
+  * Fixed DIST_SUBDIRS at toplevel Makefile.am.
+
+  * Fixed AM_LDFLAGS in sresolv/Makefile.am.
+
+  * Not declaring inline functions with global scope in <sofia-sip/http_header.h>
+
+  * Added su_source_create() prototype to su-glib/so_source.c.
+
+2006-05-11  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added more info about outbound, gruu and win32 DLL to RELEASE.
+
+  * sres.c: storing last dot into the error record, too.
+  Bug reported by Thomas Rosenblatt.
+
+  * Added new files to dist, too.
+  - libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
+  - win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
+  - win32/tests/test_nua/test_nat_tags.cpp
+
+  * Now building libsofia_sip_ua.dll on win32.
+  
+  We define both IN_LIBSOFIA_SIP_UA and IN_LIBSOFIA_SRES in
+  libsofia_sip_ua.dsp.
+  
+  Because of DLL linkage, we compile tags typedefs as C++
+  (see win32/tests/test_nua/test_nat_tags.cpp).
+  
+  Removed LIBSOFIA_SIP_UA_STATIC from win32/sofia-sip/su_configure.h.
+  
+  Added libsofia_sip_ua_static.lib, too. If you want to compile against
+  that, you need define LIBSOFIA_SIP_UA_STATIC by yourself. 
+  
+  Added libsofia-sip-ua-static/libsofia_sip_ua_static.dsp.
+  
+  Using multithreaded DLL runtime for all projects.
+  
+  * Added SOFIAPUBFUN/SOFIAPUBVAR to stun module, too.
+
+  * Added test_nat_tags.c to nua module.
+
+  * Fixed a memory leak in nta_outgoing_mcreate().
+
+  * Added SRESPUBFUN and sres_config.h to sresolv module.
+
+  * Updated headers.
+  
+  Added sofia-sip/ prefix to documentation entries referring to include files.
+  
+  Added SOFIAPUBFUN and SOFIAPUBVAR to files that missed them.
+  
+  Removed some deprecated functions and macros.
+
+  * Avoid #include ordering problem with sip_parser.h in sip_test_msg.c, too.
+
+  * Silenced warnings in tport_type_tcp.c.
+
+  * Added @deprecated to deprecated sip functions.
+
+  * Moved ntlm functions to auth_ntlm.h from auth_plugin.h> in iptsec module.
+
+  * Reordered #includes in http module.
+  Avoid #include ordering problem with <sofia-sip/http_parser.h>.
+
+  * Removed utf8 and unicode-related stuff from library.
+  
+  Source files are still included in source tar.
+
+  * Reordered #includes in sip module.
+  Avoid #include ordering problem with sip_parser.h.
+
+  * Updated ADD-A-HEADER file in sip module.
+
+  * Added SOFIAPUBFUN and SOFIAPUBVAR to all public nua functions and variables.
+
+2006-05-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * nua/outbound.c: Adding Accept-Contact (a) to keepalive OPTIONS, too.
+  Just in case the message gets forwarded.
+
+  * Remove dependency to Makefile in targets for marshal file generation in nua_glib.
+
+  * Fixed includes in outbound.[hc].
+
+  * Added Doxyfiles to libsofia-sip-ua-glib. 
+  
+  Note that the files are not actually commented. 
+
+  * nua, soa: Adding Warnings to the response if appropriate.
+
+  * Refactored outbound code in nua module.
+  Added outbound.c, outbound.h.
+
+  * Added registration refresh tests to test_nua.c.
+  Added command line option --expensive and environment variable
+  EXPENSIVE_CHECKS, too.
+
+  * Updated refreshing of publications in nua_publish.c
+  Added nua_publish_usage_refresh(), nua_publish_usage_shutdown().
+
+  * Updated dialog usage refreshes.
+  Updated nua_dialog_usage_refresh(), nh_call_pending().
+
+  * Added expiration time settings to nua/test_proxy.[hc].
+  Added test_proxy_set_expiration() and test_proxy_get_expiration().
+
+  * Fixed timing problem when testing nat binding change.
+
+2006-05-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * nua_register.c: use nua-generated contact for refresh interval calculation.
+  Allow SIPS uris in contacts, too.
+
+  * nua_register.c: ignoring bad received parameters in Via header. 
+
+  * Updated config file handling in sresolv/sres.c. 
+  
+  Using reference counting with config structure when copying
+  resolver objects.
+  
+  Trying harder to avoid re-parsing resolv.conf and checking for
+  updated servers.
+  
+  Changed SRES_UPDATE_INTERVAL_SECS to 5 for non-WIN32 platforms.
+  
+  * su/su_alloc.c, su/sofia-sip/su_alloc.h: su_home_ref() takes const pointer.
+
+2006-05-08  kai.vehmanen at nokia.com
+
+  * Added sip_dig and stunc to VC6/win32 workspace file.
+
+  * Fixed sip_dig errors when building on VC6/win32.
+
+  * Fixed STUN bugs when build with VC6/win32.
+
+  * Updated STUN NAT type check interface to utilize current IETF BEHAVE terms.
+
+  * Print sofia-sip version in stunc usage.
+
+2006-05-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * url module: using SOFIAPUBFUN and SOFIAPUBVAR instead of URL_DLL.
+
+  * Fixed overflow problem with su_timer_run().
+  After 25 days the su_timer_run() timer started to misbehave,
+  1 < <31 milliseconds is bit more than 24 days, 20 hours, 31 minutes...
+
+2006-05-06  kai.vehmanen at nokia.com
+
+  * Pretty-print the NAT type check results with STUN stunc.
+
+  * Do not use resend when doing NAT type checking with STUN. The resends do not currently include the request attribute bytes as they should do.
+
+  * Minor mods to STUN module.
+
+  * Added optional local port randomization to stunc. Making repeated checks from the same local port will produce unreliable results.
+
+  * Fixed STUN's Test-IV.
+
+  * Added lots more documentation about the STUN nattype algorithm. Added a Test-IV step that is improved over the RFC3489 algorithm.
+
+  * Refactored the STUN nattype checks. There are still a few cases where the detection fails.
+
+  * Moved req-specific states to stun.c, moved stun_nattype_t to public header, added documentation to all stun enum fields.
+
+  * Removed deprecated STUN function definitions from stun.c.
+
+2006-05-05  kai.vehmanen at nokia.com
+
+  * Removed commented code segments.
+
+  * nua-glib: added bind URL and STUN server parameters for nua_glib_constructor()
+
+  * Fixed compiler warnings in stun.
+
+  * Removed various deprecated functions that were already commented out from the code. Closed sf.net bug #1456403.
+
+  * Fixed stunc argument parsing. It is now possible to given STUN server address as a hostname instead of requiring a dotted decimal IP-address.
+
+  * Always install auth_ntlm.h as it is needed by auth_client.h.
+
+2006-05-04  kai.vehmanen at nokia.com
+
+	* Updated developer docs w.r.t. VCS system. Darcs is now the
+	primary version control system and sf.net CVS is only used as a
+	backup.
+
+	* Fixed header paths and added missing libraries that caused
+	errors with debug/release builds.
+
+	* Added sip_options to the win32 SofiaSIP workspace.
+
+2006-05-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * sres_cache.c: fixed problem using macro as offsetof() argument.
+
+  * test_sresolv.v: added more tests for A6 record parsing.
+
+  * sres.c, sres_cache.c: records are now allocated in a single chunk.
+  
+  Bug hunted down by Thomas Rosenblatt: strings and domains belonging to
+  record were allocated from resolver home, not from cache home.
+  
+  * Fixed problem with config without search domains in sresolv/sres.c.
+
+  * Added information for COPYRIGHTS file to README.developers.
+
+  * Setting send buffer size to at least 64K in Windows in tport_type_tcp.c.
+
+  * Using SOFIAPUBFUN and SOFIAPUBVAR in bnf.h.
+
+  * Silenced sprious warnings by MSG_HEADER_INIT() in msg_header.h.
+
+  * NUTAG_KEEPALIVE() now uses milliseconds.
+  Changes in sofia-sip/nua_tag.h, nua_params.c, nua_register.c, test_nua.c.
+
+  * Renamed su_create_wait as su_wait_create in
+  libsofia-sip-ua-glib/su-glib/su_source_test.c
+
+  * stun/stun.c: s/su_destroy_timer/su_timer_destroy/.
+
+  * Added sofia-sip/auth_ntlm.h auth_ntlm.c to dist in iptsec module.
+
+  * Added license to Makefiles (kv)
+    
+  Added copyright lines and reference to LGPL license to the Makefile.am and
+  configure.ac files.
+
+  * poll_test.c: Renamed call s/su_create_wait/su_wait_create/. (kv)
+
+  * Added libsofia-sip-ua-glib/ChangeLog to darcs (kv)
+
+  * Added win32 registry name server discovery (kv)
+  
+  Based on a patch from Dimitri E. Prado.
+  Decreased update interval to 180secs (SRES_UPDATE_INTERVAL_SECS).
+
+2006-05-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Not using SU_MSG_RINITIALIZER anymore.
+
+	Fixed nta/nta.c, nth/nth_client.c, su/su_root.c.
+
+	* Added SOFIAPUBFUN and SOFIAPUBVAR to public include files in su
+	module.
+
+	* Not compiling tport_threadpool.c in win32.
+
+	* Updated documentation in sip/sip_util.c.
+
+	Updated sip_contact_create_from_via(),
+	sip_contact_string_from_via(), and
+	sip_contact_create_from_via_with_transport() documents.
+
+	* Added _sips._udp SRV records to sresolv/example.com zonefile.
+
+	Updated named.conf so it can be directly used to run bind.
+
+	* Added public prototype for tport_is_dgram() into
+	<sofia-sip/tport.h>.
+
+	* Added nta_outgoing_transport() to nta/nta.c and
+	<sofia-sip/nta_tport.h>.
+
+  * nua module:
+
+	* Improved keepalive timeout handling in nua/nua_register.c.
+
+	* Fixed double free in nua/nua_register.c.
+
+	Let nua_stack_process_response() take care of removing REGISTER
+	dialog usage.
+
+	* Checking for Max-Forwards header and its contents in
+	nua/test_proxy.c.
+
+	* Fixed STUN_ERROR() macro in <stun/stun_internal.h>.
+
+	* Fixed invalid check by nua_stack_init_instance() in
+	nua/nua_params.c.
+
+	* Updated nua/test_nua.c.
+
+	Using nat by default. Added --symmetric and -N options, enabling
+	symmetric nat and logging, respectively.
+
+	* Added tags to nua/test_nat.[hc].
+
+	TESTNATTAG_SYMMETRIC(1) enables symmetric nat.
+	TESTNATTAG_LOGGING(1) enables logging of nat binding changes.
+
+	* Updated outbound protocol engine in nua/nua_register.c
+
+	We enable rport and disable outbound by default. Fixed problem
+	when nat binding was changed. Fixed syntax error problems when
+	creating Accept-Contact header in OPTIONS request used to validate
+	registration.
+
+	* Added nua_generate_instance_identifier() to nua module.
+
+	* Changed default values in nua_params.c.
+
+	NUTAG_OUTBOUND() is "natify", and NUTAG_KEEPALIVE() is 120 seconds.
+
+	* Fixed nua/test_proxy.c.
+
+  	Registrar was not returning all contacts in 200 OK to response to
+	REGISTER.
+
+  * iptsec module:
+
+	* Added auc_copy_credentials().
+
+	Implementation in iptsec/auth_client.c, prototype in
+	<iptsec/sofia-sip/auth_client.h>. Replaced msg_param_t with char
+	const *, too.
+
+	* Added SOFIAPUBFUN to auth_struct_copy(), too.
+	
+  * iptsec module (by Martti Mela):
+
+	* ntlm support now compiles, not working.
+
+	* added auth_ntlm.[ch]
+
+	* more NTLM methods and header file auth_ntlm.h
+
+	* still more ifdefs for NTLM enabling
+
+	* added configure flag for enabling NTLM (disabled by default)
+
+	* fixed gssapidatas
+
+	* NTLM implementation continued.
+
+2006-05-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * iptsec module:
+
+	* Updated headers in iptsec module.
+	Added SOFIAPUBFUN and SOFIAPUBVAR where needed. 
+	Removed auc_with_uicc().
+
+	* Fixed memory management problems in iptsec module.
+	The authenticator client in auth_client.c leaked memory when
+	re-challenged. The client did not duplicate strings from
+	challenge, and tried to use freed values after challenge was
+	freed.
+	Now we are actually running the tests in test_auth_digest.c, too.
+	The problem was reported and patch submitted by Colin Whittaker.
+  
+  * sresolv module:
+
+	* Updated sresolv API.
+
+	Added sres_search() and sres_search_cached_answers() to the
+	sresolv API. Added sres_blocking_search(). Added ignore_cache
+	parameter to sres_blocking_query() and
+	sres_blocking_query_sockaddr() prototypes. Renumbered
+	SRES_TIMEOUT_ERR and SRES_RECORD_ERR so that they do not overlap
+	with transaction signature errors. Added sres_record_type().
+
+	* Updated sresolv documentation.
+
+	* Making cache threadsafe and locking it during sres_cache_store().
+  	Problem reported by Thomas Rosenblatt.
+
+	* Moved sip-dig from libsofia-sip-ua/sresolv/ to utils.
+
+	* Updated utils/sip-dig.c manpage and -p option handling.
+
+  * Added text about preloading and stack use to su/su_alloc.c.
+
+  * Fixed handle leaks in nua_test.c.
+  Added delay before nua_shutdown() in order to ease debugging.
+
+  * Fixed nua handle reference counting problems in nua module.
+  Problem reported by Colin Whittaker.
+
+  * Updated documentation of auc_authorize() in iptsec/auth_client.c.
+
+  * Added null pointer check to auc_authorize() in iptsec/auth_client.c.
+  Patch proposed by Colin Whittaker.
+
+  * Destroying session when initial INVITE is CANCELed.
+  Patch proposed by Colin Whittaker.
+
+2006-04-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * sresolv module:
+
+  	Added SRESTAG_CACHE() to <sofia-sip/sresolv.h>.
+
+  	Added ends0 and no-edns0 options in resolv.conf to sresolv/sres.c.
+
+  	Fixed sresolv #includes.
+  	Added #include <arpa/inet.h> and <fcntl.h> into sresolv/sres.c
+  	Added prerequisite #includes to sresolv files.
+
+    	Added @todo about cache poisoning. Updated sresolv documentation.
+
+	Fixed bugs in sresolv/sres_blocking.c.
+
+	Silenced printing spurious network errors in sresolv/sres.c.
+
+	Added sres_is_blocking() to sres_blocking.c. Updated
+	sres_resolver_get_async(), too.
+
+	Added sip-dig.c to sresolv module.
+
+  * tport module:
+
+  	Added missing "typedef" keyword to tport_pri_type_t in
+ 	sofia-sip/tport_tag.h
+
+	Fixed TPTAG_CONNECT() usage in tport/tport.c.
+
+	Now running some SCTP tests in test_tport.c
+
+ 	Updated tport_tls.c:
+	- Not requiring client certificate in tls.
+	- Tried to improve error handling, too.
+
+  	Now using stream-like sending semantics with SCTP.
+
+  	Updated datagram reception in tport_type_udp.c. We now avoid
+	peeking and fussing around with message size, and simply allocate
+	64K buffer, receive(), then reduce the buffer size.
+
+  	Updated tport_recv_stun_dgram() in tport_stub_stun.c. Now using
+	already received data within a msg_t.
+
+  	Updated SigComp interface in tport_stub_sigcomp.c and tport_sigcomp.c.
+
+  	Added a slot for stun handle to all primary transports.
+	Changed tport_primary_t in tport_internal.h, updated tport_type_stun.c.
+
+	Moved rest of the threadpool stuff into tport_threadpool.c.
+  	tport_threadpool.c does not work at the moment, disable it.
+
+  	Updated tport_connect() interface.
+
+	Calling tport_alloc_seconary() when client socket has been
+	created, making it possible to set socket options before
+	connecting the socket. Currently, this benefits SCTP and TLS. This
+	change affects tport_internal.h, tport.c, tport_type_sctp.c,
+	tport_type_tcp.c, and tport_type_tls.c.
+
+  	Added TPORT_DLL to tport_keepalive(), too.
+
+  	Added tport_ref() and tport_unref() to tport module.
+
+  	Fixed bug #1473936 in tport/tport.c. tport_primary_by_name() now
+	returns transports regardless of their protocol family if
+	tpn->tpn_host is not a literal IP address.
+
+  * msg module:
+
+	Updated msg_recv_buffer() prototype.
+
+  	Reclaiming the un-committed part of buffer in msg/msg_parser.c.
+	The allocation pattern for UDP has changed: now we allocate 64K,
+	then realloc to the actual size.
+
+  * nta module:
+
+  	Fixed bug #1472683 in nta/nta.c.
+	The rport parameter was missing from ACK.
+	The CANCEL had Via line with duplicate branch parameter.
+
+  	Fixed merge artifact in nta/test_nta_api.c.
+
+  	Always having NTATAG_SIGCOMP_OPTIONS() and storing its value.
+
+  * nua module:
+
+  	Added explicit check for NULL pointers to
+	unregister_expires_contacts().
+
+	Added missing events to nua.docs.
+
+	More fixes to nua/nua_publish.c. nua_unpublish uses tags from
+	initial nua_publish() 900 status is returned when there is no
+	Expires header in 2XX response to PUBLISH.
+
+	Re-indented nua_publish.c.
+
+	Added better error checking to nua_creq_msg().
+	Fixed Service-Route header processing, too.
+
+	Added nua_add_contact_by_aor() to nua_register.c. The
+	nua_add_contact_by_aor() takes care of adding other
+	registration-related headers like Service-Route, too.
+
+	Moved nua_publish() documentation from nua.c/nua.docs to
+	nua_publish.c. Updated documentation, added nua_r_unpublish
+	documentation.
+
+	Improved PUBLISH handling in nua/nua_publish.c. Saving the initial
+	PUBLISH message along with message body and content type. They are
+	re-used if 412 is received or if 2XX response contains Expires: 0.
+	If 2XX response is received without Expires header, we report
+	internal error to application.
+
+	Fixed route handling in SUBSCRIBE in the file nua/nua_subnotref.c.
+	There was a problem using dialog route set when there was an
+	initial route original SUBSCRIBE.
+
+  * Updated copyright year in sofia-footer.html.in.
+
+  * Fixed prototype of host_is_domain().
+
+  * Fixed doxygen warnings in su module.
+
+  * Updated sofia-sip.spec.in.
+  Separated glib library to sofia-sip-glib and sofia-sip-glib-devel packages.
+  Added sofia-sip-docs package.
+
+  * Added su_timer_set_interval() to su/su_timer.c and sofia-sip/su_wait.h.
+
+  * Defining __func__ in stun/stunc.c for the benefit of older C compilers.
+
+  * Removed // comments.
+
+2006-04-25  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added compilation and run-time checks for MSG_TRUNC.
+
+    M ./libsofia-sip-ua/tport/tport_internal.h -2 +3
+    M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+    M ./libsofia-sip-ua/tport/tport_type_udp.c -4 +34
+    M ./m4/sac-su2.m4 +5
+
+  * Fixed #includes in sresolv files.
+
+    M ./libsofia-sip-ua/sresolv/sres_blocking.c +2
+    M ./libsofia-sip-ua/sresolv/sres_cache.c +3
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c +9
+
+  * Fixed syntax error with G_DEFINE_TYPE(NuaGlib).
+
+    M ./libsofia-sip-ua-glib/nua-glib/nua_glib.c -1 +1
+
+  * Added --with sctp and --without glib to sofia-sip.spec.in.
+
+    M ./packages/sofia-sip.spec.in -3 +10
+
+  * Renumbered test case NUA-9.1.2 in test_nua.c
+
+    M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+2006-04-20  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Not trying to set up stun transport unless we have stun server configured.
+  Files: nua/nua_register.c.
+
+    M ./libsofia-sip-ua/nua/Makefile.am +1
+    M ./libsofia-sip-ua/nua/nua_register.c -6 +16
+
+  * Fixed auth-int authentication for INVITE requests.
+  Files: nua/nua_stack.c, nua/nua_session.c, iptsec/auth_client.c.
+
+    M ./libsofia-sip-ua/iptsec/auth_client.c +6
+    M ./libsofia-sip-ua/nua/nua_stack.c -4 +5
+
+  * Added outbound_connect_gruuize() - generate gruu from gruu paramter in our contact.
+  File: nua/nua_register.c.
+
+    M ./libsofia-sip-ua/nua/nua_register.c +53
+
+  * Added "SSL_VERIFY_PEER" environment variable.
+
+    M ./libsofia-sip-ua/tport/tport_tls.c -2 +2
+
+  * Restored SCTP in tport_type_sctp.c. Increased maximum message size to 64 K.
+
+    M ./libsofia-sip-ua/tport/tport_type_sctp.c -7 +7
+
+  * Using SSL_VERIFY_NONE - do not ask for client certificate.
+  It looks like openssl does not allow for client not to have certificate.
+
+    M ./libsofia-sip-ua/tport/tport_tls.c -1 +2
+
+  * More memory management problems in stun.
+
+    M ./libsofia-sip-ua/stun/stun_common.c -1 +1
+
+  * Fixed memory management problems in stun.
+
+    M ./libsofia-sip-ua/stun/stun.c -1
+
+  * Fixed blunder in error record creation.
+  sres_create_error_rr() in in sres.c.
+
+    M ./libsofia-sip-ua/sresolv/sres.c -2 +4
+
+  * Using outbound keepalive interval of 15 seconds.
+  outbound_connect_start_keepalive() in nua/nua_register.c
+
+    M ./libsofia-sip-ua/nua/nua_register.c -2 +1
+
+  * Added nta_agent_init_sigcomp() and nta_agent_deinit_sigcomp().
+
+    M ./libsofia-sip-ua/nta/nta.c -3 +28
+    M ./libsofia-sip-ua/nta/nta_internal.h -9 +21
+
+  * Renamed tport_try_accept_sigcomp() as tport_sigcomp_accept_incomplete().
+
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+    M ./libsofia-sip-ua/tport/tport_internal.h -1 +1
+    M ./libsofia-sip-ua/tport/tport_stub_sigcomp.c -1 +1
+
+  * Maded tport stun plugin pointer private.
+
+    M ./libsofia-sip-ua/tport/tport_stub_stun.c -2 +7
+
+  * Updated SCTP semantics to use "TCP".
+
+    M ./libsofia-sip-ua/tport/tport.c -3 +8
+    M ./libsofia-sip-ua/tport/tport_type_sctp.c -6 +20
+
+  * Fixed C++ compilation on <sres.h>.
+
+  * Fixed outbound problems.
+  Not unregistering contacts with instance-id and reg-id.
+  Avoiding crash when processing timeout responses.
+
+    M ./libsofia-sip-ua/nua/nua_register.c -16 +31
+
+  * Addeed --enable-sctp.
+
+    M ./m4/sac-tport.m4 -4 +6
+    M ./packages/sofia-sip.spec.in +1
+
+  * Updated compression interface in tport.
+  Added tport_compressor_t type, tport_delivered_with_comp().
+  Removed tpac_sigcomp_accept() and tport_delivered_using_udvm().
+
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h -10 +8
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_plugins.h -6 +93
+    M ./libsofia-sip-ua/tport/tport.c -24 +11
+    M ./libsofia-sip-ua/tport/tport_internal.h -15 +10
+    M ./libsofia-sip-ua/tport/tport_stub_sigcomp.c -114 +53
+
+  * Removed direct SigComp stuff from nta.c.
+  Added nta_compressor_vtable.
+
+    M ./libsofia-sip-ua/nta/nta.c -209 +100
+    M ./libsofia-sip-ua/nta/nta_internal.h +33
+
+  * Fixed aor/tport handling for sip/sips cases.
+
+    M ./libsofia-sip-ua/nua/nua_register.c -4 +13
+
+  * Disabled ntlm client for now.
+
+2006-04-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Removed - from ntlm variable names (mp)
+
+    M ./libsofia-sip-ua/iptsec/auth_module.c -11 +11
+    M ./libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h -1 +1
+
+  * Fixed --without-sigcomp (mp)
+
+    M ./m4/sac-tport.m4 -1 +1
+
+  * iptsec: started NTLM support (mm)
+
+    M ./libsofia-sip-ua/iptsec/auth_client.c +9
+    M ./libsofia-sip-ua/iptsec/auth_module.c +390
+    M ./libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h +7
+
+  * Changed internal nua error responses to use 9XX status codes.
+
+    M ./libsofia-sip-ua/nua/nua_event_server.c -9 +10
+    M ./libsofia-sip-ua/nua/nua_message.c -4 +4
+    M ./libsofia-sip-ua/nua/nua_options.c -3 +3
+    M ./libsofia-sip-ua/nua/nua_params.c -3 +3
+    M ./libsofia-sip-ua/nua/nua_publish.c -5 +5
+    M ./libsofia-sip-ua/nua/nua_register.c -6 +6
+    M ./libsofia-sip-ua/nua/nua_session.c -29 +30
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +4
+    M ./libsofia-sip-ua/nua/nua_stack.h -2 +2
+    M ./libsofia-sip-ua/nua/nua_subnotref.c -5 +7
+
+  * Added test for some of the internal errors.
+
+    M ./libsofia-sip-ua/nua/test_nua.c +138
+
+  * Fixed NTA API test for SigComp options (they are now always processed). 
+
+    M ./libsofia-sip-ua/nta/test_nta_api.c -8 +4
+
+  * Added missing #includes to sres.c.
+
+  * Removed experimental code enabling STUN.
+
+    M ./libsofia-sip-ua/tport/tport.c -5
+
+  * Added su_init()/su_deinit() here.
+
+    M ./libsofia-sip-ua/tport/test_tport.c -1 +5
+
+  * Removed some warnings (and fixed a bug) in encoding functions ofb stun_common.c
+
+    M ./libsofia-sip-ua/stun/stun_common.c -9 +11
+
+  * Removed stupid VC98 warning from tport_threadpool.c
+
+    M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+
+  * Added missing __func__ to tport_type_tcp and tport_threadpool.c.
+
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+    M ./libsofia-sip-ua/tport/tport_threadpool.c +7
+    M ./libsofia-sip-ua/tport/tport_type_tcp.c +7
+
+  * Added inlined IN6_IS_ADDR_LOOPBACK() to su_localinfo.c.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c +16
+
+  * Fixed pointer artithmetics by memccpy() in su_strcat_all().
+  (function in su/su_strdup.c).
+
+  * Added missing Winsock errors to <su_errno.h>
+
+  * Fixed address scoping error in stun_mini.c.
+
+  * Added missing __func__ to stun C files.
+
+  * Added things missing from win32 to new sresolv modules.
+
+    M ./libsofia-sip-ua/sresolv/sres.c -5 +35
+    M ./libsofia-sip-ua/sresolv/sres_blocking.c -4 +28
+    M ./libsofia-sip-ua/sresolv/sres_cache.c -1 +9
+
+  * Fixed C99ism in nua_register.c
+
+    M ./libsofia-sip-ua/nua/nua_register.c -1 +3
+
+  * Removed automatically generated file tport_tag_ref.c from version control system.
+
+    R ./libsofia-sip-ua/tport/tport_tag_ref.c
+
+2006-04-11  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+  Synchronizing CVS with darcs (other contributors pp = Pekka Pessi, 
+  mm = Martti Mela).
+
+  * NDEBUG oops. (pp)
+
+    M ./libsofia-sip-ua/sresolv/sres.c -1 +1
+
+  * Added sres_resolver_copy(). (pp)
+  Storing application-provided option strings in res_options.
+  Removed warnigns.
+
+    M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h +3
+    M ./libsofia-sip-ua/sresolv/sres.c -9 +90
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -1 +1
+
+  * Fixed stun miniserver (and stun stub in tport). (pp)
+
+    M ./libsofia-sip-ua/stun/stun_common.c -12 +7
+    M ./libsofia-sip-ua/stun/stun_mini.c -4 +4
+    M ./libsofia-sip-ua/tport/tport_stub_stun.c -1 +1
+
+  * Updated copyrights for nua-glib.
+
+    M ./COPYRIGHTS -1 +2
+    M ./libsofia-sip-ua-glib/nua-glib/nua_glib.c +2
+    M ./libsofia-sip-ua-glib/nua-glib/sofia-sip/nua_glib.h -1 +2
+
+  * Fixed segfault with stun_handle_destroy() on a NULL handle.
+
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +2
+
+  * Updated RELEASE. (pp)
+
+    M ./RELEASE -4 +13
+
+  * Disabled SIGCOMP until tport plugin is ready. (pp)
+  Handling sigcomp options regarless of HAVE_SIGCOMP value.
+
+    M ./libsofia-sip-ua/nta/nta.c -27 +30
+
+  * Added stun server and compression plugins. (pp)
+  Added TPORT_STUN_SERVER().
+  Having stun server dependencies in <tport_stub_stun.c>.
+  Moved sigcomp dependencies into <tport_stub_sigcomp.c>.
+
+    M ./libsofia-sip-ua/tport/Makefile.am -1 +3
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h -23 +15
+    A ./libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+    M ./libsofia-sip-ua/tport/test_tport.c -2 +3
+    M ./libsofia-sip-ua/tport/tport.c -136 +82
+    M ./libsofia-sip-ua/tport/tport_internal.h -35 +72
+    M ./libsofia-sip-ua/tport/tport_sigcomp.c -150 +193
+    A ./libsofia-sip-ua/tport/tport_stub_sigcomp.c
+    A ./libsofia-sip-ua/tport/tport_stub_stun.c
+    M ./libsofia-sip-ua/tport/tport_tag.c +1
+    M ./libsofia-sip-ua/tport/tport_tag_ref.c +3
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -3 +21
+    M ./libsofia-sip-ua/tport/tport_type_udp.c -144 +4
+
+  * http_add_tl() now accepts NULL http struct pointer. (pp)
+
+    M ./libsofia-sip-ua/http/http_tag_class.c -1 +3
+
+  * Update documentation of msg_copy() and msg_dup(). (pp)
+
+    M ./libsofia-sip-ua/msg/msg_header_copy.c -4 +7
+
+  * Removed some HAVE_SIGCOMP code. (pp)
+
+    M ./libsofia-sip-ua/nta/nta.c -42 +13
+    M ./libsofia-sip-ua/nta/nta_internal.h -9 +2
+
+  * Added su_sockaddr_scope(). (pp)
+  Using su_sockaddr_scope() in stun_mini.c.
+
+    M ./libsofia-sip-ua/stun/stun_mini.c -15 +38
+    M ./libsofia-sip-ua/su/sofia-sip/su_localinfo.h +3
+    M ./libsofia-sip-ua/su/su_localinfo.c -1 +18
+
+  * Fixed nat testing code. (pp)
+
+    M ./libsofia-sip-ua/nua/test_nat.c -4 +2
+    M ./libsofia-sip-ua/nua/test_nua.c +1
+
+  * Updated stack initialization. (pp)
+  Transports are initialized by nua_stack_init_transport() in nua_register.c.
+  UICC (you don't want to know) is initialized by nua_stack_set_from() in
+  nua_params.c.
+
+    M ./libsofia-sip-ua/nua/nua_params.c -4 +15
+    M ./libsofia-sip-ua/nua/nua_register.c -1 +70
+    M ./libsofia-sip-ua/nua/nua_stack.c -54 +18
+    M ./libsofia-sip-ua/nua/nua_stack.h -2 +4
+    M ./libsofia-sip-ua/nua/nua_tag.c -2
+    M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -7 +6
+
+  * Fixed su_root_run() usage in docs. (pp) 
+  Thanks for hint by Julio Auto.
+
+    M ./libsofia-sip-ua/nua/nua.docs -1 +1
+
+  * Fixed allocation bug. (pp)
+
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -4 +3
+
+  * Change version back to 1.11.7work.
+
+    M ./configure.ac -1 +1
+
+  * Changed outbound_connect_nat_detect() prototype. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_register.c -7 +11
+
+  * Removed obsoleted nua events. (pp)
+  
+  Removed nua events nua_i_media_event, nua_r_set_media_param,
+  nua_r_get_media_param, nua_r_media_setup, nua_r_media_describe,
+  nua_r_media_event, nua_i_announce, nua_i_describe, nua_i_get_parameter,
+  nua_i_pause, nua_i_options2, nua_i_play, nua_i_record, nua_i_set_parameter,
+  nua_i_setup, nua_i_teardown, nua_r_setup, nua_r_play, nua_r_record,
+  nua_r_pause, nua_r_describe, nua_r_teardown, nua_r_options2, nua_r_announce,
+  nua_r_get_parameter, and nua_r_set_parameter.
+  
+  Removed nua functions nua_announce(), nua_describe(), nua_get_media_param(),
+  nua_get_parameter(), nua_media_describe(), nua_media_event(),
+  nua_media_setup(), nua_options2(), nua_pause(), nua_play(), nua_record(),
+  nua_set_media_param(), nua_set_parameter(), nua_setup(), and nua_teardown(),
+
+    M ./libsofia-sip-ua/nua/sofia-sip/nua.h -33
+
+  * Moved preference/parameter setting/getting into its own nua_params.c module. (pp)
+
+    M ./libsofia-sip-ua/nua/Makefile.am +1
+    M ./libsofia-sip-ua/nua/nua.c -140
+    A ./libsofia-sip-ua/nua/nua_params.c
+    A ./libsofia-sip-ua/nua/nua_params.h
+    M ./libsofia-sip-ua/nua/nua_stack.c -661 +42
+    M ./libsofia-sip-ua/nua/nua_stack.h -125 +10
+    M ./libsofia-sip-ua/nua/nua_tag.c -6 +9
+    M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -24 +74
+    M ./libsofia-sip-ua/nua/test_nua.c -1 +24
+
+  * Removed obsoleted functions from nua. (pp)
+
+    M ./libsofia-sip-ua/nua/nua.c -110
+    M ./libsofia-sip-ua/nua/sofia-sip/nua.h -54
+
+  * Updated documentation in nua. (pp)
+
+    M ./libsofia-sip-ua/nua/Doxyfile -2 +2
+    M ./libsofia-sip-ua/nua/nua.c -68 +24
+    M ./libsofia-sip-ua/nua/nua.docs -27 +2
+    M ./libsofia-sip-ua/nua/nua_common.c -4 +4
+    M ./libsofia-sip-ua/nua/nua_dialog.c -12 +17
+    M ./libsofia-sip-ua/nua/nua_dialog.h -1 +1
+    M ./libsofia-sip-ua/nua/nua_event_server.c -14 +15
+    M ./libsofia-sip-ua/nua/nua_options.c -2 +2
+    M ./libsofia-sip-ua/nua/nua_register.c -22 +190
+    M ./libsofia-sip-ua/nua/nua_session.c -6 +7
+    M ./libsofia-sip-ua/nua/nua_stack.c -22 +31
+    M ./libsofia-sip-ua/nua/nua_stack.h -11 +1
+    M ./libsofia-sip-ua/nua/nua_subnotref.c -3 +3
+
+  * stun: fixed mem leaks with valgrind (mm)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +3
+    M ./libsofia-sip-ua/stun/stun.c -5 +50
+    M ./libsofia-sip-ua/stun/stun_common.c -12 +38
+    M ./libsofia-sip-ua/stun/stunc.c -8 +9
+
+  * changed tport to use stun_discovery_done instead of stun_bind_done (mm)
+
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +1
+
+  * removed stun_bind_ enums and replaced with stun_discovery_ scheisse (mm)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h +5
+    M ./libsofia-sip-ua/stun/stun.c -6 +8
+    M ./libsofia-sip-ua/stun/stunc.c -3 +4
+
+  * Added test for su_home_unref()ing a cloned home. (pp)
+
+    M ./libsofia-sip-ua/su/su_alloc_test.c -9 +13
+    M ./libsofia-sip-ua/su/su_strlst.c -2 +8
+
+  * Added new sresolv headers to packages. (pp)
+
+    M ./libsofia-sip-ua/sresolv/Makefile.am -1 +6
+    M ./packages/sofia-sip.spec.in +1
+
+  * Update version to 1.11.8work as per new release guidelines.
+
+    M ./configure.ac -1 +1
+
+  * Signal stun_error to the client if STUN DNS-SRV lookup is started but fails.
+
+    M ./libsofia-sip-ua/stun/stun.c -36 +41
+
+  * Fixed stun compilation.
+
+    M ./libsofia-sip-ua/stun/stun.c -3 +6
+
+  * Fixed operations on Transaction-ID. TID is a 128bit opaque value.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h +2
+    M ./libsofia-sip-ua/stun/stun.c -10 +8
+    M ./libsofia-sip-ua/stun/stun_common.c -2 +2
+
+  * Removed ssl headers from stun_common.h. Public headers should not have config.h dependent sections.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h -9
+    M ./libsofia-sip-ua/stun/stun_internal.h +9
+
+  * tls somehow works now (mm)
+
+    M ./libsofia-sip-ua/stun/stun.c -2 +5
+
+  * updated stunc with cool features & cleanup. Removed stun_request_t from public callbacks (mm)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -2
+    M ./libsofia-sip-ua/stun/stun.c -33 +69
+    M ./libsofia-sip-ua/stun/stun_internal.h +1
+    M ./libsofia-sip-ua/stun/stunc.c -99 +140
+
+  * Using HAVE_CONFIG_H. (pp)
+
+    M ./libsofia-sip-ua/stun/stun_common.c -2 +2
+
+  * Added test for <sys/select.h>. (pp)
+  Removed HAVE_SU_WAIT_H - nobody is using it anymore.
+
+    M ./m4/sac-su2.m4 -12 +4
+
+  * Updated win32/config.h.in. (pp)
+
+    M ./win32/config.h.in -7 +67
+
+  * Updated (for testing stun). (pp)
+
+    M ./libsofia-sip-ua/nua/test_nat.c -175 +183
+
+  * Added quick hack for using stun. (pp)
+
+    M ./libsofia-sip-ua/tport/tport.c +7
+
+  * Updated tport_stun_bind_done(). (pp)
+
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -11 +9
+
+  * No need to define HAVE_SU_WAIT_H. (pp)
+
+    M ./libsofia-sip-ua/stun/stun_dns.c -1
+
+  * Update documents. (pp)
+
+    M ./libsofia-sip-ua/sresolv/resolve_sip.c -1 +1
+    M ./libsofia-sip-ua/sresolv/sres.c -5 +9
+    M ./libsofia-sip-ua/sresolv/sres_blocking.c -4 +9
+    M ./libsofia-sip-ua/sresolv/sres_cache.c -4 +39
+    M ./libsofia-sip-ua/sresolv/sresolv.c +34
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +8
+
+  * stunc works, kikkelis kokkelis!! (mm)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +3
+    M ./libsofia-sip-ua/stun/stun.c -5 +19
+    M ./libsofia-sip-ua/stun/stunc.c -50 +169
+
+  * Added stun_mini_t. (pp)
+
+    M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +19
+    A ./libsofia-sip-ua/stun/stun_mini.c
+
+  * Updated stun todo-file in stun.docs.
+
+    M ./libsofia-sip-ua/stun/stun.docs -4 +1
+
+  * Also mark deprecated typedefs and defines.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -9 +9
+
+  * Adds interface to query active primary server address.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h +1
+    M ./libsofia-sip-ua/stun/stun.c -30 +39
+    M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+
+  * Minor update to STUN DNS-SRV interface.
+
+    M ./libsofia-sip-ua/stun/ChangeLog +4
+    M ./libsofia-sip-ua/stun/lookup_stun_server.c -17 +31
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -5 +4
+    M ./libsofia-sip-ua/stun/stun.c -3 +4
+    M ./libsofia-sip-ua/stun/stun_dns.c -34 +67
+
+  * Using updated tport_keepalive() prototype. (pp)
+
+    M ./libsofia-sip-ua/nta/nta.c -1 +2
+
+  * Added STUN tport. (pp)
+  Moved upnp stuff to its own file.
+
+    M ./libsofia-sip-ua/tport/Makefile.am -3 +3
+    M ./libsofia-sip-ua/tport/tport.c +1
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -422 +88
+
+  * Updated tport_keepalive() prototype.  (pp)
+  Implemented tport_is_updating(), added tport_has_been_updated().
+
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h -1 +2
+    M ./libsofia-sip-ua/tport/tport.c -8 +40
+    M ./libsofia-sip-ua/tport/tport_internal.h -5 +10
+    M ./libsofia-sip-ua/tport/tport_threadpool.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_connect.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_sctp.c -4 +4
+    M ./libsofia-sip-ua/tport/tport_type_tcp.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_tls.c -6 +6
+    M ./libsofia-sip-ua/tport/tport_type_udp.c -1 +1
+
+  * Removed torture_stun.c.
+
+    M ./libsofia-sip-ua/stun/Makefile.am -10 +1
+    R ./libsofia-sip-ua/stun/torture_stun.c
+
+  * Fix STUNTAG_DOMAIN with test_nattype and test_lifetime processes.
+
+    M ./libsofia-sip-ua/stun/stun.c -7 +28
+
+  * Renamed all get_nattype and get_lifetime functions and enums to test_nattype and test_lifetime.
+
+    M ./libsofia-sip-ua/stun/ChangeLog +4
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -14 +8
+    M ./libsofia-sip-ua/stun/stun.c -52 +30
+    M ./libsofia-sip-ua/stun/stunc.c -6 +9
+
+  * Moved deprecated functions at the end of stun.c. Fixed postponing shared-secret and bind discovery processes for DNS-SRV lookups.
+
+    M ./libsofia-sip-ua/stun/stun.c -159 +172
+
+  * stun_request_shared_secret() renamed to stun_obtain_shared_secret().
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +1
+
+  * stun.h: Deprecated stun_handle_release().
+
+    M ./libsofia-sip-ua/stun/ChangeLog -3 +4
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +2
+
+  * tag list stored for stun_obtain_shared_secret (mm)
+
+    M ./libsofia-sip-ua/stun/stun.c -1 +11
+
+  * non-compiling: need args for stun_obtain_shared_secret() (mm)
+
+    M ./libsofia-sip-ua/stun/stun.c -1 +1
+
+  * stun api upd's also for tls; tport (mm)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +14
+    M ./libsofia-sip-ua/stun/sofia-sip/stun_tag.h -4 +4
+    M ./libsofia-sip-ua/stun/stun.c -17 +150
+    M ./libsofia-sip-ua/stun/stun_common.c -3 +5
+    M ./libsofia-sip-ua/stun/stun_tag.c -8 +9
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -5 +5
+
+  * Removed separate virtual function for compression initialization. (pp)
+
+    M ./libsofia-sip-ua/tport/tport.c -3
+    M ./libsofia-sip-ua/tport/tport_internal.h -2
+    M ./libsofia-sip-ua/tport/tport_sigcomp.c -2
+    M ./libsofia-sip-ua/tport/tport_threadpool.c -1
+    M ./libsofia-sip-ua/tport/tport_type_connect.c -1
+    M ./libsofia-sip-ua/tport/tport_type_sctp.c -2
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -4 +3
+    M ./libsofia-sip-ua/tport/tport_type_tcp.c -2
+    M ./libsofia-sip-ua/tport/tport_type_tls.c -2
+    M ./libsofia-sip-ua/tport/tport_type_udp.c -2
+
+  * Added su_socket() wrapper function. (pp)
+
+    M ./libsofia-sip-ua/su/sofia-sip/su.h -2
+    M ./libsofia-sip-ua/su/su.c -6 +12
+
+  * Removee v-p from the vtable names. (pp)
+
+    M ./libsofia-sip-ua/tport/tport.c -20 +20
+    M ./libsofia-sip-ua/tport/tport_internal.h -11 +11
+    M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+    M ./libsofia-sip-ua/tport/tport_type_connect.c -4 +1
+    M ./libsofia-sip-ua/tport/tport_type_sctp.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +1
+    M ./libsofia-sip-ua/tport/tport_type_tcp.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_tls.c -2 +2
+    M ./libsofia-sip-ua/tport/tport_type_udp.c -2 +2
+
+  * Removed temp test program from sresolv. (pp)
+
+    M ./libsofia-sip-ua/sresolv/Makefile.am -2 +1
+
+  * Added 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa. (pp)
+
+    A ./libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+    M ./libsofia-sip-ua/sresolv/Makefile.am -1 +2
+
+  * Added notes to RELEASE. (pp)
+
+    M ./RELEASE +17
+
+  * Sanitized stun_common.[hc] slightly. (pp)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h -1 +1
+    M ./libsofia-sip-ua/stun/stun_common.c -45 +53
+
+  * Added notes about string and header manipulation function. (pp)
+
+    M! ./RELEASE -10
+
+  * Fixed problem with initial un-REGISTER by test_nua.c in test_proxy.c (pp)
+
+    M ./libsofia-sip-ua/nua/test_proxy.c -4 +7
+
+  * Fixed problems with updated API. Added sres_resolver_update().  (pp)
+
+    M ./libsofia-sip-ua/sresolv/Makefile.am -1 +2
+    M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -55 +21
+    A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
+    M ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -2 +3
+    M ./libsofia-sip-ua/sresolv/sres.c -17 +37
+    M ./libsofia-sip-ua/sresolv/sres_blocking.c +1
+    M ./libsofia-sip-ua/sresolv/sresolv.c -36 +52
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -2 +2
+
+  * Fixed AC_CHECK_HEADERS depending on <sys/socket.h>. (pp)
+
+    M ./m4/sac-su2.m4 -1 +3
+
+  * Fixed HAVE_SOCKADDR_LL in case we have <netpacket/packet.h>. (pp)
+
+    M ./libsofia-sip-ua/su/su_uniqueid.c -1 +1
+
+  * Fixed su_timer_set_for_ever(). (pp)
+
+    M ./libsofia-sip-ua/su/su_timer.c -6 +9
+
+  * Fixed stupid bug with su_home_desctructor(). (pp)
+
+    M ./libsofia-sip-ua/su/su_alloc.c +10
+    M ./libsofia-sip-ua/su/su_alloc_test.c -2 +13
+
+  * New API working with test program. (pp)
+
+    M ./libsofia-sip-ua/sresolv/Makefile.am -1 +1
+    M ./libsofia-sip-ua/sresolv/run_test_sresolv +5
+    M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -15 +62
+    M ./libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h -1 +1
+    M ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -14 +1
+    M ./libsofia-sip-ua/sresolv/sres.c -143 +237
+    A ./libsofia-sip-ua/sresolv/sres_blocking.c
+    M ./libsofia-sip-ua/sresolv/sres_cache.c -2 +2
+    M ./libsofia-sip-ua/sresolv/sresolv.c -56 +57
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -198 +117
+
+  * Initial change for multithreaded and synchronous resolver (pp)
+
+     ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -> ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h
+     ./libsofia-sip-ua/sresolv/sresolv.c -> ./libsofia-sip-ua/sresolv/sres.c
+    M ./libsofia-sip-ua/sresolv/Makefile.am -1 +1
+    A ./libsofia-sip-ua/sresolv/sofia-resolv/
+    M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -259 +90
+    A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
+    A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
+    A ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
+    M ./libsofia-sip-ua/sresolv/sres.c -1075 +852
+    A ./libsofia-sip-ua/sresolv/sres_cache.c
+    A ./libsofia-sip-ua/sresolv/sresolv.c
+    M ./libsofia-sip-ua/sresolv/sresolv.docs -7 +71
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -29 +20
+
+  * Fixed make top-level rules for manpage creation when doxygen is not installed.
+
+    M ./Makefile.am -1 +1
+
+  * Abort connect timer if socket connect() refused.
+
+    M ./libsofia-sip-ua/stun/stun.c -7 +5
+
+  * Updated nua_stack_tport_update(). (pp)
+
+    M ./libsofia-sip-ua/nua/nua_register.c -6 +6
+
+  * Renamed register_usage as outbound_connect. (pp)
+  Added tags NUTAG_OUTBOUND(), NUTAG_OUTBOUND_SET1(), NUTAG_OUTBOUND_SET2(),
+  NUTAG_OUTBOUND_SET3(), and NUTAG_OUTBOUND_SET4().
+
+    M ./libsofia-sip-ua/nua/nua_options.c -3 +4
+    M ./libsofia-sip-ua/nua/nua_register.c -363 +498
+    M ./libsofia-sip-ua/nua/nua_stack.c -3 +11
+    M ./libsofia-sip-ua/nua/nua_stack.h -10 +8
+    M ./libsofia-sip-ua/nua/nua_tag.c +6
+    M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h +110
+
+  * Added usage_peer_info method to dialog usage. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_dialog.c +6
+    M ./libsofia-sip-ua/nua/nua_dialog.h +3
+
+  * Added possibility to run tests with external proxy. (pp)
+
+    M ./libsofia-sip-ua/nua/test_nua.c -37 +98
+
+  * Added auth_status_init_with(), as_profile and as_alt_uri. (pp)
+
+    M ./libsofia-sip-ua/iptsec/auth_module.c -4 +16
+    M ./libsofia-sip-ua/iptsec/sofia-sip/auth_module.h -2 +12
+
+  * Fixed url_param(). (pp)
+
+    M ./libsofia-sip-ua/url/url.c -9 +18
+
+  * Use "_" instead of "+" in token64_e(). (pp)
+
+    M ./libsofia-sip-ua/ipt/token64.c -3 +3
+
+  * Added tport with HTTP CONNECT, too. (pp)
+
+    A ./libsofia-sip-ua/tport/tport_type_connect.c
+
+  * Split tport.c into multiple modules. (pp)
+  STUN, UPnP and SigComp still need some polishing. 
+
+    M ./libsofia-sip-ua/tport/Makefile.am -3 +7
+    M ./libsofia-sip-ua/tport/test_tport.c -13 +11
+    M ./libsofia-sip-ua/tport/tport.c -4114 +156
+    A ./libsofia-sip-ua/tport/tport_internal.h
+    A ./libsofia-sip-ua/tport/tport_logging.c
+    A ./libsofia-sip-ua/tport/tport_sigcomp.c
+    A ./libsofia-sip-ua/tport/tport_tag_ref.c
+    A ./libsofia-sip-ua/tport/tport_threadpool.c
+    A ./libsofia-sip-ua/tport/tport_type_sctp.c
+    A ./libsofia-sip-ua/tport/tport_type_stun.c
+    A ./libsofia-sip-ua/tport/tport_type_tcp.c
+    A ./libsofia-sip-ua/tport/tport_type_tls.c
+    A ./libsofia-sip-ua/tport/tport_type_udp.c
+
+  * Completed HTTP CONNECT.  (pp)
+  Added --http-proxy to sip-options.
+
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +1
+    M ./libsofia-sip-ua/tport/tport.c -11 +55
+    M ./utils/sip-options.c -1 +6
+
+  * Generating Contact from public vias if no local Vias are available. (pp)
+
+    M ./libsofia-sip-ua/nta/nta.c -3 +11
+
+  * Added HTTP CONNECT. (pp)
+
+    M ./libsofia-sip-ua/tport/tport.c -682 +981
+
+  * Added http to LDADD and INCLUDE. (pp)
+
+    M ./libsofia-sip-ua/nea/Makefile.am -1 +2
+    M ./libsofia-sip-ua/nta/Makefile.am +1
+    M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+    M ./libsofia-sip-ua/tport/Makefile.am +2
+
+  * Clean up timers upon destroy in stun.
+
+    M ./libsofia-sip-ua/stun/stun.c -9 +20
+
+  * Fixed typo in stun.
+
+    M ./libsofia-sip-ua/stun/stun.c -1 +1
+
+  * Adding Vias belonging to public transport to sa_public_vias list.
+  Now testing nta_agent_public_via(), too. (pp)
+
+    M ./libsofia-sip-ua/nta/Makefile.am +1
+    M ./libsofia-sip-ua/nta/nta.c -26 +63
+    M ./libsofia-sip-ua/nta/test_nta_api.c -1 +14
+
+  * Using tport_tcreate() instead of tport_create(). (pp)
+
+    M ./libsofia-sip-ua/nth/nth_client.c -1 +1
+
+  * Added vtables for transports. (pp)
+  API: tport_is_public().
+
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h -7 +3
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h -1 +14
+    M ./libsofia-sip-ua/tport/test_tport.c +7
+    M ./libsofia-sip-ua/tport/tport.c -1069 +1136
+    M ./libsofia-sip-ua/tport/tport_tls.c -43 +22
+
+  * STUN documentation update - no functional changes. (pp)
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -39 +31
+    M ./libsofia-sip-ua/stun/stun.c -26 +30
+
+  * Fixed bugs STUN DNS-SRV implementation. (pp)
+
+    M ./libsofia-sip-ua/stun/stun.c -20 +38
+
+  * restructured nat scheisse in tport, nta, nua. Lost weight for about 200 lines. (mm)
+
+    M ./libsofia-sip-ua/nta/nta.c -4
+    M ./libsofia-sip-ua/nua/nua_stack.c +4
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h +8
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+    M ./libsofia-sip-ua/tport/tport.c -62 +38
+    M ./libsofia-sip-ua/tport/tport_tag.c +1
+
+  * initial support for dynamic address changes for register (mm)
+
+    M ./libsofia-sip-ua/nua/nua_register.c +18
+    M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+    M ./libsofia-sip-ua/tport/tport.c -76 +136
+    M ./libsofia-sip-ua/tport/tport_tag.c +1
+
+  * updated RELEASE (pp)
+
+    M ./RELEASE +9
+
+  * Cleanup STUN headers.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -10 +3
+    M ./libsofia-sip-ua/stun/stun.c -1 +3
+    M ./libsofia-sip-ua/stun/stun_dns.c -1
+
+  * Added initial DNS-SRV lookup support to stun.
+
+    M ./libsofia-sip-ua/nth/Makefile.am +1
+    M ./libsofia-sip-ua/stun/Makefile.am +1
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -14 +17
+    M ./libsofia-sip-ua/stun/stun.c -82 +196
+    M ./libsofia-sip-ua/stun/stun_dns.c +9
+    M ./libsofia-sip-ua/tport/Makefile.am +1
+
+  * Add direct doxygen links to the public STUN APIs.
+
+    M ./libsofia-sip-ua/stun/stun.docs -4 +8
+
+  * The correct tcp service name for STUN server discovery is 'stun', not 'stun-tls'.
+
+    M ./libsofia-sip-ua/stun/lookup_stun_server.c -1 +1
+    M ./libsofia-sip-ua/stun/stun_dns.c -6 +6
+
+  * Fixed manpage generation rule to work with automake-1.8.5.
+
+    M ./Makefile.am -1 +1
+
+  * updated STUN API, tport-stun-http mods in progress (mm)
+
+    M ./libsofia-sip-ua/nta/nta.c -1 +1
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -24 +74
+    M ./libsofia-sip-ua/stun/stun.c -23 +101
+    M ./libsofia-sip-ua/stun/stunc.c -4 +4
+    M ./libsofia-sip-ua/tport/tport.c -30 +122
+
+  * Added STUNTAG_DOMAIN to suitable places. Added more doxygen documentation - especially considering tag params to functions.
+
+    M ./libsofia-sip-ua/stun/stun.c -7 +39
+
+  * Added STUN DNS-SRV functionality to stun module. A simple test app is also provided. This code is not yet used by other parts of the stun module.
+
+    M ./RELEASE +1
+    M ./libsofia-sip-ua/stun/Makefile.am -8 +5
+    A ./libsofia-sip-ua/stun/lookup_stun_server.c
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -3 +24
+    A ./libsofia-sip-ua/stun/stun_dns.c
+
+  * Updates to stun module doxygen documentation.
+
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -44 +31
+    M ./libsofia-sip-ua/stun/stun.c -15 +38
+
+  * async stun bind in tport, callback to NTA (mm)
+
+    M ./libsofia-sip-ua/nta/nta.c -8 +18
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h +24
+    M ./libsofia-sip-ua/stun/sofia-sip/stun_tag.h +5
+    M ./libsofia-sip-ua/stun/stun.c -31 +122
+    M ./libsofia-sip-ua/stun/stun_common.c -1
+    M ./libsofia-sip-ua/stun/stun_tag.c +19
+    M ./libsofia-sip-ua/stun/stunc.c -4 +4
+    M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+    M ./libsofia-sip-ua/tport/tport.c -78 +331
+
+  * Checking for re-registration upon nat binding change. (pp)
+
+    M ./libsofia-sip-ua/nua/test_nua.c -10 +66
+
+  * Added keepalive and probe OPTIONS to registration. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_options.c +3
+    M ./libsofia-sip-ua/nua/nua_register.c -309 +685
+    M ./libsofia-sip-ua/nua/nua_stack.h +6
+
+  * Removed warning. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_subnotref.c -1 +1
+
+  * Removing dialog usages when handle is being destroyed. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +7
+
+  * Added nua_dialog_usage_refresh() and nua_dialog_usage_public(). (pp)
+
+    M ./libsofia-sip-ua/nua/nua_dialog.c +15
+    M ./libsofia-sip-ua/nua/nua_dialog.h -2 +13
+
+  * Added test_nat_flush(). (pp)
+
+    M ./libsofia-sip-ua/nua/test_nat.c -14 +109
+    M ./libsofia-sip-ua/nua/test_nat.h +2
+
+  * Handling multiple bindings in test_proxy.c. (pp)
+
+    M ./libsofia-sip-ua/nua/test_proxy.c -46 +244
+
+  * Added nta_agent_bind_tport_update(), nta_agent_tport_is_updating() functions. (pp)
+  Added tport_is_updating(), too. Removed NTATAG_UPDATE_TPORT().
+
+    M ./libsofia-sip-ua/nta/nta.c -5 +19
+    M ./libsofia-sip-ua/nta/nta_internal.h +2
+    M ./libsofia-sip-ua/nta/nta_tag.c -1
+    M ./libsofia-sip-ua/nta/sofia-sip/nta_tag.h -9
+    M ./libsofia-sip-ua/nta/sofia-sip/nta_tport.h -1 +10
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h -2 +2
+    M ./libsofia-sip-ua/tport/tport.c +6
+
+  * Added nua_prack(). (pp)
+
+    M ./libsofia-sip-ua/nua/nua.c -9 +29
+
+  * Do not log error if su_timer_set() is called with NULL timer. (pp)
+
+    M ./libsofia-sip-ua/su/su_timer.c -3 +1
+
+  * Added su_task_execute(). (pp)
+
+    M ./libsofia-sip-ua/su/sofia-sip/su_wait.h +4
+    M ./libsofia-sip-ua/su/su_root.c +71
+
+  * Fixed event saving and handling. (pp)
+  Now we have a separate list for special events (nua_i_outbound).
+
+    M ./libsofia-sip-ua/nua/test_nua.c -304 +356
+
+  * Added nua_i_outbound. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_common.c +1
+    M ./libsofia-sip-ua/nua/sofia-sip/nua.h +2
+
+  * Deregistering wait events. (pp)
+
+    M ./libsofia-sip-ua/nua/test_nat.c -1 +8
+
+  * Mention Sofia-SIP User Agent Library instead Nokia UA Library in dox. (pp)
+
+    M ./libsofia-sip-ua/nua/nua.c -3 +3
+    M ./libsofia-sip-ua/nua/nua_dialog.h -1 +1
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+    M ./libsofia-sip-ua/nua/nua_stack.h -1 +1
+    M ./libsofia-sip-ua/nua/sofia-sip/nua.h -1 +2
+    M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -2 +2
+
+  * Fixed request line handling bug in nta_msg_request_complete(). (pp)
+
+    M ./libsofia-sip-ua/nta/nta.c -3 +9
+
+  * Using SOFIAPUBFUN in msg_header.h. Avoiding use of msg_param_t where possible. (pp)
+      
+  API CHANGE:
+  Allowing NULL as message public pointer (using default) in calls to
+  msg_serialize(), msg_header_add(), msg_header_prepend(),
+  msg_header_add_dup(), msg_header_add_dup_as(), msg_header_add_make(),
+  msg_header_add_str(), msg_header_insert(), msg_header_remove(), 
+  msg_header_remove_all(), and msg_header_replace().
+
+    M ./libsofia-sip-ua/msg/msg_parser.c -155 +182
+    M ./libsofia-sip-ua/msg/msg_parser_util.c -3 +3
+    M ./libsofia-sip-ua/msg/sofia-sip/msg_header.h -89 +138
+
+  * Added OPTIONS keepalive to nua_register.c. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_register.c -208 +526
+
+  * Added nta_default_leg(). (pp)
+
+    M ./libsofia-sip-ua/nta/nta.c +7
+    M ./libsofia-sip-ua/nta/sofia-sip/nta.h +2
+
+  * Added process_options() to test_proxy. (pp)
+
+    M ./libsofia-sip-ua/nua/test_proxy.c -28 +132
+
+  * Added nua_creq_save_restart() to nua_stack. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -20 +39
+    M ./libsofia-sip-ua/nua/nua_stack.h +6
+
+  * Added url_cmp_all(). (pp)
+
+    M ./libsofia-sip-ua/url/sofia-sip/url.h -1 +5
+    M ./libsofia-sip-ua/url/torture_url.c -3 +21
+    M ./libsofia-sip-ua/url/url.c -15 +177
+
+  * nua_dialog_store_peer_info() now optionally removes peer info. (pp)
+  If the SIP message given to nua_dialog_store_peer_info() is redirection
+  response, reset peer info.
+  
+
+    M ./libsofia-sip-ua/nua/nua_dialog.c +14
+
+  * Fixed bug in sip_transport_d() parsing different tls transports. (pp)
+  This bug affected mainly parsing futuristic Via headers.
+
+    M ./libsofia-sip-ua/sip/sip_parser.c -2 +3
+    M ./libsofia-sip-ua/sip/torture_sip.c +48
+
+  * Fixed sip_contact_string_from_via() (pp)
+
+    M ./libsofia-sip-ua/sip/sip_util.c -2 +2
+
+  * Registering successfully behind NAT. (pp)
+
+    M ./libsofia-sip-ua/nua/nua_register.c -125 +589
+    M ./libsofia-sip-ua/nua/nua_stack.c -121 +49
+    M ./libsofia-sip-ua/nua/nua_stack.h +6
+    M ./libsofia-sip-ua/nua/nua_subnotref.c -9 +10
+    M ./libsofia-sip-ua/nua/nua_tag.c +3
+    M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h +20
+
+  * Added sip_contact_string_from_via(), sip_transport_has_tls(). (pp)
+
+    M ./libsofia-sip-ua/sip/sip_basic.c -53 +1
+    M ./libsofia-sip-ua/sip/sip_util.c -37 +133
+    M ./libsofia-sip-ua/sip/sofia-sip/sip_util.h +11
+
+2006-03-16  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  Synchronizing CVS with darcs.
+	
+  * Fixed lib-sofia-sip-ua-glib Makefile.ams.
+  Tried to sanitize glib-less compilation.
+
+    M ./Makefile.am -2 +6
+    M ./libsofia-sip-ua-glib/Makefile.am -12 +4
+    M ./libsofia-sip-ua-glib/nua-glib/Makefile.am -2
+
+  * Added host_has_domain_invalid().
+
+    M ./libsofia-sip-ua/bnf/bnf.c -3 +23
+    M ./libsofia-sip-ua/bnf/sofia-sip/hostdomain.h +1
+    M ./libsofia-sip-ua/bnf/torture_bnf.c +18
+
+  * More string manipulation functions
+  Added:
+  - su_strcat_all()
+  - su_slprintf(), su_slvprintf()
+  - su_strlst_create_with(), su_strlst_vcreate_with()
+  - su_strlst_create_with_dup(), su_strlst_vcreate_with_dup()
+
+    M ./libsofia-sip-ua/su/sofia-sip/su_alloc.h -1 +4
+    M ./libsofia-sip-ua/su/sofia-sip/su_strlst.h -1 +23
+    M ./libsofia-sip-ua/su/su_alloc_test.c -32 +74
+    M ./libsofia-sip-ua/su/su_sprintf.c -1 +1
+    M ./libsofia-sip-ua/su/su_strdup.c -6 +53
+    M ./libsofia-sip-ua/su/su_strlst.c -23 +197
+
+  * Binding the endpoint behind "nat" to both IP families, if possible.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -3 +13
+
+  * Removed nutag_media_subsystem and nutag_media_session.
+
+    M ./libsofia-sip-ua/nua/nua_tag.c -3
+
+  * Using nua_500_error.
+
+    M ./libsofia-sip-ua/nua/nua_event_server.c -2 +2
+
+  * Allowing intending of #include directives in fix-include-sofia-sip.
+
+    M ./scripts/fix-include-sofia-sip -197 +197
+
+2006-03-13  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Release 1.11.7
+
+  * Synchronized CVS with darcs.
+
+  * Added man pages to dist.
+
+  * Updated libsofia-sip-ua-glib dist targets.
+
+    M ./libsofia-sip-ua-glib/Makefile.am -2 +4
+    M ./libsofia-sip-ua-glib/nua-glib/Makefile.am -26 +25
+    M ./libsofia-sip-ua-glib/su-glib/Makefile.am -2 +6
+    M ./libsofia-sip-ua/sofia.am -1 +1
+
+  * Removed warnings on 64bit platforms.
+
+    M ./libsofia-sip-ua/soa/soa.c -3 +3
+    M ./libsofia-sip-ua/stun/stun_common.c -8 +19
+    M ./libsofia-sip-ua/su/su_timer_test.c -2 +1
+
+  * Added missing files to dist.
+
+    M ./libsofia-sip-ua/bnf/Makefile.am -1 +1
+    M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+
+  * Using alarm() with su_test.c.
+
+  * Fixed hc_print usage in msg_header_prepare().
+  Some headers use snprintf() which may return -1 on some platforms if 
+  buffer is too small.
+
+  * Fixed problems in test_nua on win32.
+
+  * Fixed problem of using destroying registered handle in su_root.
+  This is a bug showing only in win32.
+
+  * Cleaning ACK transactions in test_proxy
+
+  * Fixed source file building rules for GNU make >= 3.80.
+  The way VPATH is handled and $@ expands has changed between GNU make 3.79
+  and 3.80.
+
+    M ./libsofia-sip-ua/http/Makefile.am -6 +14
+    M ./libsofia-sip-ua/msg/Makefile.am -13 +13
+    M ./libsofia-sip-ua/sip/Makefile.am -7 +18
+    M ./libsofia-sip-ua/sofia.am -1 +1
+
+  * Using sofia-sip/su_errno.h for error codes not present in win32.
+
+    M ./libsofia-sip-ua/msg/msg_mime.c -6 +1
+    M ./libsofia-sip-ua/msg/msg_parser.c -4
+    M ./libsofia-sip-ua/soa/soa.c -8 +1
+    M ./libsofia-sip-ua/su/sofia-sip/su_errno.h +36
+    M ./libsofia-sip-ua/su/su_errno.c -6 +22
+    M ./win32/sofia-sip/su_configure.h -7
+
+  * Fixed problems with nua timers.
+
+    M ./libsofia-sip-ua/nua/nua_dialog.c -2 +2
+    M ./libsofia-sip-ua/nua/nua_session.c -3 +7
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+2006-03-13  Martti Mela  <martti.mela at nokia.com>
+	
+  * win32 defs, compiles and installs in mingw environment
+
+2006-03-09  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+  * Synchronized darcs and CVS. 
+	
+  * Added missing su_source_test.c file.
+
+    A ./libsofia-sip-ua-glib/su-glib/su_source_test.c
+
+  * Added missing Makefile.am for su-glib.
+
+    A ./libsofia-sip-ua-glib/su-glib/Makefile.am
+
+  * Modified Makefile.ams to correctly build the new glib library.
+
+    M ./configure.ac +4
+    A ./libsofia-sip-ua-glib/Makefile.am
+
+  * Added sofia-sip-ua-glib to the packaging files.
+
+    M ./packages/Makefile.am -2 +2
+    A ./packages/sofia-sip-ua-glib.pc.in
+    M ./packages/sofia-sip-ua.pc.in -2 +2
+    M ./packages/sofia-sip.spec.in -4 +7
+
+  * Added nua-glib module to the tree.
+
+    A ./libsofia-sip-ua-glib/nua-glib/
+    A ./libsofia-sip-ua-glib/nua-glib/Doxyfile
+    A ./libsofia-sip-ua-glib/nua-glib/Makefile.am
+    A ./libsofia-sip-ua-glib/nua-glib/nua_glib.c
+    A ./libsofia-sip-ua-glib/nua-glib/nua_glib.docs
+    A ./libsofia-sip-ua-glib/nua-glib/nua_glib_marshal.list
+    A ./libsofia-sip-ua-glib/nua-glib/sofia-sip/
+    A ./libsofia-sip-ua-glib/nua-glib/sofia-sip/nua_glib.h
+    A ./libsofia-sip-ua-glib/nua-glib/test_nua_glib.c
+
+  * Moved glib stuff from libsofia-sip-ua to libsofia-sip-ua-glib.
+
+     ./libsofia-sip-ua/su/su_source.c -> ./libsofia-sip-ua-glib/su-glib/su_source.c
+     ./libsofia-sip-ua/su/sofia-sip/su_source.h -> ./libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
+    A ./libsofia-sip-ua-glib/su-glib/
+    A ./libsofia-sip-ua-glib/su-glib/sofia-sip/
+    M ./libsofia-sip-ua-glib/su-glib/su_source.c -1 +3
+    M ./libsofia-sip-ua/Makefile.am -1
+    M ./libsofia-sip-ua/su/Makefile.am -10 +7
+    M ./libsofia-sip-ua/su/sofia-sip/su_configure.h.in -2
+    M ./libsofia-sip-ua/su/su_root_test.c -4
+    M ./libsofia-sip-ua/su/su_test.c -18 +2
+    M ./m4/sac-su2.m4 -5 +9
+
+  * Created libsofia-sip-ua-glib.
+
+    M ./Makefile.am -1 +1
+    A ./libsofia-sip-ua-glib/
+
+2006-03-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated globally unique identifier (uuid) generation.
+  Using getifaddrs() and /dev/urandom. Added checks for /dev/urandom
+  and <netpacket/packet.h> (for link-level addresses).
+
+    M ./configure.ac -13 +5
+    M ./libsofia-sip-ua/su/sofia-sip/su_uniqueid.h +3
+    M ./libsofia-sip-ua/su/su_uniqueid.c -15 +91
+    M ./m4/sac-general.m4 +16
+    M ./m4/sac-su2.m4 -1 +1
+
+  * Cache checked functions a bit more efficiently in sac-su2.m4.
+
+    M ./m4/sac-su2.m4 -25 +28
+
+  * Added sip_via_port().
+
+    M ./libsofia-sip-ua/nta/nta.c -15 +1
+    M ./libsofia-sip-ua/sip/sip_basic.c +38
+    M ./libsofia-sip-ua/sip/sofia-sip/sip_header.h -1 +4
+
+  * Using sofia-sip/sofia_features.h.
+
+    M ./libsofia-sip-ua/features/features.c -1 +1
+
+  * Using nua_owner_t instead of nua_handle_t with <nua_dialog.h>.
+  Prepare to move nua_dialog.[hc] to nta or to its own module.
+
+    M ./libsofia-sip-ua/nua/nua_dialog.c -114 +75
+    M ./libsofia-sip-ua/nua/nua_dialog.h -28 +19
+    M ./libsofia-sip-ua/nua/nua_register.c -1 +1
+    M ./libsofia-sip-ua/nua/nua_session.c -7 +8
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+    M ./libsofia-sip-ua/nua/nua_stack.h -5 +5
+    M ./libsofia-sip-ua/nua/nua_subnotref.c -10 +10
+
+  * Added fake "nat" to test_nua
+
+    M ./libsofia-sip-ua/nua/Makefile.am -1 +2
+    A ./libsofia-sip-ua/nua/test_nat.c
+    A ./libsofia-sip-ua/nua/test_nat.h
+    M ./libsofia-sip-ua/nua/test_nua.c -30 +242
+
+  * Removed spurious message when sofia-sip subdirectory is recreated.
+
+    M ./libsofia-sip-ua/http/Makefile.am -1 +1
+    M ./libsofia-sip-ua/msg/Makefile.am -2 +2
+    M ./libsofia-sip-ua/sip/Makefile.am -1 +1
+
+2006-03-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Renamed sofia-sip/features.h as sofia-sip/sofia_features.h.
+
+    M ./RELEASE +3
+    M ./configure.ac -1 +1
+    M ./libsofia-sip-ua/features/Makefile.am -1 +1
+    M ./libsofia-sip-ua/features/sofia-sip/features.h.in -2 +4
+    M ./scripts/fix-include-sofia-sip -2 +5
+
+  * Generating man pages in $(srcdir).
+
+    M ./Makefile.am -5 +3
+
+  * Split nua_stack.c into multiple files.
+
+    M ./libsofia-sip-ua/nua/Makefile.am +6
+    M ./libsofia-sip-ua/nua/nua.c -52 +13
+    A ./libsofia-sip-ua/nua/nua_dialog.c
+    A ./libsofia-sip-ua/nua/nua_dialog.h
+    A ./libsofia-sip-ua/nua/nua_event_server.c
+    A ./libsofia-sip-ua/nua/nua_message.c
+    A ./libsofia-sip-ua/nua/nua_options.c
+    A ./libsofia-sip-ua/nua/nua_publish.c
+    A ./libsofia-sip-ua/nua/nua_register.c
+    A ./libsofia-sip-ua/nua/nua_session.c
+    M ./libsofia-sip-ua/nua/nua_stack.c -5026 +177
+    M ./libsofia-sip-ua/nua/nua_stack.h -125 +166
+    A ./libsofia-sip-ua/nua/nua_subnotref.c
+    A ./libsofia-sip-ua/nua/nua_tag_ref.c
+
+  * Added nta_check_*() functions.
+
+    M ./libsofia-sip-ua/nta/Makefile.am -1 +1
+    A ./libsofia-sip-ua/nta/nta_check.c
+    M ./libsofia-sip-ua/nta/sofia-sip/nta.h +26
+
+  * msg_parser.awk was printing spurious errors by SIP-ETag header etc.
+
+  * Removed doxygen crud from <sofia-sip/sl_utils.h>.
+
+  * Added SIPS_DEFAULT_PORT and SIPS_DEFAULT_SERV.
+
+    M ./libsofia-sip-ua/sip/sofia-sip/sip.h -1 +7
+
+  * Removed redundant reference to <sl_utils.h>.
+
+    M ./libsofia-sip-ua/nea/nea.c -2
+    M ./libsofia-sip-ua/nea/nea_server.c -1
+
+  * Added some error checking to the win32 autogen scripts.
+
+    M ./win32/Makefile.am -1 +1
+    M ./win32/autogen.cmd -2 +4
+    M ./win32/build_sources.cmd -22 +53
+    M ./win32/version_files.cmd +1
+
+2006-03-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Do not use glib upon --without-glib-dir or --without-glib in configure.
+
+    M ./m4/sac-su2.m4 -4 +4
+
+  * Returning unparsed remote SDP in SOATAG_REMOTE_SDP_STR()
+
+    M ./libsofia-sip-ua/soa/soa.c -2 +2
+
+  * Using SU_HAVE_PTHREADS to check for pthread support in nua_stack.h
+
+    M ./libsofia-sip-ua/nua/nua_stack.h -1 +5
+
+  * Fixed documentation problems.
+
+    M ./Makefile.am -2 +3
+    M ./utils/sip-date.c -2 +2
+
+  * Fixed problems when there is no stun available.
+
+    M ./libsofia-sip-ua/tport/tport.c -9 +5
+
+  * Fixed BDSSOCK checks in sac-su2.m4.
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c -1 +1
+    M ./m4/sac-su2.m4 -55 +73
+
+  * Using int as SOATAG_AF() value.
+
+    M ./libsofia-sip-ua/soa/sofia-sip/soa_tag.h -2 +2
+    M ./libsofia-sip-ua/soa/test_soa.c -1 +1
+
+2006-03-03  Martti Mela  martti.mela at nokia.com
+
+  * mingw support
+
+    M ./configure.ac -3 +5
+    M ./libsofia-sip-ua/stun/Makefile.am -4 +4
+    M ./libsofia-sip-ua/su/sofia-sip/su_addrinfo.h +11
+    M ./libsofia-sip-ua/su/su_addrinfo.c +9
+    M ./m4/sac-general.m4 +1
+    M ./m4/sac-su2.m4 -1 +9
+
+  * mingw mods
+
+    M ./configure.ac -1 +2
+    M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+    M ./libsofia-sip-ua/stun/stun.c -3 +34
+    M ./libsofia-sip-ua/stun/stun_common.c +10
+    M ./libsofia-sip-ua/su/su_addrinfo.c -6 +2
+    M ./libsofia-sip-ua/su/su_source.c -1 +5
+    M ./libsofia-sip-ua/su/su_time0.c -1 +7
+    M ./libsofia-sip-ua/tport/tport.c -4 +8
+    M ./m4/sac-general.m4 +30
+    M ./m4/sac-su2.m4 -31 +72
+    M ./packages/sofia-sip.spec.in -1 +1
+
+2006-03-01  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Synchronized darcs and CVS. 
+	
+  * Added utils/Doxyfile
+
+    A ./utils/Doxyfile
+
+  * Changed output from localinfo so that emacs is not fooled anymore.
+
+    M ./libsofia-sip-ua/su/run_addrinfo -1 +1
+    M ./libsofia-sip-ua/su/run_localinfo -1 +1
+
+  * Added SU_ADDRLEN() macro.
+
+    M ./libsofia-sip-ua/su/sofia-sip/su.h +16
+
+  * Not creating sofia-sip when building sip_parser_table.c
+
+    M ./libsofia-sip-ua/sip/Makefile.am -1
+
+  * Printing warning message if resolv.conf nameserver address is IPv6.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -4 +5
+
+  * Fixed problems with sa_len in nth_test.c.
+  Added explicit su_wait() to to send_request().
+
+    M ./libsofia-sip-ua/nth/nth_test.c -2 +8
+
+  * Disabling IPv6 resolving in nta test. Not reying in ICMP in nta test.
+
+    M ./libsofia-sip-ua/nta/run_test_nta -1 +2
+    M ./libsofia-sip-ua/nta/test_nta.c -2 +15
+
+  * Fixed problem of BSD awk returning -0 from 10 % 5.
+
+    M ./libsofia-sip-ua/msg/msg_parser.awk -1 +3
+
+  * Fixed problems in stun/tport.
+
+    M ./libsofia-sip-ua/stun/stun.c +3
+    M ./libsofia-sip-ua/tport/tport.c -9 +12
+
+  * Fixed signedness problem in msg_date_d().
+
+    M ./libsofia-sip-ua/msg/msg_date.c -2 +3
+
+  * Fixed url_cmp() crashing with invalid URLs.
+
+    M ./libsofia-sip-ua/url/sofia-sip/url.h -2 +3
+    M ./libsofia-sip-ua/url/url.c -2 +6
+
+  * Removed warnings on BSDish systems.
+
+    M ./libsofia-sip-ua/su/su.c -2 +2
+
+  * Added tests for getifaddrs(), using it in su_localinfo.c.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c -40 +161
+    M ./libsofia-sip-ua/su/su_port.c +2
+    M ./m4/sac-su2.m4 -11 +8
+
+  * Fixed typo in utils/sip-date.c
+
+    M ./utils/sip-date.c -1 +1
+
+  * Defining missing SOL_TCP.
+
+    M ./libsofia-sip-ua/stun/stun.c +5
+
+  * Fixed A6 record handling, sa_len usage.
+  Removed some warnings, too. Disabled IN6 nameservers for the moment.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -15 +20
+
+  * Disabled a badly designed test failing in BSD systems.
+
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -1 +16
+
+  * Removed debugging feature from msg_parser.awk making it fail with BSD awk.
+
+    M ./libsofia-sip-ua/msg/msg_parser.awk -36 +36
+
+  * Using default sip and sips port in url comparisons if url has IP address
+
+    M ./libsofia-sip-ua/url/torture_url.c +26
+    M ./libsofia-sip-ua/url/url.c +4
+
+2006-02-20 martti.mela at nokia.com
+
+  * stun: initial keepalive support
+
+    M ./libsofia-sip-ua/nta/nta.c +10
+    M ./libsofia-sip-ua/nta/sofia-sip/nta.h +2
+    M ./libsofia-sip-ua/nua/nua_stack.c +4
+    M ./libsofia-sip-ua/stun/ChangeLog +31
+    M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +11
+    M ./libsofia-sip-ua/stun/stun.c -79 +219
+    M ./libsofia-sip-ua/stun/stun_internal.h -1
+    M ./libsofia-sip-ua/tport/sofia-sip/tport.h +3
+    M ./libsofia-sip-ua/tport/tport.c -1 +90
+
+  * stun: dst addr improvements
+
+    M! ./libsofia-sip-ua/stun/ChangeLog -18
+    M! ./libsofia-sip-ua/stun/stun.c -7 +16
+
+2006-02-20  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * If opaque is not given, do not include it in challenge (auth_module.c).
+
+    M ./libsofia-sip-ua/iptsec/auth_module.c -2 +4
+
+  * Generating man pages for utilities.
+
+    M ./Makefile.am -4 +22
+    M ./configure.ac +3
+    M ./libsofia-sip-ua/su/Doxyfile -3 +1
+    M ./libsofia-sip-ua/su/addrinfo.c -29 +24
+    M ./libsofia-sip-ua/su/localinfo.c -35 +29
+    M ./utils/Makefile.am +3
+    M ./utils/sip-date.c -44 +34
+    M ./utils/sip-options.c -30 +42
+
+  * Including <unistd.h> for getpid() in test_nta.c.
+
+  * Added install script.
+
+    A ./win32/install.cmd
+    M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -4 +4
+
+  * Simplified use of sofia-sip/su_configure.h in win32
+
+     ./win32/su_configure_win32.h -> ./win32/sofia-sip/su_configure.h
+    M ./win32/autogen.cmd -4 +3
+    A ./win32/sofia-sip/
+
+  * Fixed tests of unsigned tag values in test_nua.c
+  Tests pass now on amd64, too.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -4 +4
+
+2006-02-15  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Release 1.11.6.
+	
+  * Fixed problems in doxygen documentation and dist.
+
+  * Updated PRACK and nta_outgoing_prack().
+
+  nta_outgoing_prack() accepts now RSeq sequence numbers in NTATAG_RSEQ().
+  When PRACK is sent using nta_outgoing_tmcreate(), there is functions
+  nta_outgoing_setrseq() and nta_outgoing_rseq() for updating the rseq number
+  within transaction.
+
+  * Corrected su_torture.c, Shutdown semantics differ on WINSOCK/BSDSOCK.
+
+  * Fixed su_wait() with 0 wait objects in windows.
+
+  * Fixed win32-compatibility problems in test programs.
+
+  * Not using NULL restart pointer in ua_authenticate().
+
+2006-02-14  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed problems with sofia-sip/ header prefix in win32.
+
+  * Fixed win32/VC configuration problems.
+
+  * Fixed win32 pthread dist.
+
+  * Fixed include paths.
+
+  * Use #include <sofia-sip/su_tag_class.h>.
+
+  * Be explicit with input when generating source files.
+
+  * Added make target clean-built-sources.
+
+  * Fixed #include su_module_debug.h.
+
+  * Moved public include files to sofia-sip subdirectories.
+
+  All public include files installed in ${sofiadir} are now in sofia-sip
+  subdirectories. They are installed to ${sofiadir}/sofia-sip, too.
+
+  ${sofiadir} is defined by configure script relative to your ${prefix}, by
+  default ${sofidir} is ${prefix}/include/sofia-sip-1.11. The default prefix
+  is /usr/local and ${sofiadir} is /usr/local/include/sofia-sip-1.11. When
+  using package manager, the ${prefix} is usually /usr and ${sofiadir} is
+  /usr/include/sofia-sip-1.11.
+
+  The public include files should be referenced using sofia-sip path, e.g.,
+  <sofia-sip/su.h>.
+
+  You can either fix your applications to use the new include file names
+  with the fix-include-sofia-sip sed script found in scripts/ directory, or 
+  add both ${sofiadir} and ${sofiadir}/sofia-sip into your include path, 
+  e.g.,
+
+  INCLUDES = -I/usr/include/sofia-1.11 -I/usr/include/sofia-1.11/sofia-sip 
+
+  At the same time, I took the liberty to rename two include files
+
+  sofia_sip_features.h => sofia-sip/features.h
+  su_memmem.h => sofia-sip/su_bm.h	
+
+  The fix-include-sofia-sip sed script takes care of both of them.
+	
+  * Improved 100rel handling in nua.
+  Added test_100rel to test_nua.c.
+
+  * Using CONDITION_PARAMS macro instead of CONDITION_FUNCTION in test_nua.c
+
+  * Improving getaddrinfo replacements.
+  Testing functions getaddrinfo()/freeaddrinfo(), getnameinfo() and
+  gai_strerror() separately. 
+  There is no gai_strerror() in windows, I think.
+
+2006-02-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Code cleanup and memory leak fix in soa/sdp.
+  Fixed memory leak related to parsing sdp in soa.
+  Cleaned up handling of rejected media (related to bug report #1419078).
+
+     ./libsofia-sip-ua/sdp/run-tests -> ./libsofia-sip-ua/sdp/run_test_sdp
+     ./libsofia-sip-ua/sdp/sdp_test.c -> ./libsofia-sip-ua/sdp/test_sdp.c
+     ./libsofia-sip-ua/sdp/sdp_torture.c -> ./libsofia-sip-ua/sdp/torture_sdp.c
+    M ./libsofia-sip-ua/sdp/Makefile.am -4 +4
+    M ./libsofia-sip-ua/sdp/run_test_sdp -4 +4
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -8 +11
+    M ./libsofia-sip-ua/sdp/sdp_print.c -1 +5
+    M ./libsofia-sip-ua/sdp/test_sdp.c -6 +6
+    M ./libsofia-sip-ua/sdp/torture_sdp.c -47 +38
+    M ./libsofia-sip-ua/soa/soa.c -13 +20
+    M ./libsofia-sip-ua/soa/soa_static.c -11
+
+2006-02-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Add helper functions to update or modify sdp attributes.
+  Feature request #1420698:
+  Added sdp_attribute_append(), sdp_attribute_replace(), and
+  sdp_attribute_remove().
+
+    M ./libsofia-sip-ua/sdp/sdp.c -18 +115
+    M ./libsofia-sip-ua/sdp/sdp.h -9 +21
+    M ./libsofia-sip-ua/sdp/sdp_torture.c -1 +22
+
+  * Using unsigned in bit fields.
+
+    M ./libsofia-sip-ua/sdp/sdp_print.c -2 +2
+
+  * Fixed bug in sending error response to a request containing Record-Route.
+
+    M ./libsofia-sip-ua/nta/nta.c -30 +33
+
+2006-01-25  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated autoconf macros.
+  Using cache for various checks.
+  Deprecated HAVE_LONG_LONG (use #ifdef longlong instead).
+  Collected information used by su_localinfo.c to one place.
+
+    M ./libsofia-sip-ua/su/su_taglist.c -2 +2
+    M ./m4/sac-su2.m4 -64 +103
+
+  * Updated Win32 port.
+  Added autogen.cmd, build_sources.cmd, version_files.cmd and version.awk.
+  Fixed problems with configuration.
+  Updated pthread-w32 to version 2.7.0.
+
+  * Fixed VC/Win32 problems in libsofia-sip-ua.
+  Signedness problems, includes, linkage, winsock initialization.
+
+    M ./libsofia-sip-ua/msg/msg_types.h -1 +2
+    M ./libsofia-sip-ua/nta/nta.c -2 +2
+    M ./libsofia-sip-ua/nua/test_nua.c -5 +5
+    M ./libsofia-sip-ua/nua/test_proxy.c -7 +11
+    M ./libsofia-sip-ua/su/su_root.c +8
+    M ./libsofia-sip-ua/su/su_types.h +2
+    M ./libsofia-sip-ua/su/su_wait.h +2
+
+  * Fixed gawk internal error in msg_parser.awk.
+  It looks like some gawk versions had problems when a function argument
+  was an unitialized variable.
+
+    M ./libsofia-sip-ua/msg/msg_parser.awk -1 +6
+
+  * Defining missing error codes in <su_errno.h>.
+
+    M ./libsofia-sip-ua/msg/msg_mime.c -7
+    M ./libsofia-sip-ua/soa/soa.c -7
+    M ./libsofia-sip-ua/stun/stun.c -6
+    M ./libsofia-sip-ua/su/su_errno.h +12
+    M ./libsofia-sip-ua/su/su_memmem.c -7 +2
+    M ./libsofia-sip-ua/tport/tport.c -5
+
+  * Added checks for different net includes.
+  Checks for sys/ioctl.h, netinet/in.h, net/if.h net/if_types.h and sys/ioctl.h.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c -12 +16
+    M ./m4/sac-su2.m4 -2 +7
+
+  * Fixed rejection of subscriptions in nea server.
+  Event server does not send extra NOTIFY before 403 response anymore.
+
+    M ./libsofia-sip-ua/nea/nea_server.c -1 +1
+
+  * Added functions for scanning domain names and IP addresses.
+  Added span_ip4_address()/scan_ip4_address(), 
+        span_ip6_address()/scan_ip6_address(), 
+        span_ip6_reference()/scan_ip6_reference(),
+        span_ip_address()/scan_ip_address(), 
+        span_domain()/scan_domain(), and
+        span_host()/scan_host(). 
+
+    M ./libsofia-sip-ua/bnf/bnf.c -2 +588
+    M ./libsofia-sip-ua/bnf/bnf.h -2 +18
+    M ./libsofia-sip-ua/bnf/torture_bnf.c -25 +220
+
+2006-01-23  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Removed *_dll.h files - defining *_DLL macros in <su_config.h>.
+
+  * Using random probe when finding port that is available with all transports.
+
+  * Updated auth_mod API.
+
+    Added auth_status_ref().
+    Removed antique functions auth_mod_check_ireq(), auth_mod_check_ireq2() and
+    auth_mod_check_msg().
+
+2006-01-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed doxygen input files (kv).
+
+  * Using su_home_t reference counting in nua.
+
+  * Modified cloned su_home_t semantics.
+
+  Now we allow reference counting for clones as well as threadsafeness for them.
+  Added su_home_is_threadsafe(), modified prototype of su_home_unref().
+
+  * Fixed memory leaks in nea test code.
+
+  * Fixed memory leak in nea_server.c
+
+2006-01-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Restorered tag lists for modules.
+
+    M ./libsofia-sip-ua/nta/Makefile.am +2
+    M ./libsofia-sip-ua/nta/nta_tag.h +3
+    M ./libsofia-sip-ua/nth/nth_tag.h +3
+    M ./libsofia-sip-ua/nua/Makefile.am +2
+    M ./libsofia-sip-ua/nua/nua_tag.h +3
+    M ./libsofia-sip-ua/sip/sip_tag.c.in +13
+    M ./libsofia-sip-ua/sip/sip_tag.h.in +3
+    M ./libsofia-sip-ua/soa/Makefile.am +1
+    M ./libsofia-sip-ua/soa/soa_tag.h +3
+    M ./libsofia-sip-ua/stun/Makefile.am -2 +8
+    M ./libsofia-sip-ua/su/tag_dll.awk -3 +5
+    M ./libsofia-sip-ua/tport/tport_tag.h -1 +4
+    M ./utils/Makefile.am +4
+
+  * Fixed test code for pthread_rwlock_trywrlock().
+
+    M ./m4/sac-su2.m4 -3 +3
+
+2006-01-05  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  2nd sync today for darcs and CVS.
+
+  * Added namespace-specific filter tags.
+
+  * Freeing nua_r_authorize events.
+
+  * Added NSTAG_TYPEDEF(t) and ns_tag_class[].
+
+  * Not using <msg_auth.h>.
+
+  Synching darcs and CVS.
+
+  * Not using msg_auth.h anymore.
+
+    M ./libsofia-sip-ua/msg/msg_auth.c -1
+    M ./libsofia-sip-ua/msg/test_msg.c -1
+
+  * Really adding expires=0 to all contacts when un-registering.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+    M ./libsofia-sip-ua/nua/test_nua.c -3 +26
+
+  * Removed sip_rfc2543 files.
+
+    R ./libsofia-sip-ua/sip/sip_rfc2543.c
+    R ./libsofia-sip-ua/sip/sip_rfc2543.h.in
+
+  * Adding nua_authenticate() tags to request.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +1
+    M ./libsofia-sip-ua/nua/test_nua.c +12
+
+  * Using unsigned in sdp_media_t::m_mode bitfield.
+  enum is signed in VC6.
+
+    M ./libsofia-sip-ua/sdp/sdp.h -1 +1
+
+  * Documented sdp_f_mode_manual and sdp_f_mode_always better.
+
+    M ./libsofia-sip-ua/sdp/sdp.h -1 +1
+    M ./libsofia-sip-ua/sdp/sdp_print.c -8 +10
+
+2006-01-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  Syncinc darcs and CVS.
+	
+  * Added more tests for call hold.
+
+  * Using msg_header_replace_param() in nua_stack.c.
+
+  * Using ss_retry_after in nea.c.
+
+  * Marking two single headers in a message as fatal error.
+
+  * Made headers C++-safe (bug #1376379).
+
+  * Removed dead #include files
+
+  * Removed Last modified things.
+
+  * Removed msg_bnf.h
+
+  * Added NTATAG_TCP_RPORT(). 
+  Do not use rport with TCP by default.
+
+  * Added test for comp=sigcomp.
+  The comp=sigcomp should not be included if destination does not support
+  compression.
+  Modernized parameter handling, too.
+
+  * Documented TP_AI_ flags.
+  Test our TP_AI_ assumptions.
+  Added a test for asymmetric SigComp on TCP. 
+  We use TP_AI_COMPRESSED flag in this test.
+
+  * Added TPTAG_FRESH() and a test for it.
+
+  * Augmented documentation for SIPTAG_HEADER_STR().
+
+  * Use #include <stdio.h> for FILE.
+
+  * Fixed include_sofiadir handling in pkg-config and rpm files. 
+
+2005-12-27  Martti Mela <martti.mela at nokia.com
+
+  * stun minor update
+
+  * first working version of STUN transaction engine
+
+  * stun transaction engine, first impressions
+
+
+2005-12-23  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   Syncing darcs and CVS.
+
+  * Added stun_internal.h to dist.
+
+    M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+
+  * Better handling of optional tags in nta_agent_get_params().
+
+    M ./libsofia-sip-ua/nta/nta.c +4
+    M ./libsofia-sip-ua/nta/test_nta_api.c -8 +9
+
+  * Removed warnings from su_perror() (moved to su_log.h).
+
+    M ./libsofia-sip-ua/su/poll_test.c +1
+    M ./libsofia-sip-ua/su/su_test.c +2
+    M ./libsofia-sip-ua/su/su_timer_test.c +1
+
+  * Added su_errno.h and su_errno.c.
+
+    M ./libsofia-sip-ua/su/Makefile.am -2 +2
+    M ./libsofia-sip-ua/su/su.c -103
+    M ./libsofia-sip-ua/su/su.h -15 +3
+    A ./libsofia-sip-ua/su/su_errno.c
+    A ./libsofia-sip-ua/su/su_errno.h
+    M ./libsofia-sip-ua/su/su_log.c -2 +13
+    M ./libsofia-sip-ua/su/su_log.h -2 +6
+
+  * Prepare for 1.11.5pre1.
+
+    M ./RELEASE -2 +41
+    M ./TODO -2 +5
+    M ./configure.ac -2 +9
+
+  * Added su_home_destructor() to su_alloc.[hc].
+
+    M ./libsofia-sip-ua/su/su_alloc.c -9 +56
+    M ./libsofia-sip-ua/su/su_alloc.h -6 +11
+    M ./libsofia-sip-ua/su/su_alloc_lock.c -15 +18
+    M ./libsofia-sip-ua/su/su_alloc_test.c -20 +40
+
+  * Building features module first after su.
+
+    M ./libsofia-sip-ua/Makefile.am -2 +2
+
+  * Using su_home_new(size) instead of su_home_clone(NULL, size).
+
+    M ./libsofia-sip-ua/http/test_http.c -1 +1
+    M ./libsofia-sip-ua/iptsec/auth_module.c -1 +1
+    M ./libsofia-sip-ua/iptsec/test_auth_digest.c -2 +2
+    M ./libsofia-sip-ua/nea/nea.c -1 +1
+    M ./libsofia-sip-ua/nea/nea_server.c -1 +1
+    M ./libsofia-sip-ua/sip/torture_sip.c -7 +7
+
+  * Improved argument checking in sresolv.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -67 +118
+    M ./libsofia-sip-ua/sresolv/sresolv.h -4 +3
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -13 +26
+
+  * Updated function names in conformance.docs.
+
+    M ./libsofia-sip-ua/docs/conformance.docs -17 +17
+
+  * Fixed problems with autogenerating files with header boilerplates.
+
+    M ./libsofia-sip-ua/http/Makefile.am -2 +4
+    M ./libsofia-sip-ua/sip/Makefile.am -2 +5
+
+  * Added explicit dependencies for autogenerated sources.
+
+    M ./libsofia-sip-ua/msg/Makefile.am -2 +6
+
+  * Using parameter manipulation functions and shortcuts.
+
+    M ./libsofia-sip-ua/nea/nea.c -3 +2
+    M ./libsofia-sip-ua/nta/nta.c -5 +5
+    M ./libsofia-sip-ua/nta/test_nta.c -2 +2
+    M ./libsofia-sip-ua/nua/nua_stack.c -6 +18
+
+  * Fixed su_home_auto() problems.
+
+    M ./libsofia-sip-ua/su/su_alloc.c -4 +8
+
+  * Added hc_update member to msg_hclass_t.
+  The hc_update is used to update shortcuts to well-known parameters.
+  Updated manipulation functions for header parameters to use hc_update.
+  Added updating functions for SIP headers.
+
+    M ./libsofia-sip-ua/http/http_parser.h -4 +6
+    M ./libsofia-sip-ua/msg/msg_basic.c -4 +10
+    M ./libsofia-sip-ua/msg/msg_header_copy.c +6
+    M ./libsofia-sip-ua/msg/msg_mime.c -60 +86
+    M ./libsofia-sip-ua/msg/msg_mime.h -2 +2
+    M ./libsofia-sip-ua/msg/msg_mime_protos.h.in +5
+    M ./libsofia-sip-ua/msg/msg_mime_table.c.in -2 +5
+    M ./libsofia-sip-ua/msg/msg_parser.c +3
+    M ./libsofia-sip-ua/msg/msg_parser.h -14 +18
+    M ./libsofia-sip-ua/msg/msg_parser_util.c -20 +152
+    M ./libsofia-sip-ua/msg/msg_tag.c -1 +8
+    M ./libsofia-sip-ua/msg/msg_types.h +4
+    M ./libsofia-sip-ua/msg/test_class.c -2 +4
+    M ./libsofia-sip-ua/msg/test_msg.c -1 +1
+    M ./libsofia-sip-ua/sip/sip.h -4 +5
+    M ./libsofia-sip-ua/sip/sip_basic.c -158 +124
+    M ./libsofia-sip-ua/sip/sip_caller_prefs.c -54 +40
+    M ./libsofia-sip-ua/sip/sip_event.c -53 +49
+    M ./libsofia-sip-ua/sip/sip_extra.c -37 +36
+    M ./libsofia-sip-ua/sip/sip_mime.c -70 +15
+    M ./libsofia-sip-ua/sip/sip_parser.h -7 +10
+    M ./libsofia-sip-ua/sip/sip_prack.c +1
+    M ./libsofia-sip-ua/sip/sip_reason.c -15 +23
+    M ./libsofia-sip-ua/sip/sip_refer.c -36 +53
+    M ./libsofia-sip-ua/sip/sip_security.c -13 +35
+    M ./libsofia-sip-ua/sip/sip_session.c -2 +22
+    M ./libsofia-sip-ua/sip/torture_sip.c -13 +137
+
+  * Added manipulation functions for header parameters.
+  msg_header_find_param(), msg_header_add_param(), 
+  msg_header_replace_param(), and msg_header_remove_param().
+
+    M ./libsofia-sip-ua/http/http_basic.c -1 +1
+    M ./libsofia-sip-ua/iptsec/auth_client.c -4 +5
+    M ./libsofia-sip-ua/iptsec/auth_module.c -3 +3
+    M ./libsofia-sip-ua/msg/msg_header.h -5 +9
+    M ./libsofia-sip-ua/msg/msg_mime.c -3 +3
+    M ./libsofia-sip-ua/msg/msg_parser.c -5 +5
+    M ./libsofia-sip-ua/msg/msg_parser_util.c +62
+    M ./libsofia-sip-ua/msg/test_msg.c +24
+
+Tue Dec 20 19:51:57 EET 2005  Pekka.Pessi at nokia.com
+  * Reduced overhead in su_home_auto().
+
+    M ./libsofia-sip-ua/su/su_alloc.c -5 +8
+    M ./libsofia-sip-ua/su/su_alloc.h -2 +5
+    M ./libsofia-sip-ua/su/su_alloc_test.c +12
+
+  * Fixed bug in histogram bucket search.
+  Bug was detected using coverity.
+
+    M ./libsofia-sip-ua/sip/validator.c -2 +2
+
+  * Updated param type and usage in SIP headers.
+  A single param has type "char const *".
+  Via has no "hidden" anymore, but "rport" and "comp" were added.
+  Contact has no "action" anymore.
+
+    M ./libsofia-sip-ua/sip/sip.h -42 +44
+    M ./libsofia-sip-ua/sip/sip_basic.c -12 +23
+    M ./libsofia-sip-ua/sip/sip_header.h -1 +1
+    M ./libsofia-sip-ua/sip/sip_util.c -9 +8
+    M ./libsofia-sip-ua/sip/sip_util.h -8 +5
+    M ./libsofia-sip-ua/sip/torture_sip.c +11
+
+  * Updated documentation of SIP headers.
+
+    M ./libsofia-sip-ua/sip/sip_event.c -10 +11
+    M ./libsofia-sip-ua/sip/sip_extra.c -5 +6
+
+  * Refactored sres_resolver_sockets().
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -57 +80
+
+  * Added stateless operation to test_proxy.
+  Using nta_incoming_default() and nta_outgoing_default().
+
+    M ./libsofia-sip-ua/nua/test_nua.c -3 +6
+    M ./libsofia-sip-ua/nua/test_proxy.c +46
+    M ./libsofia-sip-ua/nua/test_proxy.h -15 +2
+
+  * Added nta_outgoing_default(), nta_incoming_default().
+  Stateless response processing can be done with default transactions.
+  Also added nta_incoming_method_name(), nta_incoming_method_name() and
+  nta_incoming_gettag(). Deprecated nta_msg_response_complete().
+  Updated API tests.
+
+    M ./libsofia-sip-ua/nta/Makefile.am -3 +5
+    M ./libsofia-sip-ua/nta/nta.c -51 +268
+    M ./libsofia-sip-ua/nta/nta.h +8
+    M ./libsofia-sip-ua/nta/nta_internal.h -1 +5
+    A ./libsofia-sip-ua/nta/run_test_nta_api
+    A ./libsofia-sip-ua/nta/test_nta_api.c
+
+  * Replaced nta_msg_response_complete() with nta_incoming_complete_response().
+
+    M ./libsofia-sip-ua/nta/nta.c -61 +83
+    M ./libsofia-sip-ua/nta/nta.h -5 +9
+    M ./libsofia-sip-ua/nta/test_nta.c -628 +67
+
+  * Documented GUID format.
+
+    M ./libsofia-sip-ua/sip/sip_basic.c +6
+
+  * Added test_sec_ext() for testing security agreement headers.
+
+    M ./libsofia-sip-ua/sip/torture_sip.c +62
+
+  * Fixed handling of 6XX responses in sip_response_terminates_dialog().
+  Bug found by coverity.
+
+    M ./libsofia-sip-ua/sip/sip_util.c -1 +1
+
+  * Fixed bugs with auto allocation.
+  In C89 and later, the automatic variable may go away when block is exited.
+  The buggy code relied on behaviour of K&R C, where automatic variables are
+  reclaimed when function returns.
+
+    M ./libsofia-sip-ua/nea/nea.c -3 +2
+    M ./libsofia-sip-ua/nea/nea_server.c -5 +4
+    M ./libsofia-sip-ua/nta/nta.c -7 +4
+    M ./libsofia-sip-ua/nua/nua_stack.c -8 +6
+    M ./libsofia-sip-ua/su/su_localinfo.c -2 +2
+    M ./libsofia-sip-ua/tport/tport.c -2 +3
+
+  * Added ELI_BADHINTS to su_localinfo.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c +3
+    M ./libsofia-sip-ua/su/su_localinfo.h -2 +3
+   
+2005-12-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   Again, syncing darcs and CVS.
+
+  * Disabling stun for the moment, use --enable-stun to use it. [pp]
+
+    M ./configure.ac -2 +9
+
+  * working async stun support [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -139 +131
+    M ./libsofia-sip-ua/stun/stun.h -1 +3
+    M ./libsofia-sip-ua/stun/stun_common.c -14 +18
+    M ./libsofia-sip-ua/stun/stunc.c -21 +15
+    M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+
+  * initial async stun support. Does not work with tport yet. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -269 +350
+    M ./libsofia-sip-ua/stun/stun.h -6 +28
+    M ./libsofia-sip-ua/stun/stun_common.c -5 +23
+    M ./libsofia-sip-ua/stun/stun_common.h -1 +1
+    M ./libsofia-sip-ua/stun/stun_internal.h -4 +5
+    M ./libsofia-sip-ua/stun/stunc.c -3 +10
+    M ./libsofia-sip-ua/stun/torture_stun.c -2 +2
+
+  * async stunning contd. Juhui! [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -19 +13
+    M ./libsofia-sip-ua/stun/stun_common.c -4 +9
+    M ./libsofia-sip-ua/stun/stun_internal.h -1 +16
+
+  * stun asyncing contd. NOT WORKING [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -70 +86
+    M ./libsofia-sip-ua/stun/stun.h -9 +7
+    M ./libsofia-sip-ua/stun/stun_common.c -3 +8
+    M ./libsofia-sip-ua/stun/stun_common.h -1 +4
+    M ./libsofia-sip-ua/stun/stun_internal.h -3 +6
+    M ./libsofia-sip-ua/stun/stunc.c -13 +17
+    M ./libsofia-sip-ua/stun/torture_stun.c -12 +15
+
+  * stun async contd. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -26 +56
+    M ./libsofia-sip-ua/stun/stun.h +4
+    M ./libsofia-sip-ua/stun/stunc.c -4 +9
+
+  * DON'T APPLY THIS: does not work. I need this for syncing. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -81 +209
+    M ./libsofia-sip-ua/stun/stun.h -3 +15
+    M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+    M ./libsofia-sip-ua/stun/stunc.c -3 +7
+    M ./libsofia-sip-ua/stun/torture_stun.c -4 +4
+
+  * async connect continued [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -24 +71
+
+  * async stun continued [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -27 +53
+    M ./libsofia-sip-ua/stun/torture_stun.c +7
+    M ./libsofia-sip-ua/tport/test_tport.c -1 +8
+    M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+  * su_localinfo returns now valid address also in Windows [mm]
+
+    M ./libsofia-sip-ua/nua/test_nua.c +3
+    M ./libsofia-sip-ua/su/su_localinfo.c +4
+
+  * tport cygwin modifications [mm]
+
+    M ./libsofia-sip-ua/tport/tport.c -3 +7
+
+  * Declaring h_errno as a variable imported from DLL (when using WIN32). [pp]
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c -3 +8
+
+  * Try random port next if a port is taken. [pp]
+
+    M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+  * Moved LGPL reference so that it will be included in the autogenerated
+    files. [pp]
+
+    M ./libsofia-sip-ua/http/http_parser_table.c.in -8 +8
+    M ./libsofia-sip-ua/http/http_protos.h.in -6 +6
+    M ./libsofia-sip-ua/http/http_tag.c.in -8 +8
+    M ./libsofia-sip-ua/http/http_tag.h.in -7 +7
+    M ./libsofia-sip-ua/msg/msg_mime_protos.h.in -6 +6
+    M ./libsofia-sip-ua/msg/msg_protos.h.in -6 +6
+    M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_hclasses.h.in -6 +7
+    M ./libsofia-sip-ua/sip/sip_parser_table.c.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_protos.h.in -5 +5
+    M ./libsofia-sip-ua/sip/sip_rfc2543.h.in -6 +5
+    M ./libsofia-sip-ua/sip/sip_tag.c.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_tag.h.in -7 +7
+
+  * Collected copyrights belonging someone else but Nokia to COPYRIGHTS
+    file. [pp]
+
+    M ./COPYRIGHTS -1 +223
+    M ./libsofia-sip-ua/ipt/rc4.c -24
+    M ./libsofia-sip-ua/su/getopt.c -24
+    M ./libsofia-sip-ua/su/su_md5.c -11 +14
+
+  * Fixed bug in su_addrinfo.c [FIX]. [pp]
+  Setting ai_addrlen even if there is no sa_len.
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c +1
+
+  * sresolv now compiles without IPv6 [mm]
+
+    M ./libsofia-sip-ua/nua/nua.h -2
+    M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+  * using 500 timers instead of 500000 timers in su_timer_test [mm]
+
+    M ./libsofia-sip-ua/su/su_timer_test.c -2 +2
+
+  * added #include <netinet/tcp.h> to stun_common.h [mm]
+
+    M ./libsofia-sip-ua/nth/Makefile.am -3 +2
+    M ./libsofia-sip-ua/stun/stun_common.h +1
+
+  * added stun_internal.h [mm]
+
+    A ./libsofia-sip-ua/stun/stun_internal.h
+
+  * tport_stun_cb parameter type change [mm]
+
+    R ./libsofia-sip-ua/sip/sip_p_tag.c
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+  * initial async stun, compiles not works. [mm]
+
+    M ./libsofia-sip-ua/nth/Makefile.am -2 +3
+    M ./libsofia-sip-ua/sip/sip_p_tag.c -105
+    M ./libsofia-sip-ua/stun/stun.c -65 +121
+    M ./libsofia-sip-ua/stun/stun.h -23 +18
+    M ./libsofia-sip-ua/stun/stunc.c -2 +26
+    M ./libsofia-sip-ua/stun/torture_stun.c -4 +29
+    M ./libsofia-sip-ua/tport/tport.c -3 +17
+
+  * Removed sip_rfc2543{.h,.h.in,.c} from dist. [pp]
+
+    M ./libsofia-sip-ua/sip/Makefile.am -3 +2
+
+2005-12-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   Again, syncing darcs and CVS.
+
+  * Disabling stun for the moment, use --enable-stun to use it. [pp]
+
+    M ./configure.ac -2 +9
+
+  * working async stun support [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -139 +131
+    M ./libsofia-sip-ua/stun/stun.h -1 +3
+    M ./libsofia-sip-ua/stun/stun_common.c -14 +18
+    M ./libsofia-sip-ua/stun/stunc.c -21 +15
+    M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+
+  * initial async stun support. Does not work with tport yet. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -269 +350
+    M ./libsofia-sip-ua/stun/stun.h -6 +28
+    M ./libsofia-sip-ua/stun/stun_common.c -5 +23
+    M ./libsofia-sip-ua/stun/stun_common.h -1 +1
+    M ./libsofia-sip-ua/stun/stun_internal.h -4 +5
+    M ./libsofia-sip-ua/stun/stunc.c -3 +10
+    M ./libsofia-sip-ua/stun/torture_stun.c -2 +2
+
+  * async stunning contd. Juhui! [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -19 +13
+    M ./libsofia-sip-ua/stun/stun_common.c -4 +9
+    M ./libsofia-sip-ua/stun/stun_internal.h -1 +16
+
+  * stun asyncing contd. NOT WORKING [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -70 +86
+    M ./libsofia-sip-ua/stun/stun.h -9 +7
+    M ./libsofia-sip-ua/stun/stun_common.c -3 +8
+    M ./libsofia-sip-ua/stun/stun_common.h -1 +4
+    M ./libsofia-sip-ua/stun/stun_internal.h -3 +6
+    M ./libsofia-sip-ua/stun/stunc.c -13 +17
+    M ./libsofia-sip-ua/stun/torture_stun.c -12 +15
+
+  * stun async contd. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -26 +56
+    M ./libsofia-sip-ua/stun/stun.h +4
+    M ./libsofia-sip-ua/stun/stunc.c -4 +9
+
+  * DON'T APPLY THIS: does not work. I need this for syncing. [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -81 +209
+    M ./libsofia-sip-ua/stun/stun.h -3 +15
+    M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+    M ./libsofia-sip-ua/stun/stunc.c -3 +7
+    M ./libsofia-sip-ua/stun/torture_stun.c -4 +4
+
+  * async connect continued [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -24 +71
+
+  * async stun continued [mm]
+
+    M ./libsofia-sip-ua/stun/stun.c -27 +53
+    M ./libsofia-sip-ua/stun/torture_stun.c +7
+    M ./libsofia-sip-ua/tport/test_tport.c -1 +8
+    M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+  * su_localinfo returns now valid address also in Windows [mm]
+
+    M ./libsofia-sip-ua/nua/test_nua.c +3
+    M ./libsofia-sip-ua/su/su_localinfo.c +4
+
+  * tport cygwin modifications [mm]
+
+    M ./libsofia-sip-ua/tport/tport.c -3 +7
+
+  * Declaring h_errno as a variable imported from DLL (when using WIN32). [pp]
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c -3 +8
+
+  * Try random port next if a port is taken. [pp]
+
+    M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+  * Moved LGPL reference so that it will be included in the autogenerated
+    files. [pp]
+
+    M ./libsofia-sip-ua/http/http_parser_table.c.in -8 +8
+    M ./libsofia-sip-ua/http/http_protos.h.in -6 +6
+    M ./libsofia-sip-ua/http/http_tag.c.in -8 +8
+    M ./libsofia-sip-ua/http/http_tag.h.in -7 +7
+    M ./libsofia-sip-ua/msg/msg_mime_protos.h.in -6 +6
+    M ./libsofia-sip-ua/msg/msg_protos.h.in -6 +6
+    M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_hclasses.h.in -6 +7
+    M ./libsofia-sip-ua/sip/sip_parser_table.c.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_protos.h.in -5 +5
+    M ./libsofia-sip-ua/sip/sip_rfc2543.h.in -6 +5
+    M ./libsofia-sip-ua/sip/sip_tag.c.in -7 +7
+    M ./libsofia-sip-ua/sip/sip_tag.h.in -7 +7
+
+  * Collected copyrights belonging someone else but Nokia to COPYRIGHTS
+    file. [pp]
+
+    M ./COPYRIGHTS -1 +223
+    M ./libsofia-sip-ua/ipt/rc4.c -24
+    M ./libsofia-sip-ua/su/getopt.c -24
+    M ./libsofia-sip-ua/su/su_md5.c -11 +14
+
+  * Fixed bug in su_addrinfo.c [FIX]. [pp]
+  Setting ai_addrlen even if there is no sa_len.
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c +1
+
+  * sresolv now compiles without IPv6 [mm]
+
+    M ./libsofia-sip-ua/nua/nua.h -2
+    M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+  * using 500 timers instead of 500000 timers in su_timer_test [mm]
+
+    M ./libsofia-sip-ua/su/su_timer_test.c -2 +2
+
+  * added #include <netinet/tcp.h> to stun_common.h [mm]
+
+    M ./libsofia-sip-ua/nth/Makefile.am -3 +2
+    M ./libsofia-sip-ua/stun/stun_common.h +1
+
+  * added stun_internal.h [mm]
+
+    A ./libsofia-sip-ua/stun/stun_internal.h
+
+  * tport_stun_cb parameter type change [mm]
+
+    R ./libsofia-sip-ua/sip/sip_p_tag.c
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+  * initial async stun, compiles not works. [mm]
+
+    M ./libsofia-sip-ua/nth/Makefile.am -2 +3
+    M ./libsofia-sip-ua/sip/sip_p_tag.c -105
+    M ./libsofia-sip-ua/stun/stun.c -65 +121
+    M ./libsofia-sip-ua/stun/stun.h -23 +18
+    M ./libsofia-sip-ua/stun/stunc.c -2 +26
+    M ./libsofia-sip-ua/stun/torture_stun.c -4 +29
+    M ./libsofia-sip-ua/tport/tport.c -3 +17
+
+  * Removed sip_rfc2543{.h,.h.in,.c} from dist. [pp]
+
+    M ./libsofia-sip-ua/sip/Makefile.am -3 +2
+
+2005-12-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  Syncing darcs and CVS.
+
+   * Removed debugging printf()s. [pp]
+
+    M ./libsofia-sip-ua/su/su_root.c -16 +2
+
+  * Removed duplicate function msg_params_matching(). [pp]
+
+    M ./libsofia-sip-ua/msg/msg_header.h -2
+    M ./libsofia-sip-ua/msg/msg_parser_util.c -36
+    M ./libsofia-sip-ua/sip/sip_pref_util.c -1 +1
+
+  * Compilation support for non-IPv6 environments [pp]
+
+    M ./libsofia-sip-ua/nta/nta.c +9
+    M ./libsofia-sip-ua/nta/portbind.c -1 +2
+    M ./libsofia-sip-ua/nta/test_nta.c +5
+    M ./libsofia-sip-ua/sip/Makefile.am -2 +2
+    M ./libsofia-sip-ua/soa/soa.c +7
+    M ./libsofia-sip-ua/su/su.h +6
+    M ./libsofia-sip-ua/su/su_root.c +14
+    M ./libsofia-sip-ua/tport/test_tport.c -1 +1
+    M ./libsofia-sip-ua/tport/tport.c -1 +58
+
+  * additional #ifdefs for IPv6 (un)support. [mm]
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c +13
+    M ./libsofia-sip-ua/sresolv/sresolv.h +4
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c +18
+
+  * Added check for socket library. [pp]
+
+    M ./configure.ac -1
+    M ./m4/sac-su.m4 +2
+
+  * Fixed .h file generation. [pp]
+
+    M ./libsofia-sip-ua/msg/Makefile.am -1 +5
+
+  * Added test for recursive pthread_rwlock_rdlock()/pthread_rwlock_unlock().
+
+    M ./m4/sac-su2.m4 +41
+
+  * Using TP_AI flags not overlapping with AI flags in <su_addrinfo.h>. [pp]
+
+    M ./libsofia-sip-ua/tport/tport.c -4 +6
+
+  * Using red-black tree in su_timer.c. [pp]
+  Added test using 500000 timers in su_timer_test.c.
+
+    M ./libsofia-sip-ua/su/su_timer.c -130 +216
+    M ./libsofia-sip-ua/su/su_timer_test.c -13 +54
+
+  * Fixed bug in sdp_rtpmap_find_matching(). [pp]
+
+    M ./libsofia-sip-ua/sdp/sdp.c -3 +1
+
+  * Cleaned up su_addrinfo.c. [pp]
+  Cleaned up comments.
+  Using SU_HAVE_ flags. 
+  Added support for SCTP in getaddrinfo() replacement.
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c -10 +38
+	
+  * Declaring sockaddr_storage in su.h if it is not provided in environment.
+
+    M ./libsofia-sip-ua/su/su.h +23
+    M ./libsofia-sip-ua/su/su_configure.h.in +3
+    M ./libsofia-sip-ua/su/su_configure_win32.h +6
+    M ./m4/sac-su2.m4 +7
+
+  * Support for CygWin's (buggy) pthread implementation. [mm]
+  Added SU_HAVE_IN6 for disabling IPv6 support from the environments
+  that do not support IPv6.
+
+    M ./libsofia-sip-ua/su/addrinfo.c +11
+    M ./libsofia-sip-ua/su/localinfo.c +6
+    M ./libsofia-sip-ua/su/su_localinfo.c -1 +4
+    M ./libsofia-sip-ua/su/su_port.c -1 +38
+    M ./libsofia-sip-ua/su/su_proxy.c +2
+    M ./libsofia-sip-ua/su/su_root_test.c -1 +3
+    M ./libsofia-sip-ua/su/su_test.c -4 +6
+
+2005-11-30  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  Syncing darcs with CVS.
+	
+  * Silenced warning in su_addrinfo.c.
+
+    M ./libsofia-sip-ua/su/su_addrinfo.c -1 +2
+
+  * Added su_getaddrinfo() and su_getnameinfo() replacement functions.
+
+    M ./libsofia-sip-ua/su/Makefile.am -2 +3
+    M ./libsofia-sip-ua/su/su.c -58
+    M ./libsofia-sip-ua/su/su.h -15 +1
+    A ./libsofia-sip-ua/su/su_addrinfo.c
+    A ./libsofia-sip-ua/su/su_addrinfo.h
+    M ./libsofia-sip-ua/su/su_configure.h.in +3
+    M ./libsofia-sip-ua/su/su_localinfo.c -3 +3
+    M ./libsofia-sip-ua/su/su_wait.h -2 +2
+    M ./m4/sac-su2.m4 -2 +8
+
+  * Not using Unix network includes, use Sofia includes.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+
+  * Using AC_GNU_SOURCE.
+
+    M ./configure.ac -2 +2
+
+  * Using sip-options consistently in utils/sip-options.c.
+
+    M ./utils/sip-options.c -8 +9
+
+  * Updated RELEASE and TODO.
+
+    M ./RELEASE +4
+    M ./TODO -2 +2
+
+  * Using nua_i_state event in nua_cli.c.
+
+    M ./utils/nua_cli.c -76 +88
+
+  * Updated ABNF grammar for Subscription-State in sip_event.c.
+  Added more tests for Subscription-State.
+
+    M ./libsofia-sip-ua/sip/sip_event.c -12 +17
+    M ./libsofia-sip-ua/sip/torture_sip.c -13 +16
+
+  * Fixed test_class.c documentation.
+
+    M ./libsofia-sip-ua/msg/test_class.c -2 +2
+
+  * Proofread conformance specification.
+
+    M ./libsofia-sip-ua/docs/conformance.docs -375 +547
+
+  * Fixed doxytags for main doxygen pages.
+
+    M ./libsofia-sip-ua/docs/Doxyfile -16 +16
+
+  * Fixed types of NUATAGs
+  Changed type of NUTAG_INVITE_TIMER, NUTAG_SESSION_TIMER, and NUTAG_MIN_SE
+  value to unsigned.
+
+    M ./libsofia-sip-ua/nua/nua_tag.c -3 +3
+
+  * Added test for handlin refer subscriptions.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -1 +58
+
+  * Added test_mime_negotiation() to test_nua.c
+
+    M ./libsofia-sip-ua/nua/test_nua.c +166
+
+  * Cosmetic changes in nua_dialog_usage_t in nua_stack.h.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +1
+    M ./libsofia-sip-ua/nua/nua_stack.h -3 +3
+
+  * Added NHP_ISSET() to nua_stack.h.
+
+    M ./libsofia-sip-ua/nua/nua_stack.h -1 +5
+
+  * Added process_subsribe() for refer subscriptions in nua_stack.c.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +88
+
+  * Removed duplicate nua_i_subscription.
+
+    M ./libsofia-sip-ua/nua/nua_common.c -2
+
+  * Renumbered test cases, state transitions in nua.docs and test_nua.c.
+
+    M ./libsofia-sip-ua/nua/nua.docs -79 +79
+    M ./libsofia-sip-ua/nua/nua_stack.c +3
+    M ./libsofia-sip-ua/nua/test_nua.c -78 +131
+
+  * Added NUTAG_REFER_EXPIRES() with default value of 300.
+  Handling expiration of implicit subscriptions created by REFER.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +75
+    M ./libsofia-sip-ua/nua/nua_stack.h +4
+    M ./libsofia-sip-ua/nua/nua_tag.c +2
+    M ./libsofia-sip-ua/nua/nua_tag.h +26
+
+  * Refactored register_expires_contacts()
+  Fixed memory leak, bug in '*'handling.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -10 +18
+
+  * Rewrote uas_check_session_content(). 
+  Returning empty Accept-Encoding header in 415/406 responses.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -21 +41
+
+  * Do not throttle at termination. [FIX]
+  
+  nea_server now sends NOTIFYs that terminate subscription even if the 
+  previous NOTIFY transaction has not completed yet.
+  
+  This fixes the race condition in nua_terminate() (where terminating NOTIFY
+  was is never sent).
+
+    M ./libsofia-sip-ua/nea/nea_server.c -1 +4
+
+  * Fixed rule to build sip_tag_ref.c.
+
+    M ./libsofia-sip-ua/sip/Makefile.am -2 +1
+
+  * Explicitly saving and destroying messages in ua_signal().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -23 +23
+    M ./libsofia-sip-ua/nua/nua_stack.h +1
+
+  * Updated Content-Encoding (e) header parsing.
+
+    M ./libsofia-sip-ua/sip/sip.h -1 +1
+    M ./libsofia-sip-ua/sip/sip_mime.c -4 +4
+    M ./libsofia-sip-ua/sip/torture_sip.c -3 +4
+
+  * Updated Session-Expires and Min-SE header to RFC 4028.
+  A parameter list was added to Min-SE header.
+
+    M ./libsofia-sip-ua/sip/sip.h +1
+    M ./libsofia-sip-ua/sip/sip_session.c -18 +30
+    M ./libsofia-sip-ua/sip/torture_sip.c +10
+
+  * Update RELEASE.
+  Added text about API changes related nua_authorize(), nua_i_subscription and
+  NEATAG_SUB(), NUTAG_HOLD(), sdp_rtpmap_t.
+  Mentioning su_getlocalinfo() bug.
+
+    M ./RELEASE -3 +16
+
+  * Fixed installing and distributing m4 files.
+  Not installing m4/sac-su2.m4. 
+  Including m4/sac-tport.m4 and m4/sac-openssl.m4 in distribution.
+
+    M ./Makefile.am -1 +2
+
+  * Deprecated NUTAG_HOLD().
+
+  * Updated documentation in nea, nua, nta, sip and tport modules.
+
+  * Updated documentation.
+
+    M ./libsofia-sip-ua/docs/Doxyfile.aliases +1
+    M ./libsofia-sip-ua/docs/conformance.docs -172 +177
+    M ./libsofia-sip-ua/docs/mainpage.docs -5 +7
+
+  * Updated subscriptuion authorization and nua_terminate() semantics.
+  Subscription authorization now rejects SUBSCRIBE if 
+  NUTAG_SUBSTATE(nua_substate_terminated) parameter is set.
+  Correct status code is relayed to application, too.
+  nua_terminate() now always terminates whole notifier.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -49 +65
+
+  * Fixed nua_handle_has_active_call() in nua_stack.c.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +10
+    M ./libsofia-sip-ua/nua/test_nua.c +32
+
+  * Renamed authenticate_watcher() as authorize_watcher().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -13 +13
+
+  * Cleanup of subscription logging and comments in nua_stack.c.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -21 +41
+
+  * Using SIPTAG_END() in nua_stack.c.
+  We now pass NTATAG and TPTAG to lower layers. Beware.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -28 +29
+
+  * Added NH_PISSET() macro to <nua_stack.h>.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +8
+    M ./libsofia-sip-ua/nua/nua_stack.h +7
+
+  * Fixed doxytag file names for modules nea and features.
+
+    M ./libsofia-sip-ua/docs/Doxyfile -1 +1
+    M ./libsofia-sip-ua/features/Doxyfile -1 +1
+	
+	M ./libsofia-sip-ua/nea/Doxyfile -1 +1
+
+  * Moved typedefs nua_t and nua_handle_t into <nua_tag.h>
+
+    M ./libsofia-sip-ua/nua/nua.h -6
+    M ./libsofia-sip-ua/nua/nua_tag.h -3 +6
+
+  * Added sip_add_tagis() and SIPTAG_END().
+  SIPTAG_END() allows grouping tags into blocks.
+
+    M ./libsofia-sip-ua/sip/sip_header.h +3
+    M ./libsofia-sip-ua/sip/sip_tag.c.in -1 +2
+    M ./libsofia-sip-ua/sip/sip_tag.h.in +4
+    M ./libsofia-sip-ua/sip/sip_tag_class.c -12 +38
+    M ./libsofia-sip-ua/sip/torture_sip.c +12
+
+  * Fixed scope for V4MAPPED and V4COMPAT IP6 addresses in su_localinfo.c.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c -6 +21
+
+  * Cleaned up debug printing in su_memmem.c.
+
+    M ./libsofia-sip-ua/su/su_memmem.c -11 +21
+
+  * Added end_tag_class[].
+
+    M ./libsofia-sip-ua/su/su_tag_class.h -13 +1
+    M ./libsofia-sip-ua/su/su_tag_inline.h -1 +1
+    M ./libsofia-sip-ua/su/su_taglist.c -48 +84
+
+  * Added replacement functions memccpy().
+  Also moved memcspn() to a file of its own.
+
+    M ./libsofia-sip-ua/su/Makefile.am -5 +13
+    A ./libsofia-sip-ua/su/memccpy.c
+    A ./libsofia-sip-ua/su/memcspn.c
+    M ./libsofia-sip-ua/su/memspn.c -50 +1
+    M ./libsofia-sip-ua/su/strcasestr.c -1 +1
+    M ./m4/sac-su2.m4 -2 +13
+
+  * Added win32/config.h.in
+
+    M ./configure.ac +1
+    A ./win32/config.h.in
+
+  * Added AC_TYPE_LONGLONG.
+
+    M ./configure.ac -3 +2
+    M ./m4/sac-general.m4 -7 +5
+
+  * Tried to fix automatic generation of source files.
+
+    M ./libsofia-sip-ua/http/Makefile.am -10 +9
+    M ./libsofia-sip-ua/msg/Makefile.am -22 +14
+    M ./libsofia-sip-ua/sip/Makefile.am -13 +12
+
+  * Moved bitfields last in sdp_rtpmap_t aka struct sdp_rtpmap_s.
+
+    M ./libsofia-sip-ua/sdp/sdp.c -1 +3
+    M ./libsofia-sip-ua/sdp/sdp.h -5 +5
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -2 +2
+    M ./libsofia-sip-ua/sdp/sdp_torture.c -4 +9
+
+  * Removed RFC2543-compatible tag code.
+
+    M ./libsofia-sip-ua/nta/nta.c -95 +46
+    M ./libsofia-sip-ua/nta/nta.h -4 +3
+    M ./libsofia-sip-ua/nta/nta_tag.h -2 +2
+    M ./libsofia-sip-ua/nta/test_nta.c -18 +20
+
+  * Fixed memory leaks in tport.c and nta.c.
+
+    M ./libsofia-sip-ua/nta/nta.c +11
+    M ./libsofia-sip-ua/tport/tport.c +2
+
+  * Fixed a memory leak when processing re-SUBSCRIBE in nea_server.c.
+
+    M ./libsofia-sip-ua/nea/nea_server.c -2 +2
+
+  * Cleaned #including standard headers in msg module.
+
+    M ./libsofia-sip-ua/msg/msg_header.h +1
+    M ./libsofia-sip-ua/msg/test_msg.c -7 +7
+
+  * Removed extra prototype.
+
+    M ./libsofia-sip-ua/iptsec/auth_plugin_delayed.c -4
+
+  * Casting getpid() return type to something accepted by printf().
+
+    M ./libsofia-sip-ua/nua/test_nua.c -1 +1
+
+  * Doing system #include after sofia #include.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -12 +11
+
+  * Not using nta_incoming_tag_3261() anymore.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -4 +2
+
+  * Added #include <limits.h> to libsofia-sip-ua/su/su.h.
+
+    M ./libsofia-sip-ua/su/su.h -2 +3
+
+  * Added client timeout and NTHTAG_EXPIRES() to nth http client library.
+
+    M ./libsofia-sip-ua/nth/nth_client.c -7 +29
+    M ./libsofia-sip-ua/nth/nth_tag.c -1 +2
+    M ./libsofia-sip-ua/nth/nth_tag.h -1 +7
+    M ./libsofia-sip-ua/nth/nth_test.c -9 +111
+
+  * Fixed RFC 1890/RFC 1891.
+
+    M ./libsofia-sip-ua/docs/Doxyfile.aliases +2
+
+  * Added conformance.docs
+
+    M ./libsofia-sip-ua/docs/Doxyfile -1 +1
+    A ./libsofia-sip-ua/docs/conformance.docs
+
+  * Moved memspn from msg module to su
+
+     ./libsofia-sip-ua/msg/memspn.c -> ./libsofia-sip-ua/su/memspn.c
+
+  * Using package-specific install directory for public header files.
+  Default install directory for public header file has been changed
+  from '${prefix}/include/' to '${prefix}/include/sofia-sip-MAJOR.MINOR'.
+  The pkgconfig .pc file has been updated accordingly.
+
+  * Removed <win32/config.h>
+
+    R ./win32/config.h
+
+2005-11-28  Martti Mela  <martti.mela at nokia.com>
+
+	* Added nua_authorize(), enhanced nua_i_subscription. Added
+	nua_notifier test cases for test_nua. With great help from Pekka.
+
+	M ./libsofia-sip-ua/nea/Makefile.am
+	M ./libsofia-sip-ua/nea/nea.h
+	M ./libsofia-sip-ua/nea/nea_tag.c
+	M ./libsofia-sip-ua/nta/test_nta.c
+	M ./libsofia-sip-ua/nua/nua.c
+	M ./libsofia-sip-ua/nua/nua.docs
+	M ./libsofia-sip-ua/nua/nua.h
+	M ./libsofia-sip-ua/nua/nua_common.c
+	M ./libsofia-sip-ua/nua/nua_stack.c
+	M ./libsofia-sip-ua/nua/nua_stack.h
+	M ./libsofia-sip-ua/nua/test_nua.c
+	M ./libsofia-sip-ua/nua/test_proxy.c
+	M ./utils/Makefile.am
+
+2005-11-28  Martti Mela  <martti.mela at nokia.com>
+
+	* nua.h: added event nua_i_subscription
+	
+	* nua_commmon.c: added event nua_i_subscription
+	
+	* nua_stack.c: ua_event for nua_i_subscription (nea subscribers)
+
+	* nea.h, nea_tag.c, nea_tag_ref.c, nea_server.c: support for a new
+	tag, NEATAG_SUB(). Added nea_sub_get_request().
+
+2005-11-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* configure.ac: Added VER_LIBSOFIA_SIP_UA variables. 
+
+2005-11-14  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   tagged rel-sofia-sip-1_11_4
+
+  * Fixed Win32 includes for XP. Added win32/README.txt.
+
+    M ./libsofia-sip-ua/su/su.h -4 +5
+    M ./win32/Makefile.am -1 +2
+    A ./win32/README.txt
+
+  * Added a blurb about win32 bugs into RELEASE.
+
+    M ./RELEASE -1 +3
+
+2005-11-11  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated RELEASE.
+
+    M ./RELEASE -1 +9
+
+  * Updated dua documentation.
+
+    M ./libsofia-sip-ua/nua/nua.c +4
+    M ./libsofia-sip-ua/nua/nua.docs -10 +12
+    M ./libsofia-sip-ua/nua/nua_stack.h -2 +3
+
+  * Fixed warnings in libsofia-sip-ua/tport/tport.c.
+
+    M ./libsofia-sip-ua/tport/tport.c -2 +1
+
+  * Fixed WIN32 test cases in libsofia-sip-ua/su/su_torture.c.
+  Using SU_WAIT_TIMEOUT and correct IP address.
+
+    M ./libsofia-sip-ua/su/su_torture.c -2 +2
+
+  * Added codec-level negotiation and codec selection for RTP media.
+  Added SOATAG_RTP_SELECT(), SOATAG_RTP_SORT() and SOATAG_RTP_MISMATCH() for
+  indicating sdp negotiation preferences. Select the RTP codec according to the
+  preferences when sending or processing the answer.
+
+    M ./libsofia-sip-ua/soa/soa.c -7 +52
+    M ./libsofia-sip-ua/soa/soa_session.h +5
+    M ./libsofia-sip-ua/soa/soa_static.c -21 +320
+    M ./libsofia-sip-ua/soa/soa_tag.c +89
+    M ./libsofia-sip-ua/soa/soa_tag.h +19
+    M ./libsofia-sip-ua/soa/test_soa.c -19 +382
+
+  * Added funtions for rtp payload type management.
+  
+  Added sdp_media_uses_rtp(), sdp_rtpmap_match(), sdp_rtpmap_find_matching()
+  and sdp_rtpmap_well_known[]. Fixed RTP timestamp rate for G722: it was 16000
+  but it should be 8000.
+
+    M ./libsofia-sip-ua/sdp/sdp.c -1 +76
+    M ./libsofia-sip-ua/sdp/sdp.h +12
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -37 +94
+    M ./libsofia-sip-ua/sdp/sdp_torture.c -11 +140
+
+  * Generating browsing info for win32 projects.
+
+    M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -2 +2
+    M ./win32/nta_test/nta_test.dsp -1 +1
+    M ./win32/su/su_alloc_test/su_alloc_test.dsp -2 +2
+    M ./win32/su/su_root_test/su_root_test.dsp -2 +2
+    M ./win32/su/su_tag_test/su_tag_test.dsp -2 +2
+    M ./win32/su/su_test/su_test.dsp -2 +2
+    M ./win32/su/su_time_test/su_time_test.dsp -2 +2
+    M ./win32/su/su_timer_test/su_timer_test.dsp -2 +2
+    M ./win32/su/su_torture/su_torture.dsp -2 +2
+    M ./win32/su/test_memmem/test_memmem.dsp -2 +2
+    M ./win32/su/torture_htable/torture_htable.dsp -2 +2
+    M ./win32/su/torture_rbtree/torture_rbtree.dsp -2 +2
+    M ./win32/su/torture_su_memmem/torture_su_memmem.dsp -2 +2
+    M ./win32/su/torture_su_port/torture_su_port.dsp -2 +2
+
+  * Added tests for su_vsend() and su_vrecv() in su_torture.c.
+
+    M ./libsofia-sip-ua/su/su_torture.c +89
+
+  * Added #include <limits.h> to nua_stack.c (because MSG_TIME_MAX).
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +1
+
+  * Added SU_WAIT_CONNECT. Fixed su_vrecv() and su_vsend() on Win32.
+
+    M ./libsofia-sip-ua/su/su.c -9 +10
+    M ./libsofia-sip-ua/su/su_wait.h +3
+
+  * Fixed tport.c on Win32 port.
+  Added a separate "connecting" phase. 
+  Checking EWOULDBLOCK in addition to EAGAIN. 
+  Fixed TP_AI_CLOSE and TP_AI_SHUTDOWN flags.
+  Improved logging.
+
+    M ./libsofia-sip-ua/tport/tport.c -35 +98
+
+  * Removed 1.11.3 stuff from RELEASE.
+
+    M ./RELEASE -16 +2
+
+  *  Removed Last modified from ipt module.
+
+    M ./libsofia-sip-ua/ipt/rc4.h -1
+    M ./libsofia-sip-ua/ipt/torture_base64.c -1
+    M ./libsofia-sip-ua/ipt/ucs2.c -1
+    M ./libsofia-sip-ua/ipt/ucs4.c -1
+    M ./libsofia-sip-ua/ipt/uniqueid.h -1
+    M ./libsofia-sip-ua/ipt/utf8.c -1
+    M ./libsofia-sip-ua/ipt/utf8.h -1
+    M ./libsofia-sip-ua/ipt/utf8internal.h -1
+    M ./libsofia-sip-ua/ipt/utf8test.c -1
+
+  * Removed Last modified from sdp module.
+
+    M ./libsofia-sip-ua/sdp/sdp.c -1
+    M ./libsofia-sip-ua/sdp/sdp.h -1
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -1
+    M ./libsofia-sip-ua/sdp/sdp_rtp.h -1
+    M ./libsofia-sip-ua/sdp/sdp_tag.c -1
+    M ./libsofia-sip-ua/sdp/sdp_tag.h -1
+    M ./libsofia-sip-ua/sdp/sdp_test.c -1
+    M ./libsofia-sip-ua/sdp/sdp_torture.c -1
+
+2005-11-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Avoid comp=sigcomp in Via in nta/nta.c
+  Not inserting comp=sigcomp in topmost Via of request if there is no
+  comp=sigcomp in request-URI or route-URI.
+
+    M ./libsofia-sip-ua/nta/nta.c -20 +15
+
+  * Added Doxygen entries for SIPTAG_*_REF.
+
+    M ./libsofia-sip-ua/sip/sip_tag.h.in -5 +17
+
+  * Fixed AC_DEFINE([HAVE_SOFIA_SIGCOMP])
+
+    M ./m4/sac-tport.m4 -1 +1
+
+  * Not using $(srcdir)/../ for Makefile.am inclusion.
+
+    M ./libsofia-sip-ua/features/Makefile.am -1 +1
+    M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+    M ./libsofia-sip-ua/sdp/Makefile.am -1 +1
+    M ./libsofia-sip-ua/soa/Makefile.am -1 +1
+
+  * Added PACKAGE_NAME and PACKAGE_VERSION to msg_parser.awk.
+
+    M ./libsofia-sip-ua/msg/msg_parser.awk +2
+
+  * Not using ancient MSG_DUMP and MSG_STREAM_LOG env variables.
+  Use TPORT_DUMP and TPORT_LOG instead.
+
+    M ./utils/nua_env -3 +3
+
+  * Fixed --without-glib case in m4/sac-su2.m4.
+
+    M ./m4/sac-su2.m4 -4 +7
+
+  * Removed m4/sac-glib.m4
+
+    R ./m4/sac-glib.m4
+
+2005-11-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated documentation of nta_agent_add_tport().
+  The uri parameter to nta_agent_add_tport() is used to control which sockets
+  the tport binds the server sockets as well as which transport, encryption
+  and compression protocols are used.
+
+    M ./libsofia-sip-ua/nta/nta.c -1 +46
+
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   tagged rel-sofia-sip-1_11_3
+
+  * Not using sip_params_replace().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * Using sip_complete_message instead of sip_message_complete in nua_stack.c.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+   * Removed $(srcdir)s from built_sources targets in libsofia-sip-ua/sofia.am
+
+    M ./libsofia-sip-ua/sofia.am -2 +2
+
+  * Updated nta ChangeLog.
+
+    M ./libsofia-sip-ua/nta/ChangeLog +4
+
+  * Renamed tport_test.c as test_tport.c
+
+     ./libsofia-sip-ua/tport/tport_test.c -> ./libsofia-sip-ua/tport/test_tport.c
+    M ./libsofia-sip-ua/tport/ChangeLog +4
+    M ./libsofia-sip-ua/tport/Doxyfile -1 +1
+    M ./libsofia-sip-ua/tport/Makefile.am -7 +9
+    M ./libsofia-sip-ua/tport/test_tport.c -1 +1
+    R ./libsofia-sip-ua/tport/tport_test.h
+
+  * Renamed test modules and programs.
+  Renamed msg_test.c as test_msg.c.
+  Renamed msg_test_class.[hc] as test_class.[hc],
+          msg_test_protos.h(.in) as test_protos.h(.in),
+  	msg_test_table.c(.in) as test_table.c(.in).
+
+     ./libsofia-sip-ua/msg/msg_test.c -> ./libsofia-sip-ua/msg/test_msg.c
+     ./libsofia-sip-ua/msg/msg_test_class.c -> ./libsofia-sip-ua/msg/test_class.c
+     ./libsofia-sip-ua/msg/msg_test_class.h -> ./libsofia-sip-ua/msg/test_class.h
+     ./libsofia-sip-ua/msg/msg_test_protos.h.in -> ./libsofia-sip-ua/msg/test_protos.h.in
+     ./libsofia-sip-ua/msg/msg_test_table.c.in -> ./libsofia-sip-ua/msg/test_table.c.in
+    M ./libsofia-sip-ua/msg/ChangeLog +8
+    M ./libsofia-sip-ua/msg/Makefile.am -28 +36
+    M ./libsofia-sip-ua/msg/msg.docs -1 +1
+    M ./libsofia-sip-ua/msg/msg_name_hash.c -1 +1
+    M ./libsofia-sip-ua/msg/test_class.c -8 +8
+    M ./libsofia-sip-ua/msg/test_class.h -3 +3
+    M ./libsofia-sip-ua/msg/test_msg.c -5 +5
+    M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+    M ./libsofia-sip-ua/msg/test_table.c.in -7 +7
+    M ./libsofia-sip-ua/tport/tport_test.c -2 +2
+
+  * Renamed auth_digest_test.c as test_auth_digest.c.
+
+     ./libsofia-sip-ua/iptsec/auth_digest_test.c -> ./libsofia-sip-ua/iptsec/test_auth_digest.c
+    M ./libsofia-sip-ua/iptsec/ChangeLog +4
+    M ./libsofia-sip-ua/iptsec/Makefile.am -3 +3
+    M ./libsofia-sip-ua/iptsec/test_auth_digest.c -4 +4
+
+  * Renamed http_test.c as test_http.c.
+
+     ./libsofia-sip-ua/http/http_test.c -> ./libsofia-sip-ua/http/test_http.c
+    M ./libsofia-sip-ua/http/ChangeLog +4
+    M ./libsofia-sip-ua/http/Makefile.am -3 +3
+    M ./libsofia-sip-ua/http/test_http.c -6 +6
+
+2005-11-07  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Using new nta_agent_create() prototype in utils/sip-options.c
+
+    M ./utils/sip-options.c -1 +1
+
+  * Added test proxy to nua module.
+
+    M ./libsofia-sip-ua/nua/Makefile.am +2
+    M ./libsofia-sip-ua/nua/test_nua.c -35 +175
+    A ./libsofia-sip-ua/nua/test_proxy.c
+    A ./libsofia-sip-ua/nua/test_proxy.h
+
+  * Cleaned up sip parser.
+  Renamed msg_name_addr_d/msg_name_addr_e as sip_name_addr_d/sip_name_addr_e
+  (because the function is sip-specific).
+  Not using old sip-specific parser macros.
+
+    M ./libsofia-sip-ua/sip/sip.docs -6 +3
+    M ./libsofia-sip-ua/sip/sip.h -1 +1
+    M ./libsofia-sip-ua/sip/sip_basic.c -100 +284
+    M ./libsofia-sip-ua/sip/sip_caller_prefs.c -13 +13
+    M ./libsofia-sip-ua/sip/sip_event.c -32 +32
+    M ./libsofia-sip-ua/sip/sip_extra.c -13 +13
+    M ./libsofia-sip-ua/sip/sip_feature.c -8 +8
+    M ./libsofia-sip-ua/sip/sip_header.c -36 +3
+    M ./libsofia-sip-ua/sip/sip_mime.c -18 +18
+    M ./libsofia-sip-ua/sip/sip_parser.c -12 +12
+    M ./libsofia-sip-ua/sip/sip_parser.h -3 +14
+    M ./libsofia-sip-ua/sip/sip_prack.c -2 +2
+    M ./libsofia-sip-ua/sip/sip_pref_util.c -2 +2
+    M ./libsofia-sip-ua/sip/sip_reason.c -6 +6
+    M ./libsofia-sip-ua/sip/sip_refer.c -24 +24
+    M ./libsofia-sip-ua/sip/sip_rfc2543.c -2 +2
+    M ./libsofia-sip-ua/sip/sip_security.c -10 +10
+    M ./libsofia-sip-ua/sip/sip_session.c -6 +6
+    M ./libsofia-sip-ua/sip/sip_tag_class.c -11 +14
+    M ./libsofia-sip-ua/sip/sip_time.c -1 +1
+    M ./libsofia-sip-ua/sip/sip_util.c -47 +19
+    M ./libsofia-sip-ua/sip/torture_sip.c -8 +56
+
+  * Updated documentation in url module.
+
+    M ./libsofia-sip-ua/url/torture_url.c -3 +2
+    M ./libsofia-sip-ua/url/url.c -3 +5
+    M ./libsofia-sip-ua/url/url.h -3 +1
+    M ./libsofia-sip-ua/url/url_tag.c -4 +2
+    M ./libsofia-sip-ua/url/url_tag.h -3 +2
+    M ./libsofia-sip-ua/url/url_tag_class.h -3 +2
+
+  * Using updated nta api in nua module.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -23 +34
+
+  * Not using msg_copy_all().
+
+    M ./libsofia-sip-ua/nth/nth_client.c -11 +6
+
+  * Not misusing SIP_NONE.
+
+    M ./libsofia-sip-ua/sip/torture_sip.c -2 +2
+
+  * Updated documentation in msg module.
+  Removed bogus @ingroup msg.
+
+    M ./libsofia-sip-ua/msg/msg.c -3 +1
+    M ./libsofia-sip-ua/msg/msg.h -4 +1
+    M ./libsofia-sip-ua/msg/msg_addr.h -2 +1
+    M ./libsofia-sip-ua/msg/msg_buffer.h -2 +1
+    M ./libsofia-sip-ua/msg/msg_dll.h -3 +1
+    M ./libsofia-sip-ua/msg/msg_tag.c -2 +1
+    M ./libsofia-sip-ua/msg/msg_tag_class.h -4 +1
+
+  * Updated msg module interfaces.
+  Added msg_header_free(), msg_header_free_all().
+  Removed msg_dup_all() and msg_copy_all().
+
+    M ./libsofia-sip-ua/msg/msg.h -2 +2
+    M ./libsofia-sip-ua/msg/msg_header.h -3 +8
+    M ./libsofia-sip-ua/msg/msg_header_copy.c +159
+    M ./libsofia-sip-ua/msg/msg_internal.h -2 +28
+    M ./libsofia-sip-ua/msg/msg_mime.c -48 +47
+    M ./libsofia-sip-ua/msg/msg_parser.c -198 +21
+    M ./libsofia-sip-ua/msg/msg_parser_util.c -171 +14
+    M ./libsofia-sip-ua/msg/msg_test.c -69 +41
+    M ./libsofia-sip-ua/msg/msg_test_class.c -28 +24
+    M ./libsofia-sip-ua/msg/msg_test_class.h -3 +2
+    M ./libsofia-sip-ua/msg/msg_test_protos.h.in -2 +2
+
+  * Removed msg_clone() from msg module.
+  Moved msg_set_parent() into msg/msg.c.
+
+    M ./libsofia-sip-ua/msg/msg.c +23
+    M ./libsofia-sip-ua/msg/msg.h -2
+    M ./libsofia-sip-ua/msg/msg_parser.c -46
+
+  * Cleaned up nta module interfaces.
+  Use uint32_t instead of sip_u32_t.
+  Removed old funtions not using reference counting with messages:
+  Replaced nta_outgoing_getresponse() with nta_outgoing_getresponse_ref(), 
+  and nta_outgoing_getrequest() with nta_outgoing_getrequest_ref().
+  Removed nta_incoming_getresponse(), nta_leg_stateful().
+  Removed nta_outgoing_tmcreate(): use nta_outgoing_mcreate() instead.
+
+    M ./libsofia-sip-ua/nta/nta.c -298 +243
+    M ./libsofia-sip-ua/nta/nta.h -21 +14
+    M ./libsofia-sip-ua/nta/nta_compat.c -6 +132
+    M ./libsofia-sip-ua/nta/nta_compat.h +3
+    M ./libsofia-sip-ua/nta/nta_internal.h -11 +4
+    M ./libsofia-sip-ua/nta/nta_stateless.h -9 +5
+    M ./libsofia-sip-ua/nta/run_test_nta -5 +5
+    M ./libsofia-sip-ua/nta/sl_utils_log.c -1 +1
+    M ./libsofia-sip-ua/nta/sl_utils_print.c -1 +1
+    M ./libsofia-sip-ua/nta/test_nta.c -24 +14
+
+  * Not using msg_clone().
+
+    M ./libsofia-sip-ua/nth/nth_client.c -1 +1
+
+  * Not using stateless functions anymore in nea.
+
+    M ./libsofia-sip-ua/nea/nea.h -12 +3
+    M ./libsofia-sip-ua/nea/nea_server.c -8 +3
+
+  * Removed sip_complete_response().
+
+    M ./libsofia-sip-ua/sip/sip_parser.c -47
+    M ./libsofia-sip-ua/sip/sip_util.h -7
+
+  * Not using sip_none anymore.
+
+    M ./libsofia-sip-ua/sip/sip_header.c -1 +1
+
+  * Fixed sip_object() prototype.
+
+    M ./libsofia-sip-ua/sip/sip_protos.h.in -1 +1
+
+  * Cleaned up sip types. 
+  Not using special typedefs sip_u32_t or sip_u16_t.
+
+    M ./libsofia-sip-ua/sip/sip.h -15 +11
+    M ./libsofia-sip-ua/sip/sip_basic.c -4 +4
+    M ./libsofia-sip-ua/sip/sip_header.h -2 +2
+    M ./libsofia-sip-ua/sip/sip_util.c -2 +2
+    M ./libsofia-sip-ua/sip/sip_util.h -1 +1
+
+  * Defining MSG_TIME_MAX both in msg_types.h and msg_time.h.
+
+    M ./libsofia-sip-ua/msg/msg_date.h -3 +6
+    M ./libsofia-sip-ua/msg/msg_types.h -1 +6
+
+  * Removed sip_transport.c.
+
+    R ./libsofia-sip-ua/sip/sip_transport.c
+
+  * Removed annoying Last modified from iptsec.
+
+2005-11-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+	
+  * Removed annoying Last modified from msg module.
+
+  * Removed Last modified things from sip module.
+
+  * Removed sip/sip_transport.[hc], not used anymore.
+
+    R ./libsofia-sip-ua/sip/sip_transport.c
+    R ./libsofia-sip-ua/sip/sip_transport.h
+
+2005-11-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Renamed nta_test as test_nta.
+
+     ./libsofia-sip-ua/nta/nta_test.c -> ./libsofia-sip-ua/nta/test_nta.c
+     ./libsofia-sip-ua/nta/run_nta_test -> ./libsofia-sip-ua/nta/run_test_nta
+    M ./libsofia-sip-ua/nta/Makefile.am -4 +4
+    M ./libsofia-sip-ua/nta/run_test_nta -2 +2
+
+  * Updated libsofia-sip-ua/nua/ChangeLog.
+
+    M ./libsofia-sip-ua/nua/ChangeLog +21
+
+  * Fixed race in nea/nea_server.c.
+  Do not free subscribers while they are being processed by application.
+
+    M ./libsofia-sip-ua/nea/nea_server.c -5 +7
+
+  * Added unpublish, unregister, do_register to nua/test_nua.c.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -8 +28
+
+  * Added test_events().
+
+    M ./libsofia-sip-ua/nua/test_nua.c +409
+
+  * Added nua_unpublish(). 
+  Some cosmetic changes, too.
+
+    M ./libsofia-sip-ua/nua/nua.h -1 +4
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+  * Cleaned up allocations in nua/test_nua.c.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -6 +8
+
+  * Added loopback message test.
+
+    M ./libsofia-sip-ua/nua/test_nua.c +49
+
+2005-11-02  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed buglets in su/su_alloc.c.
+  su_alloc() did zero memory. su_realloc() used su_alloc().
+
+    M ./libsofia-sip-ua/su/su_alloc.c -5 +7
+
+  * Closing /proc/net/if_inet6 after use in su/su_localinfo.c.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c +2
+
+  * Using su_home_new().
+
+    M ./libsofia-sip-ua/msg/msg.c -2 +2
+
+  * Fixed allocation code for message parser table.
+  Allocating parser table as a single memory block.
+
+    M ./libsofia-sip-ua/msg/msg_mclass.c -12 +12
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +15
+
+  * Updated documentation in nta/nta_stateless.h.
+
+    M ./libsofia-sip-ua/nta/nta_stateless.h -4 +4
+
+  * Plugging memory leaks in nta.
+  Plugged memory leaks in 100rel code.
+
+    M ./libsofia-sip-ua/nta/nta.c -38 +63
+    M ./libsofia-sip-ua/nta/nta_test.c -31 +109
+
+  * Moved deprecated functions to nta/nta_compat.c.
+  nta_msg_vsend() and msg_msg_send() should not be used anymore.
+  
+  nta_msg_discard() is also deprecated, but getting rid of references to it
+  takes time.
+
+    M ./libsofia-sip-ua/nta/nta.c -43 +42
+    M ./libsofia-sip-ua/nta/nta_compat.c -1 +31
+
+  * Plugged memory leak in nth_engine_create() in nth/nth_client.c 
+  Use su_home_new() instead of su_salloc().
+
+    M ./libsofia-sip-ua/nth/nth_client.c -3 +2
+
+2005-11-01  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  tagged rel-sofia-sip_1_11_2+win32
+
+  * Disabled listen-on-v6 in sresolv/run_test_sresolv.
+
+    M ./libsofia-sip-ua/sresolv/run_test_sresolv -4 +15
+
+  * Fixed search path on sresolc/sresolv.c
+  Not invoking callback on main query if subqueries are still running.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -11 +20
+
+  * Added ns record for root.zone.
+
+    M ./libsofia-sip-ua/sresolv/root.zone -1 +5
+
+  * Using su_close() instead of close().
+
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +3
+    M ./libsofia-sip-ua/stun/stun.c -1 +1
+    M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+  * Fixed HAVE_SIGPIPE.
+
+    M ./configure.ac -1 +2
+
+  * Using SU_HAVE_GLIB.
+
+    M ./libsofia-sip-ua/su/su_test.c -2 +2
+
+  * Removed annoying last modified.
+
+    M ./libsofia-sip-ua/sresolv/sresolv.c -2
+    M ./libsofia-sip-ua/sresolv/test_sresolv.c -1
+    M ./libsofia-sip-ua/stun/stun.c -1
+
+  * Using AC_DEFINE with HAVE_SOFIA_STUN.
+
+    M ./configure.ac -1 +1
+
+  * Removed annoying Last modified from su and win32 files.
+
+  * Not using sint32_t.
+
+    M ./libsofia-sip-ua/su/su.c -1
+    M ./libsofia-sip-ua/su/su.h -1
+    M ./libsofia-sip-ua/su/su_localinfo.c -4 +4
+
+  * Fixed ipv6 side on libc replacement libsofia_sip_ua/su/inet_pton.c.
+
+    M ./libsofia-sip-ua/su/inet_pton.c -20 +20
+
+  * Removed ntv6 files from win32 port.
+
+    M ./win32/Makefile.am -23 +13
+
+  * Using win32 include files tpipv6.h and wspiapi.h provided by system.
+
+    M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -8
+
+  * Using SU_HAVE_IN6 on win32, too.
+
+    M ./libsofia-sip-ua/su/su.c -1 +1
+    M ./libsofia-sip-ua/su/su.h -6 +6
+    M ./libsofia-sip-ua/su/su_torture.c -1 +1
+    M ./win32/config.h -3 +3
+    M ./win32/su_configure_win32.h -2 +1
+
+  * Added HAVE_SIGPIPE.
+
+    M ./configure.ac +6
+
+  * Removed Microsoft include file win32/wspiapi.h.
+
+    R ./win32/wspiapi.h
+
+  * Removed win32 tpipv6.h file.
+
+    R ./win32/tpipv6.h
+
+  * Fixed win32 socket handling problems in su/su_root_test and torture_su_port.c.
+
+    M ./libsofia-sip-ua/su/su_root_test.c +5
+    M ./libsofia-sip-ua/su/torture_su_port.c +4
+
+  * Renamed SU_SOCKADDR_INADDR_ANY as SU_HAS_INADDR_ANY() in su/su.h.
+
+    M ./libsofia-sip-ua/su/su.h -2 +4
+
+  * Added "su" test programs to win32 port.
+
+  * Fixed win32 config.h.
+
+    M ./win32/config.h -3 +6
+
+  * Added su test programs to win32 workspace.
+
+    M ./win32/SofiaSIP.dsw -1 +166
+
+  * Providing __func__ replacement in su/torture_su_port.c.
+
+    M ./libsofia-sip-ua/su/torture_su_port.c -1 +7
+
+  * Not using IN6 if it is not found by configure.
+
+    M ./libsofia-sip-ua/su/su_torture.c -1 +2
+
+  * Not using SIGPIPE if it is not found by configure.
+
+    M ./libsofia-sip-ua/su/su_timer_test.c +2
+
+  * Not using glib in su/su_test.c if it is not found by configure.
+
+    M ./libsofia-sip-ua/su/su_test.c -2 +6
+
+  * Added inet_pton() and inet_ntop() replacement functions.
+
+    M ./libsofia-sip-ua/su/Makefile.am -1 +2
+    M ./libsofia-sip-ua/su/inet_ntop.c -57 +30
+    A ./libsofia-sip-ua/su/inet_pton.c
+    M ./libsofia-sip-ua/su/su.h -11 +2
+
+  * Removed ntv6 from include path of win32 port.
+
+    M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -6 +10
+
+  * Removed ntv6 files.
+
+    R ./libsofia-sip-ua/su/aton.c
+    R ./libsofia-sip-ua/su/ntoa.c
+
+2005-10-31  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed testcases not working with libc implementation.
+
+    M ./libsofia-sip-ua/su/test_memmem.c -6 +6
+
+  * Defining SU_DLL in su/su_config.h for non-WIN32 targets.
+
+    M ./libsofia-sip-ua/su/su_config.h -1 +1
+
+  * Removing libsofia-sip-ua/nea/nea_dll.h from dist, too.
+
+    M ./libsofia-sip-ua/nea/Makefile.am -1 +1
+
+  * Added strtoull.c, strcasestr.c and inet_ntop.c to distribution.
+
+    M ./libsofia-sip-ua/su/Makefile.am -1 +1
+
+  * Added inet_ntop() to libsofia-sip-ua/su
+
+    A ./libsofia-sip-ua/su/inet_ntop.c
+
+  * Not inlining attribute functions in tport/tport.c.
+
+    M ./libsofia-sip-ua/tport/tport.c -4 +4
+
+  * Updated _DLL linkage things.
+  The DLL linkage macros SIP_DLL, NTA_DLL, etc. are now defined in win32-specific
+  config.h file.
+
+    M ./libsofia-sip-ua/bnf/bnf.h -4 +5
+    M ./libsofia-sip-ua/http/http.h -9 +1
+    M ./libsofia-sip-ua/http/http_dll.h -3 +3
+    M ./libsofia-sip-ua/http/http_header.h -2
+    M ./libsofia-sip-ua/http/http_status.h -1
+    M ./libsofia-sip-ua/ipt/utf8.h -4 +6
+    M ./libsofia-sip-ua/iptsec/auth_dll.h -3 +3
+    M ./libsofia-sip-ua/msg/msg_dll.h -6 +6
+    M ./libsofia-sip-ua/nea/nea.h -8 +8
+    M ./libsofia-sip-ua/nta/nta_dll.h -3 +4
+    M ./libsofia-sip-ua/nth/nth_tag.h -3 +3
+    M ./libsofia-sip-ua/sdp/sdp.h -8
+    M ./libsofia-sip-ua/sdp/sdp_tag.h -4 +3
+    M ./libsofia-sip-ua/sip/sip_dll.h -5 +4
+    M ./libsofia-sip-ua/su/su_config.h -7 +3
+    M ./libsofia-sip-ua/tport/tport.h -9
+    M ./libsofia-sip-ua/tport/tport_tag.h -3 +3
+    M ./libsofia-sip-ua/url/url_dll.h -4 +3
+
+  * Removed nea/nea_dll.h
+
+    R ./libsofia-sip-ua/nea/nea_dll.h
+
+  * Added prototype for strcasestr() replacement function.
+
+    M ./libsofia-sip-ua/soa/soa_static.c +3
+
+  * Added tests for strcasestr() replacement function.
+
+    M ./libsofia-sip-ua/su/test_memmem.c -19 +148
+
+  * Removed double const.
+  VC98 does not support ANSI const.
+
+    M ./libsofia-sip-ua/su/su_wait.h -3 +3
+
+  * Fixed __func__ usage.
+  VC98++ does not have __func__. Use innocent value instead.
+
+    M ./libsofia-sip-ua/nua/nua_stack.h +2
+    M ./libsofia-sip-ua/soa/soa.c +7
+
+  * Fixed C99-ism in sdp/sdp_parse.c.
+  A variable was declared in the middle of block.
+
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -4 +6
+
+  * Fixed setsockopt() in tport/tport.c.
+  Explicit (void *) cast for argument of setsockopt().
+
+    M ./libsofia-sip-ua/tport/tport.c -2 +4
+
+  * Added missing replacement functions.
+
+    A ./libsofia-sip-ua/su/strcasestr.c
+    A ./libsofia-sip-ua/su/strtoull.c
+
+  * Using longlong instead of long long.
+  longlong is defined in "config.h".
+
+    M ./libsofia-sip-ua/sdp/sdp_parse.c +4
+    M ./libsofia-sip-ua/sdp/sdp_print.c -1 +1
+    M ./libsofia-sip-ua/soa/soa.c -2 +2
+    M ./libsofia-sip-ua/su/tstdef.h -1 +1
+
+  * Using su_seterrno() and su_errno().
+  Not using directly errno in soa/soa.c and tport/tport.c.
+
+    M ./libsofia-sip-ua/soa/soa.c -37 +38
+    M ./libsofia-sip-ua/tport/tport.c -10 +10
+
+  * Removed whoami from msg/msg_parser.awk.
+  whoami is not used.
+
+    M ./libsofia-sip-ua/msg/msg_parser.awk -1
+
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added coverage files used by gcc 3.4.3 to MOSTLYCLEANFILES.
+
+    M ./m4/sac-general.m4 -1 +1
+
+2005-10-21  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed lib64 problem.
+
+    M ./packages/sofia-sip.spec.in -6 +9
+
+2005-10-13  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Removed RCS/CVS Ids and dates from files in order to allow
+	smoother darcs usage.
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Defining SU_HAVE_TAGSTACK.
+
+    M ./libsofia-sip-ua/su/su_configure.h.in +3
+    M ./m4/sac-su2.m4 +6
+
+2005-10-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added --without-glib option, added SU_HAVE_GLIB in su_configure.h.
+
+    M ./configure.ac -5
+    M ./libsofia-sip-ua/su/Makefile.am +2
+    M ./libsofia-sip-ua/su/su_configure.h.in +2
+    M ./m4/sac-su2.m4 -1 +22
+
+  * Added --output (and --help) options to coverage script.
+
+    M ./libsofia-sip-ua/sofia.am -1 +1
+    M ./scripts/coverage -2 +25
+
+2005-10-06  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Renamed options as sip-options, sip_date as sip-date.
+
+     ./utils/options.c -> ./utils/sip-options.c
+     ./utils/sip_date.c -> ./utils/sip-date.c
+    M ./utils/Makefile.am -1 +1
+
+  * Added all doc files.
+
+    M ./packages/debian/control -2 +1
+    M ./packages/debian/docs +3
+    M ./packages/sofia-sip.spec.in -24 +22
+
+  * Added a separate Makefile.am in packages.
+
+    A ./COPYRIGHTS
+    M ./Makefile.am -6 +2
+    A ./packages/Makefile.am
+
+  * Cleaned up output.
+
+    M ./scripts/coverage -4 +8
+
+  * Adding +x to all scripts.
+
+    M ./autogen.sh +3
+
+  * Added %{?dist} to release.
+
+    M ./packages/sofia-sip.spec.in -1 +4
+
+  * sofia-sip-ua.pc is in packages, too.
+
+    M ./Makefile.am -1 +1
+
+  * DIST_SUBDIR too deep in directory structure does not work.
+
+    M ./configure.ac -4
+    M ./libsofia-sip-ua/docs/Makefile.am -3 +21
+    R ./libsofia-sip-ua/docs/pictures/Makefile.am
+    M ./libsofia-sip-ua/sdp/Makefile.am -3 +11
+    M ./libsofia-sip-ua/sdp/tests/Makefile.am -11
+    M ./libsofia-sip-ua/sip/Makefile.am -3 +19
+    M ./libsofia-sip-ua/sip/images/Makefile.am -5
+    M ./libsofia-sip-ua/sip/tests/Makefile.am -55
+
+  * Added packages subdirectory for package stuff.
+
+     ./sofia-sip-ua.pc.in -> ./packages/sofia-sip-ua.pc.in
+     ./sofia-sip.spec.in -> ./packages/sofia-sip.spec.in
+    M ./Makefile.am -1 +2
+    M ./configure.ac -2 +2
+    A ./packages/
+
+  * Added coverage and built-sources targets at top-level.
+
+    M ./Makefile.am -2 +2
+
+  * Fixed coverage target in libsofia-sip-ua/Makefile.am.
+
+    M ./libsofia-sip-ua/Makefile.am -4 +6
+    M ./libsofia-sip-ua/bnf/Makefile.am +2
+    M ./libsofia-sip-ua/http/Makefile.am +2
+    M ./libsofia-sip-ua/ipt/Makefile.am +2
+    M ./libsofia-sip-ua/iptsec/Makefile.am +2
+    M ./libsofia-sip-ua/msg/Makefile.am +2
+    M ./libsofia-sip-ua/nea/Makefile.am +2
+    M ./libsofia-sip-ua/nta/Makefile.am +2
+    M ./libsofia-sip-ua/nth/Makefile.am +2
+    M ./libsofia-sip-ua/nua/Makefile.am +2
+    M ./libsofia-sip-ua/sdp/Makefile.am +2
+    M ./libsofia-sip-ua/sip/Makefile.am +2
+    M ./libsofia-sip-ua/soa/Makefile.am +2
+    M ./libsofia-sip-ua/sresolv/Makefile.am +2
+    M ./libsofia-sip-ua/stun/Makefile.am +2
+    M ./libsofia-sip-ua/tport/Makefile.am +2
+    M ./libsofia-sip-ua/url/Makefile.am +2
+
+  * Removed su/su.mak.
+
+    R ./libsofia-sip-ua/su/su.mak
+
+  * Added EXPENSIVE_CHECKS.
+
+    M ./configure.ac +1
+    M ./docs/build_system.txt +11
+    M ./m4/sac-general.m4 +13
+
+  * Moved 'testutils' as 'scripts' in toplevel.
+
+     ./libsofia-sip-ua/testutils -> ./scripts
+    M ./libsofia-sip-ua/sofia.am -1 +1
+
+  * Including only library sources in coverage output.
+
+    M ./libsofia-sip-ua/su/Makefile.am -1 +1
+
+  * coverage prints error if check is not made, doesn't depend on check.
+
+    M ./libsofia-sip-ua/sofia.am -2 +2
+
+  * Including all input files in output.
+
+    M ./libsofia-sip-ua/testutils/coverage -20 +27
+
+2005-10-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Importing darcs-to-cvs-2005-10-04.
+
+  * Using DIST_SUBDIRS when including dist-only dirs 
+
+    M ./Makefile.am -1 +2
+    M ./libsofia-sip-ua/Makefile.am -1 +4
+    M ./libsofia-sip-ua/docs/Makefile.am -3 +1
+    M ./libsofia-sip-ua/sdp/Makefile.am -1 +1
+    M ./libsofia-sip-ua/sip/Makefile.am -1 +1
+
+2005-10-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Importing darcs-to-cvs-2005-10-03.
+	
+  * Removed old .def files.
+
+    R ./libsofia-sip-ua/ipt/ipt.def
+    R ./libsofia-sip-ua/iptsec/iptsec.def
+    R ./libsofia-sip-ua/msg/msg.def
+    M ./libsofia-sip-ua/nta/nta.def -92
+    M ./libsofia-sip-ua/nta/sl_utils.def -15
+    R ./libsofia-sip-ua/nua/nua.def
+    M ./libsofia-sip-ua/sdp/sdp.def -42
+    R ./libsofia-sip-ua/sip/sip.def
+    R ./libsofia-sip-ua/su/su.def
+    M ./libsofia-sip-ua/tport/tport.def -21
+
+  * Added automake conditional ENABLE_COVERAGE.
+
+    M ./m4/sac-general.m4 +3
+
+  * Added make target for calculating coverage.
+
+    M ./libsofia-sip-ua/Makefile.am -1 +5
+    M ./libsofia-sip-ua/sofia.am +5
+    M ./libsofia-sip-ua/su/Makefile.am +2
+    A ./libsofia-sip-ua/testutils/
+    A ./libsofia-sip-ua/testutils/coverage
+
+2005-09-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Importing darcs-to-cvs-2005-09-29.
+		
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added nua improvements.
+
+	    M ./TODO +3
+
+2005-09-23  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* darcs changes:
+	
+	Fri Sep 23 18:58:29 EEST 2005  Pekka.Pessi at nokia.com
+	  * Building msg_test class into msg_test library, use that in tport.
+
+	    M ./libsofia-sip-ua/msg/Makefile.am -5 +7
+	    M ./libsofia-sip-ua/tport/Makefile.am -6 +2
+
+	Fri Sep 23 18:57:20 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using --with-aclocal and ${ACLOCAL} to get correct aclocal
+	    install directory.
+
+	    M ./Makefile.am -2
+	    M ./configure.ac +11
+	    M ./sofia-sip.spec.in -1 +1
+
+	Fri Sep 23 18:36:46 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added win32 into dist.
+
+	    M ./Makefile.am -1 +1
+	    M ./configure.ac +1
+	    A ./win32/Makefile.am
+
+	Fri Sep 23 18:18:30 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added nta/{agent.pem,cafile.pem} to EXTRA_DIST
+
+	    M ./libsofia-sip-ua/nta/Makefile.am -1 +2
+
+	Fri Sep 23 18:10:45 EEST 2005  Pekka.Pessi at nokia.com
+	  * Respect --without-sigcomp.
+
+	    M ./m4/sac-tport.m4 -1 +1
+
+	* darcs changes --from-tag pessi-darcs-2:
+
+	Fri Sep 23 17:46:00 EEST 2005  Pekka.Pessi at nokia.com
+	  tagged pessi-darcs-2
+
+	Fri Sep 23 17:20:02 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added msg_header_replace().
+
+	    M ./libsofia-sip-ua/msg/msg_header.h +4
+	    M ./libsofia-sip-ua/msg/msg_parser.c +85
+	    M ./libsofia-sip-ua/msg/msg_test.c +76
+
+	Thu Sep 22 13:18:52 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added nta_test project
+
+	    A ./win32/nta_test/
+	    A ./win32/nta_test/nta_test.dsp
+
+	Thu Sep 22 13:17:53 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added build directory for win32.
+
+	    A ./win32/SofiaSIP.dsw
+	    A ./win32/config.h
+	    A ./win32/libsofia-sip-ua/
+	    A ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp
+	    A ./win32/libsofia-sip-ua/sofia-sip-ua.def
+	    A ./win32/su_configure_win32.h
+	    A ./win32/tpipv6.h
+	    A ./win32/unistd.h
+	    A ./win32/wspiapi.h
+
+	Thu Sep 22 13:15:32 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added win32 pthread library.
+
+	    A ./win32/pthread/
+	    A ./win32/pthread/ChangeLog
+	    A ./win32/pthread/md5.sum.txt
+	    A ./win32/pthread/pthread.def
+	    A ./win32/pthread/pthread.dll
+	    A ./win32/pthread/pthread.h
+	    A ./win32/pthread/pthread.lib
+	    A ./win32/pthread/sched.h
+	    A ./win32/pthread/semaphore.h
+
+	Thu Sep 22 13:13:03 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added ntv6 library.
+
+	    A ./win32/
+	    A ./win32/ntv6/
+	    A ./win32/ntv6/include/
+	    A ./win32/ntv6/include/icmp6.h
+	    A ./win32/ntv6/include/ip6.h
+	    A ./win32/ntv6/include/ip6addr.h
+	    A ./win32/ntv6/include/ip6exp.h
+	    A ./win32/ntv6/include/ipsec.h
+	    A ./win32/ntv6/include/ipv6.h
+	    A ./win32/ntv6/include/ntddip6.h
+	    A ./win32/ntv6/include/ntddnapt.h
+	    A ./win32/ntv6/include/ntddtcp.h
+	    A ./win32/ntv6/include/packoff.h
+	    A ./win32/ntv6/include/packon.h
+	    A ./win32/ntv6/include/tcp6info.h
+	    A ./win32/ntv6/include/tcpinfo.h
+	    A ./win32/ntv6/include/tdi.h
+	    A ./win32/ntv6/include/tdistat.h
+	    A ./win32/ntv6/include/ws2ip6.h
+	    A ./win32/ntv6/include/ws2tcpip-msr.h
+	    A ./win32/ntv6/lib/
+	    A ./win32/ntv6/lib/wship6.lib
+
+	Tue Sep 20 12:51:58 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed typo.
+
+	    M ./libsofia-sip-ua/soa/soa.docs -1 +1
+
+	Tue Sep 20 12:51:41 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added SIPS_PORT()
+
+	    M ./libsofia-sip-ua/sip/sip_header.h +3
+
+	Mon Sep 19 20:12:33 EEST 2005  Pekka.Pessi at nokia.com
+	  * Updated. Added rules for ignoring SDP. corrected some 
+
+	    M ./libsofia-sip-ua/soa/soa.docs -8 +18
+
+	Fri Sep 16 10:23:14 EEST 2005  Pekka.Pessi at nokia.com
+	  * Parsing URI along with DNS entries in subjectAltName.
+
+	    M ./libsofia-sip-ua/tport/tport_tls.c -5 +12
+
+	Fri Sep 16 10:22:39 EEST 2005  Pekka.Pessi at nokia.com
+	  * Not requiring client to provide its certificate.
+
+	    M ./libsofia-sip-ua/tport/tport_tls.c -1 +1
+
+	Fri Sep 16 10:21:56 EEST 2005  Pekka.Pessi at nokia.com
+	  * Removed merge artifact.
+
+	    M ./libsofia-sip-ua/tport/tport.c -7
+
+	Fri Sep 16 10:21:32 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed NAPTR service fields for SIPS/TLS and SIP/SCTP.
+
+	    M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+	Thu Sep 15 09:57:38 EEST 2005  Pekka.Pessi at nokia.com
+	  * Included m4 files in devel rpm, too.
+
+	    M ./sofia-sip.spec.in +4
+
+	Thu Sep 15 09:56:25 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added --with-sigcomp to tport.
+
+	    M ./m4/sac-tport.m4 +21
+
+	Thu Sep 15 09:55:57 EEST 2005  Pekka.Pessi at nokia.com
+	  * Moved SAC_GNU_SOURCE into sac-general.m4
+
+	    M ./m4/sac-general.m4 +11
+	    M ./m4/sac-su.m4 -10
+
+	Thu Sep 15 09:55:26 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed debugging output in nua_stack.c.
+
+	    M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+
+	Thu Sep 15 09:53:11 EEST 2005  Pekka.Pessi at nokia.com
+	  * Installing m4data into m4dir
+
+	    M ./Makefile.am +4
+
+2005-09-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* darcs changes --from-tag pessi-darcs-1:
+
+	Fri Sep  9 11:38:44 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added --with sigcomp.
+
+	    M ./sofia-sip.spec.in +4
+
+	Fri Sep  9 00:33:36 EEST 2005  Pekka.Pessi at nokia.com
+	  * Including *.h.in files in devel package.
+
+	    M ./sofia-sip.spec.in +1
+
+	Thu Sep  8 18:52:06 EEST 2005  Pekka.Pessi at nokia.com
+	  * New version.
+
+	    M ./configure.ac -1 +1
+
+	Thu Sep  8 18:51:27 EEST 2005  Pekka.Pessi at nokia.com
+	  * Keeping section headers in configure script.
+
+	    M ./configure.ac -17 +16
+
+	Thu Sep  8 18:26:35 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using autoconf to figure out 64-bit types. Avoid off_t and
+	    64-bit constants.
+
+	    M ./configure.ac +6
+	    M ./libsofia-sip-ua/nta/sl_read_payload.c -1 +1
+	    M ./libsofia-sip-ua/nua/nua_stack.c -6 +5
+	    M ./libsofia-sip-ua/sdp/sdp_parse.c -3 +2
+	    M ./libsofia-sip-ua/sdp/sdp_print.c -5 +5
+	    M ./libsofia-sip-ua/sip/validator.c -18 +18
+	    M ./libsofia-sip-ua/soa/soa.c -3 +4
+	    M ./libsofia-sip-ua/su/su_time.c -1 +1
+	    M ./libsofia-sip-ua/su/tstdef.h -3 +3
+
+	Thu Sep  8 18:17:58 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using RETSIGTYPE.
+
+	    M ./configure.ac -3 +4
+	    M ./libsofia-sip-ua/nth/http-server.c -2 +2
+	    M ./libsofia-sip-ua/soa/test_soa.c -1 +3
+	    M ./libsofia-sip-ua/su/su_test.c -1 +1
+	    M ./libsofia-sip-ua/su/su_timer_test.c -1 +1
+
+	Thu Sep  8 18:02:14 EEST 2005  Pekka.Pessi at nokia.com
+	  * Checking for netinet/tcp.h, too.
+
+	    M ./m4/sac-tport.m4 +2
+
+2005-09-08  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am: Added requirement for automake-1.6.1
+	or newer.
+
+	* autogen.sh: Fixed interop problem with older automake 
+	versions.
+
+	* configure.ac: Do not compile STUN if OpenSSL is not
+	available.
+
+2005-07-20  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Makefile.am: Added doxygen target.

Added: freeswitch/trunk/libs/sofia-sip/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+#
+# Makefile.am for sofia-sip package
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+AUTOMAKE_OPTIONS = foreign 1.7
+
+SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages
+DIST_SUBDIRS = libsofia-sip-ua libsofia-sip-ua-glib utils packages win32
+
+# note: when glib devel files are not available, make should not
+#       enter the libsofia-sip-ua-glib subdir at all
+if HAVE_GLIB
+GLIB_SUBDIRS = libsofia-sip-ua-glib
+endif
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+EXTRA_DIST =	AUTHORS COPYING COPYRIGHTS ChangeLog.ext-trees \
+		README README.developers RELEASE TODO 
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST += 	m4/sac-general.m4 m4/sac-su.m4 \
+		m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
+
+dist_man_MANS = man/man1/sip-date.1 man/man1/sip-options.1 \
+		man/man1/localinfo.1 man/man1/addrinfo.1 \
+		man/man1/stunc.1 man/man1/sip-dig.1
+
+$(dist_man_MANS): manpages
+
+manpages: built-sources
+	-mkdir -p man man/man1 2> /dev/null
+if HAVE_DOXYGEN
+	cd utils && $(DOXYGEN) Doxyfile.build
+	@rm -f man/man1/_*.1
+else
+	-touch $(dist_man_MANS)
+endif
+
+CLEANFILES = $(dist_man_MANS)
+
+coverage built-sources clean-built-sources doxygen:
+	for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do $(MAKE) $(AM_MAKEFLAGS) -C $$i $@ ; done
+
+.PHONY: coverage built-sources clean-built-sources doxygen manpages

Added: freeswitch/trunk/libs/sofia-sip/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,758 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip package
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = README $(am__configure_deps) $(dist_man_MANS) \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/config.h.in $(top_srcdir)/configure \
+	$(top_srcdir)/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in \
+	$(top_srcdir)/libsofia-sip-ua/su/sofia-sip/su_configure.h.in \
+	AUTHORS COPYING ChangeLog TODO compile config.guess config.sub \
+	depcomp install-sh ltmain.sh missing
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =  \
+	libsofia-sip-ua/features/sofia-sip/sofia_features.h
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-exec-recursive install-info-recursive \
+	install-recursive installcheck-recursive installdirs-recursive \
+	pdf-recursive ps-recursive uninstall-info-recursive \
+	uninstall-recursive
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d $(distdir) \
+    || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = -I m4
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AUTOMAKE_OPTIONS = foreign 1.7
+SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages
+DIST_SUBDIRS = libsofia-sip-ua libsofia-sip-ua-glib utils packages win32
+
+# note: when glib devel files are not available, make should not
+#       enter the libsofia-sip-ua-glib subdir at all
+ at HAVE_GLIB_TRUE@GLIB_SUBDIRS = libsofia-sip-ua-glib
+EXTRA_DIST = AUTHORS COPYING COPYRIGHTS ChangeLog.ext-trees README \
+	README.developers RELEASE TODO m4/sac-general.m4 m4/sac-su.m4 \
+	m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
+dist_man_MANS = man/man1/sip-date.1 man/man1/sip-options.1 \
+		man/man1/localinfo.1 man/man1/addrinfo.1 \
+		man/man1/stunc.1 man/man1/sip-dig.1
+
+CLEANFILES = $(dist_man_MANS)
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+	      cd $(srcdir) && $(AUTOMAKE) --foreign  \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	cd $(top_srcdir) && $(AUTOHEADER)
+	rm -f stamp-h1
+	touch $@
+
+libsofia-sip-ua/su/sofia-sip/su_configure.h: libsofia-sip-ua/su/sofia-sip/stamp-h2
+	@if test ! -f $@; then \
+	  rm -f libsofia-sip-ua/su/sofia-sip/stamp-h2; \
+	  $(MAKE) libsofia-sip-ua/su/sofia-sip/stamp-h2; \
+	else :; fi
+
+libsofia-sip-ua/su/sofia-sip/stamp-h2: $(top_srcdir)/libsofia-sip-ua/su/sofia-sip/su_configure.h.in $(top_builddir)/config.status
+	@rm -f libsofia-sip-ua/su/sofia-sip/stamp-h2
+	cd $(top_builddir) && $(SHELL) ./config.status libsofia-sip-ua/su/sofia-sip/su_configure.h
+
+distclean-hdr:
+	-rm -f config.h stamp-h1 libsofia-sip-ua/su/sofia-sip/su_configure.h libsofia-sip-ua/su/sofia-sip/stamp-h2
+libsofia-sip-ua/features/sofia-sip/sofia_features.h: $(top_builddir)/config.status $(top_srcdir)/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-man1: $(man1_MANS) $(man_MANS)
+	@$(NORMAL_INSTALL)
+	test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
+	@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.1*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+	  else file=$$i; fi; \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    1*) ;; \
+	    *) ext='1' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+	done
+uninstall-man1:
+	@$(NORMAL_UNINSTALL)
+	@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.1*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    1*) ;; \
+	    *) ext='1' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+	  rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+	done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	mkdir $(distdir)
+	$(mkdir_p) $(distdir)/libsofia-sip-ua/docs $(distdir)/libsofia-sip-ua/features/sofia-sip $(distdir)/libsofia-sip-ua/su/sofia-sip $(distdir)/m4 $(distdir)/man/man1 $(distdir)/packages $(distdir)/utils $(distdir)/win32
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(mkdir_p) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	    distdir=`$(am__cd) $(distdir) && pwd`; \
+	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+	    (cd $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$top_distdir" \
+	        distdir="$$distdir/$$subdir" \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r $(distdir)
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+	$(am__remove_distdir)
+
+dist-tarZ: distdir
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__remove_distdir)
+
+dist-shar: distdir
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__remove_distdir)
+
+dist dist-all: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir); chmod a+w $(distdir)
+	mkdir $(distdir)/_build
+	mkdir $(distdir)/_inst
+	chmod a-w $(distdir)
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && cd $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+	$(am__remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+	@cd $(distuninstallcheck_dir) \
+	&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(MANS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(man1dir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-man
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man: install-man1
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-info: uninstall-info-recursive
+
+uninstall-man: uninstall-man1
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+	check-am clean clean-generic clean-libtool clean-recursive \
+	ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
+	dist-shar dist-tarZ dist-zip distcheck distclean \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-recursive distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-man1 install-strip installcheck installcheck-am \
+	installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic maintainer-clean-recursive \
+	mostlyclean mostlyclean-generic mostlyclean-libtool \
+	mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+	uninstall uninstall-am uninstall-info-am uninstall-man \
+	uninstall-man1
+
+
+$(dist_man_MANS): manpages
+
+manpages: built-sources
+	-mkdir -p man man/man1 2> /dev/null
+ at HAVE_DOXYGEN_TRUE@	cd utils && $(DOXYGEN) Doxyfile.build
+ at HAVE_DOXYGEN_TRUE@	@rm -f man/man1/_*.1
+ at HAVE_DOXYGEN_FALSE@	-touch $(dist_man_MANS)
+
+coverage built-sources clean-built-sources doxygen:
+	for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do $(MAKE) $(AM_MAKEFLAGS) -C $$i $@ ; done
+
+.PHONY: coverage built-sources clean-built-sources doxygen manpages
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/README	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+=============================================================
+README / Sofia-SIP - RFC3261 compliant SIP User-Agent library
+=============================================================
+
+Introduction
+------------
+
+Sofia-SIP is an open-source SIP User-Agent library, compliant 
+with the IETF RFC3261 specification. It can be used as 
+a building block for SIP client software for uses such as VoIP, 
+IM, and many other real-time and person-to-person communication 
+services. The primary target platform for Sofia-SIP is 
+GNU/Linux. Sofia-SIP is based on a SIP stack developed at 
+the Nokia Research Center. Sofia-SIP is licensed under the LGPL.
+
+
+Quick start
+-----------
+
+Sofia-SIP uses the GNU autotools, so building procedure
+is the usual:
+
+sh> sh autogen.sh (if building from darcs)
+sh> ./configure
+sh> make
+sh> make install
+
+See also 'docs/devel_platform_notes.txt' for notes on compiling
+Sofia-SIP in different environments.
+
+See the "options-client-example" (available using darcs at
+http://sofia-sip.org/repos/options-client-example/ or with CVS as
+a module in Sofia-SIP CVS tree) for an example of a small app that
+is utilizing Sofia-SIP, and specifically the libsofia-sip-ua
+library component.
+
+There are also multiple example clients under
+the "sofia-sip/utils" directory:
+
+- sip-options, query using SIP OPTIONS method
+- sip-date, SIP date printer/parser
+
+The Sofia-SIP su submodule also provides some small utilities:
+
+- addrinfo (libsofia-sip-ua/su), resolve host names 
+- localinfo (libsofia-sip-ua/su), prints information about
+  local network interfaces 
+
+
+References
+----------
+
+Project website:
+- http://sofia-sip.sourceforge.net
+- http://www.sourceforge.net/projects/sofia-sip
+
+Mailing list:
+- http://sourceforge.net/mail/?group_id=143636
+
+Version control repositories:
+- see the project website (link above)
+
+Licensing
+---------
+
+Sofia-SIP is licensed under terms of the GNU LGPL.
+See the file "COPYING" for more information.

Added: freeswitch/trunk/libs/sofia-sip/README.developers
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/README.developers	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,134 @@
+===============================================================
+README.developers - Sofia-SIP development practices
+===============================================================
+
+Introduction
+============
+
+This file is a collection of practices and rules for Sofia-SIP
+development. If you have questions, or would like to make 
+changes, raise the issue on sofia-sip-devel (see 
+http://lists.sourceforge.net/lists/listinfo/sofia-sip-devel ).
+
+
+Important files for developers
+==============================
+
+AUTHORS
+	List of contributors. When contributing new code, add 
+	yourself to AUTHORS, and also remember to update the
+	per source file copyright statements.
+
+COPYRIGHTS
+	List of licenses and related copyright statements. While 
+	majority of Sofia-SIP is licensed under LGPL, there are
+	a few files with different, but LGPL compatible, licensing 
+	terms.
+	
+README.developers 
+	This file.
+
+TODO
+	Not in active use yet.
+
+<dir>/ChangeLog files
+	All non-trivial changes to the source code should
+	be documented in the ChangeLog files. See also the 
+	top-level ChangeLog.
+
+
+Version numbering 
+=================
+
+Package version
+---------------
+
+For public releases, the package version is:
+     vMAJOR.MINOR.REVISION, where MINOR is even
+
+For development releases and snaphots the version is one of:
+     vMAJOR.MINOR.REVISION, where minor is odd
+     vMAJOR.MINOR.REVISION.YEAR.MONTH.DAY, where minor is odd
+
+For all releases, the version should be changed in configure.ac 
+and committed to Darcs/CVS before making the release package. The person 
+doing the release is responsible for updating the version number.
+
+Library interface versions
+--------------------------
+
+Sofia-SIP libraries utilize libtool interface versioning. See
+
+  - http://www.gnu.org/software/libtool/manual.html#Versioning
+  - http://www.gnu.org/software/libtool/manual.html#Using-Automake
+
+The interface versions are set in top-level 'configure.ac' file.
+Additionally, the SONAME version (CURRENT-AGE) is set in the
+same place. These version numbers are available for use as autoconf 
+variables (see the library 'Makefile.am' files and 
+'packages/sofia-sip.spec.in').
+
+All changes to the library versions should be marked to the
+appropriate library 'ChangeLog' file. The library version should
+be changed at the same time as the first interface change is 
+committed since the previous release. The interface version is 
+frozen (should be marked to the 'ChangeLog' file) at the time
+the next release is tagged (in other words, intra-release changes
+need not be tracked with libtool versions).
+
+The goal should always be to avoid breaking the API/ABIs until
+absolutely necessary. Interfaces clearly marked as private can
+be changed without change to library interface version, but
+otherwise all public functions, types, variables and definitions
+fall under interface change control.
+
+
+Version control tags
+====================
+
+Tagging releases and snapshots
+------------------------------
+
+- source repository (*)
+    - master Darcs tree at:
+      http://sofia-sip.org/repos/sofia-sip
+    - CVS tree (only used to track major releases) at:
+      http://sourceforge.net/cvs/?group_id=143636
+- tags: rel-sofia-sip-x_y_z
+    - stable and development releases (matches release 
+      version sofia-sip-x.y.z)
+- tags: snapshot_rel_YEARMMDD
+    - snapshot releases at
+      http://sofia-sip.sourceforge.net/snapshots/
+
+Notes (*):
+    - Information about Darcs:
+      http://abridgegame.org/darcs/
+      http://lwn.net/Articles/110516/
+
+
+Sending patches
+===============
+
+People without Darcs access
+---------------------------
+
+Send your patches to sofia-sip-devel. Someone from the 
+development team (see AUTHORS) will handle the patch.
+
+People with Darcs access
+------------------------
+
+Trivial changes can be committed without review. For non-trivial 
+changes, you should first send a proposal to sofia-sip-devel and
+wait for comments. There are no strict approval rules so use of
+common sense is recommended. ;)
+
+Tips for making patches
+-----------------------
+
+- test your patch on a clean checkout from version control system
+- remember to check for updates before pushing your changes
+  to the master repository
+
+

Added: freeswitch/trunk/libs/sofia-sip/RELEASE
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/RELEASE	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,96 @@
+==============================================
+Release notes for current version of Sofia-SIP
+==============================================
+
+Changes since last release
+--------------------------
+
+<changes since last written in freshmeat.net "Changes:" style;
+ and in less than 10 lines />
+
+Bugs in blaa and foo have been fixed. The stack now supports
+use of foobar...
+
+API/ABI changes and versioning
+------------------------------
+
+<see previous release notes at
+ http://sofia-sip.sourceforge.net/relnotes/ for examples ;
+ - should include all changes to public headers, and 
+   other important information to developers; 
+ - and should be updated _continuously_! />
+
+**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X.
+
+libsofia-sip-ua:
+- **template**: Added foobar() function (sofia-sip/foobar.h).
+- Added sip_is_allowed() function and k_bitmap field to the 
+  sip_allow_t structure 
+- Added SIP header Refer-Sub and related functions
+- Added <sofia-sip/sip_extra.h> include file
+- Added auc_info() function (sofia-sip/auth_client.h)
+- This release is ABI/API compatible with applications linked against 
+  any 1.12.x release. However, applications built against this release won't 
+  work against an older library. The ABI has been tested with the nua module 
+  unit test (test_nua) built against original 1.12.0 release.
+
+libsofia-sip-ua-glib:
+- The 'nua-glib' module has been removed from the library and moved
+  to a separate package 'sofia-nua-glib'. The remaining library (su-glib) 
+  is now considered stable and will be API/ABI compatible with later 
+  releases in the 1.12.x series.
+- ABI has been modified and applications built against 1.12.4 and earlier 
+  releases need to be rebuilt.
+
+Contributors to this release
+----------------------------
+
+<list of people who contributed to _this_ release
+ - update as people's patches are added, or when you commit stuff
+ - current development team members (see AUTHORS) may be omitted
+ - name of the contributor should be enough (email addresses in AUTHORS),
+   plus a brief description of what was contributed
+ - roughly sorted by number of patches accepted
+/> 
+
+- **template**: First Surname (patch to nua/soa/msg)
+- Petteri Puolakka (patch to stun)
+
+See the AUTHORS file in the distribution package.
+
+Notes on new features
+---------------------
+
+RFC 4488 defines the Refer-Sub header. Its datatypes, related functions and
+methods declared in <sofia-sip/sip_extra.h> include file. The Refer-Sub
+header structure can be accessed from sip_t structure with sip_refer_sub()
+method, e.g.,
+
+  if (sip_refer_sub(sip) && 
+      strcasecmp("false", sip_refer_sub(sip)->rs_value) == 0) {
+     /* Do not create implicit subscription */ 
+  }
+
+<information about major new features
+ - new/changed/removed functionality
+ - links to further documentation
+ - section may be omitted for minor releases
+/> 
+
+Bugs fixed in this release
+--------------------------
+
+< notable bugs fixed in this release
+ - check the sf.net bug tracker; see closed bugs,
+   sorted by closing date
+ - other bugs as fixed in CVS/darcs
+/>
+
+- **template**: #9499652 sf.net bug item title
+
+- Fixed crash when nua_bye() was called while a NOTIFY client transaction
+  was in progress. Problem reported by Anthony Minnessale.
+- Not using close() with sockets in sres.c. Problem reported by
+  Roman Filonenko.
+- Bug in zero-padding STUN messages with a message integrity 
+  attribute. Patch by Petteri Puolakka.

Added: freeswitch/trunk/libs/sofia-sip/RELEASE.template
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/RELEASE.template	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+==============================================
+Release notes for current version of Sofia-SIP
+==============================================
+
+Changes since last release
+--------------------------
+
+<changes since last written in freshmeat.net "Changes:" style;
+ and in less than 10 lines />
+
+Bugs in blaa and foo have been fixed. The stack now supports
+use of foobar...
+
+API/ABI changes and versioning
+------------------------------
+
+<see previous release notes at
+ http://sofia-sip.sourceforge.net/relnotes/ for examples ;
+ - should include all changes to public headers, and 
+   other important information to developers; 
+ - and should be updated _continuously_! />
+
+**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X.
+
+libsofia-sip-ua:
+- **template**: Added foobar() function (sofia-sip/foobar.h).
+- This release is ABI/API compatible with applications linked against 
+  any 1.12.x release. However, applications built against this release won't 
+  work against an older library. The ABI has been tested with the nua module 
+  unit test (test_nua) built against original 1.12.0 release.
+
+libsofia-sip-ua-glib:
+- No ABI/API changes, compatible with 1.12.0. Note, libsofia-sip-ua-glib
+  interface is not considered stable and may change in a future 1.12.x
+  release.
+
+Contributors to this release
+----------------------------
+
+<list of people who contributed to _this_ release
+ - update as people's patches are added, or when you commit stuff
+ - current development team members (see AUTHORS) may be omitted
+ - name of the contributor should be enough (email addresses in AUTHORS),
+   plus a brief description of what was contributed
+ - roughly sorted by number of patches accepted
+/> 
+
+- **template**: First Surname (patch to nua/soa/msg)
+
+See the AUTHORS file in the distribution package.
+
+Notes on new features
+---------------------
+
+<information about major new features
+ - new/changed/removed functionality
+ - links to further documentation
+ - section may be omitted for minor releases
+/> 
+
+Bugs fixed in this release
+--------------------------
+
+< notable bugs fixed in this release
+ - check the sf.net bug tracker; see closed bugs,
+   sorted by closing date
+ - other bugs as fixed in CVS/darcs
+/>
+
+- **template**: #9499652 sf.net bug item title

Added: freeswitch/trunk/libs/sofia-sip/TODO
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/TODO	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29 @@
+===============================================================
+TODO / Sofia-SIP
+===============================================================
+
+version: 20060907-2
+
+Release roadmap
+---------------
+
+1.11/1.12 series
+    - first version of the new nua+soa API 
+ 	- nua_respond_nit() (non-INVITEs)
+	- nua_set_hparams()/nua_get_hparams() [DONE]
+	- session object ownership changes [DONE]
+        - allow multiple registrations (lines) and selecting 
+          service route, outbound proxy, and transport independently
+          for each handle; NUTAG_IDENTITY
+    - doxygen documentation updates [DONE]
+    - rpm and dpkg packaging [DONE]
+    - NAT work: STUN fixes (DNS support) [DONE]
+
+not roadmapped:
+    - expand the call-state-change mechanism
+    - update http headers TE, Cookie, Set-Cookie
+
+2.0 serias
+    - a verified stable API (1.12 is the current stable candidate)
+
+See README.developers for information about versioning.

Added: freeswitch/trunk/libs/sofia-sip/aclocal.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/aclocal.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7048 @@
+# generated automatically by aclocal 1.9.2 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+
+# serial 47 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+         [],
+         [m4_define([AC_PROVIDE_IFELSE],
+	         [m4_ifdef([AC_PROVIDE_$1],
+		           [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+    [AC_LIBTOOL_CXX],
+    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+  ])])
+dnl And a similar setup for Fortran 77 support
+  AC_PROVIDE_IFELSE([AC_PROG_F77],
+    [AC_LIBTOOL_F77],
+    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+    [AC_LIBTOOL_GCJ],
+    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+      [AC_LIBTOOL_GCJ],
+      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+	[AC_LIBTOOL_GCJ],
+      [ifdef([AC_PROG_GCJ],
+	     [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([A][M_PROG_GCJ],
+	     [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([LT_AC_PROG_GCJ],
+	     [define([LT_AC_PROG_GCJ],
+		defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+    ;;
+  *)
+    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    AC_PATH_MAGIC
+  fi
+  ;;
+esac
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+	[avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+    [AC_HELP_STRING([--with-pic],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+	 [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+  ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+[$]*
+EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+       echo_test_string="`eval $cmd`" &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+    then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+   test "X$echo_testing_string" = "X$echo_test_string"; then
+  :
+else
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+	 test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running configure again with it.
+      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+    else
+      # Try using printf.
+      echo='printf %s\n'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+	 echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+	 test "X$echo_testing_string" = "X$echo_test_string"; then
+	# Cool, printf works
+	:
+      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+	export CONFIG_SHELL
+	SHELL="$CONFIG_SHELL"
+	export SHELL
+	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      else
+	# maybe with a smaller string...
+	prev=:
+
+	for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+	  if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+	  then
+	    break
+	  fi
+	  prev="$cmd"
+	done
+
+	if test "$prev" != 'sed 50q "[$]0"'; then
+	  echo_test_string=`eval $prev`
+	  export echo_test_string
+	  exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+	else
+	  # Oops.  We lost completely, so just stick with echo.
+	  echo=echo
+	fi
+      fi
+    fi
+  fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+	[avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+  ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$5], , :, [$5])
+else
+    ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+     else
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$4], , :, [$4])
+else
+    ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+ *)
+    # If test is not a shell built-in, we'll probably end up computing a
+    # maximum length that is only half of the actual maximum length, but
+    # we can't tell.
+    while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+	       = "XX$teststring") >/dev/null 2>&1 &&
+	    new_result=`expr "X$teststring" : ".*" 2>&1` &&
+	    lt_cv_sys_max_cmd_len=$new_result &&
+	    test $i != 17 # 1/2 MB should be enough
+    do
+      i=`expr $i + 1`
+      teststring=$teststring$teststring
+    done
+    teststring=
+    # Add a significant safety factor because C++ compilers can tack on massive
+    # amounts of additional arguments before passing them to the linker.
+    # It appears as though 1/2 is a usable value.
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# --------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}]
+EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_unknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# -------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+   ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_AC_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+    	  lt_cv_dlopen_self_static, [dnl
+	  _LT_AC_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s out/conftest.err; then
+       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+   test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \
+   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         AC_MSG_RESULT([yes])
+       else
+  AC_MSG_RESULT([no])
+fi
+       ;;
+   *)
+  AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi4*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+    if AC_TRY_EVAL(ac_compile); then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=yes
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_ARG_WITH([tags],
+    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+        [include additional configurations @<:@automatic@:>@])],
+    [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    AC_MSG_WARN([output file `$ofile' does not exist])
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+    else
+      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+    fi
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+    "") ;;
+    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+	;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      AC_MSG_ERROR([tag name \"$tagname\" already exists])
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+	if test -n "$CXX" && test "X$CXX" != "Xno"; then
+	  AC_LIBTOOL_LANG_CXX_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      F77)
+	if test -n "$F77" && test "X$F77" != "Xno"; then
+	  AC_LIBTOOL_LANG_F77_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      GCJ)
+	if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+	  AC_LIBTOOL_LANG_GCJ_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      RC)
+	AC_LIBTOOL_LANG_RC_CONFIG
+	;;
+
+      *)
+	AC_MSG_ERROR([Unsupported tag name: $tagname])
+	;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+  fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 dll's
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+#- set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="ifelse([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi4*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | kfreebsd*-gnu)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case "$host_cpu" in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  case $host_cpu in
+  alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*)
+    lt_cv_deplibs_check_method=pass_all ;;
+  *)
+    # glibc up to 2.1.1 does not perform some relocations on ARM
+    # this will be overridden with pass_all, but let us keep it just in case
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;;
+  esac
+  lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
+  else
+    lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sco3.2v5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+    if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      # Tru64's nm complains that /dev/null is an invalid object file
+      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+      */dev/null* | *'Invalid file or object type'*)
+	lt_cv_path_NM="$tmp_nm -B"
+	break
+        ;;
+      *)
+	case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	*/dev/null*)
+	  lt_cv_path_NM="$tmp_nm -p"
+	  break
+	  ;;
+	*)
+	  lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	  continue # so that we can try to find one that supports BSD flags
+	  ;;
+	esac
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments.  Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+# DIRECTORY is not provided, it is assumed to be `libltdl'.  LIBLTDL will
+# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with
+# '${top_srcdir}/' (note the single quotes!).  If your package is not
+# flat and you're not using automake, define top_builddir and
+# top_srcdir appropriately in the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case $enable_ltdl_convenience in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments.  Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+# DIRECTORY is not provided and an installed libltdl is not found, it is
+# assumed to be `libltdl'.  LIBLTDL will be prefixed with '${top_builddir}/'
+# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single
+# quotes!).  If your package is not flat and you're not using automake,
+# define top_builddir and top_srcdir appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, lt_dlinit,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AC_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    LTDLINCL=
+  fi
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+	 [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+	   [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# --------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+_LT_AC_SYS_COMPILER
+
+#
+# Check for any special shared library compilation flags.
+#
+_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
+if test "$GCC" = no; then
+  case $host_os in
+  sco3.2v5*)
+    _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
+    ;;
+  esac
+fi
+if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
+  AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
+  if echo "$old_CC $old_CFLAGS " | grep "[[ 	]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ 	]]" >/dev/null; then :
+  else
+    AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
+    _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
+  fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
+  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+  $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
+  [],
+  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+# Report which librarie types wil actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+  ;;
+  darwin* | rhapsody*)
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    case "$host_os" in
+    rhapsody* | darwin1.[[012]])
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+      ;;
+    *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[[012]])
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+      ;;
+    esac
+    output_verbose_link_cmd='echo'
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
+    _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+    # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag  -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+    _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+  else
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+  fi
+    ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+  AC_PROG_LD
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+	grep 'no-whole-archive' > /dev/null; then
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  aix4* | aix5*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
+      no_entry_flag=""
+    else
+      aix_use_runtimelinking=no
+
+      # Test if we are trying to use run time linking or normal
+      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+      # need to do runtime linking.
+      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+	for ld_flag in $LDFLAGS; do
+	  case $ld_flag in
+	  *-brtl*)
+	    aix_use_runtimelinking=yes
+	    break
+	    ;;
+	  esac
+	done
+      esac
+
+      exp_sym_flag='-bexport'
+      no_entry_flag='-bnoentry'
+    fi
+
+    # When large executables or shared objects are built, AIX ld can
+    # have problems creating the table of contents.  If linking a library
+    # or program results in "error TOC overflow" add -mminimal-toc to
+    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+    _LT_AC_TAGVAR(archive_cmds, $1)=''
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes; then
+      case $host_os in aix4.[012]|aix4.[012].*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
+	collect2name=`${CC} -print-prog-name=collect2`
+	if test -f "$collect2name" && \
+	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	then
+	  # We have reworked collect2
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	else
+	  # We have old collect2
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+	fi
+      esac
+      shared_flag='-shared'
+    else
+      # not using gcc
+      if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	shared_flag='-G'
+      else
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag='${wl}-G'
+	else
+	  shared_flag='${wl}-bM:SRE'
+	fi
+      fi
+    fi
+
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+    if test "$aix_use_runtimelinking" = yes; then
+      # Warning - without using the other runtime loading flags (-brtl),
+      # -berok will link without error, but may produce a broken library.
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      _LT_AC_SYS_LIBPATH_AIX
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
+      if test "$host_cpu" = ia64; then
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+      else
+	# Determine the default libpath from the value encoded in an empty executable.
+	_LT_AC_SYS_LIBPATH_AIX
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	# Warning - without using the other run time loading flags,
+	# -berok will link without error, but may produce a broken library.
+	_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	# -bexpall does not export symbols beginning with underscore (_)
+	_LT_AC_TAGVAR(always_export_symbols, $1)=yes
+	# Exported symbols can be pulled into shared objects from archives
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+	# This is similar to how AIX traditionally builds it's shared libraries.
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+      fi
+    fi
+    ;;
+  chorus*)
+    case $cc_basename in
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+    # as there is no search path for DLLs.
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	cp $export_symbols $output_objdir/$soname.def;
+      else
+	echo EXPORTS > $output_objdir/$soname.def;
+	cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+  ;;
+
+  darwin* | rhapsody*)
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    case "$host_os" in
+    rhapsody* | darwin1.[[012]])
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+      ;;
+    *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[[012]])
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+      ;;
+    esac
+    lt_int_apple_cc_single_mod=no
+    output_verbose_link_cmd='echo'
+    if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+      lt_int_apple_cc_single_mod=yes
+    fi
+    if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    else
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    fi
+    _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+
+    # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+    if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    else
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+    _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+  else
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+  fi
+    ;;
+
+  dgux*)
+    case $cc_basename in
+      ec++)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      ghcx)
+	# Green Hills C++ Compiler
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  freebsd[12]*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  freebsd-elf*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  freebsd* | kfreebsd*-gnu)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+    ;;
+  gnu*)
+    ;;
+  hpux9*)
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				# but as the default
+				# location of the library.
+
+    case $cc_basename in
+    CC)
+      # FIXME: insert proper C++ library support
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    aCC)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      case "$host_cpu" in
+      hppa*64*)
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+        ;;
+      ia64*)
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        ;;
+      *)
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        ;;
+      esac
+    fi
+    case "$host_cpu" in
+    hppa*64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+    ia64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					      # but as the default
+					      # location of the library.
+      ;;
+    *)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					      # but as the default
+					      # location of the library.
+      ;;
+    esac
+
+    case $cc_basename in
+      CC)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      aCC)
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  ;;
+	esac
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test $with_gnu_ld = no; then
+	    case "$host_cpu" in
+	    ia64*|hppa*64*)
+	      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+	      ;;
+	    *)
+	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      ;;
+	    esac
+	  fi
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  irix5* | irix6*)
+    case $cc_basename in
+      CC)
+	# SGI C++
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+	# Archives containing C++ object files must be created using
+	# "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test "$with_gnu_ld" = no; then
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+	  else
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+	  fi
+	fi
+	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+	;;
+    esac
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    ;;
+  linux*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	;;
+      icpc)
+	# Intel C++
+	with_gnu_ld=yes
+	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	;;
+      cxx)
+	# Compaq C++
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	runpath_var=LD_RUN_PATH
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+    esac
+    ;;
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  m88k*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  mvs*)
+    case $cc_basename in
+      cxx)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+    ;;
+  osf3*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+	;;
+      RCC)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      cxx)
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Archives containing C++ object files must be created using
+	# the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+	;;
+      RCC)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      cxx)
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	  echo "-hidden">> $lib.exp~
+	  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version	$verstring` -update_registry $objdir/so_locations -o $lib~
+	  $rm $lib.exp'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	 _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  sco*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    case $cc_basename in
+      CC)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC)
+	# Sun C++ 4.x
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      lcc)
+	# Lucid
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  solaris*)
+    case $cc_basename in
+      CC)
+	# Sun C++ 4.2, 5.x and Centerline C++
+	_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	$CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	case $host_os in
+	  solaris2.[0-5] | solaris2.[0-5].*) ;;
+	  *)
+	    # The C++ compiler is used as linker so we must use $wl
+	    # flag to pass the commands to the underlying system
+	    # linker.
+	    # Supported since Solaris 2.6 (maybe 2.5.1?)
+	    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	    ;;
+	esac
+	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+	# Archives containing C++ object files must be created using
+	# "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	;;
+      gcx)
+	# Green Hills C++ Compiler
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	# The C++ compiler must be used to create the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	;;
+      *)
+	# GNU C++ compiler with Solaris linker
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	  if $CC --version | grep -v '^2\.7' > /dev/null; then
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  else
+	    # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	    # platform.
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  fi
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	fi
+	;;
+    esac
+    ;;
+  sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC)
+	# NonStop-UX NCC 3.20
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+	  || test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+	   _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+	   _LT_AC_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+	   _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="      program t\n      end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+aix4* | aix5*)
+  test "$enable_shared" = yes && enable_static=no
+  ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars.  Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    _LT_AC_TAGVAR(compiler, $1) \
+    _LT_AC_TAGVAR(CC, $1) \
+    _LT_AC_TAGVAR(LD, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+    _LT_AC_TAGVAR(predep_objects, $1) \
+    _LT_AC_TAGVAR(postdep_objects, $1) \
+    _LT_AC_TAGVAR(predeps, $1) \
+    _LT_AC_TAGVAR(postdeps, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+    _LT_AC_TAGVAR(archive_cmds, $1) \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+    _LT_AC_TAGVAR(module_cmds, $1) \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+    _LT_AC_TAGVAR(include_expsyms, $1); do
+
+    case $var in
+    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(module_cmds, $1) | \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\[$]0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+    ;;
+  esac
+
+ifelse([$1], [],
+  [cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  AC_MSG_NOTICE([creating $ofile])],
+  [cfgfile="$ofile"])
+
+  cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+])
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris* | sysv5*)
+  symcode='[[BDRT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ 	]]\($symcode$symcode*\)[[ 	]][[ 	]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+	if grep ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+	  cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+	  cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -f conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix4* | aix5*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68)
+	  # Green Hills C++ Compiler
+	  # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++)
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx)
+	    # Green Hills C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | kfreebsd*-gnu)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+	    if test "$host_cpu" != ia64; then
+	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+	    case "$host_cpu" in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux*)
+	case $cc_basename in
+	  KCC)
+	    # KAI C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  icpc)
+	    # Intel C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  cxx)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx)
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC)
+	    # Rational C++ 2.4.1
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx)
+	    # Digital/Compaq C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      sco*)
+	case $cc_basename in
+	  CC)
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx)
+	    # Green Hills C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC)
+	    # Sun C++ 4.x
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc)
+	    # Lucid
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC)
+	    # NonStop-UX NCC 3.20
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      unixware*)
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    linux*)
+      case $CC in
+      icc* | ecc*)
+	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      ccc*)
+        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix4* | aix5*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+],[
+  runpath_var=
+  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_AC_TAGVAR(archive_cmds, $1)=
+  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+  _LT_AC_TAGVAR(module_cmds, $1)=
+  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_AC_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+      # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+  linux*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds"
+      supports_anon_versioning=no
+      case `$LD -v 2>/dev/null` in
+        *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+        *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+        *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+        *\ 2.11.*) ;; # other 2.11 versions
+        *) supports_anon_versioning=yes ;;
+      esac
+      if test $supports_anon_versioning = yes; then
+        _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+        $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+      else
+        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds"
+      fi
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+    ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then
+      runpath_var=LD_RUN_PATH
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+      # ancient GNU ld didn't support --whole-archive et. al.
+      if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ 	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+  	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+      fi
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+	  for ld_flag in $LDFLAGS; do
+  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+  	    aix_use_runtimelinking=yes
+  	    break
+  	  fi
+	  done
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_AC_TAGVAR(archive_cmds, $1)=''
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" && \
+  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	  then
+  	  # We have reworked collect2
+  	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	  else
+  	  # We have old collect2
+  	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+  	  # It fails to find uninstalled libraries when the uninstalled
+  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+  	  # to unsupported forces relinking
+  	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+  	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+  	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	esac
+	shared_flag='-shared'
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+  	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+  	if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+  	fi
+	fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+	if test "$host_cpu" = ia64; then
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an empty executable.
+	 _LT_AC_SYS_LIBPATH_AIX
+	 _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  # -bexpall does not export symbols beginning with underscore (_)
+	  _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+	  # Exported symbols can be pulled into shared objects from archives
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds it's shared libraries.
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      # see comment about different semantics on the GNU ld section
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    bsdi4*)
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+    if test "$GXX" = yes ; then
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      case "$host_os" in
+      rhapsody* | darwin1.[[012]])
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+	;;
+      *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[[012]])
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+	;;
+      esac
+    	lt_int_apple_cc_single_mod=no
+    	output_verbose_link_cmd='echo'
+    	if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+    	  lt_int_apple_cc_single_mod=yes
+    	fi
+    	if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+    	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    	else
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      fi
+      _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+        if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        else
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        fi
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+      ;;
+
+    dgux*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*)
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+	  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	ia64*)
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+	  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    openbsd*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      else
+       case $host_os in
+	 openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	   _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	   ;;
+	 *)
+	   _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	   ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+      esac
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[[78]]* | unixware7*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv5*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  		$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+        then
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
+  ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+  AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && break
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+SED=$lt_cv_path_SED
+])
+AC_MSG_RESULT([$SED])
+])
+
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN([PKG_CHECK_MODULES], [
+  succeeded=no
+
+  if test -z "$PKG_CONFIG"; then
+    AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+  fi
+
+  if test "$PKG_CONFIG" = "no" ; then
+     echo "*** The pkg-config script could not be found. Make sure it is"
+     echo "*** in your path, or set the PKG_CONFIG environment variable"
+     echo "*** to the full path to pkg-config."
+     echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+  else
+     PKG_CONFIG_MIN_VERSION=0.9.0
+     if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+        AC_MSG_CHECKING(for $2)
+
+        if $PKG_CONFIG --exists "$2" ; then
+            AC_MSG_RESULT(yes)
+            succeeded=yes
+
+            AC_MSG_CHECKING($1_CFLAGS)
+            $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+            AC_MSG_RESULT($$1_CFLAGS)
+
+            AC_MSG_CHECKING($1_LIBS)
+            $1_LIBS=`$PKG_CONFIG --libs "$2"`
+            AC_MSG_RESULT($$1_LIBS)
+        else
+            $1_CFLAGS=""
+            $1_LIBS=""
+            ## If we have a custom action on failure, don't print errors, but 
+            ## do set a variable so people can do so.
+            $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+            ifelse([$4], ,echo $$1_PKG_ERRORS,)
+        fi
+
+        AC_SUBST($1_CFLAGS)
+        AC_SUBST($1_LIBS)
+     else
+        echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+        echo "*** See http://www.freedesktop.org/software/pkgconfig"
+     fi
+  fi
+
+  if test $succeeded = yes; then
+     ifelse([$3], , :, [$3])
+  else
+     ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+  fi
+])
+
+
+
+#                                                        -*- Autoconf -*-
+# Copyright (C) 2002, 2003  Free Software Foundation, Inc.
+# Generated from amversion.in; do not edit by hand.
+
+# 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, 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
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+	 [AM_AUTOMAKE_VERSION([1.9.2])])
+
+# AM_AUX_DIR_EXPAND
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                              -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 6
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# serial 7						-*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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, 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.
+
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking.   -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+#   Free Software Foundation, Inc.
+
+# 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, 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.
+
+#serial 2
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+  # Strip MF so we end up with the name of the file.
+  mf=`echo "$mf" | sed -e 's/:.*$//'`
+  # Check whether this is an Automake generated Makefile or not.
+  # We used to match only the files named `Makefile.in', but
+  # some people rename them; so instead we look at the file content.
+  # Grep'ing the first line is not enough: some people post-process
+  # each Makefile.in and add a new line on top of each file to say so.
+  # So let's grep whole file.
+  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+    dirpart=`AS_DIRNAME("$mf")`
+  else
+    continue
+  fi
+  # Extract the definition of DEPDIR, am__include, and am__quote
+  # from the Makefile without running `make'.
+  DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+  test -z "$DEPDIR" && continue
+  am__include=`sed -n 's/^am__include = //p' < "$mf"`
+  test -z "am__include" && continue
+  am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+  # When using ansi2knr, U may be empty or an underscore; expand it
+  U=`sed -n 's/^U = //p' < "$mf"`
+  # Find all dependency output files, they are included files with
+  # $(DEPDIR) in their names.  We invoke sed twice because it is the
+  # simplest approach to changing $(DEPDIR) to its actual value in the
+  # expansion.
+  for file in `sed -n "
+    s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+    # Make sure the directory exists.
+    test -f "$dirpart/$file" && continue
+    fdir=`AS_DIRNAME(["$file"])`
+    AS_MKDIR_P([$dirpart/$fdir])
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                            -*- Autoconf -*-
+
+# This macro actually does too much some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 11
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+   test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+              [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+	      		     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+                  [_AM_DEPENDENCIES(CC)],
+                  [define([AC_PROG_CC],
+                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                  [_AM_DEPENDENCIES(CXX)],
+                  [define([AC_PROG_CXX],
+                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $1 | $1:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+#                                                          -*- Autoconf -*-
+# Copyright (C) 2003  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 1
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 3
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode is disabled by default
+  AC_ARG_ENABLE(maintainer-mode,
+[  --enable-maintainer-mode  enable make rules and dependencies not useful
+			  (and sometimes confusing) to the casual installer],
+      USE_MAINTAINER_MODE=$enableval,
+      USE_MAINTAINER_MODE=no)
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes.	-*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 2
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+#  -*- Autoconf -*-
+
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 3
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+
+# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake.  There are at least two reasons why we must not
+# use `-m 0755':
+#   - it causes special bits like SGID to be ignored,
+#   - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out.  Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+  # We used to keeping the `.' as first argument, in order to
+  # allow $(mkdir_p) to be used without argument.  As in
+  #   $(mkdir_p) $(somedir)
+  # where $(somedir) is conditionally defined.  However this is wrong
+  # for two reasons:
+  #  1. if the package is installed by a user who cannot write `.'
+  #     make install will fail,
+  #  2. the above comment should most certainly read
+  #     $(mkdir_p) $(DESTDIR)$(somedir)
+  #     so it does not work when $(somedir) is undefined and
+  #     $(DESTDIR) is not.
+  #  To support the latter case, we have to write
+  #     test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+  #  so the `.' trick is pointless.
+  mkdir_p='mkdir -p --'
+else
+  # On NextStep and OpenStep, the `mkdir' command does not
+  # recognize any option.  It will interpret all options as
+  # directories to create, and then abort because `.' already
+  # exists.
+  for d in ./-p ./--version;
+  do
+    test -d $d && rmdir $d
+  done
+  # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+  if test -f "$ac_aux_dir/mkinstalldirs"; then
+    mkdir_p='$(mkinstalldirs)'
+  else
+    mkdir_p='$(install_sh) -d'
+  fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 2
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 3
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# AM_PROG_INSTALL_STRIP
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004  Free Software Foundation, Inc.
+
+# 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, 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.
+
+# serial 1
+
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      AM_RUN_LOG([$_am_tar --version]) && break
+    done
+    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x $1 -w "$$tardir"'
+    am__tar_='pax -L -x $1 -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+    am__untar='cpio -i -H $1 -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_$1}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    AM_RUN_LOG([$am__untar <conftest.tar])
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/sac-general.m4])
+m4_include([m4/sac-openssl.m4])
+m4_include([m4/sac-su.m4])
+m4_include([m4/sac-su2.m4])
+m4_include([m4/sac-tport.m4])

Added: freeswitch/trunk/libs/sofia-sip/autogen.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/autogen.sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+#!/bin/sh 
+
+set -x
+${AUTORECONF:-autoreconf} -i
+find . \( -name 'run*' -o -name '*.sh' \) -a -type f | xargs chmod +x
+chmod +x scripts/*

Added: freeswitch/trunk/libs/sofia-sip/compile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/compile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,140 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2004-09-10.20
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# 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, 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit 0
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit 0
+    ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as `compile cc -o foo foo.c'.
+	# So we strip `-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no `-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # `.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  mv "$cofile" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/config.guess
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.guess	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1411 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-17'
+
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+## for Red Hat Linux
+if test -f /etc/redhat-release ; then
+    VENDOR=redhat ;
+else
+    VENDOR= ;
+fi
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit 0 ;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    macppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mipseb-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sun3:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    Alpha*:OpenVMS:*:*)
+	echo alpha-hp-vms
+	exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7 && exit 0 ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c \
+	  && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && exit 0
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:[45])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    # avoid double evaluation of $set_cc_for_build
+	    test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    *:UNICOS/mp:*:*)
+	echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' 
+	exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+	# Determine whether the default compiler uses glibc.
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#if __GLIBC__ >= 2
+	LIBC=gnu
+	#else
+	LIBC=
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
+    x86:Interix*:[34]*)
+	echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+	exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit 0 ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu
+	exit 0 ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    ppc:Linux:*:*)
+	echo powerpc-${VENDOR:-unknown}-linux-gnu
+	exit 0 ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-${VENDOR:-unknown}-linux-gnu
+	exit 0 ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu
+	exit 0 ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    x86_64:Linux:*:*)
+	echo x86_64-${VENDOR:-unknown}-linux-gnu
+	exit 0 ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0 ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0 ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit 0 ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#ifdef __INTEL_COMPILER
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0
+	test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit 0 ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit 0 ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit 0 ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit 0 ;;
+    i*86:*:5:[78]*)
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit 0 ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit 0 ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Darwin:*:*)
+	case `uname -p` in
+	    *86) UNAME_PROCESSOR=i686 ;;
+	    powerpc) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit 0 ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit 0 ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit 0 ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit 0 ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit 0 ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/config.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,396 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to the random number source name. */
+#undef DEV_URANDOM
+
+/* Define to 1 if you have addrinfo structure. */
+#undef HAVE_ADDRINFO
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_getcpuclockid' function. */
+#undef HAVE_CLOCK_GETCPUCLOCKID
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have /dev/urandom. */
+#undef HAVE_DEV_URANDOM
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have epoll interface. */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_create' function. */
+#undef HAVE_EPOLL_CREATE
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have WIN32 FILETIME type and GetSystemTimeAsFileTime().
+   */
+#undef HAVE_FILETIME
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if the C compiler supports __func__ */
+#undef HAVE_FUNC
+
+/* Define to 1 if the C compiler supports __FUNCTION__ */
+#undef HAVE_FUNCTION
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getipnodebyname' function. */
+#undef HAVE_GETIPNODEBYNAME
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddr.h> header file. */
+#undef HAVE_IFADDR_H
+
+/* Define to 1 if you have SIOCGIFCONF */
+#undef HAVE_IFCONF
+
+/* Define to 1 if you have SIOCGIFNUM ioctl */
+#undef HAVE_IFNUM
+
+/* Define to 1 if you have ifr_ifindex in <net/if.h> */
+#undef HAVE_IFR_IFINDEX
+
+/* Define to 1 if you have ifr_index in <net/if.h> */
+#undef HAVE_IFR_INDEX
+
+/* Define to 1 if you have the `if_nameindex' function. */
+#undef HAVE_IF_NAMEINDEX
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initstate' function. */
+#undef HAVE_INITSTATE
+
+/* Define to 1 if you have inlining compiler */
+#undef HAVE_INLINE
+
+/* Define to 1 if you have WIN32 INTERFACE_INFO_EX type. */
+#undef HAVE_INTERFACE_INFO_EX
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <iphlpapi.h> header file. */
+#undef HAVE_IPHLPAPI_H
+
+/* Define to 1 if you have IPV6_RECVERR in <netinet/in6.h> */
+#undef HAVE_IPV6_RECVERR
+
+/* Define to 1 if you have IP_RECVERR in <netinet/in.h> */
+#undef HAVE_IP_RECVERR
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `memccpy' function. */
+#undef HAVE_MEMCCPY
+
+/* Define to 1 if you have the `memcspn' function. */
+#undef HAVE_MEMCSPN
+
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memspn' function. */
+#undef HAVE_MEMSPN
+
+/* Define to 1 if you are compiling in MinGW environment */
+#undef HAVE_MINGW
+
+/* Define to 1 if you have MSG_TRUNC flag */
+#undef HAVE_MSG_TRUNC
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+#undef HAVE_NETINET_SCTP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define to 1 if you have OpenSSL */
+#undef HAVE_OPENSSL
+
+/* Define to 1 if you have the <openssl/tls1.h> header file. */
+#undef HAVE_OPENSSL_TLS1_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have /proc/net/if_inet6 control file */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define to 1 if you have working pthread_rwlock_t implementation. A thread
+   may hold multiple concurrent read locks on rwlock - that is, successfully
+   call the pthread_rwlock_rdlock() function n times. If so, the application
+   shall ensure that the thread performs matching unlocks - that is, it calls
+   the pthread_rwlock_unlock() function n times. */
+#undef HAVE_PTHREAD_RWLOCK
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have sa_len in struct sockaddr */
+#undef HAVE_SA_LEN
+
+/* Define to 1 if you have SCTP */
+#undef HAVE_SCTP
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SIGCOMP
+
+/* Define to 1 if you have the <sigcomp.h> header file. */
+#undef HAVE_SIGCOMP_H
+
+/* Define to 1 if you have SIGPIPE */
+#undef HAVE_SIGPIPE
+
+/* Define to 1 if you have IPv6 structures and constants */
+#undef HAVE_SIN6
+
+/* Define to 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY. */
+#undef HAVE_SIO_ADDRESS_LIST_QUERY
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if we use NTLM library */
+#undef HAVE_SOFIA_NTLM
+
+/* Define to 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SOFIA_SIGCOMP
+
+/* Define to 1 always */
+#undef HAVE_SOFIA_SIP
+
+/* Define to 1 if we use S/MIME library */
+#undef HAVE_SOFIA_SMIME
+
+/* Define to 1 if we use DNS library */
+#undef HAVE_SOFIA_SRESOLV
+
+/* Define to 1 if we use STUN library */
+#undef HAVE_SOFIA_STUN
+
+/* Define to 1 if we use SRTP */
+#undef HAVE_SRTP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if your CC supports C99 struct initialization */
+#undef HAVE_STRUCT_KEYWORDS
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have TLS */
+#undef HAVE_TLS
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if we use UPnP */
+#undef HAVE_UPNP
+
+/* Define to 1 you have WIN32 */
+#undef HAVE_WIN32
+
+/* Define to 1 if you have the <windef.h> header file. */
+#undef HAVE_WINDEF_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Define to format (%lli) for long long */
+#undef LLI
+
+/* Define to format (%llu) for unsigned long long */
+#undef LLU
+
+/* Define to format (%llx) for long long hex */
+#undef LLX
+
+/* Define printf() modifier for ssize_t */
+#undef MOD_ZD
+
+/* Define printf() modifier for size_t */
+#undef MOD_ZU
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to a at least 64-bit int type */
+#undef longlong
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t

Added: freeswitch/trunk/libs/sofia-sip/config.sub
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.sub	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1500 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k \
+	| m32r | m68000 | m68k | m88k | mcore \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| msp430 \
+	| ns16k | ns32k \
+	| openrisc | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| s390 | s390x \
+	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+	| strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xscale | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* \
+	| bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* \
+	| m32r-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| msp430-* \
+	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| s390-* | s390x-* \
+	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+	| xtensa-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	mmix*)
+		basic_machine=mmix-knuth
+		os=-mmixware
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nv1)
+		basic_machine=nv1-cray
+		os=-unicosmp
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	or32 | or32-*)
+		basic_machine=or32-unknown
+		os=-coff
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparc | sparcv9 | sparcv9b)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/configure
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/configure	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29140 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for sofia-sip 1.12.4work.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','`
+  ;;
+esac
+
+echo=${ECHO-echo}
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+       echo_test_string="`eval $cmd`" &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+    then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+   test "X$echo_testing_string" = "X$echo_test_string"; then
+  :
+else
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+	 test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running configure again with it.
+      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+    else
+      # Try using printf.
+      echo='printf %s\n'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+	 echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+	 test "X$echo_testing_string" = "X$echo_test_string"; then
+	# Cool, printf works
+	:
+      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+	export CONFIG_SHELL
+	SHELL="$CONFIG_SHELL"
+	export SHELL
+	echo="$CONFIG_SHELL $0 --fallback-echo"
+      elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	echo="$CONFIG_SHELL $0 --fallback-echo"
+      else
+	# maybe with a smaller string...
+	prev=:
+
+	for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+	  if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+	  then
+	    break
+	  fi
+	  prev="$cmd"
+	done
+
+	if test "$prev" != 'sed 50q "$0"'; then
+	  echo_test_string=`eval $prev`
+	  export echo_test_string
+	  exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+	else
+	  # Oops.  We lost completely, so just stick with echo.
+	  echo=echo
+	fi
+      fi
+    fi
+  fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+   ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+tagnames=${tagnames+${tagnames},}CXX
+
+tagnames=${tagnames+${tagnames},}F77
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='sofia-sip'
+PACKAGE_TARNAME='sofia-sip'
+PACKAGE_VERSION='1.12.4work'
+PACKAGE_STRING='sofia-sip 1.12.4work'
+PACKAGE_BUGREPORT=''
+
+ac_unique_file="libsofia-sip-ua/sip/sofia-sip/sip.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS VER_LIBSOFIA_SIP_UA_MAJOR_MINOR include_sofiadir LIBVER_SOFIA_SIP_UA_CUR LIBVER_SOFIA_SIP_UA_REV LIBVER_SOFIA_SIP_UA_AGE LIBVER_SOFIA_SIP_UA_SOVER LIBVER_SOFIA_SIP_UA_GLIB_CUR LIBVER_SOFIA_SIP_UA_GLIB_REV LIBVER_SOFIA_SIP_UA_GLIB_AGE LIBVER_SOFIA_SIP_UA_GLIB_SOVER build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE MINGW_ENVIRONMENT HAVE_MINGW32_TRUE HAVE_MINGW32_FALSE CWFLAG SOFIA_CFLAGS ENABLE_COVERAGE_TRUE ENABLE_COVERAGE_FALSE MOSTLYCLEANFILES CPP ETAGS AR ac_ct_AR LD ac_ct_LD EGREP LN_S ECHO RANLIB ac_ct_RANLIB CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL NDEBUG_TRUE NDEBUG_FALSE TESTS_ENVIRONMENT EXPENSIVE_CHECKS_TRUE EXPENSIVE_CHECKS_FALSE ACLOCAL_AMFLAGS DOXYGEN HAVE_DOXYGEN_TRUE HAVE_DOXYGEN_FALSE COREFOUNDATION_TRUE COREFOUNDATION_FALSE PKG_CONFIG GLIB_CFLAGS GLIB_LIBS HAVE_GLIB_TRUE HAVE_GLIB_FALSE GLIB_VERSION SOFIA_GLIB_PKG_REQUIRES REPLACE_LIBADD HAVE_TLS_TRUE HAVE_TLS_FALSE HAVE_NTLM_TRUE HAVE_NTLM_FALSE LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_option in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval "enable_$ac_feature=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_$ac_feature='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_$ac_package='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    eval "with_$ac_package=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    eval "$ac_envvar='$ac_optarg'"
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+	      localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_SOFIA_CFLAGS_set=${SOFIA_CFLAGS+set}
+ac_env_SOFIA_CFLAGS_value=$SOFIA_CFLAGS
+ac_cv_env_SOFIA_CFLAGS_set=${SOFIA_CFLAGS+set}
+ac_cv_env_SOFIA_CFLAGS_value=$SOFIA_CFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+ac_env_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+ac_env_CXXCPP_set=${CXXCPP+set}
+ac_env_CXXCPP_value=$CXXCPP
+ac_cv_env_CXXCPP_set=${CXXCPP+set}
+ac_cv_env_CXXCPP_value=$CXXCPP
+ac_env_F77_set=${F77+set}
+ac_env_F77_value=$F77
+ac_cv_env_F77_set=${F77+set}
+ac_cv_env_F77_value=$F77
+ac_env_FFLAGS_set=${FFLAGS+set}
+ac_env_FFLAGS_value=$FFLAGS
+ac_cv_env_FFLAGS_set=${FFLAGS+set}
+ac_cv_env_FFLAGS_value=$FFLAGS
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures sofia-sip 1.12.4work to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+			  [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+			  [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of sofia-sip 1.12.4work:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-maintainer-mode  enable make rules and dependencies not useful
+			  (and sometimes confusing) to the casual installer
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-coverage       compile test-coverage (disabled)
+  --enable-shared[=PKGS]
+                          build shared libraries [default=yes]
+  --enable-static[=PKGS]
+                          build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-ndebug             compile with NDEBUG (disabled)
+  --enable-expensive-checks   run also expensive checks (disabled)
+  --disable-size-compat            use compatibility size_t types (enabled)
+  --enable-corefoundation     compile with OSX COREFOUNDATION (disabled)
+  --disable-stun              disable stun module (enabled)
+  --enable-ntlm               enable NTLM support (disabled)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-pic              try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-tags[=TAGS]
+                          include additional configurations [automatic]
+  --with-rt               use POSIX realtime library (used by default)
+  --with-glib=version     use GLib (default=2.0)
+  --with-glib-dir=PREFIX  explicitly define GLib path
+  --with-openssl          use OpenSSL (enabled)
+  --with-sigcomp=dir      use Sofia SigComp package (not used by default)
+  --enable-sctp          use LK-SCTP (not used by default)
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  SOFIA_CFLAGS
+              CFLAGS not used during configure
+  CPP         C preprocessor
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CXXCPP      C++ preprocessor
+  F77         Fortran 77 compiler command
+  FFLAGS      Fortran 77 compiler flags
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d $ac_dir || continue
+    ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+    cd $ac_dir
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_srcdir/configure.gnu; then
+      echo
+      $SHELL $ac_srcdir/configure.gnu  --help=recursive
+    elif test -f $ac_srcdir/configure; then
+      echo
+      $SHELL $ac_srcdir/configure  --help=recursive
+    elif test -f $ac_srcdir/configure.ac ||
+	   test -f $ac_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\_ACEOF
+sofia-sip configure 1.12.4work
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by sofia-sip $as_me 1.12.4work, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo               = `(hostinfo) 2>/dev/null               || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+      # Get rid of the leading space.
+      ac_sep=" "
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+{
+  (set) 2>&1 |
+    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      sed -n \
+	"s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+}
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=$`echo $ac_var`
+	echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core &&
+  rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+     ' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . $cache_file;;
+      *)                      . ./$cache_file;;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+	       sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+  eval ac_new_val="\$ac_env_${ac_var}_value"
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR=1.12
+
+include_sofiadir='${includedir}/sofia-sip-1.12'
+
+LIBVER_SOFIA_SIP_UA_CUR=3
+
+LIBVER_SOFIA_SIP_UA_REV=0
+
+LIBVER_SOFIA_SIP_UA_AGE=3
+
+LIBVER_SOFIA_SIP_UA_SOVER=0
+ # CUR-AGE
+LIBVER_SOFIA_SIP_UA_GLIB_CUR=3
+
+LIBVER_SOFIA_SIP_UA_GLIB_REV=0
+
+LIBVER_SOFIA_SIP_UA_GLIB_AGE=0
+
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER=3
+ # CUR-AGE
+
+# dnl calls AC_CANONICAL_ macros that are required by AM_INIT_AUTOMAKE
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f $ac_dir/shtool; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+  ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+  ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+  ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+
+echo "$as_me:$LINENO: checking cached information" >&5
+echo $ECHO_N "checking cached information... $ECHO_C" >&6
+hostcheck="$host"
+if test "${ac_cv_hostcheck+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+   ac_cv_hostcheck="$hostcheck"
+fi
+
+if test "$ac_cv_hostcheck" != "$hostcheck"; then
+  echo "$as_me:$LINENO: result: changed" >&5
+echo "${ECHO_T}changed" >&6
+  { echo "$as_me:$LINENO: WARNING: config.cache exists!" >&5
+echo "$as_me: WARNING: config.cache exists!" >&2;}
+  { { echo "$as_me:$LINENO: error: you must do 'make distclean' first to compile
+ for different host or different parameters." >&5
+echo "$as_me: error: you must do 'make distclean' first to compile
+ for different host or different parameters." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+
+
+
+am__api_version="1.9"
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	    break 3
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+done
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL=$ac_install_sh
+  fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$*" != "X $srcdir/configure conftest.file" \
+      && test "$*" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { { echo "$as_me:$LINENO: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" >&2;}
+   { (exit 1); exit 1; }; }
+   fi
+
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $.  echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+  # We used to keeping the `.' as first argument, in order to
+  # allow $(mkdir_p) to be used without argument.  As in
+  #   $(mkdir_p) $(somedir)
+  # where $(somedir) is conditionally defined.  However this is wrong
+  # for two reasons:
+  #  1. if the package is installed by a user who cannot write `.'
+  #     make install will fail,
+  #  2. the above comment should most certainly read
+  #     $(mkdir_p) $(DESTDIR)$(somedir)
+  #     so it does not work when $(somedir) is undefined and
+  #     $(DESTDIR) is not.
+  #  To support the latter case, we have to write
+  #     test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+  #  so the `.' trick is pointless.
+  mkdir_p='mkdir -p --'
+else
+  # On NextStep and OpenStep, the `mkdir' command does not
+  # recognize any option.  It will interpret all options as
+  # directories to create, and then abort because `.' already
+  # exists.
+  for d in ./-p ./--version;
+  do
+    test -d $d && rmdir $d
+  done
+  # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+  if test -f "$ac_aux_dir/mkinstalldirs"; then
+    mkdir_p='$(mkinstalldirs)'
+  else
+    mkdir_p='$(install_sh) -d'
+  fi
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+all:
+	@echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  SET_MAKE=
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+   test -f $srcdir/config.status; then
+  { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='sofia-sip'
+ VERSION='1.12.4work'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  STRIP=$ac_ct_STRIP
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
+    # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+  enableval="$enable_maintainer_mode"
+  USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
+fi;
+  echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
+
+  MAINT=$MAINTAINER_MODE_TRUE
+
+
+          ac_config_headers="$ac_config_headers config.h"
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+
+### checks for programs
+### -------------------
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+          ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+  enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Find the output, starting from the most likely.  This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+	;;
+    conftest.$ac_ext )
+	# This is the source file.
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	# FIXME: I believe we export ac_cv_exeext for Libtool,
+	# but it would be cool to find out if it's true.  Does anybody
+	# maintain Libtool? --akim.
+	export ac_cv_exeext
+	break;;
+    * )
+	break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  export ac_cv_exeext
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std1 is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC"   am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for compilation environment" >&5
+echo $ECHO_N "checking for compilation environment... $ECHO_C" >&6
+if test "${ac_cc_environment+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+machine=`$CC -dumpmachine`
+if test "$machine" = mingw32 ; then
+  ac_cc_environment=$machine
+fi
+
+fi
+echo "$as_me:$LINENO: result: $ac_cc_environment" >&5
+echo "${ECHO_T}$ac_cc_environment" >&6
+
+if test "$ac_cc_environment" = mingw32 ; then
+CFLAGS="$CFLAGS -I\$(top_srcdir)/win32/pthread -DWINVER=0x0501 \
+	-D_WIN32_WINNT=0x0501 -DIN_LIBSOFIA_SIP_UA -DIN_LIBSOFIA_SRES \
+	-mms-bitfields \
+	-pipe -mno-cygwin -mwindows -mconsole -Wall -g -O0"
+LDFLAGS="$LDFLAGS -Wl,--enable-auto-image-base"
+LIBS="-L\$(top_srcdir)/win32/pthread -lpthreadVC2 -lws2_32 \
+	-lwsock32"
+MINGW_ENVIRONMENT=1
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINGW 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WIN32 1
+_ACEOF
+
+fi
+
+
+if test "x$ac_cc_environment" != x; then
+  HAVE_MINGW32_TRUE=
+  HAVE_MINGW32_FALSE='#'
+else
+  HAVE_MINGW32_TRUE='#'
+  HAVE_MINGW32_FALSE=
+fi
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_CC" && ac_cv_prog_ac_ct_CC="gcc"
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_CC" && ac_cv_prog_ac_ct_CC="cc"
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32* ) # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="cl"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable cc found in \$PATH" >&5
+echo "$as_me: error: no acceptable cc found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std1 is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC"   am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+#
+# Wall
+#
+echo "$as_me:$LINENO: checking for maximum warnings compiler flag" >&5
+echo $ECHO_N "checking for maximum warnings compiler flag... $ECHO_C" >&6
+if test "${ac_cv_cwflag+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case "${CC-cc}" in
+  *gcc*) ac_cv_cwflag=-Wall;;
+  *)	case "$host" in
+    *irix*)	ac_cv_cwflag=-fullwarn ;;
+    *solaris*)  ac_cv_cwflag="-erroff=%none,E_END_OF_LOOP_CODE_NOT_REACHED -xCC"
+	        ;;
+    *)		ac_cv_cwflag=;;
+		esac
+  ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cwflag" >&5
+echo "${ECHO_T}$ac_cv_cwflag" >&6
+CWFLAG=$ac_cv_cwflag
+
+
+
+
+#
+# GCoverage
+#
+# Check whether --enable-coverage or --disable-coverage was given.
+if test "${enable_coverage+set}" = set; then
+  enableval="$enable_coverage"
+
+else
+  enable_coverage=no
+fi;
+
+if test X$enable_coverage != Xno ; then
+case "${CC-cc}" in
+  *gcc*)
+	SOFIA_CFLAGS="$SOFIA_CFLAGS -fprofile-arcs -ftest-coverage"
+	;;
+  *) { { echo "$as_me:$LINENO: error: --enable-coverage requires gcc" >&5
+echo "$as_me: error: --enable-coverage requires gcc" >&2;}
+   { (exit 1); exit 1; }; }
+esac
+fi
+
+
+
+if test X$enable_coverage != Xno; then
+  ENABLE_COVERAGE_TRUE=
+  ENABLE_COVERAGE_FALSE='#'
+else
+  ENABLE_COVERAGE_TRUE='#'
+  ENABLE_COVERAGE_FALSE=
+fi
+
+
+MOSTLYCLEANFILES="*.bb *.bbg *.da *.gcov *.gcda *.gcno"
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	    break 3
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+done
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL=$ac_install_sh
+  fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Extract the first word of "etags", so it can be a program name with args.
+set dummy etags; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ETAGS+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ETAGS"; then
+  ac_cv_prog_ETAGS="$ETAGS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ETAGS="etags"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ETAGS" && ac_cv_prog_ETAGS="echo"
+fi
+fi
+ETAGS=$ac_cv_prog_ETAGS
+if test -n "$ETAGS"; then
+  echo "$as_me:$LINENO: result: $ETAGS" >&5
+echo "${ECHO_T}$ETAGS" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="ar"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  AR=$ac_ct_AR
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LD"; then
+  ac_cv_prog_LD="$LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LD="${ac_tool_prefix}ld"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+  echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_LD"; then
+  ac_ct_LD=$LD
+  # Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_LD"; then
+  ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LD="ld"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_LD" && ac_cv_prog_ac_ct_LD="ld"
+fi
+fi
+ac_ct_LD=$ac_cv_prog_ac_ct_LD
+if test -n "$ac_ct_LD"; then
+  echo "$as_me:$LINENO: result: $ac_ct_LD" >&5
+echo "${ECHO_T}$ac_ct_LD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  LD=$ac_ct_LD
+else
+  LD="$ac_cv_prog_LD"
+fi
+
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+  enableval="$enable_shared"
+  p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi;
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval="$enable_static"
+  p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi;
+
+# Check whether --enable-fast-install or --disable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+  enableval="$enable_fast_install"
+  p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi;
+
+echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6
+if test "${lt_cv_path_SED+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && break
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+SED=$lt_cv_path_SED
+
+fi
+
+echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval="$with_gnu_ld"
+  test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+  echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+
+echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
+echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
+if test "${lt_cv_path_NM+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+    if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      # Tru64's nm complains that /dev/null is an invalid object file
+      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+      */dev/null* | *'Invalid file or object type'*)
+	lt_cv_path_NM="$tmp_nm -B"
+	break
+        ;;
+      *)
+	case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	*/dev/null*)
+	  lt_cv_path_NM="$tmp_nm -p"
+	  break
+	  ;;
+	*)
+	  lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	  continue # so that we can try to find one that supports BSD flags
+	  ;;
+	esac
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi
+fi
+echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+echo "${ECHO_T}$lt_cv_path_NM" >&6
+NM="$lt_cv_path_NM"
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5
+echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6
+if test "${lt_cv_deplibs_check_method+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi4*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | kfreebsd*-gnu)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case "$host_cpu" in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  case $host_cpu in
+  alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*)
+    lt_cv_deplibs_check_method=pass_all ;;
+  *)
+    # glibc up to 2.1.1 does not perform some relocations on ARM
+    # this will be overridden with pass_all, but let us keep it just in case
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;;
+  esac
+  lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
+  else
+    lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sco3.2v5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+  enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line 5473 "configure"' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6
+if test "${lt_cv_cc_needs_belf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  lt_cv_cc_needs_belf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+lt_cv_cc_needs_belf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      exit(2);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+  CXX=$ac_ct_CXX
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C++ compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cxx_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+depcc="$CXX"  am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CXX_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CXX_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+
+
+if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+  am__fastdepCXX_TRUE=
+  am__fastdepCXX_FALSE='#'
+else
+  am__fastdepCXX_TRUE='#'
+  am__fastdepCXX_FALSE=
+fi
+
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6
+if test -z "$CXXCPP"; then
+  if test "${ac_cv_prog_CXXCPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_cxx_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_cxx_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+echo "$as_me:$LINENO: result: $CXXCPP" >&5
+echo "${ECHO_T}$CXXCPP" >&6
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_cxx_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_cxx_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_F77+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$F77"; then
+  ac_cv_prog_F77="$F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+F77=$ac_cv_prog_F77
+if test -n "$F77"; then
+  echo "$as_me:$LINENO: result: $F77" >&5
+echo "${ECHO_T}$F77" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$F77" && break
+  done
+fi
+if test -z "$F77"; then
+  ac_ct_F77=$F77
+  for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_F77+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_F77"; then
+  ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_F77="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_F77=$ac_cv_prog_ac_ct_F77
+if test -n "$ac_ct_F77"; then
+  echo "$as_me:$LINENO: result: $ac_ct_F77" >&5
+echo "${ECHO_T}$ac_ct_F77" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_F77" && break
+done
+
+  F77=$ac_ct_F77
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:6811:" \
+     "checking for Fortran 77 compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+rm -f a.out
+
+# If we don't use `.F' as extension, the preprocessor is not run on the
+# input file.  (Note that this only needs to work for GNU compilers.)
+ac_save_ext=$ac_ext
+ac_ext=F
+echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6
+if test "${ac_cv_f77_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+      program main
+#ifndef __GNUC__
+       choke me
+#endif
+
+      end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_f77_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_f77_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6
+ac_ext=$ac_save_ext
+ac_test_FFLAGS=${FFLAGS+set}
+ac_save_FFLAGS=$FFLAGS
+FFLAGS=
+echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5
+echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_f77_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  FFLAGS=-g
+cat >conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_f77_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_f77_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_f77_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5
+echo "${ECHO_T}$ac_cv_prog_f77_g" >&6
+if test "$ac_test_FFLAGS" = set; then
+  FFLAGS=$ac_save_FFLAGS
+elif test $ac_cv_prog_f77_g = yes; then
+  if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+    FFLAGS="-g -O2"
+  else
+    FFLAGS="-g"
+  fi
+else
+  if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+    FFLAGS="-O2"
+  else
+    FFLAGS=
+  fi
+fi
+
+G77=`test $ac_compiler_gnu = yes && echo yes`
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+
+# find the maximum length of command line arguments
+echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+ *)
+    # If test is not a shell built-in, we'll probably end up computing a
+    # maximum length that is only half of the actual maximum length, but
+    # we can't tell.
+    while (test "X"`$CONFIG_SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \
+	       = "XX$teststring") >/dev/null 2>&1 &&
+	    new_result=`expr "X$teststring" : ".*" 2>&1` &&
+	    lt_cv_sys_max_cmd_len=$new_result &&
+	    test $i != 17 # 1/2 MB should be enough
+    do
+      i=`expr $i + 1`
+      teststring=$teststring$teststring
+    done
+    teststring=
+    # Add a significant safety factor because C++ compilers can tack on massive
+    # amounts of additional arguments before passing them to the linker.
+    # It appears as though 1/2 is a usable value.
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6
+else
+  echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+fi
+
+
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris* | sysv5*)
+  symcode='[BDRT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ 	]\($symcode$symcode*\)[ 	][ 	]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+  (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+	if grep ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+	  cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+	  cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -f conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  echo "$as_me:$LINENO: result: failed" >&5
+echo "${ECHO_T}failed" >&6
+else
+  echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+echo "$as_me:$LINENO: checking for objdir" >&5
+echo $ECHO_N "checking for objdir... $ECHO_C" >&6
+if test "${lt_cv_objdir+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+echo "${ECHO_T}$lt_cv_objdir" >&6
+objdir=$lt_cv_objdir
+
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  AR=$ac_ct_AR
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  RANLIB=$ac_ct_RANLIB
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  STRIP=$ac_ct_STRIP
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+    ;;
+  *)
+    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    echo "$as_me:$LINENO: checking for file" >&5
+echo $ECHO_N "checking for file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+enable_dlopen=no
+enable_win32_dll=no
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+  enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+
+# Check whether --with-pic or --without-pic was given.
+if test "${with_pic+set}" = set; then
+  withval="$with_pic"
+  pic_mode="$withval"
+else
+  pic_mode=default
+fi;
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+#
+# Check for any special shared library compilation flags.
+#
+lt_prog_cc_shlib=
+if test "$GCC" = no; then
+  case $host_os in
+  sco3.2v5*)
+    lt_prog_cc_shlib='-belf'
+    ;;
+  esac
+fi
+if test -n "$lt_prog_cc_shlib"; then
+  { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5
+echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;}
+  if echo "$old_CC $old_CFLAGS " | grep "[ 	]$lt_prog_cc_shlib[ 	]" >/dev/null; then :
+  else
+    { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5
+echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;}
+    lt_cv_prog_cc_can_build_shared=no
+  fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_prog_compiler_static"
+   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+     else
+       lt_prog_compiler_static_works=yes
+     fi
+   fi
+   $rm conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:7845: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:7849: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    linux*)
+      case $CC in
+      icc* | ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      lt_prog_compiler_pic='-Kpic'
+      lt_prog_compiler_static='-dn'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_prog_compiler_pic_works=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:8078: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:8082: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_prog_compiler_pic_works=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6
+
+if test x"$lt_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:8138: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:8142: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s out/conftest.err; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+  if test "$hard_links" = no; then
+    { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+  runpath_var=
+  allow_undefined_flag=
+  enable_shared_with_static_runtimes=no
+  archive_cmds=
+  archive_expsym_cmds=
+  old_archive_From_new_cmds=
+  old_archive_from_expsyms_cmds=
+  export_dynamic_flag_spec=
+  whole_archive_flag_spec=
+  thread_safe_flag_spec=
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_flag_spec_ld=
+  hardcode_libdir_separator=
+  hardcode_direct=no
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  link_all_deplibs=unknown
+  hardcode_automatic=no
+  module_cmds=
+  module_expsym_cmds=
+  always_export_symbols=no
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+
+      # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      ld_shlibs=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+  linux*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_cmds="$tmp_archive_cmds"
+      supports_anon_versioning=no
+      case `$LD -v 2>/dev/null` in
+        *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+        *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+        *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+        *\ 2.11.*) ;; # other 2.11 versions
+        *) supports_anon_versioning=yes ;;
+      esac
+      if test $supports_anon_versioning = yes; then
+        archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+        $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+      else
+        archive_expsym_cmds="$tmp_archive_cmds"
+      fi
+    else
+      ld_shlibs=no
+    fi
+    ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = yes; then
+      runpath_var=LD_RUN_PATH
+      hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+      export_dynamic_flag_spec='${wl}--export-dynamic'
+      # ancient GNU ld didn't support --whole-archive et. al.
+      if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ 	whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+  	whole_archive_flag_spec=
+      fi
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+	  for ld_flag in $LDFLAGS; do
+  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+  	    aix_use_runtimelinking=yes
+  	    break
+  	  fi
+	  done
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.012|aix4.012.*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" && \
+  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	  then
+  	  # We have reworked collect2
+  	  hardcode_direct=yes
+	  else
+  	  # We have old collect2
+  	  hardcode_direct=unsupported
+  	  # It fails to find uninstalled libraries when the uninstalled
+  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+  	  # to unsupported forces relinking
+  	  hardcode_minus_L=yes
+  	  hardcode_libdir_flag_spec='-L$libdir'
+  	  hardcode_libdir_separator=
+	  fi
+	esac
+	shared_flag='-shared'
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+  	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+  	if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+  	fi
+	fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+       hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an empty executable.
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  # -bexpall does not export symbols beginning with underscore (_)
+	  always_export_symbols=yes
+	  # Exported symbols can be pulled into shared objects from archives
+	  whole_archive_flag_spec=' '
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds it's shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs=no
+      ;;
+
+    bsdi4*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      allow_undefined_flag=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_From_new_cmds='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    darwin* | rhapsody*)
+    if test "$GXX" = yes ; then
+      archive_cmds_need_lc=no
+      case "$host_os" in
+      rhapsody* | darwin1.[012])
+	allow_undefined_flag='-undefined suppress'
+	;;
+      *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	allow_undefined_flag='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[012])
+            allow_undefined_flag='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            allow_undefined_flag='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+	;;
+      esac
+    	lt_int_apple_cc_single_mod=no
+    	output_verbose_link_cmd='echo'
+    	if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+    	  lt_int_apple_cc_single_mod=yes
+    	fi
+    	if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+    	  archive_cmds='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    	else
+        archive_cmds='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      fi
+      module_cmds='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+        if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+          archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        else
+          archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        fi
+          module_expsym_cmds='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      hardcode_direct=no
+      hardcode_automatic=yes
+      hardcode_shlibpath_var=unsupported
+      whole_archive_flag_spec='-all_load $convenience'
+      link_all_deplibs=yes
+    else
+      ld_shlibs=no
+    fi
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu)
+      archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	*)
+	  archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*)
+	  hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_flag_spec_ld='+b $libdir'
+	  hardcode_libdir_separator=:
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	ia64*)
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	*)
+	  hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_separator=:
+	  hardcode_direct=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_ld='-rpath $libdir'
+      fi
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    openbsd*)
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec='${wl}-E'
+      else
+       case $host_os in
+	 openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	   archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	   hardcode_libdir_flag_spec='-R$libdir'
+	   ;;
+	 *)
+	   archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	   hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	   ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      hardcode_libdir_separator=:
+      ;;
+
+    sco3.2v5*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z text'
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+	archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+	whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=no
+      hardcode_shlibpath_var=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[78]* | unixware7*)
+      no_undefined_flag='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv5*)
+      no_undefined_flag=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  		$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      hardcode_libdir_flag_spec=
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+echo "${ECHO_T}$ld_shlibs" >&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag
+        allow_undefined_flag=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc=no
+        else
+	  archive_cmds_need_lc=yes
+        fi
+        allow_undefined_flag=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+echo "${ECHO_T}$archive_cmds_need_lc" >&6
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi4*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.01* | freebsdelf3.01*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '#line 9472 "configure"' > conftest.$ac_ext
+    if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=yes
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+   test -n "$runpath_var " || \
+   test "X$hardcode_automatic"="Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action" >&5
+echo "${ECHO_T}$hardcode_action" >&6
+
+if test "$hardcode_action" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+       else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+       ;;
+   *)
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+    ;;
+  esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+   ;;
+
+  *)
+    echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shl_load (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+  lt_cv_dlopen="shl_load"
+else
+  echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+  echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlopen (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+  lt_cv_dlopen="dlopen"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_svld_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_dld_link=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 10343 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 10441 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+# Report which librarie types wil actually be built
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+  ;;
+  darwin* | rhapsody*)
+  if test "$GCC" = yes; then
+    archive_cmds_need_lc=no
+    case "$host_os" in
+    rhapsody* | darwin1.[012])
+      allow_undefined_flag='-undefined suppress'
+      ;;
+    *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	allow_undefined_flag='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[012])
+            allow_undefined_flag='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            allow_undefined_flag='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+      ;;
+    esac
+    output_verbose_link_cmd='echo'
+    archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
+    module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+    # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+    archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag  -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    module_expsym_cmds='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    hardcode_direct=no
+    hardcode_automatic=yes
+    hardcode_shlibpath_var=unsupported
+    whole_archive_flag_spec='-all_load $convenience'
+    link_all_deplibs=yes
+  else
+    ld_shlibs=no
+  fi
+    ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    compiler \
+    CC \
+    LD \
+    lt_prog_compiler_wl \
+    lt_prog_compiler_pic \
+    lt_prog_compiler_static \
+    lt_prog_compiler_no_builtin_flag \
+    export_dynamic_flag_spec \
+    thread_safe_flag_spec \
+    whole_archive_flag_spec \
+    enable_shared_with_static_runtimes \
+    old_archive_cmds \
+    old_archive_from_new_cmds \
+    predep_objects \
+    postdep_objects \
+    predeps \
+    postdeps \
+    compiler_lib_search_path \
+    archive_cmds \
+    archive_expsym_cmds \
+    postinstall_cmds \
+    postuninstall_cmds \
+    old_archive_from_expsyms_cmds \
+    allow_undefined_flag \
+    no_undefined_flag \
+    export_symbols_cmds \
+    hardcode_libdir_flag_spec \
+    hardcode_libdir_flag_spec_ld \
+    hardcode_libdir_separator \
+    hardcode_automatic \
+    module_cmds \
+    module_expsym_cmds \
+    lt_cv_prog_compiler_c_o \
+    exclude_expsyms \
+    include_expsyms; do
+
+    case $var in
+    old_archive_cmds | \
+    old_archive_from_new_cmds | \
+    archive_cmds | \
+    archive_expsym_cmds | \
+    module_cmds | \
+    module_expsym_cmds | \
+    old_archive_from_expsyms_cmds | \
+    export_symbols_cmds | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\$0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  { echo "$as_me:$LINENO: creating $ofile" >&5
+echo "$as_me: creating $ofile" >&6;}
+
+  cat <<__EOF__ >> "$cfgfile"
+#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# ### END LIBTOOL CONFIG
+
+__EOF__
+
+
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+# Check whether --with-tags or --without-tags was given.
+if test "${with_tags+set}" = set; then
+  withval="$with_tags"
+  tagnames="$withval"
+fi;
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;}
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;}
+    else
+      { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5
+echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
+    fi
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in
+    "") ;;
+    *)  { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5
+echo "$as_me: error: invalid tag name: $tagname" >&2;}
+   { (exit 1); exit 1; }; }
+	;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5
+echo "$as_me: error: tag name \"$tagname\" already exists" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+	if test -n "$CXX" && test "X$CXX" != "Xno"; then
+	  ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_automatic_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+compiler_CXX=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+else
+  lt_prog_compiler_no_builtin_flag_CXX=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval="$with_gnu_ld"
+  test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+  echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+	grep 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec_CXX=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+ld_shlibs_CXX=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+  aix4* | aix5*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
+      no_entry_flag=""
+    else
+      aix_use_runtimelinking=no
+
+      # Test if we are trying to use run time linking or normal
+      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+      # need to do runtime linking.
+      case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+	for ld_flag in $LDFLAGS; do
+	  case $ld_flag in
+	  *-brtl*)
+	    aix_use_runtimelinking=yes
+	    break
+	    ;;
+	  esac
+	done
+      esac
+
+      exp_sym_flag='-bexport'
+      no_entry_flag='-bnoentry'
+    fi
+
+    # When large executables or shared objects are built, AIX ld can
+    # have problems creating the table of contents.  If linking a library
+    # or program results in "error TOC overflow" add -mminimal-toc to
+    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+    archive_cmds_CXX=''
+    hardcode_direct_CXX=yes
+    hardcode_libdir_separator_CXX=':'
+    link_all_deplibs_CXX=yes
+
+    if test "$GXX" = yes; then
+      case $host_os in aix4.012|aix4.012.*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
+	collect2name=`${CC} -print-prog-name=collect2`
+	if test -f "$collect2name" && \
+	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	then
+	  # We have reworked collect2
+	  hardcode_direct_CXX=yes
+	else
+	  # We have old collect2
+	  hardcode_direct_CXX=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L_CXX=yes
+	  hardcode_libdir_flag_spec_CXX='-L$libdir'
+	  hardcode_libdir_separator_CXX=
+	fi
+      esac
+      shared_flag='-shared'
+    else
+      # not using gcc
+      if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	shared_flag='-G'
+      else
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag='${wl}-G'
+	else
+	  shared_flag='${wl}-bM:SRE'
+	fi
+      fi
+    fi
+
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    always_export_symbols_CXX=yes
+    if test "$aix_use_runtimelinking" = yes; then
+      # Warning - without using the other runtime loading flags (-brtl),
+      # -berok will link without error, but may produce a broken library.
+      allow_undefined_flag_CXX='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+      hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
+      if test "$host_cpu" = ia64; then
+	hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+	allow_undefined_flag_CXX="-z nodefs"
+	archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+      else
+	# Determine the default libpath from the value encoded in an empty executable.
+	cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+	# Warning - without using the other run time loading flags,
+	# -berok will link without error, but may produce a broken library.
+	no_undefined_flag_CXX=' ${wl}-bernotok'
+	allow_undefined_flag_CXX=' ${wl}-berok'
+	# -bexpall does not export symbols beginning with underscore (_)
+	always_export_symbols_CXX=yes
+	# Exported symbols can be pulled into shared objects from archives
+	whole_archive_flag_spec_CXX=' '
+	archive_cmds_need_lc_CXX=yes
+	# This is similar to how AIX traditionally builds it's shared libraries.
+	archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+      fi
+    fi
+    ;;
+  chorus*)
+    case $cc_basename in
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+    # as there is no search path for DLLs.
+    hardcode_libdir_flag_spec_CXX='-L$libdir'
+    allow_undefined_flag_CXX=unsupported
+    always_export_symbols_CXX=no
+    enable_shared_with_static_runtimes_CXX=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	cp $export_symbols $output_objdir/$soname.def;
+      else
+	echo EXPORTS > $output_objdir/$soname.def;
+	cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+    else
+      ld_shlibs_CXX=no
+    fi
+  ;;
+
+  darwin* | rhapsody*)
+  if test "$GXX" = yes; then
+    archive_cmds_need_lc_CXX=no
+    case "$host_os" in
+    rhapsody* | darwin1.[012])
+      allow_undefined_flag_CXX='-undefined suppress'
+      ;;
+    *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[012])
+            allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            allow_undefined_flag_CXX='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+      ;;
+    esac
+    lt_int_apple_cc_single_mod=no
+    output_verbose_link_cmd='echo'
+    if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+      lt_int_apple_cc_single_mod=yes
+    fi
+    if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+      archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    else
+      archive_cmds_CXX='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    fi
+    module_cmds_CXX='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+
+    # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+    if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+      archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    else
+      archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    hardcode_direct_CXX=no
+    hardcode_automatic_CXX=yes
+    hardcode_shlibpath_var_CXX=unsupported
+    whole_archive_flag_spec_CXX='-all_load $convenience'
+    link_all_deplibs_CXX=yes
+  else
+    ld_shlibs_CXX=no
+  fi
+    ;;
+
+  dgux*)
+    case $cc_basename in
+      ec++)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      ghcx)
+	# Green Hills C++ Compiler
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+  freebsd12*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    ld_shlibs_CXX=no
+    ;;
+  freebsd-elf*)
+    archive_cmds_need_lc_CXX=no
+    ;;
+  freebsd* | kfreebsd*-gnu)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    ld_shlibs_CXX=yes
+    ;;
+  gnu*)
+    ;;
+  hpux9*)
+    hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+    hardcode_libdir_separator_CXX=:
+    export_dynamic_flag_spec_CXX='${wl}-E'
+    hardcode_direct_CXX=yes
+    hardcode_minus_L_CXX=yes # Not in the search PATH,
+				# but as the default
+				# location of the library.
+
+    case $cc_basename in
+    CC)
+      # FIXME: insert proper C++ library support
+      ld_shlibs_CXX=no
+      ;;
+    aCC)
+      archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      case "$host_cpu" in
+      hppa*64*)
+	hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+	hardcode_libdir_flag_spec_ld_CXX='+b $libdir'
+	hardcode_libdir_separator_CXX=:
+        ;;
+      ia64*)
+	hardcode_libdir_flag_spec_CXX='-L$libdir'
+        ;;
+      *)
+	hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator_CXX=:
+	export_dynamic_flag_spec_CXX='${wl}-E'
+        ;;
+      esac
+    fi
+    case "$host_cpu" in
+    hppa*64*)
+      hardcode_direct_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      ;;
+    ia64*)
+      hardcode_direct_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      hardcode_minus_L_CXX=yes # Not in the search PATH,
+					      # but as the default
+					      # location of the library.
+      ;;
+    *)
+      hardcode_direct_CXX=yes
+      hardcode_minus_L_CXX=yes # Not in the search PATH,
+					      # but as the default
+					      # location of the library.
+      ;;
+    esac
+
+    case $cc_basename in
+      CC)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      aCC)
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+	  ;;
+	*)
+	  archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  ;;
+	esac
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test $with_gnu_ld = no; then
+	    case "$host_cpu" in
+	    ia64*|hppa*64*)
+	      archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+	      ;;
+	    *)
+	      archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      ;;
+	    esac
+	  fi
+	else
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	fi
+	;;
+    esac
+    ;;
+  irix5* | irix6*)
+    case $cc_basename in
+      CC)
+	# SGI C++
+	archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+	# Archives containing C++ object files must be created using
+	# "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test "$with_gnu_ld" = no; then
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+	  else
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+	  fi
+	fi
+	link_all_deplibs_CXX=yes
+	;;
+    esac
+    hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+    hardcode_libdir_separator_CXX=:
+    ;;
+  linux*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+	hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir'
+	export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+	;;
+      icpc)
+	# Intel C++
+	with_gnu_ld=yes
+	archive_cmds_need_lc_CXX=no
+	archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	;;
+      cxx)
+	# Compaq C++
+	archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	runpath_var=LD_RUN_PATH
+	hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	hardcode_libdir_separator_CXX=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+    esac
+    ;;
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+  m88k*)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+  mvs*)
+    case $cc_basename in
+      cxx)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      hardcode_libdir_flag_spec_CXX='-R$libdir'
+      hardcode_direct_CXX=yes
+      hardcode_shlibpath_var_CXX=no
+    fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+    ;;
+  osf3*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	hardcode_libdir_separator_CXX=:
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+
+	;;
+      RCC)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      cxx)
+	allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	hardcode_libdir_separator_CXX=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	  archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+	  hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	fi
+	;;
+    esac
+    ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	hardcode_libdir_separator_CXX=:
+
+	# Archives containing C++ object files must be created using
+	# the KAI C++ compiler.
+	old_archive_cmds_CXX='$CC -o $oldlib $oldobjs'
+	;;
+      RCC)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      cxx)
+	allow_undefined_flag_CXX=' -expect_unresolved \*'
+	archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+	archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	  echo "-hidden">> $lib.exp~
+	  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version	$verstring` -update_registry $objdir/so_locations -o $lib~
+	  $rm $lib.exp'
+
+	hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	hardcode_libdir_separator_CXX=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	 archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+	  hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	fi
+	;;
+    esac
+    ;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+  sco*)
+    archive_cmds_need_lc_CXX=no
+    case $cc_basename in
+      CC)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC)
+	# Sun C++ 4.x
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      lcc)
+	# Lucid
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+  solaris*)
+    case $cc_basename in
+      CC)
+	# Sun C++ 4.2, 5.x and Centerline C++
+	no_undefined_flag_CXX=' -zdefs'
+	archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	$CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	hardcode_libdir_flag_spec_CXX='-R$libdir'
+	hardcode_shlibpath_var_CXX=no
+	case $host_os in
+	  solaris2.0-5 | solaris2.0-5.*) ;;
+	  *)
+	    # The C++ compiler is used as linker so we must use $wl
+	    # flag to pass the commands to the underlying system
+	    # linker.
+	    # Supported since Solaris 2.6 (maybe 2.5.1?)
+	    whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	    ;;
+	esac
+	link_all_deplibs_CXX=yes
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+	# Archives containing C++ object files must be created using
+	# "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	;;
+      gcx)
+	# Green Hills C++ Compiler
+	archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	# The C++ compiler must be used to create the archive.
+	old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	;;
+      *)
+	# GNU C++ compiler with Solaris linker
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+	  if $CC --version | grep -v '^2\.7' > /dev/null; then
+	    archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  else
+	    # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	    # platform.
+	    archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  fi
+
+	  hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+	fi
+	;;
+    esac
+    ;;
+  sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+    archive_cmds_need_lc_CXX=no
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC)
+	# NonStop-UX NCC 3.20
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    ld_shlibs_CXX=no
+    ;;
+esac
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+GCC_CXX="$GXX"
+LD_CXX="$LD"
+
+
+cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+	  || test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$compiler_lib_search_path_CXX"; then
+	     compiler_lib_search_path_CXX="${prev}${p}"
+	   else
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$postdeps_CXX"; then
+	   postdeps_CXX="${prev}${p}"
+	 else
+	   postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$predep_objects_CXX"; then
+	   predep_objects_CXX="$p"
+	 else
+	   predep_objects_CXX="$predep_objects_CXX $p"
+	 fi
+       else
+	 if test -z "$postdep_objects_CXX"; then
+	   postdep_objects_CXX="$p"
+	 else
+	   postdep_objects_CXX="$postdep_objects_CXX $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$rm -f confest.$objext
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+
+lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    lt_prog_compiler_wl_CXX='-Wl,'
+    lt_prog_compiler_static_CXX='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_CXX='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      lt_prog_compiler_pic_CXX=
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_CXX=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	;;
+      *)
+	lt_prog_compiler_pic_CXX='-fPIC'
+	;;
+      esac
+      ;;
+    *)
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix4* | aix5*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  lt_prog_compiler_static_CXX='-Bstatic'
+	else
+	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68)
+	  # Green Hills C++ Compiler
+	  # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++)
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  ghcx)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | kfreebsd*-gnu)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+	    if test "$host_cpu" != ia64; then
+	      lt_prog_compiler_pic_CXX='+Z'
+	    fi
+	    ;;
+	  aCC)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+	    case "$host_cpu" in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      lt_prog_compiler_pic_CXX='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux*)
+	case $cc_basename in
+	  KCC)
+	    # KAI C++ Compiler
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  icpc)
+	    # Intel C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  cxx)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx)
+	    lt_prog_compiler_pic_CXX='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC)
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    ;;
+	  RCC)
+	    # Rational C++ 2.4.1
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  cxx)
+	    # Digital/Compaq C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      sco*)
+	case $cc_basename in
+	  CC)
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    lt_prog_compiler_wl_CXX='-Qoption ld '
+	    ;;
+	  gcx)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC)
+	    # Sun C++ 4.x
+	    lt_prog_compiler_pic_CXX='-pic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  lcc)
+	    # Lucid
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC)
+	    # NonStop-UX NCC 3.20
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      unixware*)
+	;;
+      vxworks*)
+	;;
+      *)
+	lt_prog_compiler_can_build_shared_CXX=no
+	;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_prog_compiler_pic_works_CXX=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:12620: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:12624: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_prog_compiler_pic_works_CXX=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6
+
+if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then
+    case $lt_prog_compiler_pic_CXX in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+     esac
+else
+    lt_prog_compiler_pic_CXX=
+     lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_CXX=
+    ;;
+  *)
+    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+    ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:12680: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:12684: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s out/conftest.err; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+  if test "$hard_links" = no; then
+    { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix4* | aix5*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+    else
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    export_symbols_cmds_CXX="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_CXX=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_CXX in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl_CXX
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+        allow_undefined_flag_CXX=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc_CXX=no
+        else
+	  archive_cmds_need_lc_CXX=yes
+        fi
+        allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi4*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.01* | freebsdelf3.01*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '#line 13191 "configure"' > conftest.$ac_ext
+    if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=yes
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" || \
+   test -n "$runpath_var CXX" || \
+   test "X$hardcode_automatic_CXX"="Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct_CXX" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+     test "$hardcode_minus_L_CXX" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_CXX=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_CXX=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_CXX=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5
+echo "${ECHO_T}$hardcode_action_CXX" >&6
+
+if test "$hardcode_action_CXX" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+       else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+       ;;
+   *)
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+    ;;
+  esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+   ;;
+
+  *)
+    echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shl_load (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+  lt_cv_dlopen="shl_load"
+else
+  echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+  echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlopen (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+  lt_cv_dlopen="dlopen"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_svld_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_cxx_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_dld_link=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 14062 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 14160 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    compiler_CXX \
+    CC_CXX \
+    LD_CXX \
+    lt_prog_compiler_wl_CXX \
+    lt_prog_compiler_pic_CXX \
+    lt_prog_compiler_static_CXX \
+    lt_prog_compiler_no_builtin_flag_CXX \
+    export_dynamic_flag_spec_CXX \
+    thread_safe_flag_spec_CXX \
+    whole_archive_flag_spec_CXX \
+    enable_shared_with_static_runtimes_CXX \
+    old_archive_cmds_CXX \
+    old_archive_from_new_cmds_CXX \
+    predep_objects_CXX \
+    postdep_objects_CXX \
+    predeps_CXX \
+    postdeps_CXX \
+    compiler_lib_search_path_CXX \
+    archive_cmds_CXX \
+    archive_expsym_cmds_CXX \
+    postinstall_cmds_CXX \
+    postuninstall_cmds_CXX \
+    old_archive_from_expsyms_cmds_CXX \
+    allow_undefined_flag_CXX \
+    no_undefined_flag_CXX \
+    export_symbols_cmds_CXX \
+    hardcode_libdir_flag_spec_CXX \
+    hardcode_libdir_flag_spec_ld_CXX \
+    hardcode_libdir_separator_CXX \
+    hardcode_automatic_CXX \
+    module_cmds_CXX \
+    module_expsym_cmds_CXX \
+    lt_cv_prog_compiler_c_o_CXX \
+    exclude_expsyms_CXX \
+    include_expsyms_CXX; do
+
+    case $var in
+    old_archive_cmds_CXX | \
+    old_archive_from_new_cmds_CXX | \
+    archive_cmds_CXX | \
+    archive_expsym_cmds_CXX | \
+    module_cmds_CXX | \
+    module_expsym_cmds_CXX | \
+    old_archive_from_expsyms_cmds_CXX | \
+    export_symbols_cmds_CXX | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\$0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+cfgfile="$ofile"
+
+  cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_CXX
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_CXX
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_CXX
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_CXX"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+
+	else
+	  tagname=""
+	fi
+	;;
+
+      F77)
+	if test -n "$F77" && test "X$F77" != "Xno"; then
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+
+archive_cmds_need_lc_F77=no
+allow_undefined_flag_F77=
+always_export_symbols_F77=no
+archive_expsym_cmds_F77=
+export_dynamic_flag_spec_F77=
+hardcode_direct_F77=no
+hardcode_libdir_flag_spec_F77=
+hardcode_libdir_flag_spec_ld_F77=
+hardcode_libdir_separator_F77=
+hardcode_minus_L_F77=no
+hardcode_automatic_F77=no
+module_cmds_F77=
+module_expsym_cmds_F77=
+link_all_deplibs_F77=unknown
+old_archive_cmds_F77=$old_archive_cmds
+no_undefined_flag_F77=
+whole_archive_flag_spec_F77=
+enable_shared_with_static_runtimes_F77=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+objext_F77=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="      program t\n      end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+compiler_F77=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+aix4* | aix5*)
+  test "$enable_shared" = yes && enable_static=no
+  ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+GCC_F77="$G77"
+LD_F77="$LD"
+
+lt_prog_compiler_wl_F77=
+lt_prog_compiler_pic_F77=
+lt_prog_compiler_static_F77=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl_F77='-Wl,'
+    lt_prog_compiler_static_F77='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_F77='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_F77='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared_F77=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_F77=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_F77='-fPIC'
+	;;
+      esac
+      ;;
+
+    *)
+      lt_prog_compiler_pic_F77='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_F77='-Bstatic'
+      else
+	lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_F77='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static_F77='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static_F77='-non_shared'
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    linux*)
+      case $CC in
+      icc* | ecc*)
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='-KPIC'
+	lt_prog_compiler_static_F77='-static'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl_F77='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static_F77='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static_F77='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      lt_prog_compiler_pic_F77='-Kpic'
+      lt_prog_compiler_static_F77='-dn'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl_F77='-Qoption ld '
+      lt_prog_compiler_pic_F77='-PIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic_F77='-Kconform_pic'
+	lt_prog_compiler_static_F77='-Bstatic'
+      fi
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic_F77='-pic'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared_F77=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_F77"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_F77+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_prog_compiler_pic_works_F77=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_F77"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:14987: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:14991: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_prog_compiler_pic_works_F77=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6
+
+if test x"$lt_prog_compiler_pic_works_F77" = xyes; then
+    case $lt_prog_compiler_pic_F77 in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;;
+     esac
+else
+    lt_prog_compiler_pic_F77=
+     lt_prog_compiler_can_build_shared_F77=no
+fi
+
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_F77=
+    ;;
+  *)
+    lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77"
+    ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_c_o_F77=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:15047: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:15051: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s out/conftest.err; then
+       lt_cv_prog_compiler_c_o_F77=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+  if test "$hard_links" = no; then
+    { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+  runpath_var=
+  allow_undefined_flag_F77=
+  enable_shared_with_static_runtimes_F77=no
+  archive_cmds_F77=
+  archive_expsym_cmds_F77=
+  old_archive_From_new_cmds_F77=
+  old_archive_from_expsyms_cmds_F77=
+  export_dynamic_flag_spec_F77=
+  whole_archive_flag_spec_F77=
+  thread_safe_flag_spec_F77=
+  hardcode_libdir_flag_spec_F77=
+  hardcode_libdir_flag_spec_ld_F77=
+  hardcode_libdir_separator_F77=
+  hardcode_direct_F77=no
+  hardcode_minus_L_F77=no
+  hardcode_shlibpath_var_F77=unsupported
+  link_all_deplibs_F77=unknown
+  hardcode_automatic_F77=no
+  module_cmds_F77=
+  module_expsym_cmds_F77=
+  always_export_symbols_F77=no
+  export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms_F77=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs_F77=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs_F77=no
+	cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_minus_L_F77=yes
+
+      # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      ld_shlibs_F77=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag_F77=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      allow_undefined_flag_F77=unsupported
+      always_export_symbols_F77=no
+      enable_shared_with_static_runtimes_F77=yes
+      export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+	ld_shlibs_F77=no
+	cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    sunos4*)
+      archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+  linux*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_cmds_F77="$tmp_archive_cmds"
+      supports_anon_versioning=no
+      case `$LD -v 2>/dev/null` in
+        *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+        *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+        *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+        *\ 2.11.*) ;; # other 2.11 versions
+        *) supports_anon_versioning=yes ;;
+      esac
+      if test $supports_anon_versioning = yes; then
+        archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+        $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+      else
+        archive_expsym_cmds_F77="$tmp_archive_cmds"
+      fi
+    else
+      ld_shlibs_F77=no
+    fi
+    ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs_F77" = yes; then
+      runpath_var=LD_RUN_PATH
+      hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir'
+      export_dynamic_flag_spec_F77='${wl}--export-dynamic'
+      # ancient GNU ld didn't support --whole-archive et. al.
+      if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ 	whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+  	whole_archive_flag_spec_F77=
+      fi
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag_F77=unsupported
+      always_export_symbols_F77=yes
+      archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L_F77=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct_F77=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+	  export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+	  for ld_flag in $LDFLAGS; do
+  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+  	    aix_use_runtimelinking=yes
+  	    break
+  	  fi
+	  done
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds_F77=''
+      hardcode_direct_F77=yes
+      hardcode_libdir_separator_F77=':'
+      link_all_deplibs_F77=yes
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.012|aix4.012.*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" && \
+  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	  then
+  	  # We have reworked collect2
+  	  hardcode_direct_F77=yes
+	  else
+  	  # We have old collect2
+  	  hardcode_direct_F77=unsupported
+  	  # It fails to find uninstalled libraries when the uninstalled
+  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+  	  # to unsupported forces relinking
+  	  hardcode_minus_L_F77=yes
+  	  hardcode_libdir_flag_spec_F77='-L$libdir'
+  	  hardcode_libdir_separator_F77=
+	  fi
+	esac
+	shared_flag='-shared'
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+  	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+  	if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+  	fi
+	fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols_F77=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag_F77='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       cat >conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_f77_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+       hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+	archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag_F77="-z nodefs"
+	  archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an empty executable.
+	 cat >conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_f77_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	 hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag_F77=' ${wl}-bernotok'
+	  allow_undefined_flag_F77=' ${wl}-berok'
+	  # -bexpall does not export symbols beginning with underscore (_)
+	  always_export_symbols_F77=yes
+	  # Exported symbols can be pulled into shared objects from archives
+	  whole_archive_flag_spec_F77=' '
+	  archive_cmds_need_lc_F77=yes
+	  # This is similar to how AIX traditionally builds it's shared libraries.
+	  archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_minus_L_F77=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs_F77=no
+      ;;
+
+    bsdi4*)
+      export_dynamic_flag_spec_F77=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec_F77=' '
+      allow_undefined_flag_F77=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_From_new_cmds_F77='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes_F77=yes
+      ;;
+
+    darwin* | rhapsody*)
+    if test "$GXX" = yes ; then
+      archive_cmds_need_lc_F77=no
+      case "$host_os" in
+      rhapsody* | darwin1.[012])
+	allow_undefined_flag_F77='-undefined suppress'
+	;;
+      *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	allow_undefined_flag_F77='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[012])
+            allow_undefined_flag_F77='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            allow_undefined_flag_F77='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+	;;
+      esac
+    	lt_int_apple_cc_single_mod=no
+    	output_verbose_link_cmd='echo'
+    	if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+    	  lt_int_apple_cc_single_mod=yes
+    	fi
+    	if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+    	  archive_cmds_F77='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    	else
+        archive_cmds_F77='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      fi
+      module_cmds_F77='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+        if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+          archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        else
+          archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        fi
+          module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      hardcode_direct_F77=no
+      hardcode_automatic_F77=yes
+      hardcode_shlibpath_var_F77=unsupported
+      whole_archive_flag_spec_F77='-all_load $convenience'
+      link_all_deplibs_F77=yes
+    else
+      ld_shlibs_F77=no
+    fi
+      ;;
+
+    dgux*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs_F77=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_F77=yes
+      hardcode_minus_L_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu)
+      archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      hardcode_direct_F77=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L_F77=yes
+      export_dynamic_flag_spec_F77='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	*)
+	  archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*)
+	  hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_flag_spec_ld_F77='+b $libdir'
+	  hardcode_libdir_separator_F77=:
+	  hardcode_direct_F77=no
+	  hardcode_shlibpath_var_F77=no
+	  ;;
+	ia64*)
+	  hardcode_libdir_flag_spec_F77='-L$libdir'
+	  hardcode_direct_F77=no
+	  hardcode_shlibpath_var_F77=no
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L_F77=yes
+	  ;;
+	*)
+	  hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_separator_F77=:
+	  hardcode_direct_F77=yes
+	  export_dynamic_flag_spec_F77='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L_F77=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_ld_F77='-rpath $libdir'
+      fi
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      link_all_deplibs_F77=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    newsos6)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_F77=yes
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    openbsd*)
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec_F77='${wl}-E'
+      else
+       case $host_os in
+	 openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	   archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	   hardcode_libdir_flag_spec_F77='-R$libdir'
+	   ;;
+	 *)
+	   archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	   hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+	   ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_minus_L_F77=yes
+      allow_undefined_flag_F77=unsupported
+      archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag_F77=' -expect_unresolved \*'
+	archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag_F77=' -expect_unresolved \*'
+	archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec_F77='-rpath $libdir'
+      fi
+      hardcode_libdir_separator_F77=:
+      ;;
+
+    sco3.2v5*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_F77=no
+      export_dynamic_flag_spec_F77='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      no_undefined_flag_F77=' -z text'
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+	archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_shlibpath_var_F77=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+	whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;;
+      esac
+      link_all_deplibs_F77=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_direct_F77=yes
+      hardcode_minus_L_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_F77=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds_F77='$CC -r -o $output$reload_objs'
+	  hardcode_direct_F77=no
+        ;;
+	motorola)
+	  archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_F77=no
+      export_dynamic_flag_spec_F77='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var_F77=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs_F77=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_F77=yes
+      hardcode_minus_L_F77=no
+      hardcode_shlibpath_var_F77=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[78]* | unixware7*)
+      no_undefined_flag_F77='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    sysv5*)
+      no_undefined_flag_F77=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  		$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      hardcode_libdir_flag_spec_F77=
+      hardcode_shlibpath_var_F77=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    *)
+      ld_shlibs_F77=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5
+echo "${ECHO_T}$ld_shlibs_F77" >&6
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_F77" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_F77=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_F77 in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl_F77
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag_F77
+        allow_undefined_flag_F77=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc_F77=no
+        else
+	  archive_cmds_need_lc_F77=yes
+        fi
+        allow_undefined_flag_F77=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi4*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.01* | freebsdelf3.01*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '#line 16361 "configure"' > conftest.$ac_ext
+    if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=yes
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_F77=
+if test -n "$hardcode_libdir_flag_spec_F77" || \
+   test -n "$runpath_var F77" || \
+   test "X$hardcode_automatic_F77"="Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct_F77" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no &&
+     test "$hardcode_minus_L_F77" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_F77=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_F77=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_F77=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5
+echo "${ECHO_T}$hardcode_action_F77" >&6
+
+if test "$hardcode_action_F77" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+       else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+       ;;
+   *)
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+    ;;
+  esac
+fi
+
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    compiler_F77 \
+    CC_F77 \
+    LD_F77 \
+    lt_prog_compiler_wl_F77 \
+    lt_prog_compiler_pic_F77 \
+    lt_prog_compiler_static_F77 \
+    lt_prog_compiler_no_builtin_flag_F77 \
+    export_dynamic_flag_spec_F77 \
+    thread_safe_flag_spec_F77 \
+    whole_archive_flag_spec_F77 \
+    enable_shared_with_static_runtimes_F77 \
+    old_archive_cmds_F77 \
+    old_archive_from_new_cmds_F77 \
+    predep_objects_F77 \
+    postdep_objects_F77 \
+    predeps_F77 \
+    postdeps_F77 \
+    compiler_lib_search_path_F77 \
+    archive_cmds_F77 \
+    archive_expsym_cmds_F77 \
+    postinstall_cmds_F77 \
+    postuninstall_cmds_F77 \
+    old_archive_from_expsyms_cmds_F77 \
+    allow_undefined_flag_F77 \
+    no_undefined_flag_F77 \
+    export_symbols_cmds_F77 \
+    hardcode_libdir_flag_spec_F77 \
+    hardcode_libdir_flag_spec_ld_F77 \
+    hardcode_libdir_separator_F77 \
+    hardcode_automatic_F77 \
+    module_cmds_F77 \
+    module_expsym_cmds_F77 \
+    lt_cv_prog_compiler_c_o_F77 \
+    exclude_expsyms_F77 \
+    include_expsyms_F77; do
+
+    case $var in
+    old_archive_cmds_F77 | \
+    old_archive_from_new_cmds_F77 | \
+    archive_cmds_F77 | \
+    archive_expsym_cmds_F77 | \
+    module_cmds_F77 | \
+    module_expsym_cmds_F77 | \
+    old_archive_from_expsyms_cmds_F77 | \
+    export_symbols_cmds_F77 | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\$0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+cfgfile="$ofile"
+
+  cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_F77
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_F77
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_F77
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_F77
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_F77
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_F77
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_F77
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_F77
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_F77
+archive_expsym_cmds=$lt_archive_expsym_cmds_F77
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_F77
+module_expsym_cmds=$lt_module_expsym_cmds_F77
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_F77
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_F77
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_F77
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_F77
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_F77
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_F77
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_F77
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_F77
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_F77
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_F77
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_F77
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_F77"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_F77
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_F77
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_F77
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_F77
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+	else
+	  tagname=""
+	fi
+	;;
+
+      GCJ)
+	if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+
+
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+objext_GCJ=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+compiler_GCJ=$CC
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+archive_cmds_need_lc_GCJ=no
+
+
+lt_prog_compiler_no_builtin_flag_GCJ=
+
+if test "$GCC" = yes; then
+  lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:17102: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:17106: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+lt_prog_compiler_wl_GCJ=
+lt_prog_compiler_pic_GCJ=
+lt_prog_compiler_static_GCJ=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl_GCJ='-Wl,'
+    lt_prog_compiler_static_GCJ='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_GCJ='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_GCJ='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared_GCJ=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_GCJ=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_GCJ='-fPIC'
+	;;
+      esac
+      ;;
+
+    *)
+      lt_prog_compiler_pic_GCJ='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_GCJ='-Bstatic'
+      else
+	lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case "$host_cpu" in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_GCJ='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static_GCJ='-non_shared'
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic_GCJ='-KPIC'
+      lt_prog_compiler_static_GCJ='-Bstatic'
+      ;;
+
+    linux*)
+      case $CC in
+      icc* | ecc*)
+	lt_prog_compiler_wl_GCJ='-Wl,'
+	lt_prog_compiler_pic_GCJ='-KPIC'
+	lt_prog_compiler_static_GCJ='-static'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl_GCJ='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static_GCJ='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static_GCJ='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      lt_prog_compiler_pic_GCJ='-Kpic'
+      lt_prog_compiler_static_GCJ='-dn'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      lt_prog_compiler_pic_GCJ='-KPIC'
+      lt_prog_compiler_static_GCJ='-Bstatic'
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl_GCJ='-Qoption ld '
+      lt_prog_compiler_pic_GCJ='-PIC'
+      lt_prog_compiler_static_GCJ='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      lt_prog_compiler_wl_GCJ='-Wl,'
+      lt_prog_compiler_pic_GCJ='-KPIC'
+      lt_prog_compiler_static_GCJ='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic_GCJ='-Kconform_pic'
+	lt_prog_compiler_static_GCJ='-Bstatic'
+      fi
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic_GCJ='-pic'
+      lt_prog_compiler_static_GCJ='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared_GCJ=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_GCJ"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_prog_compiler_pic_works_GCJ=no
+  ac_outfile=conftest.$ac_objext
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_GCJ"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:17335: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:17339: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s conftest.err; then
+       lt_prog_compiler_pic_works_GCJ=yes
+     fi
+   fi
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6
+
+if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then
+    case $lt_prog_compiler_pic_GCJ in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;;
+     esac
+else
+    lt_prog_compiler_pic_GCJ=
+     lt_prog_compiler_can_build_shared_GCJ=no
+fi
+
+fi
+case "$host_os" in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_GCJ=
+    ;;
+  *)
+    lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ"
+    ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  lt_cv_prog_compiler_c_o_GCJ=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:17395: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:17399: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test ! -s out/conftest.err; then
+       lt_cv_prog_compiler_c_o_GCJ=yes
+     fi
+   fi
+   chmod u+w .
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+  if test "$hard_links" = no; then
+    { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+  runpath_var=
+  allow_undefined_flag_GCJ=
+  enable_shared_with_static_runtimes_GCJ=no
+  archive_cmds_GCJ=
+  archive_expsym_cmds_GCJ=
+  old_archive_From_new_cmds_GCJ=
+  old_archive_from_expsyms_cmds_GCJ=
+  export_dynamic_flag_spec_GCJ=
+  whole_archive_flag_spec_GCJ=
+  thread_safe_flag_spec_GCJ=
+  hardcode_libdir_flag_spec_GCJ=
+  hardcode_libdir_flag_spec_ld_GCJ=
+  hardcode_libdir_separator_GCJ=
+  hardcode_direct_GCJ=no
+  hardcode_minus_L_GCJ=no
+  hardcode_shlibpath_var_GCJ=unsupported
+  link_all_deplibs_GCJ=unknown
+  hardcode_automatic_GCJ=no
+  module_cmds_GCJ=
+  module_expsym_cmds_GCJ=
+  always_export_symbols_GCJ=no
+  export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms_GCJ=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs_GCJ=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs_GCJ=no
+	cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_minus_L_GCJ=yes
+
+      # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      ld_shlibs_GCJ=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag_GCJ=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs_GCJ=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      allow_undefined_flag_GCJ=unsupported
+      always_export_symbols_GCJ=no
+      enable_shared_with_static_runtimes_GCJ=yes
+      export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+	ld_shlibs_GCJ=no
+	cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_GCJ=no
+      fi
+      ;;
+
+    sunos4*)
+      archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+  linux*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_cmds_GCJ="$tmp_archive_cmds"
+      supports_anon_versioning=no
+      case `$LD -v 2>/dev/null` in
+        *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+        *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+        *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+        *\ 2.11.*) ;; # other 2.11 versions
+        *) supports_anon_versioning=yes ;;
+      esac
+      if test $supports_anon_versioning = yes; then
+        archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+        $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+      else
+        archive_expsym_cmds_GCJ="$tmp_archive_cmds"
+      fi
+    else
+      ld_shlibs_GCJ=no
+    fi
+    ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_GCJ=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs_GCJ" = yes; then
+      runpath_var=LD_RUN_PATH
+      hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir'
+      export_dynamic_flag_spec_GCJ='${wl}--export-dynamic'
+      # ancient GNU ld didn't support --whole-archive et. al.
+      if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ 	whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+  	whole_archive_flag_spec_GCJ=
+      fi
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag_GCJ=unsupported
+      always_export_symbols_GCJ=yes
+      archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L_GCJ=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct_GCJ=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+	  export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+	  for ld_flag in $LDFLAGS; do
+  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+  	    aix_use_runtimelinking=yes
+  	    break
+  	  fi
+	  done
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds_GCJ=''
+      hardcode_direct_GCJ=yes
+      hardcode_libdir_separator_GCJ=':'
+      link_all_deplibs_GCJ=yes
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.012|aix4.012.*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" && \
+  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	  then
+  	  # We have reworked collect2
+  	  hardcode_direct_GCJ=yes
+	  else
+  	  # We have old collect2
+  	  hardcode_direct_GCJ=unsupported
+  	  # It fails to find uninstalled libraries when the uninstalled
+  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+  	  # to unsupported forces relinking
+  	  hardcode_minus_L_GCJ=yes
+  	  hardcode_libdir_flag_spec_GCJ='-L$libdir'
+  	  hardcode_libdir_separator_GCJ=
+	  fi
+	esac
+	shared_flag='-shared'
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+  	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+  	if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+  	fi
+	fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols_GCJ=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag_GCJ='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+       hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+	archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag_GCJ="-z nodefs"
+	  archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an empty executable.
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	 hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag_GCJ=' ${wl}-bernotok'
+	  allow_undefined_flag_GCJ=' ${wl}-berok'
+	  # -bexpall does not export symbols beginning with underscore (_)
+	  always_export_symbols_GCJ=yes
+	  # Exported symbols can be pulled into shared objects from archives
+	  whole_archive_flag_spec_GCJ=' '
+	  archive_cmds_need_lc_GCJ=yes
+	  # This is similar to how AIX traditionally builds it's shared libraries.
+	  archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_minus_L_GCJ=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs_GCJ=no
+      ;;
+
+    bsdi4*)
+      export_dynamic_flag_spec_GCJ=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec_GCJ=' '
+      allow_undefined_flag_GCJ=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_From_new_cmds_GCJ='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes_GCJ=yes
+      ;;
+
+    darwin* | rhapsody*)
+    if test "$GXX" = yes ; then
+      archive_cmds_need_lc_GCJ=no
+      case "$host_os" in
+      rhapsody* | darwin1.[012])
+	allow_undefined_flag_GCJ='-undefined suppress'
+	;;
+      *) # Darwin 1.3 on
+      if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+      	allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
+      else
+        case ${MACOSX_DEPLOYMENT_TARGET} in
+          10.[012])
+            allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
+            ;;
+          10.*)
+            allow_undefined_flag_GCJ='-undefined dynamic_lookup'
+            ;;
+        esac
+      fi
+	;;
+      esac
+    	lt_int_apple_cc_single_mod=no
+    	output_verbose_link_cmd='echo'
+    	if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+    	  lt_int_apple_cc_single_mod=yes
+    	fi
+    	if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+    	  archive_cmds_GCJ='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+    	else
+        archive_cmds_GCJ='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      fi
+      module_cmds_GCJ='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+        if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+          archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        else
+          archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+        fi
+          module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      hardcode_direct_GCJ=no
+      hardcode_automatic_GCJ=yes
+      hardcode_shlibpath_var_GCJ=unsupported
+      whole_archive_flag_spec_GCJ='-all_load $convenience'
+      link_all_deplibs_GCJ=yes
+    else
+      ld_shlibs_GCJ=no
+    fi
+      ;;
+
+    dgux*)
+      archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs_GCJ=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec_GCJ='-R$libdir'
+      hardcode_direct_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_GCJ=yes
+      hardcode_minus_L_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu)
+      archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec_GCJ='-R$libdir'
+      hardcode_direct_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator_GCJ=:
+      hardcode_direct_GCJ=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L_GCJ=yes
+      export_dynamic_flag_spec_GCJ='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case "$host_cpu" in
+	hppa*64*|ia64*)
+	  archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	*)
+	  archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	case "$host_cpu" in
+	hppa*64*)
+	  hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_flag_spec_ld_GCJ='+b $libdir'
+	  hardcode_libdir_separator_GCJ=:
+	  hardcode_direct_GCJ=no
+	  hardcode_shlibpath_var_GCJ=no
+	  ;;
+	ia64*)
+	  hardcode_libdir_flag_spec_GCJ='-L$libdir'
+	  hardcode_direct_GCJ=no
+	  hardcode_shlibpath_var_GCJ=no
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L_GCJ=yes
+	  ;;
+	*)
+	  hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_separator_GCJ=:
+	  hardcode_direct_GCJ=yes
+	  export_dynamic_flag_spec_GCJ='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L_GCJ=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir'
+      fi
+      hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GCJ=:
+      link_all_deplibs_GCJ=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec_GCJ='-R$libdir'
+      hardcode_direct_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    newsos6)
+      archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_GCJ=yes
+      hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GCJ=:
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    openbsd*)
+      hardcode_direct_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec_GCJ='${wl}-E'
+      else
+       case $host_os in
+	 openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	   archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	   hardcode_libdir_flag_spec_GCJ='-R$libdir'
+	   ;;
+	 *)
+	   archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	   hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+	   ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_minus_L_GCJ=yes
+      allow_undefined_flag_GCJ=unsupported
+      archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag_GCJ=' -expect_unresolved \*'
+	archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_GCJ=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag_GCJ=' -expect_unresolved \*'
+	archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec_GCJ='-rpath $libdir'
+      fi
+      hardcode_libdir_separator_GCJ=:
+      ;;
+
+    sco3.2v5*)
+      archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_GCJ=no
+      export_dynamic_flag_spec_GCJ='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      no_undefined_flag_GCJ=' -z text'
+      if test "$GCC" = yes; then
+	archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+	archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      hardcode_libdir_flag_spec_GCJ='-R$libdir'
+      hardcode_shlibpath_var_GCJ=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+	whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;;
+      esac
+      link_all_deplibs_GCJ=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_direct_GCJ=yes
+      hardcode_minus_L_GCJ=yes
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_GCJ=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds_GCJ='$CC -r -o $output$reload_objs'
+	  hardcode_direct_GCJ=no
+        ;;
+	motorola)
+	  archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_GCJ=no
+      export_dynamic_flag_spec_GCJ='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var_GCJ=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs_GCJ=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_GCJ=yes
+      hardcode_minus_L_GCJ=no
+      hardcode_shlibpath_var_GCJ=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[78]* | unixware7*)
+      no_undefined_flag_GCJ='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+	archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    sysv5*)
+      no_undefined_flag_GCJ=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  		$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      hardcode_libdir_flag_spec_GCJ=
+      hardcode_shlibpath_var_GCJ=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_GCJ='-L$libdir'
+      hardcode_shlibpath_var_GCJ=no
+      ;;
+
+    *)
+      ld_shlibs_GCJ=no
+      ;;
+    esac
+  fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5
+echo "${ECHO_T}$ld_shlibs_GCJ" >&6
+test "$ld_shlibs_GCJ" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_GCJ" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_GCJ=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_GCJ in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl_GCJ
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ
+        allow_undefined_flag_GCJ=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc_GCJ=no
+        else
+	  archive_cmds_need_lc_GCJ=yes
+        fi
+        allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi4*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.01* | freebsdelf3.01*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case "$host_cpu" in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # find out which ABI we are using
+  libsuff=
+  case "$host_cpu" in
+  x86_64*|s390x*|powerpc64*)
+    echo '#line 18729 "configure"' > conftest.$ac_ext
+    if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+      case `/usr/bin/file conftest.$ac_objext` in
+      *64-bit*)
+        libsuff=64
+        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+        ;;
+      esac
+    fi
+    rm -rf conftest*
+    ;;
+  esac
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=yes
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_GCJ=
+if test -n "$hardcode_libdir_flag_spec_GCJ" || \
+   test -n "$runpath_var GCJ" || \
+   test "X$hardcode_automatic_GCJ"="Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct_GCJ" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no &&
+     test "$hardcode_minus_L_GCJ" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_GCJ=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_GCJ=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_GCJ=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5
+echo "${ECHO_T}$hardcode_action_GCJ" >&6
+
+if test "$hardcode_action_GCJ" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+       else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+       ;;
+   *)
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+    ;;
+  esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+   ;;
+
+  *)
+    echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shl_load (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+  lt_cv_dlopen="shl_load"
+else
+  echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_shl_load=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+  echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlopen (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+  lt_cv_dlopen="dlopen"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_svld_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dld_dld_link=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 19600 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+#line 19698 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}
+EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    compiler_GCJ \
+    CC_GCJ \
+    LD_GCJ \
+    lt_prog_compiler_wl_GCJ \
+    lt_prog_compiler_pic_GCJ \
+    lt_prog_compiler_static_GCJ \
+    lt_prog_compiler_no_builtin_flag_GCJ \
+    export_dynamic_flag_spec_GCJ \
+    thread_safe_flag_spec_GCJ \
+    whole_archive_flag_spec_GCJ \
+    enable_shared_with_static_runtimes_GCJ \
+    old_archive_cmds_GCJ \
+    old_archive_from_new_cmds_GCJ \
+    predep_objects_GCJ \
+    postdep_objects_GCJ \
+    predeps_GCJ \
+    postdeps_GCJ \
+    compiler_lib_search_path_GCJ \
+    archive_cmds_GCJ \
+    archive_expsym_cmds_GCJ \
+    postinstall_cmds_GCJ \
+    postuninstall_cmds_GCJ \
+    old_archive_from_expsyms_cmds_GCJ \
+    allow_undefined_flag_GCJ \
+    no_undefined_flag_GCJ \
+    export_symbols_cmds_GCJ \
+    hardcode_libdir_flag_spec_GCJ \
+    hardcode_libdir_flag_spec_ld_GCJ \
+    hardcode_libdir_separator_GCJ \
+    hardcode_automatic_GCJ \
+    module_cmds_GCJ \
+    module_expsym_cmds_GCJ \
+    lt_cv_prog_compiler_c_o_GCJ \
+    exclude_expsyms_GCJ \
+    include_expsyms_GCJ; do
+
+    case $var in
+    old_archive_cmds_GCJ | \
+    old_archive_from_new_cmds_GCJ | \
+    archive_cmds_GCJ | \
+    archive_expsym_cmds_GCJ | \
+    module_cmds_GCJ | \
+    module_expsym_cmds_GCJ | \
+    old_archive_from_expsyms_cmds_GCJ | \
+    export_symbols_cmds_GCJ | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\$0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+cfgfile="$ofile"
+
+  cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_GCJ
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_GCJ
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_GCJ
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_GCJ
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_GCJ
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_GCJ
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_GCJ
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_GCJ
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_GCJ
+archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_GCJ
+module_expsym_cmds=$lt_module_expsym_cmds_GCJ
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_GCJ
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_GCJ
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_GCJ
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_GCJ
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_GCJ
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_GCJ
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_GCJ
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_GCJ
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_GCJ
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_GCJ"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_GCJ
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_GCJ
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_GCJ
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_GCJ
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+	else
+	  tagname=""
+	fi
+	;;
+
+      RC)
+
+
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+objext_RC=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+compiler_RC=$CC
+lt_cv_prog_compiler_c_o_RC=yes
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    compiler_RC \
+    CC_RC \
+    LD_RC \
+    lt_prog_compiler_wl_RC \
+    lt_prog_compiler_pic_RC \
+    lt_prog_compiler_static_RC \
+    lt_prog_compiler_no_builtin_flag_RC \
+    export_dynamic_flag_spec_RC \
+    thread_safe_flag_spec_RC \
+    whole_archive_flag_spec_RC \
+    enable_shared_with_static_runtimes_RC \
+    old_archive_cmds_RC \
+    old_archive_from_new_cmds_RC \
+    predep_objects_RC \
+    postdep_objects_RC \
+    predeps_RC \
+    postdeps_RC \
+    compiler_lib_search_path_RC \
+    archive_cmds_RC \
+    archive_expsym_cmds_RC \
+    postinstall_cmds_RC \
+    postuninstall_cmds_RC \
+    old_archive_from_expsyms_cmds_RC \
+    allow_undefined_flag_RC \
+    no_undefined_flag_RC \
+    export_symbols_cmds_RC \
+    hardcode_libdir_flag_spec_RC \
+    hardcode_libdir_flag_spec_ld_RC \
+    hardcode_libdir_separator_RC \
+    hardcode_automatic_RC \
+    module_cmds_RC \
+    module_expsym_cmds_RC \
+    lt_cv_prog_compiler_c_o_RC \
+    exclude_expsyms_RC \
+    include_expsyms_RC; do
+
+    case $var in
+    old_archive_cmds_RC | \
+    old_archive_from_new_cmds_RC | \
+    archive_cmds_RC | \
+    archive_expsym_cmds_RC | \
+    module_cmds_RC | \
+    module_expsym_cmds_RC | \
+    old_archive_from_expsyms_cmds_RC | \
+    export_symbols_cmds_RC | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\$0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+cfgfile="$ofile"
+
+  cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_RC
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_RC
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_RC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_RC
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_RC
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_RC
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_RC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_RC
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_RC
+archive_expsym_cmds=$lt_archive_expsym_cmds_RC
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_RC
+module_expsym_cmds=$lt_module_expsym_cmds_RC
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_RC
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_RC
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_RC
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_RC
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_RC
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_RC
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_RC
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_RC
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_RC
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_RC
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_RC
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_RC"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_RC
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_RC
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_RC
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_RC
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+	;;
+
+      *)
+	{ { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5
+echo "$as_me: error: Unsupported tag name: $tagname" >&2;}
+   { (exit 1); exit 1; }; }
+	;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5
+echo "$as_me: error: unable to update list of available tagged configurations." >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+fi
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Prevent multiple expansion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-ndebug or --disable-ndebug was given.
+if test "${enable_ndebug+set}" = set; then
+  enableval="$enable_ndebug"
+
+else
+  enable_ndebug=no
+fi;
+
+
+if test x$enable_ndebug = yes; then
+  NDEBUG_TRUE=
+  NDEBUG_FALSE='#'
+else
+  NDEBUG_TRUE='#'
+  NDEBUG_FALSE=
+fi
+
+SOFIA_CFLAGS="$SOFIA_CFLAGS -DNDEBUG"
+
+
+# Check whether --enable-expensive-checks or --disable-expensive-checks was given.
+if test "${enable_expensive_checks+set}" = set; then
+  enableval="$enable_expensive_checks"
+
+else
+  enable_expensive_checks=no
+fi;
+if test $enable_expensive_checks != no; then
+TESTS_ENVIRONMENT=EXPENSIVE_CHECKS=1
+
+fi
+
+
+if test x$enable_expensive_checks != no; then
+  EXPENSIVE_CHECKS_TRUE=
+  EXPENSIVE_CHECKS_FALSE='#'
+else
+  EXPENSIVE_CHECKS_TRUE='#'
+  EXPENSIVE_CHECKS_FALSE=
+fi
+
+
+
+ACLOCAL_AMFLAGS="-I m4"
+
+
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_DOXYGEN+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$DOXYGEN"; then
+  ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DOXYGEN="doxygen"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_DOXYGEN" && ac_cv_prog_DOXYGEN="echo"
+fi
+fi
+DOXYGEN=$ac_cv_prog_DOXYGEN
+if test -n "$DOXYGEN"; then
+  echo "$as_me:$LINENO: result: $DOXYGEN" >&5
+echo "${ECHO_T}$DOXYGEN" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+
+if test $DOXYGEN = doxygen; then
+  HAVE_DOXYGEN_TRUE=
+  HAVE_DOXYGEN_FALSE='#'
+else
+  HAVE_DOXYGEN_TRUE='#'
+  HAVE_DOXYGEN_FALSE=
+fi
+
+
+### checks for libraries
+### --------------------
+
+
+
+# Check whether --with-rt or --without-rt was given.
+if test "${with_rt+set}" = set; then
+  withval="$with_rt"
+
+fi;
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset x;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *ccp;
+  char **p;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  ccp = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++ccp;
+  p = (char**) ccp;
+  ccp = (char const *const *) p;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+  }
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_const=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+  return 0;
+if (sizeof (size_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __func__" >&5
+echo $ECHO_N "checking whether $CC recognizes __func__... $ECHO_C" >&6
+if test "${ac_cv_c_var_func+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+char *s = __func__;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_var_func=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_var_func=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_var_func" >&5
+echo "${ECHO_T}$ac_cv_c_var_func" >&6
+if test $ac_cv_c_var_func = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __FUNCTION__" >&5
+echo $ECHO_N "checking whether $CC recognizes __FUNCTION__... $ECHO_C" >&6
+if test "${ac_cv_c_macro_function+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+char *s = __FUNCTION__;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_macro_function=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_macro_function=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_macro_function" >&5
+echo "${ECHO_T}$ac_cv_c_macro_function" >&6
+if test $ac_cv_c_macro_function = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNCTION 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+echo "$as_me:$LINENO: checking for sa_len" >&5
+echo $ECHO_N "checking for sa_len... $ECHO_C" >&6
+if test "${ac_cv_sa_len+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+
+ struct sockaddr t;t.sa_len = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sa_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sa_len" >&5
+echo "${ECHO_T}$ac_cv_sa_len" >&6
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for sockaddr_in6" >&5
+echo $ECHO_N "checking for sockaddr_in6... $ECHO_C" >&6
+if test "${ac_cv_sin6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <netinet/in.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "struct sockaddr_in6" >/dev/null 2>&1; then
+  ac_cv_sin6=yes
+else
+  ac_cv_sin6=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sin6" >&5
+echo "${ECHO_T}$ac_cv_sin6" >&6
+if test $ac_cv_sin6 = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6 1
+_ACEOF
+
+fi
+
+
+# Beginning of SAC_SOFIA_SU
+
+
+
+# ======================================================================
+# Check for features used by su
+
+
+case "$target" in
+*-*-solaris?.* )
+
+cat >>confdefs.h <<\_AXEOF
+#define __EXTENSIONS__ 1
+_AXEOF
+
+;;
+esac
+
+# Check includes used by su includes
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for sys/types.h" >&5
+echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/types.h usability" >&5
+echo $ECHO_N "checking sys/types.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <sys/types.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/types.h presence" >&5
+echo $ECHO_N "checking sys/types.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: sys/types.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/types.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/types.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: sys/types.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: sys/types.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/types.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: sys/types.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: sys/types.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for sys/types.h" >&5
+echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_sys_types_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6
+
+fi
+if test $ac_cv_header_sys_types_h = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SYS_TYPES 1
+_AXEOF
+
+fi
+
+
+
+ax_inttypes=false
+if test "${ac_cv_header_stdint_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdint_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdint_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdint_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking stdint.h usability" >&5
+echo $ECHO_N "checking stdint.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <stdint.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking stdint.h presence" >&5
+echo $ECHO_N "checking stdint.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdint.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: stdint.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: stdint.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: stdint.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: stdint.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: stdint.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: stdint.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: stdint.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: stdint.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: stdint.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdint.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: stdint.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdint_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_stdint_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdint_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdint_h" >&6
+
+fi
+if test $ac_cv_header_stdint_h = yes; then
+
+	ax_inttypes=true
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_STDINT 1
+_AXEOF
+
+fi
+
+
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking inttypes.h usability" >&5
+echo $ECHO_N "checking inttypes.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <inttypes.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking inttypes.h presence" >&5
+echo $ECHO_N "checking inttypes.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <inttypes.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: inttypes.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: inttypes.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: inttypes.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: inttypes.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: inttypes.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: inttypes.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: inttypes.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: inttypes.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_inttypes_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6
+
+fi
+if test $ac_cv_header_inttypes_h = yes; then
+
+	ax_inttypes=true
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INTTYPES 1
+_AXEOF
+
+fi
+
+
+
+if $ax_inttypes; then : ; else
+	{ { echo "$as_me:$LINENO: error: \"No <stdint.h> or <inttypes.h> found.\"" >&5
+echo "$as_me: error: \"No <stdint.h> or <inttypes.h> found.\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+if test "x$MINGW_ENVIRONMENT" != x1 ; then
+  if test "${ac_cv_header_pthread_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for pthread.h" >&5
+echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6
+if test "${ac_cv_header_pthread_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5
+echo "${ECHO_T}$ac_cv_header_pthread_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking pthread.h usability" >&5
+echo $ECHO_N "checking pthread.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <pthread.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking pthread.h presence" >&5
+echo $ECHO_N "checking pthread.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <pthread.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: pthread.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: pthread.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: pthread.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: pthread.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: pthread.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: pthread.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: pthread.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: pthread.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: pthread.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for pthread.h" >&5
+echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6
+if test "${ac_cv_header_pthread_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_pthread_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5
+echo "${ECHO_T}$ac_cv_header_pthread_h" >&6
+
+fi
+if test $ac_cv_header_pthread_h = yes; then
+  HAVE_PTHREADS=1;
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_PTHREADS 1
+_AXEOF
+
+fi
+
+
+else
+  HAVE_PTHREADS=1;
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_PTHREADS 1
+_AXEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+case "$ac_cv_c_inline" in
+  yes)
+cat >>confdefs.h <<\_AXEOF
+#define su_inline static inline
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_INLINE inline
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+  ;;
+  no)
+cat >>confdefs.h <<\_AXEOF
+#define su_inline static
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_INLINE 1
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+  ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define su_inline static $ac_cv_c_inline
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define SU_INLINE $ac_cv_c_inline
+_ACEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+  ;;
+esac
+
+# Check whether --enable-size-compat or --disable-size-compat was given.
+if test "${enable_size_compat+set}" = set; then
+  enableval="$enable_size_compat"
+
+else
+  enable_size_compat=yes
+fi;
+
+if test X$enable_size_compat != Xyes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISIZE_T size_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISIZE_MAX SIZE_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISSIZE_T ssize_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISSIZE_MAX SSIZE_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_USIZE_T size_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define USIZE_MAX SIZE_MAX
+_AXEOF
+else
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISIZE_T int
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISIZE_MAX INT_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISSIZE_T int
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISSIZE_MAX INT_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_USIZE_T unsigned
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define USIZE_MAX UINT_MAX
+_AXEOF
+fi
+
+
+# Check whether --enable-corefoundation or --disable-corefoundation was given.
+if test "${enable_corefoundation+set}" = set; then
+  enableval="$enable_corefoundation"
+
+else
+  enable_corefoundation=no
+fi;
+
+
+if test $enable_corefoundation = yes; then
+  COREFOUNDATION_TRUE=
+  COREFOUNDATION_FALSE='#'
+else
+  COREFOUNDATION_TRUE='#'
+  COREFOUNDATION_FALSE=
+fi
+
+
+if test $enable_corefoundation = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_OSX_CF_API 1
+_AXEOF
+
+   LIBS="-framework CoreFoundation -framework SystemConfiguration $LIBS"
+fi
+
+
+### ======================================================================
+### Test if we have stack suitable for handling tags directly
+###
+
+test -z "$ac_cv_tagstack" &&
+case "$target" in
+i?86-*-* ) ac_cv_tagstack=yes ;;
+esac
+
+echo "$as_me:$LINENO: checking for stack suitable for tags" >&5
+echo $ECHO_N "checking for stack suitable for tags... $ECHO_C" >&6
+if test "${ac_cv_tagstack+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_tagstack=no
+
+if test "$cross_compiling" = yes; then
+  ac_cv_tagstack=no
+else
+  cat >conftest.$ac_ext <<_ACEOF
+
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+  va_list ap;
+  tv i, *p = &l;
+
+  va_start(ap, h);
+
+  if (*p++ != l || *p++ != h) return 1;
+
+  for (i = l; i <= h; i++) {
+    if (*p++ != i)
+      return 1;
+  }
+
+  for (i = l; i <= h; i++) {
+    if (va_arg(ap, tv) != i)
+      return 1;
+  }
+
+  va_end(ap);
+
+  return 0;
+}
+
+int main(int avc, char **av)
+{
+  return test1((tv)1, (tv)10,
+	       (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+	       (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_tagstack=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_tagstack=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_tagstack" >&5
+echo "${ECHO_T}$ac_cv_tagstack" >&6
+
+if test $ac_cv_tagstack = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_TAGSTACK 1
+_AXEOF
+
+fi
+
+
+
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_SA_LEN 1
+_AXEOF
+
+fi
+
+
+case $ac_cv_sin6 in
+yes)
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_IN6 1
+_AXEOF
+ ;;
+ no) ;;
+  *) { { echo "$as_me:$LINENO: error: Inconsistent struct sockaddr_sin6 test" >&5
+echo "$as_me: error: Inconsistent struct sockaddr_sin6 test" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+for ac_header in unistd.h sys/time.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+for ac_header in fcntl.h dirent.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in winsock2.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WIN32 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_WINSOCK 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_WINSOCK2 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_STORAGE 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FREEADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_ADDRINFO 1
+_AXEOF
+
+
+
+for ac_header in windef.h ws2tcpip.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in iphlpapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#if HAVE_WINDEF_H
+#include <windef.h>
+#include <winbase.h>
+#endif
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTERFACE_INFO_EX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+_ACEOF
+
+
+fi
+
+done
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FILETIME 1
+_ACEOF
+
+
+else
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_BSDSOCK 1
+_AXEOF
+
+
+
+
+
+
+for ac_header in sys/socket.h sys/ioctl.h sys/filio.h sys/sockio.h \
+		  sys/select.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+for ac_header in netinet/in.h arpa/inet.h netdb.h \
+                  net/if.h net/if_types.h ifaddr.h netpacket/packet.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking whether MSG_TRUNC is declared" >&5
+echo $ECHO_N "checking whether MSG_TRUNC is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_MSG_TRUNC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+#ifndef MSG_TRUNC
+  char *p = (char *) MSG_TRUNC;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_have_decl_MSG_TRUNC=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_MSG_TRUNC=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_MSG_TRUNC" >&5
+echo "${ECHO_T}$ac_cv_have_decl_MSG_TRUNC" >&6
+if test $ac_cv_have_decl_MSG_TRUNC = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MSG_TRUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for struct addrinfo" >&5
+echo $ECHO_N "checking for struct addrinfo... $ECHO_C" >&6
+if test "${ac_cv_struct_addrinfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_addrinfo=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <netdb.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "struct.+addrinfo" >/dev/null 2>&1; then
+
+  ac_cv_struct_addrinfo=yes
+fi
+rm -f conftest*
+
+else
+  ac_cv_struct_addrinfo='sys/socket.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_addrinfo" >&5
+echo "${ECHO_T}$ac_cv_struct_addrinfo" >&6
+
+if test "$ac_cv_struct_addrinfo" = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_ADDRINFO 1
+_AXEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for struct sockaddr_storage" >&5
+echo $ECHO_N "checking for struct sockaddr_storage... $ECHO_C" >&6
+if test "${ac_cv_struct_sockaddr_storage+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_sockaddr_storage=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/socket.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "struct.+sockaddr_storage" >/dev/null 2>&1; then
+
+  ac_cv_struct_sockaddr_storage=yes
+fi
+rm -f conftest*
+
+else
+  ac_cv_struct_sockaddr_storage='sys/socket.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_sockaddr_storage" >&5
+echo "${ECHO_T}$ac_cv_struct_sockaddr_storage" >&6
+if test "$ac_cv_struct_sockaddr_storage" = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_STORAGE 1
+_AXEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for field ifr_index in struct ifreq" >&5
+echo $ECHO_N "checking for field ifr_index in struct ifreq... $ECHO_C" >&6
+if test "${ac_cv_struct_ifreq_ifr_index+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifreq_ifr_index=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>
+int
+main ()
+{
+
+struct ifreq ifreq; int index; index = ifreq.ifr_index;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_struct_ifreq_ifr_index=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  ac_cv_struct_ifreq_ifr_index='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifreq_ifr_index" >&5
+echo "${ECHO_T}$ac_cv_struct_ifreq_ifr_index" >&6
+if test "$ac_cv_struct_ifreq_ifr_index" = yes ; then
+  :
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFR_INDEX 1
+_ACEOF
+
+else
+echo "$as_me:$LINENO: checking for field ifr_ifindex in struct ifreq" >&5
+echo $ECHO_N "checking for field ifr_ifindex in struct ifreq... $ECHO_C" >&6
+if test "${ac_cv_struct_ifreq_ifr_ifindex+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifreq_ifr_ifindex=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>
+int
+main ()
+{
+
+struct ifreq ifreq; int index; index = ifreq.ifr_ifindex;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_struct_ifreq_ifr_ifindex=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  ac_cv_struct_ifreq_ifr_ifindex='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifreq_ifr_ifindex" >&5
+echo "${ECHO_T}$ac_cv_struct_ifreq_ifr_ifindex" >&6
+if test "$ac_cv_struct_ifreq_ifr_ifindex" = yes; then
+  :
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFR_IFINDEX 1
+_ACEOF
+
+fi
+
+fi # ifr_index in struct ifreq
+
+echo "$as_me:$LINENO: checking for struct ifconf" >&5
+echo $ECHO_N "checking for struct ifconf... $ECHO_C" >&6
+if test "${ac_cv_struct_ifconf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifconf=no
+if test "$ac_cv_header_net_if_h" = yes; then
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <net/if.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "struct.+ifconf" >/dev/null 2>&1; then
+  ac_cv_struct_ifconf=yes
+fi
+rm -f conftest*
+
+else
+  ac_cv_struct_ifconf='net/if.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifconf" >&5
+echo "${ECHO_T}$ac_cv_struct_ifconf" >&6
+if test "$ac_cv_struct_ifconf" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFCONF 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for ioctl SIOCGIFNUM" >&5
+echo $ECHO_N "checking for ioctl SIOCGIFNUM... $ECHO_C" >&6
+if test "${ac_cv_ioctl_siocgifnum+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_ioctl_siocgifnum=no
+if test "$ac_cv_header_sys_sockio_h" = yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/sockio.h>
+#ifdef SIOCGIFNUM
+  yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then
+  ac_cv_ioctl_siocgifnum=yes
+fi
+rm -f conftest*
+
+else
+  ac_cv_ioctl_siocgifnum='sys/sockio.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_ioctl_siocgifnum" >&5
+echo "${ECHO_T}$ac_cv_ioctl_siocgifnum" >&6
+if test "$ac_cv_ioctl_siocgifnum" = yes; then
+  HAVE_IFNUM=1
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFNUM 1
+_ACEOF
+
+else
+  HAVE_IFNUM=0
+fi
+
+
+fi
+
+done
+
+
+# ===========================================================================
+# Checks for libraries
+# ===========================================================================
+
+
+
+
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socketpair in -lsocket" >&5
+echo $ECHO_N "checking for socketpair in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socketpair+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char socketpair ();
+int
+main ()
+{
+socketpair ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_socket_socketpair=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_socketpair=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socketpair" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socketpair" >&6
+if test $ac_cv_lib_socket_socketpair = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+fi
+
+if test "${with_rt}" != no; then
+	echo "$as_me:$LINENO: checking for library containing clock_gettime" >&5
+echo $ECHO_N "checking for library containing clock_gettime... $ECHO_C" >&6
+if test "${ac_cv_search_clock_gettime+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_clock_gettime=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_clock_gettime="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_clock_gettime" = no; then
+  for ac_lib in rt; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_clock_gettime="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_search_clock_gettime" >&6
+if test "$ac_cv_search_clock_gettime" != no; then
+  test "$ac_cv_search_clock_gettime" = "none required" || LIBS="$ac_cv_search_clock_gettime $LIBS"
+
+fi
+
+fi
+
+
+# No GLib path explicitly defined, use pkg-config
+
+# Check whether --with-glib or --without-glib was given.
+if test "${with_glib+set}" = set; then
+  withval="$with_glib"
+
+case "$with_glib" in
+yes | "" ) with_glib=2.0 ;;
+esac
+
+else
+  with_glib=2.0
+fi;
+
+
+# Check whether --with-glib-dir or --without-glib-dir was given.
+if test "${with_glib_dir+set}" = set; then
+  withval="$with_glib_dir"
+
+else
+  with_glib_dir="pkg-config"
+fi;
+
+if test "$with_glib" = no || test "$with_glib_dir" = "no" ; then
+
+  : # No glib
+
+elif test "$with_glib_dir" = "pkg-config" ; then
+
+
+  succeeded=no
+
+  if test -z "$PKG_CONFIG"; then
+    # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+
+if test -n "$PKG_CONFIG"; then
+  echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  fi
+
+  if test "$PKG_CONFIG" = "no" ; then
+     echo "*** The pkg-config script could not be found. Make sure it is"
+     echo "*** in your path, or set the PKG_CONFIG environment variable"
+     echo "*** to the full path to pkg-config."
+     echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+  else
+     PKG_CONFIG_MIN_VERSION=0.9.0
+     if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+        echo "$as_me:$LINENO: checking for glib-$with_glib" >&5
+echo $ECHO_N "checking for glib-$with_glib... $ECHO_C" >&6
+
+        if $PKG_CONFIG --exists "glib-$with_glib" ; then
+            echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+            succeeded=yes
+
+            echo "$as_me:$LINENO: checking GLIB_CFLAGS" >&5
+echo $ECHO_N "checking GLIB_CFLAGS... $ECHO_C" >&6
+            GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-$with_glib"`
+            echo "$as_me:$LINENO: result: $GLIB_CFLAGS" >&5
+echo "${ECHO_T}$GLIB_CFLAGS" >&6
+
+            echo "$as_me:$LINENO: checking GLIB_LIBS" >&5
+echo $ECHO_N "checking GLIB_LIBS... $ECHO_C" >&6
+            GLIB_LIBS=`$PKG_CONFIG --libs "glib-$with_glib"`
+            echo "$as_me:$LINENO: result: $GLIB_LIBS" >&5
+echo "${ECHO_T}$GLIB_LIBS" >&6
+        else
+            GLIB_CFLAGS=""
+            GLIB_LIBS=""
+            ## If we have a custom action on failure, don't print errors, but
+            ## do set a variable so people can do so.
+            GLIB_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "glib-$with_glib"`
+
+        fi
+
+
+
+     else
+        echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+        echo "*** See http://www.freedesktop.org/software/pkgconfig"
+     fi
+  fi
+
+  if test $succeeded = yes; then
+     HAVE_GLIB=yes
+  else
+     HAVE_GLIB=no
+  fi
+
+
+else # GLib path is explicitly defined
+
+  gprefix=$with_glib_dir
+  GLIB_VERSION="$with_glib"
+  GLIBXXX=glib-$with_glib
+
+  if test "$gprefix" = "yes" ; then
+    for gprefix in /usr /usr/local /opt/$GLIBXXX
+    do
+  	test -d $gprefix/include/$GLIBXXX && break
+    done
+  fi
+
+  if ! test -d $gprefix/include/$GLIBXXX ; then
+    { { echo "$as_me:$LINENO: error: \"No $GLIBXXX in --with-glib=$with_glib_dir\"" >&5
+echo "$as_me: error: \"No $GLIBXXX in --with-glib=$with_glib_dir\"" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    exec_gprefix=${gprefix}
+    glibdir=${exec_gprefix}/lib
+    gincludedir=${gprefix}/include
+
+    # glib_genmarshal=glib-genmarshal
+    # glib_mkenums=glib-mkenums
+
+    HAVE_GLIB=yes
+
+    if test "x$MINGW_ENVIRONMENT" = x1 ; then
+      GLIB_LIBS="${glibdir}/lib$GLIBXXX.dll.a ${glibdir}/libintl.a ${glibdir}/libiconv.a"
+    else
+      GLIB_LIBS="-L${glibdir} -l$GLIBXXX -lintl -liconv"
+    fi
+    GLIB_CFLAGS="-I${gincludedir}/$GLIBXXX -I${glibdir}/$GLIBXXX/include"
+  fi
+
+fi # GLib path is explicitly defined
+
+if test "x$HAVE_GLIB" = xyes ; then
+  SOFIA_GLIB_PKG_REQUIRES="`test -n "$SOFIA_GLIB_PKG_REQUIRES" && echo "$SOFIA_GLIB_PKG_REQUIRES, "`glib-2.0"
+fi
+
+
+
+if test "x$HAVE_GLIB" = xyes; then
+  HAVE_GLIB_TRUE=
+  HAVE_GLIB_FALSE='#'
+else
+  HAVE_GLIB_TRUE='#'
+  HAVE_GLIB_FALSE=
+fi
+
+
+
+
+
+
+# ===========================================================================
+# Checks for library functions.
+# ===========================================================================
+
+echo "$as_me:$LINENO: checking for library containing socket" >&5
+echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6
+if test "${ac_cv_search_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_socket=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char socket ();
+int
+main ()
+{
+socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_socket="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_socket" = no; then
+  for ac_lib in xnet socket; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char socket ();
+int
+main ()
+{
+socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_socket="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5
+echo "${ECHO_T}$ac_cv_search_socket" >&6
+if test "$ac_cv_search_socket" != no; then
+  test "$ac_cv_search_socket" = "none required" || LIBS="$ac_cv_search_socket $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing inet_ntop" >&5
+echo $ECHO_N "checking for library containing inet_ntop... $ECHO_C" >&6
+if test "${ac_cv_search_inet_ntop+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_inet_ntop=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char inet_ntop ();
+int
+main ()
+{
+inet_ntop ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_inet_ntop="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_inet_ntop" = no; then
+  for ac_lib in socket nsl; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char inet_ntop ();
+int
+main ()
+{
+inet_ntop ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_inet_ntop="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_search_inet_ntop" >&6
+if test "$ac_cv_search_inet_ntop" != no; then
+  test "$ac_cv_search_inet_ntop" = "none required" || LIBS="$ac_cv_search_inet_ntop $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing getipnodebyname" >&5
+echo $ECHO_N "checking for library containing getipnodebyname... $ECHO_C" >&6
+if test "${ac_cv_search_getipnodebyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getipnodebyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char getipnodebyname ();
+int
+main ()
+{
+getipnodebyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_getipnodebyname="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getipnodebyname" = no; then
+  for ac_lib in xnet socket nsl; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char getipnodebyname ();
+int
+main ()
+{
+getipnodebyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_getipnodebyname="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getipnodebyname" >&5
+echo "${ECHO_T}$ac_cv_search_getipnodebyname" >&6
+if test "$ac_cv_search_getipnodebyname" != no; then
+  test "$ac_cv_search_getipnodebyname" = "none required" || LIBS="$ac_cv_search_getipnodebyname $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5
+echo $ECHO_N "checking for library containing gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_search_gethostbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gethostbyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_gethostbyname="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gethostbyname" = no; then
+  for ac_lib in xnet nsl; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_gethostbyname="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_search_gethostbyname" >&6
+if test "$ac_cv_search_gethostbyname" != no; then
+  test "$ac_cv_search_gethostbyname" = "none required" || LIBS="$ac_cv_search_gethostbyname $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing getaddrinfo" >&5
+echo $ECHO_N "checking for library containing getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_search_getaddrinfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getaddrinfo=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_getaddrinfo="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getaddrinfo" = no; then
+  for ac_lib in xnet socket nsl; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_getaddrinfo="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_search_getaddrinfo" >&6
+if test "$ac_cv_search_getaddrinfo" != no; then
+  test "$ac_cv_search_getaddrinfo" = "none required" || LIBS="$ac_cv_search_getaddrinfo $LIBS"
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in gettimeofday strerror random initstate tcsetattr flock alarm \
+                socketpair gethostname gethostbyname getipnodebyname \
+                poll epoll_create select if_nameindex \
+	        getaddrinfo getnameinfo freeaddrinfo gai_strerror getifaddrs \
+                getline getdelim getpass
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+# getline getdelim getpass are _GNU_SOURCE stuff
+
+if test $ac_cv_func_poll = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_POLL 1
+_AXEOF
+
+fi
+
+if test $ac_cv_func_epoll_create = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EPOLL 1
+_ACEOF
+
+fi
+
+if test $ac_cv_func_if_nameindex = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_IF_NAMEINDEX 1
+_AXEOF
+
+fi
+
+
+if test "${with_rt}" != no; then
+
+
+for ac_func in clock_gettime clock_getcpuclockid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
+
+
+
+
+
+
+
+for ac_func in memmem memccpy memspn memcspn strcasestr strtoull \
+		   inet_ntop inet_pton
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ :
+else
+  case "$REPLACE_LIBADD" in
+    "$ac_func.lo"   | \
+  *" $ac_func.lo"   | \
+    "$ac_func.lo "* | \
+  *" $ac_func.lo "* ) ;;
+  *) REPLACE_LIBADD="$REPLACE_LIBADD $ac_func.lo" ;;
+esac
+fi
+done
+
+
+:
+
+
+
+# ===========================================================================
+# Check pthread_rwlock_unlock()
+# ===========================================================================
+
+
+
+if test x$HAVE_PTHREADS = x1 ; then
+
+if test "$cross_compiling" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_RWLOCK 1
+_ACEOF
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+
+#define _XOPEN_SOURCE (500)
+
+#include <pthread.h>
+
+pthread_rwlock_t rw;
+
+int main()
+{
+  pthread_rwlock_init(&rw, NULL);
+  pthread_rwlock_rdlock(&rw);
+  pthread_rwlock_rdlock(&rw);
+  pthread_rwlock_unlock(&rw);
+  /* pthread_rwlock_trywrlock() should fail (not return 0) */
+  return pthread_rwlock_trywrlock(&rw) != 0 ? 0  : 1;
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_RWLOCK 1
+_ACEOF
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+{ echo "$as_me:$LINENO: WARNING: Recursive pthread_rwlock_rdlock() does not work!!! " >&5
+echo "$as_me: WARNING: Recursive pthread_rwlock_rdlock() does not work!!! " >&2;}
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+
+# ===========================================================================
+# Check IPv6 addresss configuration
+# ===========================================================================
+case "$target" in
+ *-*-linux*)
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_IF_INET6 1
+_ACEOF
+ ;;
+esac
+
+          ac_config_headers="$ac_config_headers libsofia-sip-ua/su/sofia-sip/su_configure.h"
+
+
+# End of SAC_SOFIA_SU
+
+
+
+
+# Check whether --with-openssl or --without-openssl was given.
+if test "${with_openssl+set}" = set; then
+  withval="$with_openssl"
+
+else
+  with_openssl=yes
+fi;
+
+
+if test "$with_openssl" != no  ;then
+
+for ac_header in openssl/tls1.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+    HAVE_OPENSSL=1 HAVE_TLS=1
+
+
+echo "$as_me:$LINENO: checking for BIO_new in -lcrypto" >&5
+echo $ECHO_N "checking for BIO_new in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_BIO_new+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char BIO_new ();
+int
+main ()
+{
+BIO_new ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_crypto_BIO_new=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypto_BIO_new=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_BIO_new" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_BIO_new" >&6
+if test $ac_cv_lib_crypto_BIO_new = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPTO 1
+_ACEOF
+
+  LIBS="-lcrypto $LIBS"
+
+else
+  HAVE_OPENSSL=0
+    	{ echo "$as_me:$LINENO: WARNING: OpenSSL crypto library was not found" >&5
+echo "$as_me: WARNING: OpenSSL crypto library was not found" >&2;}
+fi
+
+
+
+echo "$as_me:$LINENO: checking for TLSv1_method in -lssl" >&5
+echo $ECHO_N "checking for TLSv1_method in -lssl... $ECHO_C" >&6
+if test "${ac_cv_lib_ssl_TLSv1_method+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char TLSv1_method ();
+int
+main ()
+{
+TLSv1_method ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_ssl_TLSv1_method=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ssl_TLSv1_method=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_TLSv1_method" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_TLSv1_method" >&6
+if test $ac_cv_lib_ssl_TLSv1_method = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSSL 1
+_ACEOF
+
+  LIBS="-lssl $LIBS"
+
+else
+  HAVE_TLS=0
+    	{ echo "$as_me:$LINENO: WARNING: OpenSSL protocol library was not found" >&5
+echo "$as_me: WARNING: OpenSSL protocol library was not found" >&2;}
+fi
+
+
+    if test x$HAVE_OPENSSL = x1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+    fi
+
+    if test x$HAVE_TLS = x1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS 1
+_ACEOF
+
+    fi
+
+else
+  { echo "$as_me:$LINENO: WARNING: OpenSSL include files were not found" >&5
+echo "$as_me: WARNING: OpenSSL include files were not found" >&2;}
+fi
+
+done
+
+fi
+
+
+
+if test x$HAVE_TLS = x1; then
+  HAVE_TLS_TRUE=
+  HAVE_TLS_FALSE='#'
+else
+  HAVE_TLS_TRUE='#'
+  HAVE_TLS_FALSE=
+fi
+
+
+
+
+
+# Check whether --with-sigcomp or --without-sigcomp was given.
+if test "${with_sigcomp+set}" = set; then
+  withval="$with_sigcomp"
+
+else
+  with_sigcomp=no
+fi;
+
+if test -n "${with_sigcomp}" && test "${with_sigcomp}" != no ; then
+	if test "${with_sigcomp}" != yes ; then
+		CPPFLAGS="-I${with_sigcomp}/include $CPPFLAGS"
+		LIBS="-L${with_sigcomp}/lib -lsigcomp $LIBS"
+	else
+		LIBS="-lsigcomp $LIBS"
+	fi
+
+
+for ac_header in sigcomp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: cannot find Sofia SigComp includes" >&5
+echo "$as_me: error: cannot find Sofia SigComp includes" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+done
+
+
+	echo "$as_me:$LINENO: checking for sigcomp_library_2_5" >&5
+echo $ECHO_N "checking for sigcomp_library_2_5... $ECHO_C" >&6
+if test "${ac_cv_func_sigcomp_library_2_5+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define sigcomp_library_2_5 to an innocuous variant, in case <limits.h> declares sigcomp_library_2_5.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define sigcomp_library_2_5 innocuous_sigcomp_library_2_5
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char sigcomp_library_2_5 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef sigcomp_library_2_5
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char sigcomp_library_2_5 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_sigcomp_library_2_5) || defined (__stub___sigcomp_library_2_5)
+choke me
+#else
+char (*f) () = sigcomp_library_2_5;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != sigcomp_library_2_5;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_sigcomp_library_2_5=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_sigcomp_library_2_5=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_sigcomp_library_2_5" >&5
+echo "${ECHO_T}$ac_cv_func_sigcomp_library_2_5" >&6
+if test $ac_cv_func_sigcomp_library_2_5 = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGCOMP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SIGCOMP 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: Sofia SigComp API >= 2.5 was not found" >&5
+echo "$as_me: error: Sofia SigComp API >= 2.5 was not found" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+
+# Check for features used by tport.
+
+
+echo "$as_me:$LINENO: checking for IP_RECVERR" >&5
+echo $ECHO_N "checking for IP_RECVERR... $ECHO_C" >&6
+if test "${ac_cv_sys_ip_recverr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+  int one = 1;
+  int s = 0;
+  setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one));
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sys_ip_recverr=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sys_ip_recverr=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_ip_recverr" >&5
+echo "${ECHO_T}$ac_cv_sys_ip_recverr" >&6
+if test "$ac_cv_sys_ip_recverr" = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IP_RECVERR 1
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for IPV6_RECVERR" >&5
+echo $ECHO_N "checking for IPV6_RECVERR... $ECHO_C" >&6
+if test "${ac_cv_sys_ipv6_recverr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+  int one = 1;
+  int s = 0;
+  setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sys_ipv6_recverr=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sys_ipv6_recverr=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_ipv6_recverr" >&5
+echo "${ECHO_T}$ac_cv_sys_ipv6_recverr" >&6
+if test "$ac_cv_sys_ipv6_recverr" = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6_RECVERR 1
+_ACEOF
+
+fi
+
+
+
+
+for ac_header in netinet/tcp.h netinet/sctp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# Check whether --with-sctp or --without-sctp was given.
+if test "${with_sctp+set}" = set; then
+  withval="$with_sctp"
+
+else
+  enable_sigcomp=no
+fi;
+
+if test x$enable_sctp = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SCTP 1
+_ACEOF
+
+fi
+
+
+
+
+
+### internal modules
+### ----------------
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SIP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SRESOLV 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SMIME 0
+_ACEOF
+
+
+# Check whether --enable-stun or --disable-stun was given.
+if test "${enable_stun+set}" = set; then
+  enableval="$enable_stun"
+
+else
+  enable_stun=yes
+fi;
+
+if test x$enable_stun = xno ; then
+  { echo "$as_me:$LINENO: WARNING: ** STUN support disabled **" >&5
+echo "$as_me: WARNING: ** STUN support disabled **" >&2;}
+elif test x${HAVE_OPENSSL} != x1 ; then
+    { echo "$as_me:$LINENO: WARNING: ** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **" >&5
+echo "$as_me: WARNING: ** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **" >&2;}
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_STUN 1
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_STUN 1
+_ACEOF
+
+fi
+
+# Check whether --enable-ntlm or --disable-ntlm was given.
+if test "${enable_ntlm+set}" = set; then
+  enableval="$enable_ntlm"
+
+else
+  enable_ntlm=no
+fi;
+
+if test x$enable_ntlm = xyes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_NTLM 1
+_ACEOF
+
+fi
+
+
+if test "x$enable_ntlm" = xyes; then
+  HAVE_NTLM_TRUE=
+  HAVE_NTLM_FALSE='#'
+else
+  HAVE_NTLM_TRUE='#'
+  HAVE_NTLM_FALSE=
+fi
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SRTP 0
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UPNP 0
+_ACEOF
+
+
+### checks for header files
+### -----------------------
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      exit(2);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+
+### checks for declarations
+### -----------------------
+echo "$as_me:$LINENO: checking whether SIGPIPE is declared" >&5
+echo $ECHO_N "checking whether SIGPIPE is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_SIGPIPE+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <signal.h>
+
+
+int
+main ()
+{
+#ifndef SIGPIPE
+  char *p = (char *) SIGPIPE;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_have_decl_SIGPIPE=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_SIGPIPE=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_SIGPIPE" >&5
+echo "${ECHO_T}$ac_cv_have_decl_SIGPIPE" >&6
+if test $ac_cv_have_decl_SIGPIPE = yes; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGPIPE 1
+_ACEOF
+
+fi
+
+
+### checks for types
+### ----------------
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_signal=void
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6
+if test "${ac_cv_type_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((long long *) 0)
+  return 0;
+if (sizeof (long long))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long_long=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6
+if test $ac_cv_type_long_long = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define longlong long long
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LLU "%llu"
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define LLI "%lli"
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define LLX "%llx"
+_ACEOF
+
+else
+  :
+fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MOD_ZD "%zd"
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MOD_ZU "%zu"
+_ACEOF
+
+
+### checks for structures
+### ---------------------
+
+### checks for typedefs, structures, and compiler characteristics.
+### --------------------------------------------------------------
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset x;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *ccp;
+  char **p;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  ccp = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++ccp;
+  p = (char**) ccp;
+  ccp = (char const *const *) p;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+  }
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_const=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+case "$ac_cv_c_inline" in *inline* | yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INLINE 1
+_ACEOF
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+int
+main ()
+{
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+  yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __func__" >&5
+echo $ECHO_N "checking whether $CC recognizes __func__... $ECHO_C" >&6
+if test "${ac_cv_c_var_func+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+char *s = __func__;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_var_func=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_var_func=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_var_func" >&5
+echo "${ECHO_T}$ac_cv_c_var_func" >&6
+if test $ac_cv_c_var_func = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __FUNCTION__" >&5
+echo $ECHO_N "checking whether $CC recognizes __FUNCTION__... $ECHO_C" >&6
+if test "${ac_cv_c_macro_function+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+char *s = __FUNCTION__;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_macro_function=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_macro_function=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_macro_function" >&5
+echo "${ECHO_T}$ac_cv_c_macro_function" >&6
+if test $ac_cv_c_macro_function = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNCTION 1
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes field names in struct initialization" >&5
+echo $ECHO_N "checking whether $CC recognizes field names in struct initialization... $ECHO_C" >&6
+if test "${ac_cv_c_keyword_struct+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  struct { int foo; char *bar; } test = { foo: 1, bar: "bar" };
+  return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_keyword_struct=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_keyword_struct=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_keyword_struct" >&5
+echo "${ECHO_T}$ac_cv_c_keyword_struct" >&6
+if test $ac_cv_c_keyword_struct = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_KEYWORDS 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+  return 0;
+if (sizeof (size_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for sockaddr_in6" >&5
+echo $ECHO_N "checking for sockaddr_in6... $ECHO_C" >&6
+if test "${ac_cv_sin6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <netinet/in.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "struct sockaddr_in6" >/dev/null 2>&1; then
+  ac_cv_sin6=yes
+else
+  ac_cv_sin6=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sin6" >&5
+echo "${ECHO_T}$ac_cv_sin6" >&6
+if test $ac_cv_sin6 = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for sa_len" >&5
+echo $ECHO_N "checking for sa_len... $ECHO_C" >&6
+if test "${ac_cv_sa_len+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+
+ struct sockaddr t;t.sa_len = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sa_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sa_len" >&5
+echo "${ECHO_T}$ac_cv_sa_len" >&6
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+fi
+
+
+### checks for library functions
+### ----------------------------
+
+### checks for system services
+### --------------------------
+
+
+echo "$as_me:$LINENO: checking /dev/urandom" >&5
+echo $ECHO_N "checking /dev/urandom... $ECHO_C" >&6
+if test "${ac_cv_dev_urandom+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_dev_urandom=no
+   if test -r /dev/urandom; then ac_cv_dev_urandom=yes; fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_dev_urandom" >&5
+echo "${ECHO_T}$ac_cv_dev_urandom" >&6
+if test $ac_cv_dev_urandom = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DEV_URANDOM 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DEV_URANDOM 1
+_ACEOF
+
+fi
+
+
+### output
+### ------
+
+                                                                                                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Makefile packages/Makefile packages/sofia-sip-ua.pc packages/sofia-sip-ua-glib.pc libsofia-sip-ua/Makefile libsofia-sip-ua/bnf/Makefile libsofia-sip-ua/docs/Makefile libsofia-sip-ua/docs/Doxyfile.version libsofia-sip-ua/docs/sofia-footer.html libsofia-sip-ua/features/Makefile libsofia-sip-ua/http/Makefile libsofia-sip-ua/ipt/Makefile libsofia-sip-ua/iptsec/Makefile libsofia-sip-ua/msg/Makefile libsofia-sip-ua/nea/Makefile libsofia-sip-ua/nta/Makefile libsofia-sip-ua/nth/Makefile libsofia-sip-ua/nua/Makefile libsofia-sip-ua/sdp/Makefile libsofia-sip-ua/sip/Makefile libsofia-sip-ua/soa/Makefile libsofia-sip-ua/sresolv/Makefile libsofia-sip-ua/stun/Makefile libsofia-sip-ua/su/Makefile libsofia-sip-ua/tport/Makefile libsofia-sip-ua/url/Makefile libsofia-sip-ua/features/sofia-sip/sofia_features.h libsofia-sip-ua-glib/Makefile libsofia-sip-ua-glib/su-glib/Makefile utils/Makefile utils/Doxyfile.build win32/Makefile win32/config.h"
+
+
+          ac_config_commands="$ac_config_commands version"
+
+          ac_config_files="$ac_config_files packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+  (set) 2>&1 |
+    case `(ac_space=' '; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+  if test -w $cache_file; then
+    test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+    cat confcache >$cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[	 ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[	 ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_i=`echo "$ac_i" |
+	 sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_MINGW32_TRUE}" && test -z "${HAVE_MINGW32_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"HAVE_MINGW32\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_MINGW32\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${ENABLE_COVERAGE_TRUE}" && test -z "${ENABLE_COVERAGE_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"ENABLE_COVERAGE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"ENABLE_COVERAGE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${NDEBUG_TRUE}" && test -z "${NDEBUG_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"NDEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"NDEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${EXPENSIVE_CHECKS_TRUE}" && test -z "${EXPENSIVE_CHECKS_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"EXPENSIVE_CHECKS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"EXPENSIVE_CHECKS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_DOXYGEN_TRUE}" && test -z "${HAVE_DOXYGEN_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"HAVE_DOXYGEN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_DOXYGEN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${COREFOUNDATION_TRUE}" && test -z "${COREFOUNDATION_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"COREFOUNDATION\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"COREFOUNDATION\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_GLIB_TRUE}" && test -z "${HAVE_GLIB_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"HAVE_GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_TLS_TRUE}" && test -z "${HAVE_TLS_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"HAVE_TLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_TLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_NTLM_TRUE}" && test -z "${HAVE_NTLM_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"HAVE_NTLM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_NTLM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.  Logging --version etc. is OK.
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by sofia-sip $as_me 1.12.4work, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+		   instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+		   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf at gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+sofia-sip config.status 1.12.4work
+configured by $0, generated by GNU Autoconf 2.59,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "x$1" : 'x\([^=]*\)='`
+    ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  -*)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit 0 ;;
+  --debug | --d* | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1" ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+PACKAGE_VERSION=${PACKAGE_VERSION}
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+  case "$ac_config_target" in
+  # Handling of arguments.
+  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+  "packages/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/Makefile" ;;
+  "packages/sofia-sip-ua.pc" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-ua.pc" ;;
+  "packages/sofia-sip-ua-glib.pc" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-ua-glib.pc" ;;
+  "libsofia-sip-ua/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/Makefile" ;;
+  "libsofia-sip-ua/bnf/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/bnf/Makefile" ;;
+  "libsofia-sip-ua/docs/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/Makefile" ;;
+  "libsofia-sip-ua/docs/Doxyfile.version" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/Doxyfile.version" ;;
+  "libsofia-sip-ua/docs/sofia-footer.html" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/sofia-footer.html" ;;
+  "libsofia-sip-ua/features/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/features/Makefile" ;;
+  "libsofia-sip-ua/http/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/http/Makefile" ;;
+  "libsofia-sip-ua/ipt/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/ipt/Makefile" ;;
+  "libsofia-sip-ua/iptsec/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/iptsec/Makefile" ;;
+  "libsofia-sip-ua/msg/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/msg/Makefile" ;;
+  "libsofia-sip-ua/nea/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nea/Makefile" ;;
+  "libsofia-sip-ua/nta/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nta/Makefile" ;;
+  "libsofia-sip-ua/nth/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nth/Makefile" ;;
+  "libsofia-sip-ua/nua/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nua/Makefile" ;;
+  "libsofia-sip-ua/sdp/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sdp/Makefile" ;;
+  "libsofia-sip-ua/sip/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sip/Makefile" ;;
+  "libsofia-sip-ua/soa/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/soa/Makefile" ;;
+  "libsofia-sip-ua/sresolv/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sresolv/Makefile" ;;
+  "libsofia-sip-ua/stun/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/stun/Makefile" ;;
+  "libsofia-sip-ua/su/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/su/Makefile" ;;
+  "libsofia-sip-ua/tport/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/tport/Makefile" ;;
+  "libsofia-sip-ua/url/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/url/Makefile" ;;
+  "libsofia-sip-ua/features/sofia-sip/sofia_features.h" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/features/sofia-sip/sofia_features.h" ;;
+  "libsofia-sip-ua-glib/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua-glib/Makefile" ;;
+  "libsofia-sip-ua-glib/su-glib/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua-glib/su-glib/Makefile" ;;
+  "utils/Makefile" ) CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;;
+  "utils/Doxyfile.build" ) CONFIG_FILES="$CONFIG_FILES utils/Doxyfile.build" ;;
+  "win32/Makefile" ) CONFIG_FILES="$CONFIG_FILES win32/Makefile" ;;
+  "win32/config.h" ) CONFIG_FILES="$CONFIG_FILES win32/config.h" ;;
+  "packages/sofia-sip-${PACKAGE_VERSION}.spec" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in" ;;
+  "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+  "version" ) CONFIG_COMMANDS="$CONFIG_COMMANDS version" ;;
+  "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+  "libsofia-sip-ua/su/sofia-sip/su_configure.h" ) CONFIG_HEADERS="$CONFIG_HEADERS libsofia-sip-ua/su/sofia-sip/su_configure.h" ;;
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./confstat$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+  # Protect against being on the right side of a sed subst in config.status.
+  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s, at SHELL@,$SHELL,;t t
+s, at PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s, at PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s, at PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s, at PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s, at PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s, at PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s, at exec_prefix@,$exec_prefix,;t t
+s, at prefix@,$prefix,;t t
+s, at program_transform_name@,$program_transform_name,;t t
+s, at bindir@,$bindir,;t t
+s, at sbindir@,$sbindir,;t t
+s, at libexecdir@,$libexecdir,;t t
+s, at datadir@,$datadir,;t t
+s, at sysconfdir@,$sysconfdir,;t t
+s, at sharedstatedir@,$sharedstatedir,;t t
+s, at localstatedir@,$localstatedir,;t t
+s, at libdir@,$libdir,;t t
+s, at includedir@,$includedir,;t t
+s, at oldincludedir@,$oldincludedir,;t t
+s, at infodir@,$infodir,;t t
+s, at mandir@,$mandir,;t t
+s, at build_alias@,$build_alias,;t t
+s, at host_alias@,$host_alias,;t t
+s, at target_alias@,$target_alias,;t t
+s, at DEFS@,$DEFS,;t t
+s, at ECHO_C@,$ECHO_C,;t t
+s, at ECHO_N@,$ECHO_N,;t t
+s, at ECHO_T@,$ECHO_T,;t t
+s, at LIBS@,$LIBS,;t t
+s, at VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@,$VER_LIBSOFIA_SIP_UA_MAJOR_MINOR,;t t
+s, at include_sofiadir@,$include_sofiadir,;t t
+s, at LIBVER_SOFIA_SIP_UA_CUR@,$LIBVER_SOFIA_SIP_UA_CUR,;t t
+s, at LIBVER_SOFIA_SIP_UA_REV@,$LIBVER_SOFIA_SIP_UA_REV,;t t
+s, at LIBVER_SOFIA_SIP_UA_AGE@,$LIBVER_SOFIA_SIP_UA_AGE,;t t
+s, at LIBVER_SOFIA_SIP_UA_SOVER@,$LIBVER_SOFIA_SIP_UA_SOVER,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_CUR@,$LIBVER_SOFIA_SIP_UA_GLIB_CUR,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_REV@,$LIBVER_SOFIA_SIP_UA_GLIB_REV,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_AGE@,$LIBVER_SOFIA_SIP_UA_GLIB_AGE,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@,$LIBVER_SOFIA_SIP_UA_GLIB_SOVER,;t t
+s, at build@,$build,;t t
+s, at build_cpu@,$build_cpu,;t t
+s, at build_vendor@,$build_vendor,;t t
+s, at build_os@,$build_os,;t t
+s, at host@,$host,;t t
+s, at host_cpu@,$host_cpu,;t t
+s, at host_vendor@,$host_vendor,;t t
+s, at host_os@,$host_os,;t t
+s, at target@,$target,;t t
+s, at target_cpu@,$target_cpu,;t t
+s, at target_vendor@,$target_vendor,;t t
+s, at target_os@,$target_os,;t t
+s, at INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s, at INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s, at INSTALL_DATA@,$INSTALL_DATA,;t t
+s, at CYGPATH_W@,$CYGPATH_W,;t t
+s, at PACKAGE@,$PACKAGE,;t t
+s, at VERSION@,$VERSION,;t t
+s, at ACLOCAL@,$ACLOCAL,;t t
+s, at AUTOCONF@,$AUTOCONF,;t t
+s, at AUTOMAKE@,$AUTOMAKE,;t t
+s, at AUTOHEADER@,$AUTOHEADER,;t t
+s, at MAKEINFO@,$MAKEINFO,;t t
+s, at install_sh@,$install_sh,;t t
+s, at STRIP@,$STRIP,;t t
+s, at ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s, at INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s, at mkdir_p@,$mkdir_p,;t t
+s, at AWK@,$AWK,;t t
+s, at SET_MAKE@,$SET_MAKE,;t t
+s, at am__leading_dot@,$am__leading_dot,;t t
+s, at AMTAR@,$AMTAR,;t t
+s, at am__tar@,$am__tar,;t t
+s, at am__untar@,$am__untar,;t t
+s, at MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
+s, at MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
+s, at MAINT@,$MAINT,;t t
+s, at CC@,$CC,;t t
+s, at CFLAGS@,$CFLAGS,;t t
+s, at LDFLAGS@,$LDFLAGS,;t t
+s, at CPPFLAGS@,$CPPFLAGS,;t t
+s, at ac_ct_CC@,$ac_ct_CC,;t t
+s, at EXEEXT@,$EXEEXT,;t t
+s, at OBJEXT@,$OBJEXT,;t t
+s, at DEPDIR@,$DEPDIR,;t t
+s, at am__include@,$am__include,;t t
+s, at am__quote@,$am__quote,;t t
+s, at AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s, at AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s, at AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s, at CCDEPMODE@,$CCDEPMODE,;t t
+s, at am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s, at am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s, at MINGW_ENVIRONMENT@,$MINGW_ENVIRONMENT,;t t
+s, at HAVE_MINGW32_TRUE@,$HAVE_MINGW32_TRUE,;t t
+s, at HAVE_MINGW32_FALSE@,$HAVE_MINGW32_FALSE,;t t
+s, at CWFLAG@,$CWFLAG,;t t
+s, at SOFIA_CFLAGS@,$SOFIA_CFLAGS,;t t
+s, at ENABLE_COVERAGE_TRUE@,$ENABLE_COVERAGE_TRUE,;t t
+s, at ENABLE_COVERAGE_FALSE@,$ENABLE_COVERAGE_FALSE,;t t
+s, at MOSTLYCLEANFILES@,$MOSTLYCLEANFILES,;t t
+s, at CPP@,$CPP,;t t
+s, at ETAGS@,$ETAGS,;t t
+s, at AR@,$AR,;t t
+s, at ac_ct_AR@,$ac_ct_AR,;t t
+s, at LD@,$LD,;t t
+s, at ac_ct_LD@,$ac_ct_LD,;t t
+s, at EGREP@,$EGREP,;t t
+s, at LN_S@,$LN_S,;t t
+s, at ECHO@,$ECHO,;t t
+s, at RANLIB@,$RANLIB,;t t
+s, at ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s, at CXX@,$CXX,;t t
+s, at CXXFLAGS@,$CXXFLAGS,;t t
+s, at ac_ct_CXX@,$ac_ct_CXX,;t t
+s, at CXXDEPMODE@,$CXXDEPMODE,;t t
+s, at am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t
+s, at am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t
+s, at CXXCPP@,$CXXCPP,;t t
+s, at F77@,$F77,;t t
+s, at FFLAGS@,$FFLAGS,;t t
+s, at ac_ct_F77@,$ac_ct_F77,;t t
+s, at LIBTOOL@,$LIBTOOL,;t t
+s, at NDEBUG_TRUE@,$NDEBUG_TRUE,;t t
+s, at NDEBUG_FALSE@,$NDEBUG_FALSE,;t t
+s, at TESTS_ENVIRONMENT@,$TESTS_ENVIRONMENT,;t t
+s, at EXPENSIVE_CHECKS_TRUE@,$EXPENSIVE_CHECKS_TRUE,;t t
+s, at EXPENSIVE_CHECKS_FALSE@,$EXPENSIVE_CHECKS_FALSE,;t t
+s, at ACLOCAL_AMFLAGS@,$ACLOCAL_AMFLAGS,;t t
+s, at DOXYGEN@,$DOXYGEN,;t t
+s, at HAVE_DOXYGEN_TRUE@,$HAVE_DOXYGEN_TRUE,;t t
+s, at HAVE_DOXYGEN_FALSE@,$HAVE_DOXYGEN_FALSE,;t t
+s, at COREFOUNDATION_TRUE@,$COREFOUNDATION_TRUE,;t t
+s, at COREFOUNDATION_FALSE@,$COREFOUNDATION_FALSE,;t t
+s, at PKG_CONFIG@,$PKG_CONFIG,;t t
+s, at GLIB_CFLAGS@,$GLIB_CFLAGS,;t t
+s, at GLIB_LIBS@,$GLIB_LIBS,;t t
+s, at HAVE_GLIB_TRUE@,$HAVE_GLIB_TRUE,;t t
+s, at HAVE_GLIB_FALSE@,$HAVE_GLIB_FALSE,;t t
+s, at GLIB_VERSION@,$GLIB_VERSION,;t t
+s, at SOFIA_GLIB_PKG_REQUIRES@,$SOFIA_GLIB_PKG_REQUIRES,;t t
+s, at REPLACE_LIBADD@,$REPLACE_LIBADD,;t t
+s, at HAVE_TLS_TRUE@,$HAVE_TLS_TRUE,;t t
+s, at HAVE_TLS_FALSE@,$HAVE_TLS_FALSE,;t t
+s, at HAVE_NTLM_TRUE@,$HAVE_NTLM_TRUE,;t t
+s, at HAVE_NTLM_FALSE@,$HAVE_NTLM_FALSE,;t t
+s, at LIBOBJS@,$LIBOBJS,;t t
+s, at LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+  cat >>$CONFIG_STATUS <<\_ACEOF
+  # Split the substitutions into bite-sized pieces for seds with
+  # small command number limits, like on Digital OSF/1 and HP-UX.
+  ac_max_sed_lines=48
+  ac_sed_frag=1 # Number of current file.
+  ac_beg=1 # First line for current file.
+  ac_end=$ac_max_sed_lines # Line after last line for current file.
+  ac_more_lines=:
+  ac_sed_cmds=
+  while $ac_more_lines; do
+    if test $ac_beg -gt 1; then
+      sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    else
+      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    fi
+    if test ! -s $tmp/subs.frag; then
+      ac_more_lines=false
+    else
+      # The purpose of the label and of the branching condition is to
+      # speed up the sed processing (if there are no `@' at all, there
+      # is no need to browse any of the substitutions).
+      # These are the two extra sed commands mentioned above.
+      (echo ':t
+  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+      if test -z "$ac_sed_cmds"; then
+	ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+      else
+	ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+      fi
+      ac_sed_frag=`expr $ac_sed_frag + 1`
+      ac_beg=$ac_end
+      ac_end=`expr $ac_end + $ac_max_sed_lines`
+    fi
+  done
+  if test -z "$ac_sed_cmds"; then
+    ac_sed_cmds=cat
+  fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+	cat >$tmp/stdin
+	ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+  esac
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    configure_input=
+  else
+    configure_input="$ac_file.  "
+  fi
+  configure_input=$configure_input"Generated from `echo $ac_file_in |
+				     sed 's,.*/,,'` by configure."
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+	 # Absolute (can't be DOS-style, as IFS=:)
+	 test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 echo "$f";;
+      *) # Relative
+	 if test -f "$f"; then
+	   # Build tree
+	   echo "$f"
+	 elif test -f "$srcdir/$f"; then
+	   # Source tree
+	   echo "$srcdir/$f"
+	 else
+	   # /dev/null tree
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s, at configure_input@,$configure_input,;t t
+s, at srcdir@,$ac_srcdir,;t t
+s, at abs_srcdir@,$ac_abs_srcdir,;t t
+s, at top_srcdir@,$ac_top_srcdir,;t t
+s, at abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s, at builddir@,$ac_builddir,;t t
+s, at abs_builddir@,$ac_abs_builddir,;t t
+s, at top_builddir@,$ac_top_builddir,;t t
+s, at abs_top_builddir@,$ac_abs_top_builddir,;t t
+s, at INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+  rm -f $tmp/stdin
+  if test x"$ac_file" != x-; then
+    mv $tmp/out $ac_file
+  else
+    cat $tmp/out
+    rm -f $tmp/out
+  fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([	 ]*\)#\([	 ]*define[	 ][	 ]*\)'
+ac_dB='[	 ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([	 ]*\)#\([	 ]*\)undef\([	 ][	 ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+	cat >$tmp/stdin
+	ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+	 # Absolute (can't be DOS-style, as IFS=:)
+	 test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 # Do quote $f, to prevent DOS paths from being IFS'd.
+	 echo "$f";;
+      *) # Relative
+	 if test -f "$f"; then
+	   # Build tree
+	   echo "$f"
+	 elif test -f "$srcdir/$f"; then
+	   # Source tree
+	   echo "$srcdir/$f"
+	 else
+	   # /dev/null tree
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+  # Remove the trailing spaces.
+  sed 's/[	 ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*\)\(([^)]*)\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[	 ]*#[	 ]*undef[	 ][	 ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[	 ]*#[	 ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[	 ]*#[	 ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[	 ]*#[	 ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+      { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  fi
+# Compute $ac_file's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $ac_file | $ac_file:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X$ac_file : 'X\(//\)[^/]' \| \
+	 X$ac_file : 'X\(//\)$' \| \
+	 X$ac_file : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+  ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+  ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+  ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_dest" : 'X\(//\)[^/]' \| \
+	 X"$ac_dest" : 'X\(//\)$' \| \
+	 X"$ac_dest" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+
+  { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+  case $ac_dest in
+    depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+  # Strip MF so we end up with the name of the file.
+  mf=`echo "$mf" | sed -e 's/:.*$//'`
+  # Check whether this is an Automake generated Makefile or not.
+  # We used to match only the files named `Makefile.in', but
+  # some people rename them; so instead we look at the file content.
+  # Grep'ing the first line is not enough: some people post-process
+  # each Makefile.in and add a new line on top of each file to say so.
+  # So let's grep whole file.
+  if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+    dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  else
+    continue
+  fi
+  # Extract the definition of DEPDIR, am__include, and am__quote
+  # from the Makefile without running `make'.
+  DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+  test -z "$DEPDIR" && continue
+  am__include=`sed -n 's/^am__include = //p' < "$mf"`
+  test -z "am__include" && continue
+  am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+  # When using ansi2knr, U may be empty or an underscore; expand it
+  U=`sed -n 's/^U = //p' < "$mf"`
+  # Find all dependency output files, they are included files with
+  # $(DEPDIR) in their names.  We invoke sed twice because it is the
+  # simplest approach to changing $(DEPDIR) to its actual value in the
+  # expansion.
+  for file in `sed -n "
+    s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+    # Make sure the directory exists.
+    test -f "$dirpart/$file" && continue
+    fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    { if $as_mkdir_p; then
+    mkdir -p $dirpart/$fdir
+  else
+    as_dir=$dirpart/$fdir
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+ ;;
+  esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+

Added: freeswitch/trunk/libs/sofia-sip/configure.ac
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/configure.ac	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,194 @@
+dnl Copyright (C) 2005-2006 Nokia Corporation
+dnl Contact: Pekka Pessi <pekka.pessi at nokia.com>
+dnl Licensed under LGPL. See file COPYING.
+
+dnl 
+dnl ref: http://www.gnu.org/software/autoconf/manual/autoconf.info.gz
+dnl
+AC_PREREQ(2.57)
+
+dnl information on the package
+dnl ---------------------------
+
+dnl update both the version for AC_INIT and the LIBSOFIA_SIP_UA_MAJOR_MINOR
+AC_INIT([sofia-sip], [1.12.4work])
+AC_CONFIG_SRCDIR([libsofia-sip-ua/sip/sofia-sip/sip.h])
+AC_SUBST(VER_LIBSOFIA_SIP_UA_MAJOR_MINOR, [1.12])
+dnl Includedir specific to this sofia version
+AC_SUBST(include_sofiadir, '${includedir}/sofia-sip-1.12')
+AC_SUBST(LIBVER_SOFIA_SIP_UA_CUR, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_REV, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_AGE, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_SOVER, [0]) # CUR-AGE
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_CUR, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_REV, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_AGE, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_SOVER, [3]) # CUR-AGE
+					    
+# dnl calls AC_CANONICAL_ macros that are required by AM_INIT_AUTOMAKE
+SAC_CANONICAL_SYSTEM_CACHE_CHECK
+
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+AC_CONFIG_HEADERS([config.h])
+
+AC_GNU_SOURCE
+
+### checks for programs
+### -------------------
+AC_LANG([C])
+AC_CHECK_COMPILATION_ENVIRONMENT
+
+SAC_TOOL_CC
+AC_PROG_INSTALL
+AC_PROG_CPP
+AC_CHECK_PROG(ETAGS, etags, etags, echo)
+AC_CHECK_TOOL(AR, ar, ar)
+AC_CHECK_TOOL(LD, ld, ld)
+AC_PROG_LIBTOOL
+
+SAC_ENABLE_NDEBUG
+SAC_ENABLE_EXPENSIVE_CHECKS
+
+dnl Add parameters for aclocal
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+
+AC_CHECK_PROG([DOXYGEN], [doxygen], [doxygen], [echo])
+AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN = doxygen])
+
+### checks for libraries
+### --------------------
+
+SAC_SOFIA_SU
+SAC_OPENSSL
+SAC_TPORT
+SAC_SU
+
+### internal modules
+### ----------------
+AC_DEFINE([HAVE_SOFIA_SIP], 1, [Define to 1 always])
+AC_DEFINE([HAVE_SOFIA_SRESOLV], 1, [Define to 1 if we use DNS library])
+AC_DEFINE([HAVE_SOFIA_SMIME], 0, [Define to 1 if we use S/MIME library])
+
+AC_ARG_ENABLE(stun,
+[  --disable-stun              disable stun module (enabled)],
+ , enable_stun=yes)
+
+if test x$enable_stun = xno ; then
+  AC_MSG_WARN([** STUN support disabled **])
+elif test x${HAVE_OPENSSL} != x1 ; then
+  dnl compile STUN only if OPENSSL is available
+  AC_MSG_WARN([** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **])
+  AC_DEFINE([HAVE_SOFIA_STUN], 1, [Define to 1 if we use STUN library])
+else
+  AC_DEFINE([HAVE_SOFIA_STUN], 1, [Define to 1 if we use STUN library])
+fi
+
+dnl Disable NTLM support by default
+AC_ARG_ENABLE(ntlm,
+[  --enable-ntlm               enable NTLM support (disabled)],
+ , enable_ntlm=no)
+
+if test x$enable_ntlm = xyes ; then
+  AC_DEFINE([HAVE_SOFIA_NTLM], 1, [Define to 1 if we use NTLM library])
+fi
+AM_CONDITIONAL([HAVE_NTLM], [test "x$enable_ntlm" = xyes])
+
+
+AC_DEFINE([HAVE_SRTP], 0, [Define to 1 if we use SRTP])
+AC_DEFINE([HAVE_UPNP], 0, [Define to 1 if we use UPnP])
+
+### checks for header files
+### -----------------------
+AC_HEADER_STDC
+
+### checks for declarations
+### -----------------------
+AC_CHECK_DECL([SIGPIPE], [
+AC_DEFINE([HAVE_SIGPIPE], 1, [Define to 1 if you have SIGPIPE])],,[
+#include <signal.h>
+])
+
+### checks for types
+### ----------------
+
+AC_TYPE_SIGNAL
+AC_TYPE_LONGLONG([
+AC_DEFINE([LLU], ["%llu"], [Define to format (%llu) for unsigned long long])dnl
+AC_DEFINE([LLI], ["%lli"], [Define to format (%lli) for long long])dnl
+AC_DEFINE([LLX], ["%llx"], [Define to format (%llx) for long long hex])dnl
+])
+AC_DEFINE([MOD_ZD], ["%zd"], [Define printf() modifier for ssize_t])
+AC_DEFINE([MOD_ZU], ["%zu"], [Define printf() modifier for size_t])
+
+### checks for structures
+### ---------------------
+
+### checks for typedefs, structures, and compiler characteristics.
+### --------------------------------------------------------------
+AC_C_CONST
+AC_C_INLINE
+AC_C_INLINE_DEFINE
+AC_C_BIGENDIAN
+
+AC_C_VAR_FUNC
+AC_C_MACRO_FUNCTION
+AC_C_KEYWORD_STRUCT
+
+AC_HEADER_TIME
+AC_TYPE_SIZE_T
+
+AC_STRUCT_SIN6
+AC_SYS_SA_LEN
+
+### checks for library functions
+### ----------------------------
+
+### checks for system services
+### --------------------------
+
+AC_DEV_URANDOM
+
+### output
+### ------
+
+AC_CONFIG_FILES([
+Makefile
+packages/Makefile
+packages/sofia-sip-ua.pc
+packages/sofia-sip-ua-glib.pc
+libsofia-sip-ua/Makefile
+libsofia-sip-ua/bnf/Makefile
+libsofia-sip-ua/docs/Makefile
+libsofia-sip-ua/docs/Doxyfile.version
+libsofia-sip-ua/docs/sofia-footer.html
+libsofia-sip-ua/features/Makefile
+libsofia-sip-ua/http/Makefile
+libsofia-sip-ua/ipt/Makefile
+libsofia-sip-ua/iptsec/Makefile
+libsofia-sip-ua/msg/Makefile
+libsofia-sip-ua/nea/Makefile
+libsofia-sip-ua/nta/Makefile
+libsofia-sip-ua/nth/Makefile
+libsofia-sip-ua/nua/Makefile
+libsofia-sip-ua/sdp/Makefile
+libsofia-sip-ua/sip/Makefile
+libsofia-sip-ua/soa/Makefile
+libsofia-sip-ua/sresolv/Makefile 
+libsofia-sip-ua/stun/Makefile
+libsofia-sip-ua/su/Makefile
+libsofia-sip-ua/tport/Makefile
+libsofia-sip-ua/url/Makefile
+libsofia-sip-ua/features/sofia-sip/sofia_features.h
+libsofia-sip-ua-glib/Makefile
+libsofia-sip-ua-glib/su-glib/Makefile
+utils/Makefile
+utils/Doxyfile.build
+win32/Makefile
+win32/config.h
+])
+
+AC_CONFIG_COMMANDS([version],,[PACKAGE_VERSION=${PACKAGE_VERSION}])
+AC_CONFIG_FILES([packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in])
+
+AC_OUTPUT

Added: freeswitch/trunk/libs/sofia-sip/depcomp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/depcomp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,522 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2004-05-31.23
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+# 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, 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by `PROGRAMS ARGS'.
+  object      Object file output by `PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputing dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit 0
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit 0
+    ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+  "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> $depfile
+    echo >> $depfile
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> $depfile
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+  tmpdepfile="$stripped.u"
+  if test "$libtool" = yes; then
+    "$@" -Wc,-M
+  else
+    "$@" -M
+  fi
+  stat=$?
+
+  if test -f "$tmpdepfile"; then :
+  else
+    stripped=`echo "$stripped" | sed 's,^.*/,,'`
+    tmpdepfile="$stripped.u"
+  fi
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+
+  if test -f "$tmpdepfile"; then
+    outname="$stripped.o"
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+    sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler understands `-MD -MF file'.  However on
+  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want:
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using \ :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+    sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # Dependencies are output in .lo.d with libtool 1.4.
+      # With libtool 1.5 they are output both in $dir.libs/$base.o.d
+      # and in $dir.libs/$base.o.d and $dir$base.o.d.  We process the
+      # latter, because the former will be cleaned when $dir.libs is
+      # erased.
+      tmpdepfile1="$dir.libs/$base.lo.d"
+      tmpdepfile2="$dir$base.o.d"
+      tmpdepfile3="$dir.libs/$base.d"
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1="$dir$base.o.d"
+      tmpdepfile2="$dir$base.d"
+      tmpdepfile3="$dir$base.d"
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+      exit $stat
+   fi
+
+   if test -f "$tmpdepfile1"; then
+      tmpdepfile="$tmpdepfile1"
+   elif test -f "$tmpdepfile2"; then
+      tmpdepfile="$tmpdepfile2"
+   else
+      tmpdepfile="$tmpdepfile3"
+   fi
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a tab and a space in the [].
+      sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for `:'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no
+  for arg in "$@"; do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix="`echo $object | sed 's/^.*\././'`"
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test $1 != '--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o,
+  # because we must use -o when running libtool.
+  "$@" || exit $?
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+	set fnord "$@"
+	shift
+	shift
+	;;
+    *)
+	set fnord "$@" "$arg"
+	shift
+	shift
+	;;
+    esac
+  done
+  "$@" -E |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile"
+  echo "	" >> "$depfile"
+  . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/docs/build_system.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/build_system.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,97 @@
+=============================
+Sofia-SIP build system README
+=============================
+
+:Author: Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+:Author: Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+:Version: 20051011-5
+:Formatting: reStructuredText, http://docutils.sourceforge.net/rst.html
+
+Introduction
+============
+
+The Sofia-SIP build system practices are documented in this
+file. The instructions are aimed at developers.
+
+Quick start
+===========
+
+To build Sofia-IP::
+
+  sh> ``./autogen.sh`` (if building from a fresh CVS checkout)
+  sh> ``./configure``
+  sh> ``make``
+
+Autotool notes
+==============
+
+Macros
+------
+
+Sofia-SIP specific macros are prefixed with "``SAC\_``" and are
+defined in files under the toplevel "m4/" directory.
+
+Makefile target notes
+---------------------
+
+- all optionally compiled source files should be listed
+  separately in ``DIST_SOURCES`` variable (otherwise ``make dist``
+  will fail)
+
+Maintainer mode
+---------------
+
+Sofia-SIP tree is by default configured with automake
+maintainer mode disable. In other words, Makefiles do not
+contain rules for recreating or updating configure, Makefiles
+or other autotool-generated files. To update these files,
+you need to run top-level autogen.sh script.
+
+Those developers who need to often modify configure.ac, Makefile.am
+and macro files, can enable maintainer mode with configure
+option '--enable-maintainer-mode'.
+
+Running tests
+=============
+
+Sofia-SIP has quite complete suite of test cases. It is prudent to
+run them while making changes and before committing them to revision
+control system. However, running certain tests takes quite a long
+time. Therefore, they are run only if the environment variable
+EXPENSIVE_CHECKS has been set. EXPENSIVE_CHECKS is also set by the build
+system if configure option '--enable-expensive-checks' has been used.
+
+Code-tree layout
+================
+
+Most of the code resides in the libsofia-sip-ua directory.
+The main library, libsofia-sip-ua.so, is created by 
+collecting object files (for example bnf/bnf_objs.o) from 
+individual modules.
+
+There are some portability issues with the way the
+shared library is currently built, and we are looking
+for ways to improve the situation.
+
+Making releases
+===============
+
+See sofia-sip/docs/release_management.txt
+
+Developer documentation
+=======================
+
+Generating reference documentation from source code 
+---------------------------------------------------
+
+The libsofia-sip-ua library has a top-level make target
+"doxygen" for generating the HTML reference documentation.
+The pages will be created to libsofia-sip-ua/docs 
+subdirectory. 
+
+This special target is primarily meant for use by
+the Sofia-SIP website admins, but can be used by anyone
+with the proper set of tools:
+
+- Doxygen, http://www.stack.nl/~dimitri/doxygen/
+- Dot graph tool, http://www.research.att.com/sw/tools/graphviz/

Added: freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,42 @@
+======================================================
+Notes on compiling Sofia-SIP in different environments
+======================================================
+
+Using GNU Autotools
+-------------------
+
+If you modify autoconf or automake files (configure.ac or Makefile.am) or if
+you compile Sofia SIP that you pulled from darcs or CVS repo, you need
+up-to-date autotools. Autoconf should be at least 2.57 and automake should
+be at least 1.7. You can avoid running autoreconf explicitly if you use
+./configure option --enable-maintainer-mode.
+
+Generic POSIX (GNU/Linux, BSD, ...) 
+-----------------------------------
+
+Sofia-SIP should compile out-of-the-box on generic POSIX
+machines. Use the standard GNU autotool 'configure+make'
+procedure to build the software. See top-level INSTALL
+for more information.
+
+Mac OS X 
+--------
+
+TBD
+
+Win32 / Mingw 
+-------------
+
+TBD 
+
+Win32 / Cygwin 
+--------------
+
+TBD
+
+Visual-C on win32
+-----------------
+
+See sofia-sip/win32/README.txt
+
+ LocalWords:  automake

Added: freeswitch/trunk/libs/sofia-sip/docs/release_management.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/release_management.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+===================================
+Sofia-SIP release management README
+===================================
+
+:Author: Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+:Version: 20060809-12
+:Formatting: reStructuredText, http://docutils.sourceforge.net/rst.html
+
+Introduction
+============
+
+This README contains instructions for making new Sofia-SIP releases.
+
+Links to other resources
+========================
+
+sofia-sip/README.developers
+
+The release notes
+=================
+
+The release notes should contain the following sections:
+
+- about Sofia-SIP
+    - copied verbatim from sofia-sip/README
+- list of changes since last release
+    - maintained in sofia-sip/RELEASE
+    - see diff between cvs/darcs between previous and
+      this version
+    - written in freshmeat.net "Changes:" style 
+- notes on API/ABI interface changes 
+    - maintained in sofia-sip/RELEASE
+    - all changes in public interfaces, plus other
+      notes that developers should be aware of
+- contributors to this release
+    - maintained in sofia-sip/RELEASE
+    - also sofia-sip/AUTHORS should be updated (file
+      should list all persons/companies who have code/scripts/etc
+      copyrighted to them in the sofia-sip tree)
+
+See the RELEASE.template file for a full list of release note
+sections.
+
+Making the release tarball 
+==========================
+
+- basics: check system clock of the build host ;)
+- update the version number in sofia-sip/configure.ac
+- make sure the library versions are correct, and you've
+  frozen all library interfaces (with correct entries in
+  ChangeLog files), see README.developers for more information
+  on library versioning in general
+- make sure everything that is supposed to be in the
+  release is in the master darcs tree
+- run 'make distcheck' to verify everything is ready for
+  release (requires automake-1.7 or newer)
+- tag repos (darcs and any slave trees) with release tag
+  'rel-sofia-sip-x_y_z', where x_y_z is the version number (see
+  README.developers):
+    sh> darcs tag -m"rel-sofia-sip-x_y_z"
+    sh> cvs tag rel-sofia-sip-x_y_z
+- take a fresh checkout of the release using the release tag
+    sh> darcs get http://sofia-sip.org/repos/sofia-sip --tag=rel-sofia-sip-1_yy_z
+- create the release tarball with "make distcheck"
+- calculate md5 and sha1 hashes using md5sum and sha1sum utilities,
+  and copy the values to the release-notes (see below)
+
+Creating the release notes and updating the website
+===================================================
+
+- combine the sofia-sip/RELEASE contents with
+  the template found from sfnet_www/templates/relnotes.txt
+- store the resulting release notes to 
+  sfnet_www/relnotes/relnotes-sofia-sip-x.y.z.txt
+- add explicit link to the release notes to 
+  sfnet_www/download.html (three most recent releases,
+  see guidelines in the html comments)
+- update sfnet_www/index.html to mention the latest
+  release
+- commit the change to sf.net website CVS, and run the 
+  sfnet_www/put_online.sh script at the sourceforge.net
+  shell server
+
+Uploading the release to sourceforge.net
+========================================
+
+- use the the 'Admin' -> 'File releases' tool for
+  creating a new release
+- to upload the file, you can use for example ncftpput:
+  ncftpput -u anonymous -p USER at users.sourceforge.net upload.sourceforge.net /incoming/ sofia-sip-x.y.z.tar.gz
+- attach the release notes (relnotes-sofia-sip-x.y.z.txt)
+  to the file release
+
+Announcing releases
+===================
+
+- send an announcement mail, containing the
+  release notes, to sofia-sip-devel at lists.sourceforge.net
+- post a news item to freshmeat.net 'sofia-sip'
+  project (current project owner: Kai Vehmanen)
+
+After release
+=============
+
+- replace the RELEASE file with RELEASE.template, and
+  commit it to master source repository (see sofia-sip/README.developers)
+- change version in configure.ac from "X.Y.Z" to 
+  "X.Y.Zwork" (as it is in many cases unknown what the 
+  next version will be)
+- make a "tree open for development" commit
+
+Syncing CVS and darcs (or some other VCS)
+=========================================
+
+Some tips for synchronizing from/to different version controlled
+tree.
+
+- As CVS cannot trace file addition/move/removals, you need
+  to be extra careful with these. With darcs, you can use the
+  'darcs changes -v' command to track down all fileops since
+  last synchronization.
+
+- Always tag the src-tree with "syncuser-fromvcs-to-tovcs-yearmmdd".
+
+- Add a top-level ChangeLog entry that documents all the 
+  changes made outside the target tree (what, who and when -
+  for example produced with the "darcs changes --summary" 
+  command).
+
+Checking API/ABI compatibility
+==============================
+
+- Use a unit test binary built against an old library, 
+  to verify a new library version (forwards-compatibility).
+- Use the 'icheck' tool (in Debian) to make comparison
+  between two released versions.

Added: freeswitch/trunk/libs/sofia-sip/install-sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/install-sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,322 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2004-09-10.20
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c         (ignored)
+-d         create directories instead of installing files.
+-g GROUP   $chgrpprog installed files to GROUP.
+-m MODE    $chmodprog installed files to MODE.
+-o USER    $chownprog installed files to USER.
+-s         $stripprog installed files.
+-t DIRECTORY  install into DIRECTORY.
+-T         report an error if DSTFILE is a directory.
+--help     display this help and exit.
+--version  display version info and exit.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+  case $1 in
+    -c) shift
+        continue;;
+
+    -d) dir_arg=true
+        shift
+        continue;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift
+        shift
+        continue;;
+
+    --help) echo "$usage"; exit 0;;
+
+    -m) chmodcmd="$chmodprog $2"
+        shift
+        shift
+        continue;;
+
+    -o) chowncmd="$chownprog $2"
+        shift
+        shift
+        continue;;
+
+    -s) stripcmd=$stripprog
+        shift
+        continue;;
+
+    -t) dstarg=$2
+	shift
+	shift
+	continue;;
+
+    -T) no_target_directory=true
+	shift
+	continue;;
+
+    --version) echo "$0 $scriptversion"; exit 0;;
+
+    *)  # When -d is used, all remaining arguments are directories to create.
+	# When -t is used, the destination is already specified.
+	test -n "$dir_arg$dstarg" && break
+        # Otherwise, the last argument is the destination.  Remove it from $@.
+	for arg
+	do
+          if test -n "$dstarg"; then
+	    # $@ is not empty: it contains at least $arg.
+	    set fnord "$@" "$dstarg"
+	    shift # fnord
+	  fi
+	  shift # arg
+	  dstarg=$arg
+	done
+	break;;
+  esac
+done
+
+if test -z "$1"; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src ;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    src=
+
+    if test -d "$dst"; then
+      mkdircmd=:
+      chmodcmd=
+    else
+      mkdircmd=$mkdirprog
+    fi
+  else
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dstarg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dstarg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst ;;
+    esac
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dstarg: Is a directory" >&2
+	exit 1
+      fi
+      dst=$dst/`basename "$src"`
+    fi
+  fi
+
+  # This sed command emulates the dirname command.
+  dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+  # Make sure that the destination directory exists.
+
+  # Skip lots of stat calls in the usual case.
+  if test ! -d "$dstdir"; then
+    defaultIFS='
+	 '
+    IFS="${IFS-$defaultIFS}"
+
+    oIFS=$IFS
+    # Some sh's can't handle IFS=/ for some reason.
+    IFS='%'
+    set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+    IFS=$oIFS
+
+    pathcomp=
+
+    while test $# -ne 0 ; do
+      pathcomp=$pathcomp$1
+      shift
+      if test ! -d "$pathcomp"; then
+        $mkdirprog "$pathcomp"
+	# mkdir can fail with a `File exist' error in case several
+	# install-sh are creating the directory concurrently.  This
+	# is OK.
+	test -d "$pathcomp" || exit
+      fi
+      pathcomp=$pathcomp/
+    done
+  fi
+
+  if test -n "$dir_arg"; then
+    $doit $mkdircmd "$dst" \
+      && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+      && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+      && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+  else
+    dstfile=`basename "$dst"`
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+    trap '(exit $?); exit' 1 2 13 15
+
+    # Copy the file name to the temp name.
+    $doit $cpprog "$src" "$dsttmp" &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+      && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+      && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+    # Now rename the file to the real destination.
+    { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+      || {
+	   # The rename failed, perhaps because mv can't rename something else
+	   # to itself, or perhaps because mv is so ancient that it does not
+	   # support -f.
+
+	   # Now remove or move aside any old file at destination location.
+	   # We try this two ways since rm can't unlink itself on some
+	   # systems and the destination file might be busy for other
+	   # reasons.  In this case, the final cleanup might fail but the new
+	   # file should still install successfully.
+	   {
+	     if test -f "$dstdir/$dstfile"; then
+	       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+	       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+	       || {
+		 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+		 (exit 1); exit
+	       }
+	     else
+	       :
+	     fi
+	   } &&
+
+	   # Now rename the file to the real destination.
+	   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+	 }
+    }
+  fi || { (exit 1); exit; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+  (exit 0); exit
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,25 @@
+2006-12-05  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua-glib interface v3 frozen, version to 3:0:0 (for 1.12.5 release).
+	* nua-glib submodule has been moved from libsofia-sip-ua-glib,
+	and sofia-sip, to a standalone sofia-nua-glib package.
+
+2006-11-22  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua-glib interface v2 frozen, version to 2:0:2 (for 1.12.4 release).
+
+2006-07-25  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua-glib interface v1 frozen, version to 1:0:1 (for 1.12.2 release).
+
+2006-06-16  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua-glib interface v0 frozen, version to 0:0:0.
+
+2006-04-12  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Modified build system to require glib-2.4 or newer to compile libsofia-sip-ua-glib.
+
+2006-03-09  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua-glib created.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua-glib
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+AUTOMAKE_OPTIONS = foreign 1.7
+
+SUBDIRS=su-glib
+
+GLIB_TARGETS=su-glib/libsu-glib.la
+
+lib_LTLIBRARIES =
+if HAVE_GLIB
+lib_LTLIBRARIES += libsofia-sip-ua-glib.la
+endif
+
+libsofia_sip_ua_glib_la_SOURCES = 
+libsofia_sip_ua_glib_la_LIBADD = $(GLIB_TARGETS) $(GLIB_LIBS)
+
+# set the libtool version info version:revision:age for libsofia-sip-ua-glib
+# - soname to 'libsofia-sip-ua-glib.so.(CUR-AGE)'
+libsofia_sip_ua_glib_la_LDFLAGS = \
+	-version-info $(LIBVER_SOFIA_SIP_UA_GLIB_CUR):$(LIBVER_SOFIA_SIP_UA_GLIB_REV):$(LIBVER_SOFIA_SIP_UA_GLIB_AGE)
+
+DOXYGEN = doxygen
+
+EXTRA_DIST = docs/Doxyfile.aliases \
+	     docs/Doxyfile.conf \
+	     docs/Doxyfile.version
+
+built-sources: built-sources-recursive 
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive:
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $@ in $$subdir"; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+	done;
+
+doxygen: built-sources
+	@cd ${srcdir} ;\
+	mkdir -p docs docs/html &&\
+	for d in $(DIST_SUBDIRS) $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} in $$d \
+          && ${DOXYGEN} \
+          && popd > /dev/null ; \
+	done
+	cd ${srcdir}/docs/html && ../../${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh
+
+.PHONY: built-sources built-sources-am doxygen 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,630 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua-glib
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+SOURCES = $(libsofia_sip_ua_glib_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+ at HAVE_GLIB_TRUE@am__append_1 = libsofia-sip-ua-glib.la
+subdir = libsofia-sip-ua-glib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 = su-glib/libsu-glib.la
+am__DEPENDENCIES_2 =
+libsofia_sip_ua_glib_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2)
+am_libsofia_sip_ua_glib_la_OBJECTS =
+libsofia_sip_ua_glib_la_OBJECTS =  \
+	$(am_libsofia_sip_ua_glib_la_OBJECTS)
+ at HAVE_GLIB_TRUE@am_libsofia_sip_ua_glib_la_rpath = -rpath $(libdir)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsofia_sip_ua_glib_la_SOURCES)
+DIST_SOURCES = $(libsofia_sip_ua_glib_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-exec-recursive install-info-recursive \
+	install-recursive installcheck-recursive installdirs-recursive \
+	pdf-recursive ps-recursive uninstall-info-recursive \
+	uninstall-recursive
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = doxygen
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AUTOMAKE_OPTIONS = foreign 1.7
+SUBDIRS = su-glib
+GLIB_TARGETS = su-glib/libsu-glib.la
+lib_LTLIBRARIES = $(am__append_1)
+libsofia_sip_ua_glib_la_SOURCES = 
+libsofia_sip_ua_glib_la_LIBADD = $(GLIB_TARGETS) $(GLIB_LIBS)
+
+# set the libtool version info version:revision:age for libsofia-sip-ua-glib
+# - soname to 'libsofia-sip-ua-glib.so.(CUR-AGE)'
+libsofia_sip_ua_glib_la_LDFLAGS = \
+	-version-info $(LIBVER_SOFIA_SIP_UA_GLIB_CUR):$(LIBVER_SOFIA_SIP_UA_GLIB_REV):$(LIBVER_SOFIA_SIP_UA_GLIB_AGE)
+
+EXTRA_DIST = docs/Doxyfile.aliases \
+	     docs/Doxyfile.conf \
+	     docs/Doxyfile.version
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  libsofia-sip-ua-glib/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  libsofia-sip-ua-glib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    f=$(am__strip_dir) \
+	    echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+	    $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  p=$(am__strip_dir) \
+	  echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+	  $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsofia-sip-ua-glib.la: $(libsofia_sip_ua_glib_la_OBJECTS) $(libsofia_sip_ua_glib_la_DEPENDENCIES) 
+	$(LINK) $(am_libsofia_sip_ua_glib_la_rpath) $(libsofia_sip_ua_glib_la_LDFLAGS) $(libsofia_sip_ua_glib_la_OBJECTS) $(libsofia_sip_ua_glib_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/docs
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(mkdir_p) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	    distdir=`$(am__cd) $(distdir) && pwd`; \
+	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+	    (cd $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$top_distdir" \
+	        distdir="$$distdir/$$subdir" \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+	clean clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-recursive ctags ctags-recursive distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-recursive distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-libLTLIBRARIES install-man \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	maintainer-clean-recursive mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+	pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+	uninstall-info-am uninstall-libLTLIBRARIES
+
+
+built-sources: built-sources-recursive 
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive:
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $@ in $$subdir"; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+	done;
+
+doxygen: built-sources
+	@cd ${srcdir} ;\
+	mkdir -p docs docs/html &&\
+	for d in $(DIST_SUBDIRS) $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} in $$d \
+          && ${DOXYGEN} \
+          && popd > /dev/null ; \
+	done
+	cd ${srcdir}/docs/html && ../../${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh
+
+.PHONY: built-sources built-sources-am doxygen 
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+ at INCLUDE	     = ../../libsofia-sip-ua/docs/Doxyfile.aliases

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+ at INCLUDE	     = ../../libsofia-sip-ua/docs/Doxyfile.conf
+ at INCLUDE	     = ../../libsofia-sip-ua/docs/Doxyfile.rfc
+
+HTML_FOOTER	     = ../../libsofia-sip-ua/docs/sofia-footer.html
+
+TAGFILES            += ../../libsofia-sip-ua/docs/docs.doxytags=../docs
+TAGFILES            += ../../libsofia-sip-ua/docs/su.doxytags=../su
+TAGFILES            += ../../libsofia-sip-ua/docs/ipt.doxytags=../ipt
+TAGFILES            += ../../libsofia-sip-ua/docs/bnf.doxytags=../bnf
+TAGFILES            += ../../libsofia-sip-ua/docs/url.doxytags=../url
+TAGFILES            += ../../libsofia-sip-ua/docs/msg.doxytags=../msg
+TAGFILES            += ../../libsofia-sip-ua/docs/sip.doxytags=../sip
+TAGFILES            += ../../libsofia-sip-ua/docs/sresolv.doxytags=../sresolv
+TAGFILES            += ../../libsofia-sip-ua/docs/tport.doxytags=../tport
+TAGFILES            += ../../libsofia-sip-ua/docs/nta.doxytags=../nta
+TAGFILES            += ../../libsofia-sip-ua/docs/sdp.doxytags=../sdp
+TAGFILES            += ../../libsofia-sip-ua/docs/nua.doxytags=../nua
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+ at INCLUDE	     = ../../libsofia-sip-ua/docs/Doxyfile.version
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+PROJECT_NAME         = "sofia-sip/su-glib"
+
+OUTPUT_DIRECTORY     = ../docs/html/su-glib
+
+INPUT 		     = su_glib.docs . sofia-sip
+
+ at INCLUDE             = ../docs/Doxyfile.conf
+
+GENERATE_TAGFILE     = ../docs/su_glib.doxytags
+
+ALIASES             +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+#
+# Makefile.am for su-glib module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+S_BASE = $(top_srcdir)/libsofia-sip-ua
+B_BASE = $(top_builddir)/libsofia-sip-ua
+
+INCLUDES =		-I$(S_BASE)/su -I$(B_BASE)/su $(GLIB_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsu-glib.la
+
+check_PROGRAMS = 	su_source_test
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = 		su_source_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS =
+if HAVE_GLIB
+nobase_include_sofia_HEADERS += \
+			sofia-sip/su_source.h \
+			sofia-sip/su_glib.h
+endif
+
+libsu_glib_la_SOURCES = su_source.c
+
+libsu_glib_la_DEPENDENCIES = \
+			../../libsofia-sip-ua/libsofia-sip-ua.la
+
+LDADD = 		libsu-glib.la \
+			../../libsofia-sip-ua/libsofia-sip-ua.la \
+			$(GLIB_LIBS)
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile su_glib.docs
+
+# ----------------------------------------------------------------------
+# Automake options
+
+AUTOMAKE_OPTIONS = 	foreign
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../../libsofia-sip-ua/sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,705 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for su-glib module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libsu_glib_la_SOURCES) su_source_test.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = su_source_test$(EXEEXT)
+ at HAVE_GLIB_TRUE@am__append_1 = \
+ at HAVE_GLIB_TRUE@			sofia-sip/su_source.h \
+ at HAVE_GLIB_TRUE@			sofia-sip/su_glib.h
+
+DIST_COMMON = $(am__nobase_include_sofia_HEADERS_DIST) \
+	$(srcdir)/../../libsofia-sip-ua/sofia.am $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in
+subdir = libsofia-sip-ua-glib/su-glib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsu_glib_la_LIBADD =
+am_libsu_glib_la_OBJECTS = su_source.lo
+libsu_glib_la_OBJECTS = $(am_libsu_glib_la_OBJECTS)
+su_source_test_SOURCES = su_source_test.c
+su_source_test_OBJECTS = su_source_test.$(OBJEXT)
+su_source_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+su_source_test_DEPENDENCIES = libsu-glib.la \
+	../../libsofia-sip-ua/libsofia-sip-ua.la $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsu_glib_la_SOURCES) su_source_test.c
+DIST_SOURCES = $(libsu_glib_la_SOURCES) su_source_test.c
+am__nobase_include_sofia_HEADERS_DIST = sofia-sip/su_source.h \
+	sofia-sip/su_glib.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+S_BASE = $(top_srcdir)/libsofia-sip-ua
+B_BASE = $(top_builddir)/libsofia-sip-ua
+INCLUDES = -I$(S_BASE)/su -I$(B_BASE)/su $(GLIB_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsu-glib.la
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = su_source_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = $(am__append_1)
+libsu_glib_la_SOURCES = su_source.c
+libsu_glib_la_DEPENDENCIES = \
+			../../libsofia-sip-ua/libsofia-sip-ua.la
+
+LDADD = libsu-glib.la \
+			../../libsofia-sip-ua/libsofia-sip-ua.la \
+			$(GLIB_LIBS)
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile su_glib.docs
+
+# ----------------------------------------------------------------------
+# Automake options
+AUTOMAKE_OPTIONS = foreign
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../../libsofia-sip-ua/sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  libsofia-sip-ua-glib/su-glib/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  libsofia-sip-ua-glib/su-glib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsu-glib.la: $(libsu_glib_la_OBJECTS) $(libsu_glib_la_DEPENDENCIES) 
+	$(LINK)  $(libsu_glib_la_LDFLAGS) $(libsu_glib_la_OBJECTS) $(libsu_glib_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+su_source_test$(EXEEXT): $(su_source_test_OBJECTS) $(su_source_test_DEPENDENCIES) 
+	@rm -f su_source_test$(EXEEXT)
+	$(LINK) $(su_source_test_LDFLAGS) $(su_source_test_OBJECTS) $(su_source_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_source.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_source_test.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/../../libsofia-sip-ua $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_GLIB_SOURCE_H
+#define SU_GLIB_SOURCE_H
+
+/**
+ * @file su_glib.h
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef __GLIB_H__
+#include <glib.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN su_root_t *su_glib_root_create(su_root_magic_t *) __attribute__((__malloc__));
+SOFIAPUBFUN GSource *su_glib_root_gsource(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_GLIB_SOURCE_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_SOURCE_H /** Defined when su_source.h has been included. */
+#define SU_SOURCE_H
+
+/**
+ * @file su_source.h
+ * @brief 
+ *
+ * NOTE: This file (su_source.h) is DEPRECATED as of 1.12.2 release. 
+ *       Please use su_glib.h instead.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ *  
+ * @date Created: Thu Mar  4 19:58:50 2004 ppessi
+ * 
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef __GLIB_H__
+#include <glib.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN su_root_t *su_root_source_create(su_root_magic_t *) __attribute__((__malloc__));
+SOFIAPUBFUN GSource *su_root_source(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_SOURCE_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+/**
+
+ at mainpage Sofia-SIP su-glib Module
+
+ at section su_glib_meta Module Meta Information
+
+The su-glib module provides an interface to connect Sofia-SIP event loop 
+to an existing glib main loop. Without this interface, a glib based
+application would have to create a separate thread for running
+the Sofia-SIP event loop.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS Core library
+
+ at LICENSE LGPL
+
+ at section su_glib_contents Contents of su-glib Module
+
+The su-glib module contains the public header files as follows:
+- <su_glib.h>    the public API of the module
+- <su_source.h>  deprecated API (1.12.1 and earlier)
+
+ at section su_glib_examples Examples of use
+
+Below is a simple example of how to use su-glib:
+ at code
+  #include <glib.h>
+  #include <sofia-sip/su_glib.h>
+
+  /* ... */
+  
+  GMainLoop *ptr = g_main_loop_new(NULL, FALSE);
+  GSource *gsource;
+  su_root_t *sofia_event_loop;
+  su_timer_t *timer;
+
+  /* create a sofia event loop using su-glib function su_glib_root_source_create() */
+  sofia_event_loop = su_glib_root_create(NULL); 
+
+  /* attach the created GSource to glib event loop */
+  gsource = su_glib_root_gsource(sofia_event_loop);
+  g_source_attach(gsource, g_main_loop_get_context(ptr));
+
+  /* use the sofia event loop with libsofia-sip-ua modules */
+  timer = su_timer_create(su_root_task(sofia_event_loop), 200L);
+
+  /* ... initialize other Sofia-SIP modules/functrions */
+
+  /* run the glib mainloop */
+  g_main_loop_run(ptr);  
+ at endcode   
+
+ at section su_glib_todo Todo
+
+- see sourceforge.net issue tracker for sofia-sip 
+  (-> http://sofia-sip.sourceforge.net/development.html )
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1118 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file su_source.c
+ * @brief Wrapper for glib GSource.
+ * *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ * 
+ * @date Created: Thu Mar  4 15:15:15 2004 ppessi
+ * 
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include <glib.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#define SU_MSG_ARG_T union { char anoymous[4]; }
+
+#define su_port_s su_source_s
+
+#include "sofia-sip/su_source.h"
+#include "sofia-sip/su_glib.h"
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+static su_port_t *su_source_create(void) __attribute__((__malloc__));
+static gboolean su_source_prepare(GSource *gs, gint *return_tout);
+static gboolean su_source_check(GSource *gs);
+static gboolean su_source_dispatch(GSource *gs,
+			    GSourceFunc callback,
+			    gpointer user_data);
+static void su_source_finalize(GSource *source);
+
+static int su_source_getmsgs(su_port_t *self);
+
+static
+GSourceFuncs su_source_funcs[1] = {{
+    su_source_prepare,
+    su_source_check,
+    su_source_dispatch,
+    su_source_finalize,
+    NULL,
+    NULL
+  }};
+
+static void su_source_lock(su_port_t *self, char const *who);
+static void su_source_unlock(su_port_t *self, char const *who);
+static void su_source_incref(su_port_t *self, char const *who);
+static void su_source_decref(su_port_t *self, int blocking, char const *who);
+static struct _GSource *su_source_gsource(su_port_t *port);
+
+static int su_source_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_source_register(su_port_t *self,
+			    su_root_t *root, 
+			    su_wait_t *wait, 
+			    su_wakeup_f callback,
+			    su_wakeup_arg_t *arg,
+			    int priority);
+static int su_source_unregister(su_port_t *port,
+			      su_root_t *root, 
+			      su_wait_t *wait,	
+			      su_wakeup_f callback, 
+			      su_wakeup_arg_t *arg);
+static int su_source_deregister(su_port_t *self, int i);
+static int su_source_unregister_all(su_port_t *self,
+				  su_root_t *root);
+static int su_source_eventmask(su_port_t *self, 
+			     int index, int socket, int events);
+static void su_source_run(su_port_t *self);
+static void su_source_break(su_port_t *self);
+static su_duration_t su_source_step(su_port_t *self, su_duration_t tout);
+static int su_source_own_thread(su_port_t const *port);
+static int su_source_add_prepoll(su_port_t *port,
+			       su_root_t *root, 
+			       su_prepoll_f *, 
+			       su_prepoll_magic_t *);
+static int su_source_remove_prepoll(su_port_t *port,
+				  su_root_t *root);
+static su_timer_t **su_source_timers(su_port_t *port);
+static int su_source_multishot(su_port_t *self, int multishot);
+static int su_source_threadsafe(su_port_t *port);
+
+static
+su_port_vtable_t const su_source_vtable[1] =
+  {{
+      /* su_vtable_size: */ sizeof su_source_vtable,
+      su_source_lock,
+      su_source_unlock,
+      su_source_incref,
+      su_source_decref,
+
+      su_source_gsource,
+
+      su_source_send,
+      su_source_register,
+      su_source_unregister,
+      su_source_deregister,
+      su_source_unregister_all,
+      su_source_eventmask,
+      su_source_run,
+      su_source_break,
+      su_source_step,
+      su_source_own_thread,
+      su_source_add_prepoll,
+      su_source_remove_prepoll,
+      su_source_timers,
+      su_source_multishot,
+      su_source_threadsafe
+
+    }};
+
+/** 
+ * Port is a per-thread reactor.  
+ *
+ * Multiple root objects executed by single thread share a su_port_t object. 
+ */
+struct su_source_s {
+  su_home_t        sup_home[1];
+  su_port_vtable_t const *sup_vtable;
+  
+  GThread         *sup_tid;
+  GStaticMutex     sup_mutex[1];
+  GStaticRWLock    sup_ref[1];
+
+  GSource         *sup_source;
+  GMainLoop       *sup_main_loop;
+  
+  /* Message list - this is protected by lock  */
+  su_msg_t        *sup_head;
+  su_msg_t       **sup_tail;
+
+  /* Waits */
+  unsigned         sup_registers; /** Counter incremented by 
+				      su_port_register() or 
+				      su_port_unregister()
+				  */
+  unsigned         sup_n_waits; 
+  unsigned         sup_size_waits; 
+  unsigned         sup_max_index;
+  unsigned        *sup_indices; 
+  su_wait_t       *sup_waits; 
+  su_wakeup_f     *sup_wait_cbs; 
+  su_wakeup_arg_t**sup_wait_args; 
+  su_root_t      **sup_wait_roots; 
+
+  /* Timer list */
+  su_timer_t      *sup_timers;
+};
+
+typedef struct _SuSource
+{
+  GSource    ss_source[1];
+  su_port_t  ss_port[1];
+} SuSource;
+
+#define SU_SOURCE_OWN_THREAD(p)   ((p)->sup_tid == g_thread_self())
+
+#if 1
+#define SU_SOURCE_INCREF(p, f)    (g_source_ref(p->sup_source))
+#define SU_SOURCE_DECREF(p, f)    (g_source_unref(p->sup_source))
+
+#define SU_SOURCE_INITLOCK(p)     (g_static_mutex_init((p)->sup_mutex))
+#define SU_SOURCE_LOCK(p, f)      (g_static_mutex_lock((p)->sup_mutex))
+#define SU_SOURCE_UNLOCK(p, f)    (g_static_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_SOURCE_INCREF(p, f)    (g_source_ref(p->sup_source), printf("incref(%p) by %s\n", (p), f))
+#define SU_SOURCE_DECREF(p, f)    do { printf("decref(%p) by %s\n", (p), f), \
+  g_source_unref(p->sup_source); } while(0)
+
+#define SU_SOURCE_INITLOCK(p) \
+   (g_static_mutex_init((p)->sup_mutex), printf("init_lock(%p)\n", p))
+
+#define SU_SOURCE_LOCK(p, f)    \
+   (printf("%ld at %s locking(%p)...", g_thread_self(), f, p), g_static_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", g_thread_self(), f, p))
+
+#define SU_SOURCE_UNLOCK(p, f)  \
+  (g_static_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", g_thread_self(), f, p))
+
+#endif
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __func__))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __FUNCTION__))
+#else
+#define enter (void)0
+#endif
+
+/*=============== Public function definitions ===============*/
+
+/** Create a root that uses GSource as reactor */
+su_root_t *su_glib_root_create(su_root_magic_t *magic)
+{
+  return su_root_create_with_port(magic, su_source_create());
+}
+
+/** Deprecated */
+su_root_t *su_root_source_create(su_root_magic_t *magic)
+{
+  return su_glib_root_create(magic);
+}
+
+GSource *su_glib_root_gsource(su_root_t *root)
+{
+  g_assert(root);
+  return su_root_gsource(root);
+}
+
+/*=============== Private function definitions ===============*/
+
+/**@internal
+ *
+ * Allocates and initializes a reactor and message port object.
+ *
+ * @return
+ *   If successful a pointer to the new message port is returned, otherwise
+ *   NULL is returned.  
+ */
+su_port_t *su_source_create(void)
+{
+  SuSource *ss;
+
+  SU_DEBUG_9(("su_source_create() called\n"));
+
+  ss = (SuSource *)g_source_new(su_source_funcs, (sizeof *ss));
+
+  if (ss) {
+    su_port_t *self = ss->ss_port;
+
+    self->sup_vtable = su_source_vtable;
+    self->sup_source = ss->ss_source;
+    
+    SU_SOURCE_INITLOCK(self);
+
+    self->sup_tail = &self->sup_head;
+    self->sup_tid = g_thread_self();
+
+    SU_DEBUG_9(("su_source_with_main_context() returns %p\n", self));
+
+    return self;
+  } else {
+    su_perror("su_source_with_main_context(): su_home_clone");
+    SU_DEBUG_9(("su_source_with_main_context() fails\n"));
+    return NULL;
+  }
+}
+
+/** @internal Destroy a port. */
+static 
+void su_source_finalize(GSource *gs)
+{
+  SuSource *ss = (SuSource *)gs;
+  su_port_t *self = ss->ss_port;
+
+  assert(gs);
+
+  SU_DEBUG_9(("su_source_finalize() called\n"));
+
+  if (self->sup_waits) 
+    free(self->sup_waits), self->sup_waits = NULL;
+  if (self->sup_wait_cbs)
+    free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+  if (self->sup_wait_args)
+    free(self->sup_wait_args), self->sup_wait_args = NULL;
+  if (self->sup_wait_roots)
+    free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+  if (self->sup_indices)
+    free(self->sup_indices), self->sup_indices = NULL;
+
+  su_home_deinit(self->sup_home);
+}
+
+/* Seconds from 1.1.1900 to 1.1.1970 */
+#define NTP_EPOCH 2208988800UL 
+
+static
+gboolean su_source_prepare(GSource *gs, gint *return_tout)
+{
+  SuSource *ss = (SuSource *)gs;
+  su_port_t *self = ss->ss_port;
+
+  enter;
+  
+  if (self->sup_head)
+    return TRUE;
+
+  *return_tout = -1;
+
+  if (self->sup_timers) {
+    su_time_t now;
+    GTimeVal  gtimeval;
+    su_duration_t tout;
+
+    tout = SU_DURATION_MAX;
+
+    g_source_get_current_time(gs, &gtimeval);
+
+    now.tv_sec = gtimeval.tv_sec + 2208988800UL;
+    now.tv_usec = gtimeval.tv_usec;
+
+    tout = su_timer_next_expires(self->sup_timers, now);
+
+    if (tout == 0)
+      return TRUE;
+
+    if ((gint)tout < 0 || tout > (su_duration_t)G_MAXINT)
+      tout = -1;
+
+    *return_tout = (gint)tout;
+  }
+  
+  return FALSE;
+}
+
+static
+gboolean su_source_check(GSource *gs)
+{
+  SuSource *ss = (SuSource *)gs;
+  su_port_t *self = ss->ss_port;
+  gint tout;
+  unsigned i, I;
+
+  enter;
+
+  I = self->sup_n_waits;
+
+#if SU_HAVE_POLL
+  for (i = 0; i < I; i++) {
+    if (self->sup_waits[i].revents)
+      return TRUE;
+  }
+#endif
+
+  return su_source_prepare(gs, &tout);
+}
+
+static 
+gboolean su_source_dispatch(GSource *gs,
+			    GSourceFunc callback,
+			    gpointer user_data)
+{
+  SuSource *ss = (SuSource *)gs;
+  su_port_t *self = ss->ss_port;
+
+  enter;
+
+  if (self->sup_head)
+    su_source_getmsgs(self);
+
+  if (self->sup_timers) {
+    su_time_t now;
+    GTimeVal  gtimeval;
+    su_duration_t tout;
+    int timers = 0;
+
+    tout = SU_DURATION_MAX;
+
+    g_source_get_current_time(gs, &gtimeval);
+
+    now.tv_sec = gtimeval.tv_sec + 2208988800UL;
+    now.tv_usec = gtimeval.tv_usec;
+
+    timers = su_timer_expire(&self->sup_timers, &tout, now);
+  }
+
+#if SU_HAVE_POLL
+  {
+    su_root_t *root;
+    su_wait_t *waits = self->sup_waits;
+    unsigned i, n = self->sup_n_waits;
+    unsigned version = self->sup_registers;
+
+    for (i = 0; i < n; i++) {
+      if (waits[i].revents) {
+	root = self->sup_wait_roots[i];
+	self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL, 
+			      &waits[i], 
+			      self->sup_wait_args[i]);
+	/* Callback used su_register()/su_unregister() */
+	if (version != self->sup_registers)
+	  break;
+      }
+    }
+  }
+#endif
+
+  if (!callback)
+    return TRUE;
+
+  return callback(user_data);
+}
+
+static void su_source_lock(su_port_t *self, char const *who)
+{
+  SU_SOURCE_LOCK(self, who);
+}
+
+static void su_source_unlock(su_port_t *self, char const *who)
+{
+  SU_SOURCE_UNLOCK(self, who);
+}
+
+static void su_source_incref(su_port_t *self, char const *who)
+{
+  SU_SOURCE_INCREF(self, who);
+}
+
+static void su_source_decref(su_port_t *self, int blocking, char const *who)
+{
+  /* XXX - blocking? */
+  SU_SOURCE_DECREF(self, who);
+}
+
+GSource *su_source_gsource(su_port_t *self)
+{
+  return self->sup_source;
+}
+
+/** @internal Send a message to the port. */
+int su_source_send(su_port_t *self, su_msg_r rmsg)
+{
+  enter;
+  
+  if (self) {
+    su_msg_t *msg;
+    GMainContext *gmc;
+
+    SU_SOURCE_LOCK(self, "su_source_send");
+    
+    msg = rmsg[0]; rmsg[0] = NULL;
+    *self->sup_tail = msg;
+    self->sup_tail = &msg->sum_next;
+
+    SU_SOURCE_UNLOCK(self, "su_source_send");
+
+    gmc = g_source_get_context(self->sup_source);
+
+    if (gmc)
+      g_main_context_wakeup(gmc);
+
+    return 0;
+  }
+  else {
+    su_msg_destroy(rmsg);
+    return -1;
+  }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval 0 if there was a signal to handle, 
+ * @retval -1 otherwise.
+ */
+static
+int su_source_getmsgs(su_port_t *self)
+{
+  enter;
+  
+  if (self && self->sup_head) {
+    su_root_t *root;
+    su_msg_f f;
+
+    SU_SOURCE_INCREF(self, "su_source_getmsgs");
+    SU_SOURCE_LOCK(self, "su_source_getmsgs");
+
+    while (self->sup_head) {
+      su_msg_t *msg = self->sup_head;
+      self->sup_head = msg->sum_next;
+      if (!self->sup_head) {
+	assert(self->sup_tail == &msg->sum_next);
+	self->sup_tail = &self->sup_head;
+      }
+      root = msg->sum_to->sut_root;
+      f = msg->sum_func;
+      SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
+      if (f) 
+	f(su_root_magic(root), &msg, msg->sum_data);
+      su_msg_delivery_report(&msg);
+      SU_SOURCE_LOCK(self, "su_source_getmsgs");
+    }
+
+    SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
+    SU_SOURCE_DECREF(self, "su_source_getmsgs");
+
+    return 0;
+  }
+  else
+    return -1;
+}
+
+/** @internal
+ *
+ *  Register a @c su_wait_t object. The wait object, a callback function and
+ *  a argument pointer is stored in the port object.  The callback function
+ *  will be called when the wait object is signaled.
+ *
+ *  Please note if identical wait objects are inserted, only first one is
+ *  ever signalled.
+ * 
+ * @param self	     pointer to port
+ * @param root	     pointer to root object
+ * @param waits	     pointer to wait object
+ * @param callback   callback function pointer
+ * @param arg	     argument given to callback function when it is invoked
+ * @param priority   relative priority of the wait object 
+ *              (0 is normal, 1 important, 2 realtime)
+ * 
+ * @return
+ *   The function @su_source_register returns nonzero index of the wait object, 
+ *   or -1 upon an error.  */
+int su_source_register(su_port_t *self,
+		       su_root_t *root, 
+		       su_wait_t *wait, 
+		       su_wakeup_f callback,
+		       su_wakeup_arg_t *arg,
+		       int priority)
+{
+  unsigned i, j, I;
+  unsigned n;
+
+  enter;
+  
+  assert(SU_SOURCE_OWN_THREAD(self));
+
+  n = self->sup_n_waits;
+
+  if (n >= self->sup_size_waits) {
+    /* Reallocate size arrays */
+    unsigned size;
+    unsigned *indices;
+    su_wait_t *waits;
+    su_wakeup_f *wait_cbs;
+    su_wakeup_arg_t **wait_args;
+    su_root_t **wait_tasks;
+
+    if (self->sup_size_waits == 0)
+      size = SU_WAIT_MIN;
+    else 
+      size = 2 * self->sup_size_waits;
+
+    indices = realloc(self->sup_indices, size * sizeof(*indices));
+    if (indices) {
+      self->sup_indices = indices;
+
+      for (i = self->sup_size_waits; i < size; i++)
+	indices[i] = UINT_MAX;
+    }
+
+    for (i = 0; i < self->sup_n_waits; i++)
+      g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[i]);
+      
+    waits = realloc(self->sup_waits, size * sizeof(*waits));
+    if (waits)
+      self->sup_waits = waits;
+
+    for (i = 0; i < self->sup_n_waits; i++)
+      g_source_add_poll(self->sup_source, (GPollFD*)&waits[i]);
+      
+    wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+    if (wait_cbs)
+      self->sup_wait_cbs = wait_cbs;
+
+    wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+    if (wait_args)
+      self->sup_wait_args = wait_args;
+
+    /* Add sup_wait_roots array, if needed */
+    wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+    if (wait_tasks) 
+      self->sup_wait_roots = wait_tasks;
+
+    if (!(indices && waits && wait_cbs && wait_args && wait_tasks)) {
+      return -1;
+    }
+
+    self->sup_size_waits = size;
+  }
+
+  self->sup_n_waits++;
+
+  if (priority > 0) {
+    /* Insert */
+    for (; n > 0; n--) {
+      g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n-1]);
+      self->sup_waits[n] = self->sup_waits[n-1];
+      g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+      self->sup_wait_args[n] = self->sup_wait_args[n-1];
+      self->sup_wait_roots[n] = self->sup_wait_roots[n-1];	
+    }
+  }
+  else {
+    /* Append - no need to move anything */
+  }
+
+  self->sup_waits[n] = *wait;
+  g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+  self->sup_wait_cbs[n] = callback;
+  self->sup_wait_args[n] = arg;
+  self->sup_wait_roots[n] = root;
+
+  I = self->sup_max_index;
+
+  for (i = 0; i < I; i++)  
+    if (self->sup_indices[i] == UINT_MAX)
+      break;
+    else if (self->sup_indices[i] >= n)
+      self->sup_indices[i]++;
+
+  if (i == I) 
+    self->sup_max_index++;
+
+  if (n + 1 < self->sup_n_waits)
+    for (j = i; j < I; j++)
+      if (self->sup_indices[j] != UINT_MAX &&
+	  self->sup_indices[j] >= n)
+	self->sup_indices[j]++;
+
+  self->sup_indices[i] = n;
+
+  self->sup_registers++;
+
+  return i + 1;			/* 0 is failure */
+}
+
+/** Unregister a su_wait_t object.
+ *  
+ *  The function su_source_unregister() unregisters a su_wait_t object. The
+ *  wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param root     - pointer to root object
+ * @param wait     - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg      - argument given to callback function when it is invoked 
+ *                   (may be NULL)
+ * 
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_source_unregister(su_port_t *self,
+			 su_root_t *root, 
+			 su_wait_t *wait,	
+			 su_wakeup_f callback, /* XXX - ignored */
+			 su_wakeup_arg_t *arg)
+{
+  unsigned n, N;
+  unsigned i, I, j, *indices;
+
+  enter;
+  
+  assert(self);
+  assert(SU_SOURCE_OWN_THREAD(self));
+
+  i = (unsigned)-1;
+  N = self->sup_n_waits;
+  I = self->sup_max_index;
+  indices = self->sup_indices;
+
+  for (n = 0; n < N; n++) {
+    if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) != 0)
+      continue;
+
+    /* Found - delete it */
+    if (indices[n] == n)
+      i = n;
+    else for (i = 0; i < I; i++)
+      if (indices[i] == n)
+	break;
+
+    assert(i < I);
+
+    indices[i] = UINT_MAX;
+
+    g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+    self->sup_n_waits = N = N - 1;
+
+    if (n < N)
+      for (j = 0; j < I; j++)
+	if (self->sup_indices[j] != UINT_MAX &&
+	    self->sup_indices[j] > n)
+	  self->sup_indices[j]--;
+    
+    for (; n < N; n++) {
+      g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n+1]);
+      self->sup_waits[n] = self->sup_waits[n+1];
+      g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[n+1];
+      self->sup_wait_args[n] = self->sup_wait_args[n+1];
+      self->sup_wait_roots[n] = self->sup_wait_roots[n+1];	  
+    }
+
+    i += 1;	/* 0 is failure */
+
+    if (i == I)
+      self->sup_max_index--;
+
+    break;
+  }
+
+  self->sup_registers++;
+
+  return (int)i;
+}
+
+/** Deregister a su_wait_t object.
+ *  
+ *  The function su_source_deregister() deregisters a su_wait_t registrattion. 
+ *  The wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param i        - registration index
+ * 
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_source_deregister(su_port_t *self, int i)
+{
+  unsigned j, n, N;
+  unsigned I, *indices;
+  su_wait_t wait[1];
+
+  enter;
+  
+  assert(self);
+  assert(SU_SOURCE_OWN_THREAD(self));
+
+  if (i <= 0)
+    return -1;
+
+  N = self->sup_n_waits;
+  I = self->sup_max_index;
+  indices = self->sup_indices;
+
+  assert((unsigned)i < I + 1);
+
+  n = indices[i - 1];
+
+  if (n == UINT_MAX)
+    return -1;
+
+  self->sup_n_waits = N = N - 1;
+
+  wait[0] = self->sup_waits[n];
+
+  g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+  if (n < N)
+    for (j = 0; j < I; j++)
+      if (self->sup_indices[j] != UINT_MAX &&
+	  self->sup_indices[j] > n)
+	self->sup_indices[j]--;
+
+  for (; n < N; n++) {
+    g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n + 1]);
+    self->sup_waits[n] = self->sup_waits[n+1];
+    g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+    self->sup_wait_cbs[n] = self->sup_wait_cbs[n+1];
+    self->sup_wait_args[n] = self->sup_wait_args[n+1];
+    self->sup_wait_roots[n] = self->sup_wait_roots[n+1];	  
+  }
+
+  indices[i - 1] = UINT_MAX;
+
+  if ((unsigned)i == I)
+    self->sup_max_index--;
+
+  su_wait_destroy(wait);
+
+  self->sup_registers++;
+
+  return (int)i;
+}
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_source_unregister_all() unregisters all su_wait_t objects
+ * associated with given root object destroys all queued timers.
+ * 
+ * @param  self     - pointer to port object
+ * @param  root     - pointer to root object
+ * 
+ * @return Number of wait objects removed.
+ */
+int su_source_unregister_all(su_port_t *self, 
+			   su_root_t *root)
+{
+  unsigned i, j;
+  unsigned         n_waits;
+  su_wait_t       *waits;
+  su_wakeup_f     *wait_cbs;
+  su_wakeup_arg_t**wait_args;
+  su_root_t      **wait_roots;
+
+  enter;
+  
+  assert(SU_SOURCE_OWN_THREAD(self));
+
+  n_waits    = self->sup_n_waits;
+  waits      = self->sup_waits; 
+  wait_cbs   = self->sup_wait_cbs; 
+  wait_args  = self->sup_wait_args;
+  wait_roots = self->sup_wait_roots; 
+  
+  for (i = j = 0; (unsigned)i < n_waits; i++) {
+    if (wait_roots[i] == root) {
+      /* XXX - we should free all resources associated with this */
+      g_source_remove_poll(self->sup_source, (GPollFD*)&waits[i]);
+      continue;
+    }
+    if (i != j) {
+      g_source_remove_poll(self->sup_source, (GPollFD*)&waits[i]);
+      waits[j] = waits[i];
+      wait_cbs[j] = wait_cbs[i];
+      wait_args[j] = wait_args[i];
+      wait_roots[j] = wait_roots[i];
+      g_source_add_poll(self->sup_source, (GPollFD*)&waits[i]);
+    }
+    j++;
+  }
+  
+  self->sup_n_waits = j;
+  self->sup_registers++;
+
+  return n_waits - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_source_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port   pointer to port object
+ * @param index  registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_source_eventmask(su_port_t *self, int index, int socket, int events)
+{
+  unsigned n;
+  int retval;
+
+  enter;
+  
+  assert(self);
+  assert(SU_SOURCE_OWN_THREAD(self));
+  assert(0 < index && (unsigned)index <= self->sup_max_index);
+
+  if (index <= 0 || (unsigned)index > self->sup_max_index)
+    return -1;
+
+  n = self->sup_indices[index - 1];
+
+  if (n == UINT_MAX)
+    return -1;
+
+  g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+  retval = su_wait_mask(&self->sup_waits[n], socket, events);
+
+  g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+  return retval;
+}
+
+static
+int su_source_multishot(su_port_t *self, int multishot)
+{
+  if (multishot == -1)
+    return 1;
+  else if (multishot == 0 || multishot == 1)
+    return 1;			/* Always enabled */
+  else 
+    return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_source_threadsafe(su_port_t *port)
+{
+  return su_home_threadsafe(port->sup_home);
+}
+
+
+/** @internal Main loop.
+ * 
+ * The function @c su_source_run() runs the main loop
+ * 
+ * The function @c su_source_run() runs until @c su_source_break() is called
+ * from a callback.
+ * 
+ * @param self     pointer to root object
+ * */
+void su_source_run(su_port_t *self)
+{
+  GMainContext *gmc;
+  GMainLoop *gml;
+
+  enter;
+  
+  gmc = g_source_get_context(self->sup_source);
+  if (gmc && g_main_context_acquire(gmc)) {
+    gml = g_main_loop_new(gmc, TRUE);
+    self->sup_main_loop = gml;
+    g_main_loop_run(gml);
+    g_main_loop_unref(gml);
+    self->sup_main_loop = NULL;
+    g_main_context_release(gmc);
+  }
+}
+
+/** @internal
+ * The function @c su_source_break() is used to terminate execution of @c
+ * su_source_run(). It can be called from a callback function.
+ * 
+ * @param self     pointer to port
+ * 
+ */
+void su_source_break(su_port_t *self)
+{
+  enter;
+  
+  if (self->sup_main_loop)
+    g_main_loop_quit(self->sup_main_loop);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with 
+ * the root object.  When any wait object is signaled or timer is
+ * expired, it invokes the callbacks. 
+ * 
+ *   This function returns when a callback has been invoked or @c tout
+ *   milliseconds is elapsed. 
+ *
+ * @param self     pointer to port
+ * @param tout     timeout in milliseconds
+ * 
+ * @Return
+ *   Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ *   there are no active timers.
+ */
+su_duration_t su_source_step(su_port_t *self, su_duration_t tout)
+{
+  GMainContext *gmc;
+
+  enter;
+  
+  gmc = g_source_get_context(self->sup_source);
+
+  if (gmc && g_main_context_acquire(gmc)) {
+    gint priority = G_MAXINT;
+    if (g_main_context_prepare(gmc, &priority)) {
+      g_main_context_dispatch(gmc);
+    } else {
+      gint timeout = tout > G_MAXINT ? G_MAXINT : tout;
+      gint i, n = 0;
+      GPollFD *fds = NULL;
+
+      priority = G_MAXINT;
+
+      n = g_main_context_query(gmc, priority, &timeout, fds, n);
+      if (n > 0) {
+	fds = g_alloca(n * (sizeof *fds));
+	n = g_main_context_query(gmc, priority, &timeout, fds, n);	
+      }
+
+      if (tout < timeout)
+	timeout = tout;
+
+      i = su_wait((su_wait_t *)fds, n, timeout);
+
+      if (g_main_context_check(gmc, priority, fds, n))
+	g_main_context_dispatch(gmc);
+    }
+    g_main_context_release(gmc);
+  }
+
+  return 0;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_source_own_thread(su_port_t const *self)
+{
+  return self == NULL || SU_SOURCE_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ *  Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f    pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_source_dump(su_port_t const *self, FILE *f)
+{
+  int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+  if (f == NULL)
+    f = stdout;
+
+  fprintf(f, "su_port_t at %p:\n", self);
+  fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+  fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+  fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+  for (i = 0; i < self->sup_n_waits; i++) {
+    
+  }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_source_add_prepoll(su_port_t *port,
+			su_root_t *root, 
+			su_prepoll_f *callback, 
+			su_prepoll_magic_t *magic)
+{
+#if 0
+  if (port->sup_prepoll)
+    return -1;
+
+  port->sup_prepoll = callback;
+  port->sup_pp_magic = magic;
+  port->sup_pp_root = root;
+
+  return 0;
+#else
+  return -1;
+#endif
+}
+
+int su_source_remove_prepoll(su_port_t *port,
+			   su_root_t *root)
+{
+#if 0
+  if (port->sup_pp_root != root)
+    return -1;
+
+  port->sup_prepoll = NULL;
+  port->sup_pp_magic = NULL;
+  port->sup_pp_root = NULL;
+
+  return 0;
+#else
+  return -1;
+#endif
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_source_timers(su_port_t *self)
+{
+  return &self->sup_timers;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,517 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE su_source_test.c
+ *
+ * @brief Test program for glib and su root event loop integration.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P   su_root_t *
+#define SU_MSG_ARG_T    su_sockaddr_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+
+#include "sofia-sip/su_glib.h"
+
+struct pinger {
+  enum { PINGER = 1, PONGER = 2 } const sort;
+  char const *  name;
+  unsigned      running : 1;
+  unsigned      : 0;
+  su_root_t    *root;
+  su_socket_t   s;
+  su_timer_t   *t;
+  int           id;
+  int           rindex;
+  su_time_t     when;
+  su_sockaddr_t addr;
+  double        rtt_total;
+  int           rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+GMainLoop *global_gmainloop = NULL;
+
+static su_socket_t udpsocket(void) 
+{
+  su_socket_t s;
+  su_sockaddr_t su = { 0 };
+  socklen_t sulen = sizeof(su);
+  char nbuf[64];
+
+  su.su_family = opt_family;
+
+  su_getlocalip(&su);
+
+  s = su_socket(su.su_family, SOCK_DGRAM, 0);
+  if (s == INVALID_SOCKET) {
+    su_perror("udpsocket: socket");
+    exit(1);
+  }
+
+  if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+    su_perror("udpsocket: bind");
+    exit(1);
+  }
+
+  if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+    su_perror("udpsocket: getsockname");
+    exit(1); 
+  }
+
+  if (opt_verbatim)
+    printf("udpsocket: using address [%s]:%u\n",
+	   inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port));
+
+  return s;
+}
+
+static char *snow(su_time_t now)
+{
+  static char buf[24];
+
+  su_time_print(buf, sizeof(buf), &now);
+
+  return buf;
+}
+
+void 
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PINGER);
+
+  p->when = su_now();
+
+  snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+  if (sendto(p->s, buf, strlen(buf), 0, 
+	     &p->addr.su_sa, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_ping: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  struct sockaddr * const susa = &su.su_sa;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+  double rtt;
+
+  assert(p0 == p);
+  assert(p->sort == PINGER);
+
+  rtt = su_time_diff(now, p->when);
+
+  p->rtt_total += rtt, p->rtt_n++;
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+  if (n < 0) {
+	  su_perror("do_rtt: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+  do_ping(p, p->t, NULL);
+
+  return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PONGER);
+
+  p->id = 0;
+
+  snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+  if (sendto(p->s, buf, strlen(buf), 0, 
+	     &p->addr.su_sa, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_pong: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+
+  assert(p0 == p);
+  assert(p->sort == PONGER);
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+  if (n < 0) {
+	  su_perror("do_recv: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, snow(now));
+
+  fflush(stdout);
+
+#if 0
+  if (p->id)
+    puts("do_recv: already a pending reply");
+
+  if (su_timer_set(p->t, do_pong, p) < 0) {
+    fprintf(stderr, "do_recv: su_timer_set() error\n");
+    return 0;
+  }
+
+  p->id = 1;
+#else
+  do_pong(p, p->t, NULL);
+#endif
+
+  return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+  g_assert(global_gmainloop);
+  if (opt_verbatim)
+    printf("do_exit at %s\n", snow(su_now()));
+  g_main_loop_quit(global_gmainloop);
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+  su_wait_t w;
+  su_socket_t s;
+  long interval;
+  su_timer_t *t;
+  su_wakeup_f f;
+  int index, index0;
+
+  switch (p->sort) {
+  case PINGER: f = do_rtt;  interval = 200; break;
+  case PONGER: f = do_recv; interval = 40;  break;
+  default:
+    return SU_FAILURE;
+  }
+
+  /* Create a sockets,  */
+  s = udpsocket();
+  if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR)
+    su_perror("su_wait_create"), exit(1);
+
+  p->s = s;
+  p->t = t = su_timer_create(su_root_task(root), interval);
+  if (t == NULL) {
+    su_perror("su_timer_create");
+    return SU_FAILURE;
+  }
+
+  index0 = su_root_register(root, &w, f, p, 0);
+  if (index0 == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+
+  index = su_root_register(root, &w, f, p, 0);
+  if (index == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+
+  su_root_deregister(root, index0);
+
+  p->rindex = index;
+
+  return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+  if (opt_verbatim)
+    printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+  su_root_deregister(root, p->rindex);
+  su_timer_destroy(p->t), p->t = NULL;
+  p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_ping: %s\n", p->name);
+
+  p->addr = *arg;
+  p->id = 1;
+  su_timer_set_at(p->t, do_ping, p, su_now());
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_pong: %s\n", p->name);
+
+  p->addr = *arg;
+
+  if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_create failed!\n");
+  }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  if (opt_verbatim)
+    printf("init_ping: %s\n", p->name);
+
+  if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_reply failed!\n");
+  }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+  exit(1);
+}
+
+void
+time_test(void)
+{
+  su_time_t now = su_now(), then = now;
+  su_duration_t t1, t2;
+  su_duration_t us;
+
+  for (us = 0; us < 1000000; us += 300) {
+    then.tv_sec = now.tv_sec;
+    if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+      then.tv_usec -= 1000000, then.tv_sec++;
+    t1 = su_duration(now, then);
+    t2 = su_duration(then, now);
+    assert(t1 == -t2);
+  }
+
+  if (opt_verbatim)
+    printf("time_test: passed\n");
+}
+
+char const name[] = "su_test";
+
+void
+usage(int exitcode)
+{
+  fprintf(stderr, "usage: %s [-6vs] [pid]\n", name);
+  exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives, 
+ *                  then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ *                  waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+  su_msg_r start_msg = SU_MSG_R_INIT;
+  su_timer_t *t;
+  unsigned long sleeppid = 0;
+
+  struct pinger 
+    pinger = { PINGER, "ping", 1 }, 
+    ponger = { PONGER, "pong", 1 };
+
+  char *argv0 = argv[0];
+
+  while (argv[1]) {
+    if (strcmp(argv[1], "-v") == 0) {
+      opt_verbatim = 1;
+      argv++;
+    }
+#if SU_HAVE_IN6
+    else if (strcmp(argv[1], "-6") == 0) {
+      opt_family = AF_INET6;
+      argv++;
+    }
+#endif
+    else if (strcmp(argv[1], "-s") == 0) {
+      opt_singlethread = 1;
+      argv++;
+    }
+    else if (strlen(argv[1]) == strspn(argv[1], "0123456789")) {
+      sleeppid = strtoul(argv[1], NULL, 10);
+      argv++;
+    }
+    else {
+      usage(1);
+    }
+  }
+
+  signal(SIGTERM, term);
+
+  su_init(); atexit(su_deinit);
+
+  time_test();
+
+  global_gmainloop = g_main_loop_new(NULL, FALSE);
+  g_assert(global_gmainloop);
+  
+  root = su_glib_root_create(NULL); 
+
+  if (!root) perror("su_root_glib_create"), exit(1);
+  
+  if (!g_source_attach(su_glib_root_gsource(root), g_main_loop_get_context(global_gmainloop))) 
+    perror("g_source_attach"), exit(1);
+  
+  su_root_threading(root, 0 && !opt_singlethread);
+
+  if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1);
+  if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1); 
+
+  /* Test timer, exiting after 200 milliseconds */
+  t = su_timer_create(su_root_task(root), 200L);
+  if (t == NULL)
+    su_perror("su_timer_create"), exit(1);
+  su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+  su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong), 
+		init_ping, 0);
+  su_msg_send(start_msg);
+
+  g_main_loop_run(global_gmainloop);
+
+  su_clone_wait(root, ping);
+  su_clone_wait(root, pong);
+
+  su_timer_destroy(t);
+
+  if (pinger.rtt_n) {
+    printf("%s executed %u pings in %g, mean rtt=%g sec\n", name, 
+	   pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+  }
+  su_root_destroy(root);
+
+  g_main_loop_unref(global_gmainloop), global_gmainloop = NULL;
+
+  if (opt_verbatim)
+    printf("%s exiting\n", argv0); 
+
+#ifndef HAVE_WIN32
+   if (sleeppid)
+     kill(sleeppid, SIGTERM);
+#endif
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,415 @@
+2006-09-26  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua interface v2 frozen (2:0:2) for the 1.12.2 release
+
+2006-08-30  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* nua: added tag nutag_refer_with_id.
+
+2006-08-28  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua interface v2 opened to development, version to 2:0:2.
+
+2006-08-25  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added urltag_scan().
+
+2006-08-23  Pekka Pessi  <Pekka.Pessi at nokia.com>
+	
+	* nta.c, nta.h: added nta_leg_make_replaces(), nta_leg_by_replaces().
+	
+	* nua: event watcher (nua_subscribe, nua_watcher) now tries to re-establish
+	  subscription if the subscription was terminated with reason "deactivated" or
+	  "probation". Likewise, if SUBSCRIBE was returned a suitable error response
+	  with Retry-After header, nua tries to re-establish subscription after
+	  given interval.
+
+2006-07-27  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua interface v1 frozen (1.12.1), version to 1:0:1.
+
+2006-06-16  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua interface v0 frozen (1.12.0), version to 0:0:0.
+
+2005-11-28  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* <SUBDIRS>/Doxyfile: Fixed the use of doxytags. Now
+	a separate 'doxytags_MODNAME' file is created for each
+	module.
+	
+2005-11-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* <SUBDIRS>/Makefile.am: Changed to use the 'include_sofia_HEADERS' 
+	variable for listing public library headers. The variable
+	is defined in the top-level configure.ac.
+	
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Always including stun library.
+
+    M ./libsofia-sip-ua/Makefile.am -6 +3
+
+  * Added rule to make missing module libraries in libsofia-sip-ua/sofia.am
+
+    M ./libsofia-sip-ua/sofia.am -1 +6
+
+  * Added LDFLAG -static to all test programs in their Makefile.am
+
+    M ./libsofia-sip-ua/bnf/Makefile.am -1 +1
+    M ./libsofia-sip-ua/http/Makefile.am -2 +2
+    M ./libsofia-sip-ua/ipt/Makefile.am -1 +2
+    M ./libsofia-sip-ua/iptsec/Makefile.am +2
+    M ./libsofia-sip-ua/msg/Makefile.am -2 +2
+    M ./libsofia-sip-ua/nta/Makefile.am -1 +1
+    M ./libsofia-sip-ua/nth/Makefile.am +2
+    M ./libsofia-sip-ua/nua/Makefile.am +2
+    M ./libsofia-sip-ua/sdp/Makefile.am +3
+    M ./libsofia-sip-ua/sip/Makefile.am +4
+    M ./libsofia-sip-ua/soa/Makefile.am +2
+    M ./libsofia-sip-ua/sresolv/Makefile.am -2 +2
+    M ./libsofia-sip-ua/stun/Makefile.am -6 +1
+
+2005-10-14  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	  * Shell syntax exercise. 
+
+	    M ./autogen.sh -4 +4
+
+2005-10-13  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* <SUBDIRS>/Makefile.am: fixed COVERAGE_INPUT.
+
+2005-10-13  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* <SUBDIRS>/Makefile.am: Build all submodules as proper shared 
+	libraries (noinst_LTLIBRARIES). Fixes sf.net:#1264030.
+
+2005-09-09  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* darcs changes --from-tag pessi-darcs-1:
+
+	Thu Sep  8 21:50:24 EEST 2005  Pekka.Pessi at nokia.com
+	  * There is no separate TLS test anymore.
+
+	    M ./tport/Makefile.am -1 +1
+
+	Thu Sep  8 21:36:46 EEST 2005  Pekka.Pessi at nokia.com
+	  * Logging.
+
+	    M ./nua/nua_stack.c -4 +2
+
+	Thu Sep  8 21:36:39 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added tests for tport_convert_addr.
+
+	    M ./tport/tport_test.c +22
+
+	Thu Sep  8 21:36:27 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed receiving empty SigComp message.
+
+	    M ./tport/tport.c +7
+
+	Thu Sep  8 21:32:48 EEST 2005  Pekka.Pessi at nokia.com
+	  * Updated ChangeLogs.
+
+	    M ./nta/ChangeLog -2 +10
+
+	Thu Sep  8 21:32:37 EEST 2005  Pekka.Pessi at nokia.com
+	  * Updated ChangeLog.
+
+	    M ./iptsec/ChangeLog +11
+
+	Thu Sep  8 21:31:16 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added more tests.
+
+	    M ./nta/nta.c -2 +2
+	    M ./nta/nta_test.c -2 +44
+
+	Thu Sep  8 21:30:19 EEST 2005  Pekka.Pessi at nokia.com
+	  * Handling changes in alias list.
+
+	    M ./nta/nta.c -9 +22
+	    M ./nta/nta_test.c +1
+
+	Thu Sep  8 21:18:47 EEST 2005  Pekka.Pessi at nokia.com
+	  * Gcc4 fixes.
+
+	    M ./ipt/base64.c -1 +1
+	    M ./iptsec/auth_module.c -1 +1
+	    M ./iptsec/auth_plugin_delayed.c +4
+	    M ./nua/nua_stack.c -1 +1
+	    M ./nua/nua_tag.c -1 +1
+	    M ./nua/nua_tag.h -5 +5
+	    M ./su/htable2.h -1 +1
+	    M ./su/su.c -1 +1
+	    M ./tport/tport.c -7 +7
+
+	Thu Sep  8 21:16:39 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added tests for tport_shutdown(). Do not assert() on invalid
+	    input.
+
+	    M ./tport/tport.c -2
+	    M ./tport/tport_test.c +5
+
+	Thu Sep  8 21:13:18 EEST 2005  Pekka.Pessi at nokia.com
+	  * Log when password file is read.
+
+	    M ./iptsec/auth_module.c +3
+
+	Thu Sep  8 21:12:49 EEST 2005  Pekka.Pessi at nokia.com
+	  * Allow empty allow list.
+
+	    M ./iptsec/auth_module.c -1 +1
+
+	Thu Sep  8 21:12:26 EEST 2005  Pekka.Pessi at nokia.com
+	  * Use unsigned as auth_htable_t hash type.
+
+	    M ./iptsec/auth_module.c -5 +5
+
+	Thu Sep  8 21:10:23 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added auth_digest_credentials(). 
+	  Use opaque to match Authorization header.
+
+	    M ./iptsec/auth_digest_test.c -2 +3
+	    M ./iptsec/auth_module.c -1 +78
+	    M ./iptsec/auth_plugin.h +4
+
+	Thu Sep  8 21:07:57 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed gcc4 problems with tag classes.
+
+	    M ./http/http_tag.h.in +3
+	    M ./msg/msg_mime_protos.h.in +3
+	    M ./sdp/sdp_tag.h +3
+	    M ./su/su_tag_class.h +12
+	    M ./su/su_tag_inline.h -1 +1
+	    M ./url/url_tag_class.h +3
+
+	Thu Sep  8 21:06:22 EEST 2005  Pekka.Pessi at nokia.com
+	  * Added sip_security_client_select().
+
+	    M ./sip/sip_util.c -37 +14
+	    M ./sip/sip_util.h +4
+
+	Thu Sep  8 19:32:19 EEST 2005  Pekka.Pessi at nokia.com
+	  * Not using su_home_deinit() to destroy homes that are not
+	    initialized.
+
+	    M ./nth/nth_server.c -3 +2
+	    M ./nua/nua.c -2 +1
+	    M ./su/su_vector.c -2 +1
+
+	Thu Sep  8 19:06:31 EEST 2005  Pekka.Pessi at nokia.com
+	  * Moved function types to msg_types.h.
+
+	    M ./msg/msg_header.h -7
+	    M ./msg/msg_types.h +9
+
+	Thu Sep  8 18:35:12 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed su_clone_start() return value.
+
+	    M ./su/su_root.c -1 +1
+
+	Thu Sep  8 18:34:26 EEST 2005  Pekka.Pessi at nokia.com
+	  * Removed SIP_DLL_VAR.
+
+	    M ./sip/sip_dll.h -7
+
+	Thu Sep  8 18:29:27 EEST 2005  Pekka.Pessi at nokia.com
+	  * Avoid __func__.
+
+	    M ./sresolv/sresolv.c -3 +4
+
+	Thu Sep  8 18:29:09 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fix includes.
+
+	    M ./nta/nta.c -2 +1
+	    M ./sresolv/sresolv.c -4 +7
+	    M ./sresolv/sresolv.h -1 +1
+
+	Thu Sep  8 18:26:35 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using autoconf to figure out 64-bit types. Avoid off_t and
+	    64-bit constants.
+
+	    M ../configure.ac +6
+	    M ./nta/sl_read_payload.c -1 +1
+	    M ./nua/nua_stack.c -6 +5
+	    M ./sdp/sdp_parse.c -3 +2
+	    M ./sdp/sdp_print.c -5 +5
+	    M ./sip/validator.c -18 +18
+	    M ./soa/soa.c -3 +4
+	    M ./su/su_time.c -1 +1
+	    M ./su/tstdef.h -3 +3
+
+	Thu Sep  8 18:17:58 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using RETSIGTYPE.
+
+	    M ../configure.ac -3 +4
+	    M ./nth/http-server.c -2 +2
+	    M ./soa/test_soa.c -1 +3
+	    M ./su/su_test.c -1 +1
+	    M ./su/su_timer_test.c -1 +1
+
+	Thu Sep  8 18:13:35 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed macro expansion problem with VC6
+
+	    M ./nta/nta_test.c -2 +2
+
+	Thu Sep  8 18:12:45 EEST 2005  Pekka.Pessi at nokia.com
+	  * Compile without sresolv, too.
+
+	    M ./nta/nta.c -3 +5
+
+	Thu Sep  8 18:12:16 EEST 2005  Pekka.Pessi at nokia.com
+	  * Fixed const/non-const problems with gcc4/vc6.
+
+	    M ./msg/msg_mime.c -6 +6
+	    M ./msg/msg_parser.c -1 +1
+	    M ./nta/nta.c -4 +4
+	    M ./sip/sip_basic.c -1 +1
+	    M ./sip/sip_security.c -1 +1
+	    M ./sip/sip_util.c -2 +2
+	    M ./su/htable.h -10 +10
+
+	Thu Sep  8 18:06:04 EEST 2005  Pekka.Pessi at nokia.com
+	  * Moved msg_hclass_t definition into msg_types.h
+
+	    M ./msg/msg_header.h -37
+	    M ./msg/msg_types.h +40
+
+	Thu Sep  8 18:05:32 EEST 2005  Pekka.Pessi at nokia.com
+	  * Silenced vc6 warning.
+
+	    M ./iptsec/auth_module.c -1 +1
+
+	Thu Sep  8 18:05:07 EEST 2005  Pekka.Pessi at nokia.com
+	  * Not using __func__.
+
+	    M ./iptsec/auth_digest.c -2 +2
+
+	Thu Sep  8 18:04:38 EEST 2005  Pekka.Pessi at nokia.com
+	  * Silenced gcc4 warning.
+
+	    M ./tport/tport.c -1 +1
+
+	Thu Sep  8 18:04:16 EEST 2005  Pekka.Pessi at nokia.com
+	  * Better following autoconf macros
+
+	    M ./tport/tport.c +9
+
+	Thu Sep  8 18:02:53 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using TPORT_DLL.
+
+	    M ./tport/tport.h -10 +19
+
+	Thu Sep  8 18:01:58 EEST 2005  Pekka.Pessi at nokia.com
+	  * Not using IS_EXCLUDED_MASK.
+
+	    M ./url/url.c -1 +6
+
+	Thu Sep  8 18:01:17 EEST 2005  Pekka.Pessi at nokia.com
+	  * Explicitly using <errno.h> 
+
+	    M ./msg/msg.c +2
+	    M ./msg/msg_mclass.c +1
+	    M ./msg/msg_mime.c +1
+	    M ./msg/msg_parser.c +1
+	    M ./nta/nta.c +3
+	    M ./nth/nth_client.c +2
+	    M ./nth/nth_server.c +2
+	    M ./su/su_port.c +1
+	    M ./su/su_proxy.c +1
+	    M ./su/su_root.c +1
+
+	Thu Sep  8 17:54:28 EEST 2005  Pekka.Pessi at nokia.com
+	  * Using http_off_t instead of off_t.
+
+	    M ./http/http_basic.c -5 +5
+
+	Thu Sep  8 18:56:58 EEST 2005  Pekka.Pessi at nokia.com
+	  * Not using su_home_deinit().
+
+	    M ./nua/nua.c -3 +2
+
+	Thu Sep  8 16:40:30 EEST 2005  Pekka.Pessi at nokia.com
+	  * Adding soa_asynch.c
+
+	    A ./soa/soa_asynch.c
+
+	Thu Sep  8 03:23:00 EEST 2005  Pekka.Pessi at nokia.com
+	  * stab 2 at soa
+	  Added more functionality to soa. Stab at asynchronous API, too.
+
+	    M ./soa/Makefile.am -1 +2
+	    M ./soa/soa.c -146 +564
+	    M ./soa/soa.h -5 +24
+	    M ./soa/soa_add.h -2 +5
+	    M ./soa/soa_session.h -21 +48
+	    M ./soa/soa_static.c -30 +89
+	    M ./soa/soa_tag.c +64
+	    M ./soa/test_soa.c -7 +224
+	    M ./m4/sac-su2.m4 -1 +1
+
+	Thu Sep  8 03:12:28 EEST 2005  Pekka.Pessi at nokia.com
+	  * really run sdp tests
+	  Now really running SDP tests.
+
+	    M ./sdp/run-tests -1 +1
+
+	Thu Sep  8 03:11:35 EEST 2005  Pekka.Pessi at nokia.com
+	  * su_home_new and su_home_unref
+	  Added su_home_new() and su_home_unref(). 
+	  
+	  Fixed su_home_mutex_lock() and su_home_mutex_unlock().
+	  
+	  Slightly changed semantics of su_home_clone() versus
+	  su_home_threadsafe().
+
+	    M ./http/http_test.c -6 +6
+	    M ./msg/msg_test.c -2 +2
+	    M ./su/htable_test.c +3
+	    M ./su/su_alloc.c -173 +337
+	    M ./su/su_alloc.h -10 +18
+	    M ./su/su_alloc_lock.c -8 +31
+	    M ./su/su_alloc_test.c -5 +12
+
+	Thu Sep  8 03:07:17 EEST 2005  Pekka.Pessi at nokia.com
+	  * More liberal sdp parsing for config files.
+	  Be more liberal when parsing config files 
+	  (do not require v=, accept -1 as len argument).
+
+	    M ./sdp/sdp_parse.c -9 +25
+
+	Thu Sep  8 01:05:02 EEST 2005  Pekka.Pessi at nokia.com
+	  * su_msg_is_non_null
+	  Added su_msg_is_non_null().
+
+	    M ./su/su_wait.h +11
+
+	Thu Sep  8 01:03:31 EEST 2005  Pekka.Pessi at nokia.com
+	  * sdp_parser_home
+	  Added sdp_parser_home()
+
+	    M ./sdp/sdp.h +2
+	    M ./sdp/sdp_parse.c +10
+	
+2005-09-08  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am: Workaround for automake bug related to adding
+	custom targets to RECURSIVE_TARGETS.
+
+2005-08-25  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am: soa depends on ipt and sip, so has to
+	be after them in SUBDIRS.
+
+2005-08-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Fixed BEGIN()/END() pairs in test programs. 
+
+2005-08-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added soa module.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* libsofia-sip-ua created.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,104 @@
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+AUTOMAKE_OPTIONS = foreign
+
+# note: order does matter in the subdir list
+SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
+	  tport http nta nea iptsec nth nua
+DIST_SUBDIRS = $(SUBDIRS) docs
+
+EXTRA_DIST = sofia.am
+DOXYGEN = doxygen
+
+lib_LTLIBRARIES = libsofia-sip-ua.la
+
+libsofia_sip_ua_la_SOURCES = 
+libsofia_sip_ua_la_LIBADD = 	bnf/libbnf.la \
+				features/libfeatures.la \
+				ipt/libipt.la \
+				iptsec/libiptsec.la \
+				msg/libmsg.la \
+				nea/libnea.la \
+				nta/libnta.la \
+				nth/libnth.la \
+				nua/libnua.la \
+				http/libhttp.la \
+				sdp/libsdp.la \
+				sip/libsip.la \
+				soa/libsoa.la \
+				sresolv/libsresolv.la \
+				su/libsu.la \
+				stun/libstun.la \
+				tport/libtport.la \
+				url/liburl.la
+# set the libtool version info version:revision:age for libsofia-sip-ua
+# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
+libsofia_sip_ua_la_LDFLAGS = \
+	-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
+
+if ENABLE_COVERAGE
+COVERAGE_RECURSIVE = coverage-recursive
+coverage: $(COVERAGE_RECURSIVE)
+endif
+
+all-recursive: built-sources-recursive
+built-sources: built-sources-recursive 
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $@ in $$subdir"; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+	done;
+
+doxygen: built-sources
+	@echo Generating empty doxytags
+	cd ${srcdir}; \
+	mkdir -p docs/html ; \
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile || continue ; \
+	  if ! test -r docs/$$d.doxytags ; then \
+	    echo '<?xml version="1.0"?><tagfile/>' > docs/$$d.doxytags ; \
+	  else \
+	    sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	    mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+          fi ; \
+	done
+	@cd ${srcdir} ;\
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} first time in $$d \
+          && ${DOXYGEN} 2>&1 \
+	  | egrep -v -i -e 'Warning: (unsupported (xml/)?html tag|unable to resolve reference|could not be resolved)' \
+          ; popd > /dev/null ; \
+	  test -r docs/$$d.doxytags && \
+	  sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	  mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+	done 
+	@cd ${srcdir} ;\
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} in second time in $$d \
+          && ${DOXYGEN} 2>&1 \
+	   | egrep -v -i -e 'Warning: Unsupported (xml/)?html tag' \
+          ; popd > /dev/null ; \
+	  test -r docs/$$d.doxytags && \
+	  sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	  mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+	done 
+	cd ${srcdir}/docs/html && ../hide_emails.sh
+
+.PHONY: built-sources built-sources-am empty-doxytags doxygen 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,679 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+SOURCES = $(libsofia_sip_ua_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = libsofia-sip-ua
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libsofia_sip_ua_la_DEPENDENCIES = bnf/libbnf.la \
+	features/libfeatures.la ipt/libipt.la iptsec/libiptsec.la \
+	msg/libmsg.la nea/libnea.la nta/libnta.la nth/libnth.la \
+	nua/libnua.la http/libhttp.la sdp/libsdp.la sip/libsip.la \
+	soa/libsoa.la sresolv/libsresolv.la su/libsu.la \
+	stun/libstun.la tport/libtport.la url/liburl.la
+am_libsofia_sip_ua_la_OBJECTS =
+libsofia_sip_ua_la_OBJECTS = $(am_libsofia_sip_ua_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsofia_sip_ua_la_SOURCES)
+DIST_SOURCES = $(libsofia_sip_ua_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-exec-recursive install-info-recursive \
+	install-recursive installcheck-recursive installdirs-recursive \
+	pdf-recursive ps-recursive uninstall-info-recursive \
+	uninstall-recursive
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = doxygen
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AUTOMAKE_OPTIONS = foreign
+
+# note: order does matter in the subdir list
+SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
+	  tport http nta nea iptsec nth nua
+
+DIST_SUBDIRS = $(SUBDIRS) docs
+EXTRA_DIST = sofia.am
+lib_LTLIBRARIES = libsofia-sip-ua.la
+libsofia_sip_ua_la_SOURCES = 
+libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \
+				features/libfeatures.la \
+				ipt/libipt.la \
+				iptsec/libiptsec.la \
+				msg/libmsg.la \
+				nea/libnea.la \
+				nta/libnta.la \
+				nth/libnth.la \
+				nua/libnua.la \
+				http/libhttp.la \
+				sdp/libsdp.la \
+				sip/libsip.la \
+				soa/libsoa.la \
+				sresolv/libsresolv.la \
+				su/libsu.la \
+				stun/libstun.la \
+				tport/libtport.la \
+				url/liburl.la
+
+# set the libtool version info version:revision:age for libsofia-sip-ua
+# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
+libsofia_sip_ua_la_LDFLAGS = \
+	-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
+
+ at ENABLE_COVERAGE_TRUE@COVERAGE_RECURSIVE = coverage-recursive
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  libsofia-sip-ua/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  libsofia-sip-ua/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    f=$(am__strip_dir) \
+	    echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+	    $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  p=$(am__strip_dir) \
+	  echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+	  $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsofia-sip-ua.la: $(libsofia_sip_ua_la_OBJECTS) $(libsofia_sip_ua_la_DEPENDENCIES) 
+	$(LINK) -rpath $(libdir) $(libsofia_sip_ua_la_LDFLAGS) $(libsofia_sip_ua_la_OBJECTS) $(libsofia_sip_ua_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $$MAKEFLAGS; amf=$$2; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(mkdir_p) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	    distdir=`$(am__cd) $(distdir) && pwd`; \
+	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+	    (cd $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$top_distdir" \
+	        distdir="$$distdir/$$subdir" \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+	clean clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-recursive ctags ctags-recursive distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-recursive distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-libLTLIBRARIES install-man \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	maintainer-clean-recursive mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+	pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+	uninstall-info-am uninstall-libLTLIBRARIES
+
+ at ENABLE_COVERAGE_TRUE@coverage: $(COVERAGE_RECURSIVE)
+
+all-recursive: built-sources-recursive
+built-sources: built-sources-recursive 
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $@ in $$subdir"; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+	done;
+
+doxygen: built-sources
+	@echo Generating empty doxytags
+	cd ${srcdir}; \
+	mkdir -p docs/html ; \
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile || continue ; \
+	  if ! test -r docs/$$d.doxytags ; then \
+	    echo '<?xml version="1.0"?><tagfile/>' > docs/$$d.doxytags ; \
+	  else \
+	    sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	    mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+          fi ; \
+	done
+	@cd ${srcdir} ;\
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} first time in $$d \
+          && ${DOXYGEN} 2>&1 \
+	  | egrep -v -i -e 'Warning: (unsupported (xml/)?html tag|unable to resolve reference|could not be resolved)' \
+          ; popd > /dev/null ; \
+	  test -r docs/$$d.doxytags && \
+	  sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	  mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+	done 
+	@cd ${srcdir} ;\
+	for d in $(DIST_SUBDIRS); do \
+	  test -r $$d/Doxyfile \
+	  && pushd $$d > /dev/null \
+	  && echo running ${DOXYGEN} in second time in $$d \
+          && ${DOXYGEN} 2>&1 \
+	   | egrep -v -i -e 'Warning: Unsupported (xml/)?html tag' \
+          ; popd > /dev/null ; \
+	  test -r docs/$$d.doxytags && \
+	  sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+	    docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+	  mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+	done 
+	cd ${srcdir}/docs/html && ../hide_emails.sh
+
+.PHONY: built-sources built-sources-am empty-doxytags doxygen 
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2006-06-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip/hostdomain.h (host_is_local): Function added.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+PROJECT_NAME         = "bnf"
+OUTPUT_DIRECTORY     = ../docs/html/bnf
+
+INPUT 		     = bnf.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE     = ../docs/bnf.doxytags
+
+PREDEFINED += "static="
+
+MAX_INITIALIZER_LINES = 2

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,46 @@
+#
+# Makefile.am for bnf module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libbnf.la
+
+check_PROGRAMS = 	torture_bnf
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = sofia-sip/bnf.h sofia-sip/hostdomain.h
+
+libbnf_la_SOURCES = 	bnf.c
+
+COVERAGE_INPUT = 	$(libbnf_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD =			libbnf.la
+
+torture_bnf_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile bnf.docs
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_bnf
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,685 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for bnf module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libbnf_la_SOURCES) torture_bnf.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = torture_bnf$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/bnf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libbnf_la_LIBADD =
+am_libbnf_la_OBJECTS = bnf.lo
+libbnf_la_OBJECTS = $(am_libbnf_la_OBJECTS)
+torture_bnf_SOURCES = torture_bnf.c
+torture_bnf_OBJECTS = torture_bnf.$(OBJEXT)
+torture_bnf_LDADD = $(LDADD)
+torture_bnf_DEPENDENCIES = libbnf.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libbnf_la_SOURCES) torture_bnf.c
+DIST_SOURCES = $(libbnf_la_SOURCES) torture_bnf.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libbnf.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = sofia-sip/bnf.h sofia-sip/hostdomain.h
+libbnf_la_SOURCES = bnf.c
+COVERAGE_INPUT = $(libbnf_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libbnf.la
+torture_bnf_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile bnf.docs
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_bnf
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/bnf/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/bnf/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libbnf.la: $(libbnf_la_OBJECTS) $(libbnf_la_DEPENDENCIES) 
+	$(LINK)  $(libbnf_la_LDFLAGS) $(libbnf_la_OBJECTS) $(libbnf_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+torture_bnf$(EXEEXT): $(torture_bnf_OBJECTS) $(torture_bnf_DEPENDENCIES) 
+	@rm -f torture_bnf$(EXEEXT)
+	$(LINK) $(torture_bnf_LDFLAGS) $(torture_bnf_OBJECTS) $(torture_bnf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/bnf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_bnf.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,913 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE bnf.c
+ * @brief Character syntax table for HTTP-like protocols.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/bnf.h"
+
+#include <assert.h>
+
+#define ws    bnf_ws
+#define crlf  bnf_crlf
+#define alpha bnf_alpha
+#define digit bnf_mark|bnf_token0|bnf_safe
+#define sep   bnf_separator
+#define msep  bnf_mark|bnf_separator
+#define psep  bnf_param0|bnf_separator
+#define tok   bnf_token0
+#define mtok  bnf_mark|bnf_token0
+#define smtok bnf_mark|bnf_token0|bnf_safe
+#define safe  bnf_safe
+
+/** Table for determining class of a character */
+unsigned char const _bnf_table[256] = {
+  0,     0,     0,     0,     0,     0,     0,     0,
+  0,     ws,    crlf,  0,     0,     crlf,  0,     0,
+  0,     0,     0,     0,     0,     0,     0,     0,
+  0,     0,     0,     0,     0,     0,     0,     0,
+  ws,    mtok,  sep,   0,     safe,  mtok,  0,     mtok,  /*  !"#$%&' */
+  msep,  msep,  mtok,  tok,   sep,   smtok, smtok, psep,  /* ()*+,-./ */
+  digit, digit, digit, digit, digit, digit, digit, digit, /* 01234567 */
+  digit, digit, psep,  sep,   sep,   sep,   sep,   sep,   /* 89:;<=>? */
+  sep,   alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* @ABCDEFG */
+  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* HIJKLMNO */
+  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* PQRSTUVW */
+  alpha, alpha, alpha, psep,  sep,   psep,  0,     smtok, /* XYZ[\]^_ */
+  tok,   alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* `abcdefg */
+  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* hijklmno */
+  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* pqrstuvw */
+  alpha, alpha, alpha, sep,   0,     sep,   mtok,  0,     /* xyz{|}~  */
+};
+
+
+#define BM(c, m00, m32, m64, m96)			   \
+  ((c < 64)						   \
+   ? ((c < 32)						   \
+      ? (m00 & (1 << (31 - c)))				   \
+      : (m32 & (1 << (63 - c))))			   \
+   : ((c < 96)						   \
+      ? (m64 & (1 << (95 - c)))				   \
+      : (m96 & (1 << (127 - c)))))
+
+/** Span of a token */
+size_t bnf_span_token(char const *s)
+{
+  char const *e = s;
+  unsigned const m32 = 0x4536FFC0U, m64 = 0x7FFFFFE1U, m96 = 0xFFFFFFE2U;
+
+  while (BM(*e, 0, m32, m64, m96))
+    e++;
+
+  return e - s;
+}
+
+/** Span of a token */
+size_t bnf_span_token4(char const *s)
+{
+  char const *e = s; 
+  while (_bnf_table[(unsigned char)(*e)] & bnf_token)
+    e++; 
+  return e - s; 
+}
+
+char * bnf_span_token_end(char const *s)
+{
+  return (char *)s;
+}
+
+/** Return length of decimal-octet */
+static inline int span_ip4_octet(char const *host)
+{
+  /*
+      decimal-octet =       DIGIT
+                            / DIGIT DIGIT
+                            / (("0"/"1") 2*(DIGIT))
+                            / ("2" ("0"/"1"/"2"/"3"/"4") DIGIT)
+                            / ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5"))
+  */
+
+  if (!IS_DIGIT(host[0]))
+    return 0;
+
+  /* DIGIT */
+  if (!IS_DIGIT(host[1]))
+    return 1;
+
+  if (host[0] == '2') {
+    /* ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5")) */
+    if (host[1] == '5' && host[2] >= '0' && host[2] <= '5')
+      return 3;
+
+    /* ("2" ("0"/"1"/"2"/"3"/"4") DIGIT) */
+    if (host[1] >= '0' && host[1] <= '4' &&
+	host[2] >= '0' && host[2] <= '9')
+      return 3;
+  }
+  else if (host[0] == '0' || host[0] == '1') {
+    if (IS_DIGIT(host[2]))
+      /* ("1" 2*(DIGIT)) ... or "0" 2*(DIGIT) */
+      return 3;
+  }
+
+  /* POS-DIGIT DIGIT */
+  return 2;
+}
+
+/** Return length of valid IP4 address */
+static
+int span_canonic_ip4_address(char const *host, int *return_canonize)
+{
+  int n, len, canonize = 0;
+
+  if (host == NULL)
+    return 0;
+
+  /* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet */
+  len = span_ip4_octet(host);
+  if (len == 0 || host[len] != '.')
+    return 0;
+  if (len > 1 && host[0] == '0')
+    canonize = 1;
+  n = len + 1;
+
+  len = span_ip4_octet(host + n);
+  if (len == 0 || host[n + len] != '.')
+    return 0;
+  if (len > 1 && host[n] == '0')
+    canonize = 1;
+  n += len + 1;
+
+  len = span_ip4_octet(host + n);
+  if (len == 0 || host[n + len] != '.')
+    return 0;
+  if (len > 1 && host[n] == '0')
+    canonize = 1;
+  n += len + 1;
+
+  len = span_ip4_octet(host + n);
+  if (len == 0 || IS_DIGIT(host[n + len]) || host[n + len] == '.')
+    return 0;
+  if (len > 1 && host[n] == '0')
+    canonize = 1;
+  n += len;
+
+  if (canonize && return_canonize)
+    *return_canonize = 1;
+
+  return n;
+}
+
+/** Return length of valid IP4 address.
+ *
+ * Note that we accept here up to two leading zeroes 
+ * which makes "dotted decimal" notation ambiguous:
+ * 127.000.000.001 is interpreted same as 127.0.0.1 
+ *
+ * Note that traditionally IP address octets starting
+ * with zero have been interpreted as octal:
+ * 172.055.055.001 has been same as 172.45.45.1
+ *
+ * @b However, we interpret them as @b decimal,
+ * 172.055.055.001 is same as 172.55.55.1.
+ */
+int span_ip4_address(char const *host)
+{
+  return span_canonic_ip4_address(host, NULL);
+}
+
+/** Scan and canonize a valid IP4 address. */
+int scan_ip4_address(char **inout_host)
+{
+  char *src = *inout_host, *dst = src;
+  issize_t n;
+  int canonize = 0;
+
+  n = span_canonic_ip4_address(src, &canonize);
+  if (n == 0)
+    return -1;
+
+  *inout_host += n;
+
+  if (!canonize)
+    return n;
+
+  for (;;) {
+    char c = *dst++ = *src++;
+
+    if (IS_DIGIT(*src)) {
+      if (canonize && c == '0')
+	dst--;
+      else if (c == '.')
+	canonize = 1;
+      else
+	canonize = 0;
+    }
+    else if (*src != '.') {
+      break;
+    }
+  }
+  *dst = '\0';
+
+  return n;
+}
+
+/** Return length of hex4 */
+static inline int span_hex4(char const *host)
+{
+  if (!IS_HEX(host[0]))
+    return 0;
+  if (!IS_HEX(host[1]))
+    return 1;
+  if (!IS_HEX(host[2]))
+    return 2;
+  if (!IS_HEX(host[3]))
+    return 3;
+  return 4;
+}
+
+/** Return length of valid IP6 address */
+static inline
+int span_canonic_ip6_address(char const *host,
+			     int *return_canonize,
+			     char *hexparts[9])
+{
+  int n = 0, len, hex4, doublecolon = 0, canonize = 0;
+
+  /*
+     IPv6address    =  hexpart [ ":" IPv4address ]
+     hexpart        =  hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+     hexseq         =  hex4 *( ":" hex4)
+     hex4           =  1*4HEXDIG
+
+     There is at most 8 hex4, 6 hex4 if IPv4address is included.
+  */
+
+  if (host == NULL)
+    return 0;
+
+  for (hex4 = 0; hex4 < 8; ) {
+    len = span_hex4(host + n);
+
+    if (return_canonize) {
+      if ((len > 1 && host[n + 1] == '0') || host[n] == '0')
+	canonize = 1;
+      if (hexparts)
+	hexparts[hex4 + doublecolon] = (char *)(host + n);
+    }
+
+    if (host[n + len] == ':') {
+      if (len != 0) {
+	hex4++;
+	n += len + 1;
+	if (!doublecolon && host[n] == ':') {
+	  if (return_canonize && hexparts) {
+	    hexparts[hex4] = (char *)(host + n - 1);
+	  }
+	  doublecolon++, n++;
+	}
+      }
+      else if (n == 0 && host[1] == ':') {
+	doublecolon++, n = 2;
+      }
+      else
+	break;
+    }
+    else if (host[n + len] == '.') {
+      len = span_canonic_ip4_address(host + n, return_canonize);
+
+      if (len == 0 || hex4 > 6 || !(doublecolon || hex4 == 6))
+	return 0;
+
+      if (canonize && return_canonize)
+	*return_canonize = 1;
+
+      return n + len;
+    }
+    else {
+      if (len != 0)
+	hex4++;
+      n += len;
+      break;
+    }
+  }
+
+  if (hex4 != 8 && !doublecolon)
+    return 0;
+
+  if (IS_HEX(host[n]) || host[n] == ':')
+    return 0;
+
+  if (canonize && return_canonize)
+    *return_canonize = canonize;
+
+  return n;
+}
+
+/** Canonize scanned IP6 address.
+ *
+ * @retval Length of canonized IP6 address.
+ */
+static inline
+int canonize_ip6_address(char *host, char *hexparts[9])
+{
+  char *dst, *hex, *ip4 = NULL;
+  int i, doublecolon, j, maxparts, maxspan, span, len;
+
+  char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+  /*
+    Canonic representation has fewest chars
+     - except for mapped/compatible IP4 addresses, like
+       ::15.21.117.42 or ::ffff:15.21.117.42 which have non-canonic forms of
+       ::f15:752a or ::ffff:f15:752a
+    => we just canonize hexparts and ip4part separately
+       and select optimal place for doublecolon
+       (with expection of ::1 and ::, which are canonized)
+  */
+  for (i = 0, doublecolon = -1; i < 9; i++) {
+    hex = hexparts[i];
+    if (!hex)
+      break;
+    if (hex[0] == ':')
+      doublecolon = i;
+    while (hex[0] == '0' && IS_HEX(hex[1]))
+      hex++;
+    hexparts[i] = hex;
+  }
+  assert(i > 0);
+
+  if (hexparts[i - 1][span_hex4(hexparts[i - 1])] == '.')
+    ip4 = hexparts[--i];
+
+  maxparts = ip4 ? 6 : 8;
+
+  if (doublecolon >= 0) {
+    /* Order at most 8 (or 6) hexparts */
+    assert(i <= maxparts + 1);
+
+    if (i == maxparts + 1) {
+      /* There is an extra doublecolon */
+      for (j = doublecolon; j <= i; j++)
+	hexparts[j] = hexparts[j + 1];
+      i--;
+    }
+    else {
+      for (j = maxparts; i > doublecolon + 1; )
+	hexparts[--j] = hexparts[--i];
+      for (;j > doublecolon;)
+	hexparts[--j] = "0:";
+      i = maxparts;
+    }
+  }
+  assert(i == maxparts);
+
+  /* Scan for optimal place for "::" */
+  for (i = 0, maxspan = 0, span = 0, doublecolon = 0; i < maxparts; i++) {
+    if (hexparts[i][0] == '0')
+      span++;
+    else if (span > maxspan)
+      doublecolon = i - span, maxspan = span, span = 0;
+    else
+      span = 0;
+  }
+
+  if (span > maxspan)
+    doublecolon = i - span, maxspan = span;
+
+  dst = buf;
+
+  for (i = 0; i < maxparts; i++) {
+    if (i == doublecolon)
+      hex = i == 0 ? "::" : ":", len = 1;
+    else if (i > doublecolon && i < doublecolon + maxspan)
+      continue;
+    else
+      hex = hexparts[i], len = span_hex4(hex);
+    if (hex[len] == ':')
+      len++;
+    memcpy(dst, hex, len);
+    dst += len;
+  }
+
+  if (ip4) {
+    hex = ip4;
+    len = scan_ip4_address(&hex); assert(len > 0);
+
+    /* Canonize :: and ::1 */
+    if (doublecolon == 0 && maxspan == 6) {
+      if (len == 7 && strncmp(ip4, "0.0.0.0", len) == 0)
+	ip4 = "", len = 0;
+      else if (len == 7 && strncmp(ip4, "0.0.0.1", len) == 0)
+	ip4 = "1", len = 1;
+    }
+
+    memcpy(dst, ip4, len);
+    dst += len;
+  }
+
+  len = dst - buf;
+
+  memcpy(host, buf, len);
+
+  return len;
+}
+
+/** Return length of valid IP6 address */
+int span_ip6_address(char const *host)
+{
+  return span_canonic_ip6_address(host, NULL, NULL);
+}
+
+/** Scan and canonize valid IP6 address.
+ *
+ * @param inout_host input pointer to string to scan
+ *                   output pointer to first character after valid IP6 address
+ *
+ * @retval Length of valid IP6 address or -1 upon an error.
+ *
+ * @note Scanned IP6 is not always NUL-terminated.
+ */
+int scan_ip6_address(char **inout_host)
+{
+  int n, canonize = 0;
+  char *host = *inout_host;
+  char *hexparts[9] = { NULL };
+
+  n = span_canonic_ip6_address(host, &canonize, hexparts);
+
+  if (n == 0)
+    return -1;
+
+  *inout_host += n;
+
+  if (canonize) {
+    int len = canonize_ip6_address(host, hexparts);
+    assert(len <= n);
+    if (len < n)
+      host[len] = '\0';
+  }
+
+  return n;
+}
+
+/** Return length of valid IP6 reference. */
+int span_ip6_reference(char const *host)
+{
+  /* IPv6reference  =  "[" IPv6address "]" */
+
+  if (host && host[0] == '[') {
+    int n = span_ip6_address(host + 1);
+    if (n > 0 && host[n + 1] == ']')
+      return n + 2;
+  }
+
+  return 0;
+}
+
+/** Scan valid IP6 reference. */
+int scan_ip6_reference(char **inout_host)
+{
+  int n, canonize = 0;
+  char *host = *inout_host;
+  char *hexparts[9] = { NULL };
+
+  /* IPv6reference  =  "[" IPv6address "]" */
+
+  if (host == NULL ||
+      host[0] != '[' ||
+      (n = span_canonic_ip6_address(host + 1, &canonize, hexparts)) == 0 ||
+      host[n + 1] != ']')
+    return -1;
+
+  *inout_host += n + 2;
+
+  if (canonize) {
+    int len = canonize_ip6_address(host + 1, hexparts);
+
+    assert(len <= n);
+
+    host[len + 1] = ']';
+    if (len + 2 < n + 2)
+      host[len + 2] = '\0';
+  }
+
+  return n + 2;
+}
+
+/** Return length of valid IP4 or IP6 address. */
+int span_ip_address(char const *host)
+{
+  if (!host || !host[0])
+    return 0;
+
+  /* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet */
+  if (IS_DIGIT(host[0])) {
+    int n = span_ip4_address(host);
+    if (n)
+      return n;
+  }
+
+  if (host[0] == '[')
+    return span_ip6_reference(host);
+  else
+    return span_ip6_address(host);
+}
+
+/** Scan valid IP4/IP6 address. */
+int scan_ip_address(char **inout_host)
+{
+  char *host = *inout_host;
+
+  if (host == NULL)
+    return -1;
+
+  /* IPv6reference  =  "[" IPv6address "]" */
+  if (host[0] == '[')
+    return scan_ip6_reference(inout_host);
+
+  if (IS_DIGIT(host[0])) {
+    int n = scan_ip4_address(inout_host);
+    if (n > 0)
+      return n;
+  }
+
+  return scan_ip6_address(inout_host);
+}
+
+/** Return length of a valid domain label */
+static inline
+size_t span_domain_label(char const *label)
+{
+  /* domainlabel =  alphanum / alphanum *( alphanum / "-" ) alphanum */
+  if (IS_ALPHANUM(*label)) {
+    size_t n;
+    for (n = 1; IS_ALPHANUM(label[n]) || label[n] == '-'; n++)
+      ;
+    if (IS_ALPHANUM(label[n - 1]))
+      return n;
+  }
+
+  return 0;
+}
+
+/** Scan valid domain name and count number of labels in it. */
+static inline
+size_t span_domain_labels(char const *host, size_t *return_labels)
+{
+  size_t len, n, labels;
+  int c;
+
+  if (!host || !host[0])
+    return 0;
+
+  for (n = 0, labels = 0; ; n += len) {
+    len = span_domain_label(host + n);
+    if (len == 0)
+      return 0;
+
+    labels++;
+
+    if (host[n + len] != '.')
+      break;
+    len++;
+    if (!IS_ALPHANUM(host[n + len]))
+      break;
+  }
+
+  /* Check that last label does not start with number */
+  if (!IS_ALPHA(host[n]))
+    return 0;
+
+  c = host[n + len];
+  if (IS_ALPHANUM(c) || c == '-' || c == '.')
+    return 0;
+
+  if (return_labels)
+    *return_labels = labels;
+
+  return n + len;
+}
+
+/** Return length of a valid domain name.
+ *
+ * @code
+ * hostname         =  *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel      =  alphanum
+ *                     / alphanum *( alphanum / "-" ) alphanum
+ * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ * @endcode
+ */
+isize_t span_domain(char const *host)
+{
+  return span_domain_labels(host, NULL);
+}
+
+/** Scan valid domain name. */
+issize_t scan_domain(char **inout_host)
+{
+  char *host;
+  size_t n, labels;
+
+  n = span_domain_labels(host = *inout_host, &labels);
+  if (n == 0)
+    return -1;
+
+  /* Remove extra dot at the end of hostname */
+  if (labels > 1 && host[n - 1] == '.')
+    host[n - 1] = '\0';
+
+  *inout_host += n;
+
+  return n;
+}
+
+/** Return length of a valid domain name or IP address. */
+isize_t span_host(char const *host)
+{
+ if (!host || !host[0])
+    return 0;
+
+  if (host[0] == '[')
+    return span_ip6_reference(host);
+
+  if (IS_DIGIT(host[0])) {
+    int n = span_ip4_address(host);
+    if (n)
+      return (isize_t)n;
+  }
+
+  return span_domain(host);
+}
+
+/** Scan valid domain name or IP address. */
+issize_t scan_host(char **inout_host)
+{
+  char *host = *inout_host;
+
+  if (host == NULL)
+    return -1;
+
+  /* IPv6reference  =  "[" IPv6address "]" */
+  if (host[0] == '[')
+    return scan_ip6_reference(inout_host);
+
+  if (IS_DIGIT(host[0])) {
+    int n = scan_ip4_address(inout_host);
+    if (n > 0)
+      return (issize_t)n;
+  }
+
+  return scan_domain(inout_host);
+}
+
+#include <sofia-sip/hostdomain.h>
+
+/** Return true if @a string is valid IP4 address in dot-notation.
+ *
+ * @note Only 4-octet form is accepted, e.g., @c 127.1 is not considered
+ * valid IP4 address.
+ */
+int host_is_ip4_address(char const *string)
+{
+  int n = span_ip4_address(string);
+  return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid IP6 address in hex notation.
+ *
+ * E.g., fe80::1 is a valid IP6 address. 
+ */
+int host_is_ip6_address(char const *string)
+{
+  int n = span_ip6_address(string);
+  return n > 0 && string[n] == '\0';
+}
+
+int host_ip6_reference(char const *string)
+{
+  return host_is_ip6_reference(string);
+}
+
+/** Return true if @a string is valid IP6 reference, 
+ *  i.e. hex notation in square brackets.
+ *
+ * E.g., [::1] is a valid IP6 reference.
+ */
+int host_is_ip6_reference(char const *string)
+{
+  int n = span_ip6_reference(string);
+  return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid IP address.
+ *
+ * Valid IP address is either a IP4 adddress in quad-octet notation, 
+ * IP6 hex address or IP6 reference in square brackets ([]).
+ */
+int host_is_ip_address(char const *string)
+{
+  int n = span_ip_address(string);
+  return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid a domain name.
+ *
+ * Valid domain name consists of alphanumeric labels separated with 
+ * dot ("."). There can be a "-" in the middle of label.
+ * The last label must start with a letter.
+ *
+ * @code
+ * hostname         =  *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel      =  alphanum
+ *                     / alphanum *( alphanum / "-" ) alphanum
+ * toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ * @endcode
+ */
+int host_is_domain(char const *string)
+{
+  size_t n = string ? span_domain(string) : 0;
+  return string && n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid a host name.
+ *
+ * Check if the @a string is a domain name, IP address or IP6 reference.
+ */
+int host_is_valid(char const *string)
+{
+  size_t n = span_host(string);
+  return n > 0 && string[n] == '\0';
+}
+
+/** Returns true if @a string is describing a local address.
+ *
+ * Uses the definitions of local addresses found in RFC1700 and 
+ * RFC4291. 
+ */
+int host_is_local(char const *host)
+{
+  size_t n;
+
+  if (host_is_ip6_reference(host))
+    return (strcmp(host, "[::1]") == 0);
+  else if (host_is_ip6_address(host))
+    return (strcmp(host, "::1") == 0);
+  else if (host_is_ip4_address(host))
+    return (strncmp(host, "127.", 4) == 0);
+
+  n = span_domain(host);
+
+  return 
+    n >= 9 /* strlen("localhost") */ &&
+    strncasecmp(host, "localhost", 9) == 0 &&
+    (n == 9 || 
+     ((n == 10 || /* localhost. */
+       n == 21 || /* strlen("localhost.localdomain") */
+       n == 22) && /* strlen("localhost.localdomain.") */
+      strncasecmp(host + 9, ".localdomain.", n - 9) == 0));
+}
+
+/** Return true if @a string has domain name in "invalid." domain.
+ *
+ */
+int host_has_domain_invalid(char const *string)
+{
+  size_t n = span_domain(string);
+
+  if (n >= 7 && string[n] == '\0') {
+    static char const invalid[] = ".invalid";
+    if (string[n - 1] == '.')	/* .invalid. perhaps? */
+      n--;
+    if (n == 7 /* strlen("invalid") */)
+      return strncasecmp(string, invalid + 1, 7) == 0;
+    else
+      return strncasecmp(string + n - 8, invalid, 8) == 0;
+  }
+
+  return 0;
+}
+
+#include <sofia-sip/su.h>
+
+static size_t convert_ip_address(char const *s,
+				 uint8_t addr[16],
+				 size_t *return_addrlen)
+{
+  size_t len;
+  int canonize = 0;
+
+#if SU_HAVE_IN6
+  char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+  len = span_ip6_reference(s);
+  if (len) {
+    assert(len - 2 < sizeof buf); assert(len > 2);
+
+    if (s[len])
+      return 0;
+
+    len = len - 2;
+    s = memcpy(buf, s + 1, len), buf[len] = '\0';
+  }
+  else
+    len = span_ip6_address(s);
+
+  if (len) {
+    if (s[len] == '\0' && inet_pton(AF_INET6, s, addr) == 1) {
+      if (SU_IN6_IS_ADDR_V4MAPPED(addr) ||
+	  SU_IN6_IS_ADDR_V4COMPAT(addr)) {
+	memcpy(addr, addr + 12, 4);
+	return (void)(*return_addrlen = 4), len;
+      }
+      return (void)(*return_addrlen = 16), len;
+    }
+    else
+      return 0;
+  }
+#endif
+
+  len = span_canonic_ip4_address(s, &canonize);
+  if (len) {
+    if (canonize) {
+      char *tmp = buf;
+      s = memcpy(tmp, s, len + 1);
+      scan_ip4_address(&tmp);      
+    }
+    if (s[len] == '\0' && inet_pton(AF_INET, s, addr) == 1)
+      return (void)(*return_addrlen = 4), len;
+    else
+      return 0;
+  }
+
+  return 0;
+}
+
+/** Compare two host names or IP addresses
+ *
+ * Converts valid IP addresses to the binary format before comparing them. 
+ * Note that IP6-mapped IP4 addresses and IP6-compatible IP4 addresses are
+ * compared as IP4 addresses; that is, ::ffff:127.0.0.1, ::127.0.0.1 and
+ * 127.0.0.1 all are all equal.
+ *
+ * @param a IP address or domain name
+ * @param b IP address or domain name
+ * 
+ * @retval -1 if a < b
+ * @retval 0 if a == b
+ * @retval 1 if a > b
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+int host_cmp(char const *a, char const *b)
+{
+  uint8_t a6[16], b6[16];
+  size_t alen, blen, asize = 0, bsize = 0;
+
+  if (a == NULL || b == NULL)
+    return (a != NULL) - (b != NULL);
+
+  alen = convert_ip_address(a, a6, &asize);
+  blen = convert_ip_address(b, b6, &bsize);
+
+  if (alen > 0 && blen > 0) {
+    if (asize < bsize)
+      return -1;
+    else if (asize > bsize)
+      return 1;
+    else
+      return memcmp(a6, b6, asize);
+  }
+  else {
+    return strcasecmp(a, b);
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "bnf" - String Parser Module
+ *
+ * @section bnf_meta Module Meta Information
+ *
+ * The Sofia @b bnf module contains macros and functions for parsing
+ * text-based formats, for example, for SIP. The interface is described in
+ * <bnf.h>, the <bnf.c> contains a #_bnf_table table used to classify
+ * characters.
+ * 
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,330 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef BNF_H  /** Defined when <sofia-sip/bnf.h> has been included. */
+#define BNF_H
+
+/**@file sofia-sip/bnf.h
+ * 
+ * Parsing macros and prototypes for HTTP-like protocols.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Jun 06 10:59:34 2000 ppessi
+ *
+ */
+
+#include <sofia-sip/su_types.h>
+
+#include <string.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Parsing tokens */
+/** Control characters. */
+#define CTL   "\001\002\003\004\005\006\007" \
+    "\010\011\012\013\014\015\016\017" \
+    "\020\021\022\023\024\025\026\027" \
+    "\030\031\032\033\034\035\036\037" "\177" "\0"
+/** Space */
+#define SP      " "
+/** Horizontal tab */
+#define HT      "\t"
+/** Carriage return */
+#define CR      "\r"
+/** Line feed */
+#define LF      "\n"
+/** Line-ending characters */
+#define CRLF     CR LF
+/** Whitespace */
+#define WS       SP HT 
+/** Linear whitespace */
+#define LWS      SP HT CR LF
+/** Lower-case alphabetic characters */
+#define LOALPHA "abcdefghijklmnopqrstuvwxyz"
+/** Upper-case alphabetic characters */
+#define UPALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+/** Alphabetic characters */
+#define ALPHA    LOALPHA UPALPHA
+/** Digits */
+#define DIGIT   "0123456789"
+/** RTSP safe characters */
+#define SAFE    "$-_." /* RTSP stuff */
+#define ALPHANUM DIGIT ALPHA 
+#define HEX      DIGIT "ABCDEF" "abcdef"
+
+/** SIP token characters.
+ * @note $|&^# were token chars in RFC 2543, but no more in RFC 3261. 
+ */
+#define SIP_TOKEN  ALPHANUM "-.!%*_+`'~"
+/** SIP separator characters */
+#define SIP_SEPARATOR  "()<>@,;:\\\"/[]?={}" SP HT
+
+/** SIP Word characters (that are not token characters) */
+#define SIP_WORD "()<>:\\\"/[]?{}"
+
+/** Skip whitespace (SP HT) */
+#define skip_ws(ss) (*(ss) += span_ws(*(ss)))
+
+/** Skip linear whitespace (SP HT CR LF) */
+#define skip_lws(ss) (*(ss) += span_lws(*(ss)))
+
+/** Skip [a-zA-Z] */
+#define skip_alpha(ss) (*(ss) += span_alpha(*(ss)))
+
+/** Skip digits */
+#define skip_digit(ss) (*(ss) += span_digit(*(ss)))
+
+/** Skip characters belonging to an RTSP token. */
+#define skip_alpha_digit_safe(ss) (*(ss) += span_alpha_digit_safe(*(ss)))
+
+/** Skip characters belonging to a SIP token. */
+#define skip_token(ss)  (*(ss) += span_token(*(ss)))
+
+/** Skip characters belonging to a SIP parameter value. */
+#define skip_param(ss) (*(ss) += span_param(*(ss)))
+
+/** Skip characters belonging to a SIP word. */
+#define skip_word(ss) (*(ss) += span_word(*(ss)))
+
+/** Test if @c is CR or LF */
+#define IS_CRLF(c)       ((c) == '\r' || (c) == '\n') 
+/** Test if @c is linear whitespace */
+#define IS_LWS(c)  	 ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
+/*#define IS_LWS(c)  	 ((_bnf_table[(unsigned char)(c)] & bnf_lws))*/
+/** Test if @c is normal whitespace */
+#define IS_WS(c)   	 ((c) == ' ' || (c) == '\t')
+/** Test if @c is not whitespace (and not NUL). */
+#define IS_NON_WS(c)     (c && !IS_WS(c))
+/*#define IS_NON_WS(c)     (c && !(_bnf_table[(unsigned char)c] & bnf_ws))*/
+/** Test if @c is not linear whitespace (and not NUL). */
+#define IS_NON_LWS(c)    (c && !IS_LWS(c))
+/*#define IS_NON_LWS(c)    (c && !(_bnf_table[(unsigned char)c] & bnf_lws))*/
+/** Test if @c is a digit. */
+#define IS_DIGIT(c)   	 ((c) >= '0' && (c) <= '9')
+/** Test if @c is alphabetic. */
+#define IS_ALPHA(c)      (c && ((_bnf_table[(unsigned char)c] & bnf_alpha)))
+/** Test if @c is alphanumeric. */
+#define IS_ALPHANUM(c)   (c && (IS_DIGIT(c) || IS_ALPHA(c)))
+/** Test if @c is URL-unreserved. */
+#define IS_UNRESERVED(c) ((_bnf_table[(unsigned char)c] & bnf_unreserved))
+/** Test if @c is URL-reserved. */
+#define IS_RESERVED(c)   (c && !(_bnf_table[(unsigned char)c] & bnf_unreserved))
+/** Test if @c is valid in tokens. */
+#define IS_TOKEN(c)      ((_bnf_table[(unsigned char)c] & bnf_token))
+/** Test if @c is valid for SIP parameter value. */
+#define IS_PARAM(c)      ((_bnf_table[(unsigned char)c] & (bnf_token|bnf_param)))
+/** Test if @c is a hex digit. */
+#define IS_HEX(c)        (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
+/** Test if @c is a linear whitespace or valid in tokens. */
+#define IS_TOKENLWS(c)   ((_bnf_table[(unsigned char)c] & (bnf_token|bn_lws)))
+
+enum {
+  bnf_ws = 1,					/**< Whitespace character  */
+  bnf_crlf = 2,					/**< Line end character */
+  bnf_lws = 3,					/**< Linear whitespace */
+  bnf_alpha = 4,				/**< Alphabetic */
+  bnf_safe = 8,					/**< RTSP safe */
+  bnf_mark = 16,				/**< URL mark */
+  bnf_unreserved = bnf_alpha | bnf_mark,	/**< URL unreserved */
+  bnf_separator = 32,				/**< SIP separator */
+  /** SIP token, not alphabetic (0123456789-.!%*_+`'~) */
+  bnf_token0 = 64 | bnf_safe,				
+  bnf_token = bnf_token0 | bnf_alpha,		/**< SIP token */
+  bnf_param0 = 128,				/**< SIP parameter, not token */
+  bnf_param = bnf_token | bnf_param0 /**< SIP/HTTP parameter */
+};
+
+/** Table for determining class of a character. */
+SOFIAPUBVAR unsigned char const _bnf_table[256];
+
+/** Get number of characters before CRLF */
+#define span_non_crlf(s) strcspn(s, CR LF)
+
+/** Get number of characters before whitespace */
+#define span_non_ws(s) strcspn(s, WS)
+
+/** Get number of whitespace characters */
+#define span_ws(s) strspn(s, WS)
+
+/** Get number of characters before linear whitespace */
+#define span_non_lws(s) strcspn(s, LWS)
+
+/** Calculate span of a linear whitespace. 
+ * LWS = [*WSP CRLF] 1*WSP
+ */
+static inline isize_t span_lws(char const *s)
+{
+  char const *e = s;
+  int i = 0;
+  e += strspn(s, WS);
+  if (e[i] == '\r') i++;
+  if (e[i] == '\n') i++;
+  if (IS_WS(e[i]))
+    e += i + strspn(e + i, WS);
+  return e - s;
+}
+
+/** Calculate span of a token or linear whitespace characters.  */
+static inline isize_t span_token_lws(char const *s)
+{
+  char const *e = s; 
+  while (_bnf_table[(unsigned char)(*e)] & (bnf_token | bnf_lws))
+    e++; 
+  return e - s; 
+}
+
+#if 1
+/** Calculate span of a token characters.  */
+static inline isize_t span_token(char const *s)
+{
+  char const *e = s; 
+  while (_bnf_table[(unsigned char)(*e)] & bnf_token)
+    e++; 
+  return e - s; 
+}
+#else
+size_t bnf_span_token(char const *s);
+#define span_token(s) bnf_span_token((s))
+#endif
+
+
+/** Calculate span of a alphabetic characters.  */
+static inline isize_t span_alpha(char const *s)
+{
+  char const *e = s; 
+  while (_bnf_table[(unsigned char)(*e)] & bnf_alpha)
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of a digits.  */
+static inline isize_t span_digit(char const *s)
+{
+  char const *e = s; 
+  while (*e >= '0' && *e <= '9')
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of a hex.  */
+static inline isize_t span_hexdigit(char const *s)
+{
+  char const *e = s; 
+  while (IS_HEX(*e))
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of characters belonging to an RTSP token */
+static inline isize_t span_alpha_digit_safe(char const *s)
+{
+  char const *e = s; 
+  while (_bnf_table[(unsigned char)(*e)] & (bnf_alpha | bnf_safe))
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of a characters valid in parameters.  */
+static inline isize_t span_param(char const *s)
+{
+  char const *e = s; 
+  while (IS_PARAM(*e))
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of a SIP word.  */
+static inline isize_t span_word(char const *s)
+{
+  char const *e = s; 
+  while (*e && (IS_TOKEN(*e) || strchr(SIP_WORD, *e)))
+    e++; 
+  return e - s; 
+}
+
+/** Calculate span of a unreserved characters.  */
+static inline isize_t span_unreserved(char const *s)
+{
+  char const *e = s;
+  while (IS_UNRESERVED(*e))
+    e++;
+  return e - s;
+}
+
+/** Calculate span of a double quoted string (with escaped chars inside) */
+static inline isize_t span_quoted(char const *s)
+{
+  char const *b = s;
+
+  if (*s++ != '"')
+    return 0;
+
+  for (;;) {
+    s += strcspn(s, "\\\"");
+    if (!*s)
+      return 0;
+    if (*s++ == '"')
+      return s - b;
+    if (!*s++)
+      return 0;
+  }
+}
+
+/* RFC 2396 defines URL chars */
+/** Reserved in URLs */
+#define URL_RESERVED        ";/?:=+$,"
+
+/** Non-alphanumeric characters without syntactical meaning. */ 
+#define URL_MARK            "-_.!~*'()"
+
+/** Unreserved characters. */ 
+#define URL_UNRESERVED ALPHANUM URL_MARK
+
+/** URL hex escape. */ 
+#define URL_ESCAPED    "%"
+#define URL_DELIMS     "<>#%\""
+#define URL_UNWISE     "{}|\\^[]`"
+#define URL_SCHEME     ALPHANUM "+-."
+
+/** Get number of characters belonging to url scheme */
+#define span_url_scheme(s) strspn(s, URL_SCHEME)
+
+SOFIAPUBFUN int span_ip4_address(char const *host);
+SOFIAPUBFUN int span_ip6_address(char const *host);
+SOFIAPUBFUN int span_ip6_reference(char const *host);
+SOFIAPUBFUN int span_ip_address(char const *host);
+SOFIAPUBFUN isize_t span_domain(char const *host);
+SOFIAPUBFUN isize_t span_host(char const *host);
+
+SOFIAPUBFUN int scan_ip4_address(char **inout_host);
+SOFIAPUBFUN int scan_ip6_address(char **inout_host);
+SOFIAPUBFUN int scan_ip6_reference(char **inout_host);
+SOFIAPUBFUN int scan_ip_address(char **inout_host);
+SOFIAPUBFUN issize_t scan_domain(char **inout_host);
+SOFIAPUBFUN issize_t scan_host(char **inout_host);
+
+SOFIA_END_DECLS
+
+#endif /* !defined BNF_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_SIP_HOSTDOMAIN_H
+/** Defined when <sofia-sip/hostdomain.h> has been included. */
+#define SOFIA_SIP_HOSTDOMAIN_H
+
+/**@file sofia-sip/hostdomain.h
+ * 
+ * Predicates for handling host names: IP addresses or domain names.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar  9 16:15:22 EET 2006 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN int host_is_ip4_address(char const *string);
+SOFIAPUBFUN int host_is_ip6_address(char const *string);
+SOFIAPUBFUN int host_is_ip6_reference(char const *string);
+SOFIAPUBFUN int host_is_ip_address(char const *string);
+SOFIAPUBFUN int host_is_domain(char const *string);
+SOFIAPUBFUN int host_is_valid(char const *string);
+SOFIAPUBFUN int host_is_local(char const *string);
+SOFIAPUBFUN int host_has_domain_invalid(char const *string);
+SOFIAPUBFUN int host_cmp(char const *a, char const *b);
+
+/** This is typo. @deprecated Use host_is_ip6_reference() instead. */ 
+SOFIAPUBFUN int host_ip6_reference(char const *string);
+
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SOFIA_SIP_HOSTDOMAIN_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,366 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE torture_bnf.c
+ *
+ * Torture tests for BNF functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/bnf.h"
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "torture_bnf";
+
+int count_bnf(int bnf_flags)
+{
+  int i, n;
+
+  for (i = 0, n = 0; i < 128; i++)
+    if (_bnf_table[i] & bnf_flags)
+      n++;
+
+  return n;
+}
+
+int bnf_test(void)
+{
+  BEGIN();
+  TEST_1(IS_TOKEN('a'));
+  TEST_1(IS_TOKEN('b'));
+  /* Fixed for 1.12.2: lws = [*wsp crlf] 1*wsp */
+  TEST_SIZE(span_lws("  \r\n \r\nLoppuu"), 5);
+  TEST_SIZE(span_lws("  \r\r \nLoppuu"), 2);
+  TEST_SIZE(span_lws("  \n\r \nLoppuu"), 2);
+  TEST_SIZE(span_lws("  \r \nLoppuu"), 4);
+  TEST_SIZE(span_lws("  \n\t \nLoppuu"), 5);
+  TEST_SIZE(span_lws("  \r\n\t \nLoppuu"), 6);
+  TEST_SIZE(span_token(SIP_TOKEN), strlen(SIP_TOKEN));
+  TEST_SIZE(count_bnf(bnf_token), strlen(SIP_TOKEN "$"));
+  #define SIP_PARAM SIP_TOKEN "[:]/"
+  TEST_SIZE(span_param(SIP_PARAM), strlen(SIP_PARAM));
+  TEST_SIZE(count_bnf(bnf_param), strlen(SIP_PARAM "$"));
+
+  TEST_SIZE(span_unreserved(URL_UNRESERVED URL_ESCAPED),
+	    strlen(URL_UNRESERVED URL_ESCAPED));
+
+  TEST_SIZE(count_bnf(bnf_unreserved),
+	    strlen(URL_UNRESERVED URL_ESCAPED));
+
+  {
+    char word[] = ALPHA DIGIT "-.!%*_+`'~()<>:\\\"/[]?{}";
+    TEST_SIZE(span_word(word), strlen(word));
+  }
+
+  END();
+}
+
+int ip_test(void)
+{
+  BEGIN();
+  char *s;
+
+  TEST(span_ip4_address("127.255.249.000,"), 15);
+  TEST(span_ip4_address("0.00.000.000:,"), 12);
+
+  /* Test error detection */
+  TEST(span_ip4_address("256.00.000.000:,"), 0);
+  TEST(span_ip4_address("255.00.000.0000,"), 0);
+  TEST(span_ip4_address("255.00.000.199."), 0);
+
+  {
+    char ip0[] = "010.250.020.000,";
+    char ip1[] = "0.00.000.000:,";
+    char ip2[] = "256.00.000.000:,";
+    char ip3[] = "255.00.000.0000,";
+    char ip4[] = "255.00.000.199.";
+
+    s = ip0;
+    TEST(scan_ip4_address(&s), 15); TEST_S(s, ","); TEST_S(ip0, "10.250.20.0");
+
+    s = ip1;
+    TEST(scan_ip4_address(&s), 12); TEST_S(s, ":,"); TEST_S(ip1, "0.0.0.0");
+
+    /* Test error detection */
+    s = ip2; TEST(scan_ip4_address(&s), -1);
+    s = ip3; TEST(scan_ip4_address(&s), -1);
+    s = ip4; TEST(scan_ip4_address(&s), -1);
+  }
+
+  TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:3"), 26);
+  TEST(span_ip6_address("::beef:feed:ded:0:1:2:3"), 23);
+  TEST(span_ip6_address("::255.0.0.0,"), 11);
+  TEST(span_ip6_address("::,"), 2);
+
+  TEST(span_ip_address("[dead:beef:feed:ded:0:1:2:3]"), 28);
+  TEST(span_ip_address("::255.0.0.0,"), 11);
+  TEST(span_ip_address("[::255.0.0.0]:"), 13);
+
+  TEST(span_ip6_address("dead:beef:feed::0ded:0:1:2:3"), 28);
+  TEST(span_ip6_address("dead:beef:feed::0ded:0000:0001:0002:0003"), 40);
+
+  TEST(span_ip6_address("dead:beef:feed::0ded::0000:0001:0002:0003"), 0);
+  TEST(span_ip6_address("::dead:beef:feed::0ded:0000:0001:0002:0003"), 0);
+  TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:3:4"), 0);
+  TEST(span_ip6_address("dead:beef:feed:00ded:0:1:2:3"), 0);
+  TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:127.0.0.1"), 0);
+  TEST(span_ip6_address(":255.0.0.0,"), 0);
+  TEST(span_ip6_address("255.0.0.0,"), 0);
+
+  /* Accept colon after IP4-quad */
+  TEST(span_ip_address("::255.0.0.0:5060"), 11);
+
+  /* This is a reference */
+  TEST(span_ip6_address("[dead:beef:feed:ded:0:1:2:3]"), 0);
+  TEST(span_ip6_reference("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+  TEST(span_ip_address("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+  TEST(span_ip_address("[127.0.0.1]:1"), 0);
+
+  {
+    char ip0[] = "dead:beef:feed:ded:0:1:2:3,";
+    char ip1[] = "::beef:feed:ded:0:1:2:3;";
+    char ip1b[] = "::beef:feed:ded:0:0:2:3;";
+    char ip2[] = "::255.00.0.0,";
+    char ip3[] = "::,";
+    char ip4[] = "0:0:0:0:0:0:0:0,";
+    char ip4b[] = "0:0:0:0:0:0:0.0.0.0,";
+    char ip4c[] = "0:0:0:0:0:0:0.0.0.1,";
+    char ip5[] = "dead:beef:feed::0ded:0:1:2:3";
+    char ip6[] = "dead:beef:feed::0ded:0000:0001:0002:0003+";
+    char ip7[] = "1:0:0:2:0:0:0:3,";
+    char ip8[] = "1:0:0:2:0:0:3:4,";
+    char ip9[] = "1::2:0:0:0:3,";
+
+    s = ip0; TEST(scan_ip6_address(&s), 26); TEST_S(s, ",");
+    TEST_S(ip0, "dead:beef:feed:ded::1:2:3");
+    s = ip1; TEST(scan_ip6_address(&s), 23); TEST_S(s, ";");
+    TEST_S(ip1, "::beef:feed:ded:0:1:2:3;");
+    s = ip1b; TEST(scan_ip6_address(&s), 23); TEST_S(s, ";");
+    TEST_S(ip1b, "0:beef:feed:ded::2:3");
+    s = ip2; TEST(scan_ip6_address(&s), 12); TEST_S(s, ",");
+    TEST_S(ip2, "::255.0.0.0");
+    s = ip3; TEST(scan_ip6_address(&s), 2); TEST_S(s, ",");
+    TEST_S(ip3, "::,");
+    s = ip4; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+    TEST_S(ip4, "::");
+    s = ip4b; TEST(scan_ip6_address(&s), 19); TEST_S(s, ",");
+    TEST_S(ip4b, "::");
+    s = ip4c; TEST(scan_ip6_address(&s), 19); TEST_S(s, ",");
+    TEST_S(ip4c, "::1");
+    TEST_S(ip5, "dead:beef:feed::0ded:0:1:2:3");
+    s = ip5; TEST(scan_ip6_address(&s), 28); TEST_S(s, "");
+    TEST_S(ip5, "dead:beef:feed:ded::1:2:3");
+    s = ip6; TEST(scan_ip6_address(&s), 40); TEST_S(s, "+");
+    TEST_S(ip6, "dead:beef:feed:ded::1:2:3");
+    s = ip7; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+    TEST_S(ip7, "1:0:0:2::3");
+    s = ip8; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+    TEST_S(ip8, "1::2:0:0:3:4");
+    s = ip9; TEST(scan_ip6_address(&s), 12); TEST_S(s, ",");
+    TEST_S(ip9, "1:0:0:2::3");
+  }
+
+  {
+    char err0[] = "dead:beef:feed::0ded::0000:0001:0002:0003";
+    char err1[] = "::dead:beef:feed::0ded:0000:0001:0002:0003";
+    char err2[] = "dead:beef:feed:ded:0:1:2:3:4";
+    char err3[] = "dead:beef:feed:00ded:0:1:2:3";
+    char err4[] = "dead:beef:feed:ded:0:1:2:127.0.0.1";
+    char err5[] = ":255.0.0.0,";
+    char err6[] = "255.0.0.0,";
+    char err7[] = "dead:beef:feed:ded:0:1:2:3:4:5,";
+
+    TEST(scan_ip6_address((s = err0, &s)), -1);
+    TEST(scan_ip6_address((s = err1, &s)), -1);
+    TEST(scan_ip6_address((s = err2, &s)), -1);
+    TEST(scan_ip6_address((s = err3, &s)), -1);
+    TEST(scan_ip6_address((s = err4, &s)), -1);
+    TEST(scan_ip6_address((s = err5, &s)), -1);
+    TEST(scan_ip6_address((s = err6, &s)), -1);
+    TEST(scan_ip6_address((s = err7, &s)), -1);
+  }
+
+  {
+    char err0[] = "[dead:beef:feed::0ded::0000:0001:0002:0003]:";
+    char err1[] = "[::dead:beef:feed::0ded:0000:0001:0002:0003]+";
+    char err2[] = "[dead:beef:feed:ded:0:1:2:3:4]+";
+    char err3[] = "[dead:beef:feed:00ded:0:1:2:3]+";
+    char err4[] = "[dead:beef:feed:ded:0:1:2:127.0.0.1]";
+    char err5[] = "[:255.0.0.0],";
+    char err6[] = "[255.0.0.0],";
+    char err7[] = "[dead:beef:feed:ded:0:1:2:]";
+
+    TEST(scan_ip6_reference((s = err0, &s)), -1);
+    TEST(scan_ip6_reference((s = err1, &s)), -1);
+    TEST(scan_ip6_reference((s = err2, &s)), -1);
+    TEST(scan_ip6_reference((s = err3, &s)), -1);
+    TEST(scan_ip6_reference((s = err4, &s)), -1);
+    TEST(scan_ip6_reference((s = err5, &s)), -1);
+    TEST(scan_ip6_reference((s = err6, &s)), -1);
+    TEST(scan_ip6_reference((s = err7, &s)), -1);
+  }
+
+  END();
+}
+
+#define TEST_SCAN(scanner, input, canonic, output)			\
+  do { char s0[] = input; char *s = s0;					\
+    size_t n = sizeof(input) - sizeof(output);				\
+    TEST_SIZE(scanner(&s), n);						\
+    TEST_S(s, output);							\
+    TEST_S(s0, canonic); } while(0)
+
+#include <sofia-sip/hostdomain.h>
+
+int host_test(void)
+{
+  BEGIN();
+
+  TEST(host_is_ip4_address(NULL), 0);
+  TEST(host_is_ip6_address(NULL), 0);
+  TEST(host_ip6_reference(NULL), 0);
+  TEST(host_is_ip_address(NULL), 0);
+  TEST(host_is_domain(NULL), 0);
+  TEST(host_is_valid(NULL), 0);
+  TEST(host_has_domain_invalid(NULL), 0);
+
+  TEST_SIZE(span_host("rama"), 4);
+  TEST_SIZE(span_host("ra-ma.1-2.3-4.a4-9."), 19);
+  TEST_SIZE(span_host("a.1.b"), 5);
+  TEST_SIZE(span_host("127.255.249.000.a,"), 17);
+  TEST_SIZE(span_host("127.255.249.000,"), 15);
+  TEST_SIZE(span_host("0.00.000.000:,"), 12);
+  TEST_SIZE(span_host("127.255.249.000,"), 15);
+  TEST_SIZE(span_host("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+  TEST_SIZE(span_host("[dead:beef:feed:ded::1:2:3]:1"), 27);
+  TEST_SIZE(span_host("[::127.0.0.1]:1"), 13);
+
+  TEST_SCAN(scan_host, "rama", "rama", "");
+  TEST_SCAN(scan_host, "rama.", "rama.", "");
+  TEST_SCAN(scan_ip4_address, "127.255.249.000,", "127.255.249.0", ",");
+  TEST_SCAN(scan_host, "127.255.249.000,", "127.255.249.0", ",");
+  TEST_SCAN(scan_host, "a.1.b.", "a.1.b", "");
+  TEST_SCAN(scan_host, "ra-ma.1-2.3-4.a4-9.", "ra-ma.1-2.3-4.a4-9", "");
+  TEST_SCAN(scan_host, "127.255.249.000.a,", "127.255.249.000.a,", ",");
+  TEST_SCAN(scan_host, "0.00.000.000:,", "0.0.0.0", ":,");
+  TEST_SCAN(scan_host, "127.255.249.000,", "127.255.249.0", ",");
+  TEST_SCAN(scan_host, "[dead:beef:feed:ded:0:1:2:3]:1", 
+                       "[dead:beef:feed:ded::1:2:3]", ":1");
+  TEST_SCAN(scan_host, "[::127.0.0.1]:1", "[::127.0.0.1]:1", ":1");
+
+  /* Test error detection */
+  TEST_SIZE(span_host("256.00.000.000:,"), 0);
+  TEST_SIZE(span_host("255.00.000.0000,"), 0);
+  TEST_SIZE(span_host("255.00.000.199."), 0);
+  TEST_SIZE(span_host("[127.0.0.1]:1"), 0);
+  TEST_SIZE(span_domain("rama.1"), 0);
+  TEST_SIZE(span_domain("-ma.1-2.3-4.a4-9."), 0);
+  TEST_SIZE(span_domain("a..b"), 0);
+  TEST_SIZE(span_domain("a.b.-"), 0);
+  TEST_SIZE(span_domain("a.b-"), 0);
+
+  TEST(host_is_local("126.0.0.0"), 0);
+  TEST(host_is_local("127.0.0.0"), 1);
+  TEST(host_is_local("127.0.0.2"), 1);
+  TEST(host_is_local("0.0.0.0"), 0);
+  TEST(host_is_local("::1"), 1);
+  TEST(host_is_local("::1"), 1);
+  TEST(host_is_local("::1:3fff"), 0);
+  TEST(host_is_local("[::1]"), 1);
+  TEST(host_is_local("localdomain.domain.org"), 0);
+  TEST(host_is_local("localhost.domain.org"), 0);
+  TEST(host_is_local("localhost"), 1);
+  TEST(host_is_local("localhost.localdomain"), 1);
+  TEST(host_is_local("localhost."), 1);
+  TEST(host_is_local("localhost.localdomain."), 1);
+  TEST(host_is_local("localhost.localdomain.org"), 0);
+
+  TEST(host_has_domain_invalid("invalid"), 1);
+  TEST(host_has_domain_invalid("invalid."), 1);
+  TEST(host_has_domain_invalid("1.invalid"), 1);
+  TEST(host_has_domain_invalid("1.invalid."), 1);
+  TEST(host_has_domain_invalid("1invalid"), 0);
+  TEST(host_has_domain_invalid("valid."), 0);
+  TEST(host_has_domain_invalid("1-.invalid."), 0);
+
+  /* Invalid IP4 addresses (extra leading zeros) */
+  TEST_1(!host_cmp("127.0.0.1", "127.0.0.01"));
+  TEST_1(!host_cmp("[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]", 
+		  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+  /* Invalid reference (extra leading zeros) */
+  TEST_1(host_cmp("[0ffff:0ffff:0ffff:0ffff:0ffff:0ffff:255.255.255.255]", 
+		  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+  TEST_1(!host_cmp("::1", "::001"));
+  TEST_1(!host_cmp("[::1]", "::1"));
+  TEST_1(!host_cmp("[::1]", "::0.0.0.1"));
+  TEST_1(!host_cmp("::ffff:127.0.0.1", "127.0.0.1"));
+  TEST_1(!host_cmp("::ffff:127.0.0.1", "::ffff:7f00:1"));
+  TEST_1(!host_cmp("::ffff:127.0.0.1", "::ffff:7f00:1"));
+  TEST_1(!host_cmp("[::ffff:127.0.0.1]", "[::7f00:1]"));
+  TEST_1(host_cmp("::", "0.0.0.0"));
+  TEST_1(host_cmp("::1", "0.0.0.1"));
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      test_flags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= bnf_test(); fflush(stdout);
+  retval |= ip_test(); fflush(stdout);
+  retval |= host_test(); fflush(stdout);
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,20 @@
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added aliases for RFC links in libsofia-sip-ua/docs/Doxyfile.aliases.
+
+    M ./libsofia-sip-ua/docs/Doxyfile.aliases -7 +2208
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed aliases for Doxygen 1.4.
+
+    M ./libsofia-sip-ua/docs/Doxyfile.aliases -6 +6
+
+2005-09-08  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* hide_emails.sh: Fixed bug in hiding addresses of
+	form foo.bar-bar at something.org. Fixed sf.net 
+	bug #1277167.
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,30 @@
+PROJECT_NAME         = "libsofia-sip-ua"
+OUTPUT_DIRECTORY     = ../docs/html
+
+INPUT 		     = mainpage.docs docguide.docs conformance.docs
+
+#			release.docs
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+GENERATE_TAGFILE    = docs.doxytags
+
+TAGFILES            = 
+TAGFILES            += su.doxytags=su
+TAGFILES            += ipt.doxytags=ipt
+TAGFILES            += bnf.doxytags=bnf
+TAGFILES            += url.doxytags=url
+TAGFILES            += msg.doxytags=msg
+TAGFILES            += sip.doxytags=sip
+TAGFILES            += sresolv.doxytags=sresolv
+TAGFILES            += stun.doxytags=stun
+TAGFILES            += tport.doxytags=tport
+TAGFILES            += nta.doxytags=nta
+TAGFILES            += iptsec.doxytags=iptsec
+TAGFILES            += sdp.doxytags=sdp
+TAGFILES            += soa.doxytags=soa
+TAGFILES            += nea.doxytags=nea
+TAGFILES            += nua.doxytags=nua
+TAGFILES            += features.doxytags=features
+
+EXAMPLE_PATH = ../sip

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+# Doxyfile 1.0.0 format
+#
+
+PREDEFINED = DOX \
+ DOXYGEN_ONLY=1 \
+ DOCUMENTATION_ONLY=1 \
+ SU_HAVE_INLINE=1 su_inline=inline \
+ SOFIA_BEGIN_DECLS SOFIA_END_DECLS SOFIAPUBFUN SOFIACALL \
+ SOFIAPUBVAR=extern \
+ SU_DLL SIP_DLL RTSP_DLL SU_DLL NTA_DLL NUA_DLL MSG_DLL AUTH_DLL \
+ NTH_DLL HTTP_DLL \
+ __attribute__()=
+
+ALIASES = \
+ "MODULEPAGE=\mainpage Sofia SIP User Agent Library - " \
+ "CONTACT=\par Contact:\n" \
+ "STATUS=\par Status:\n" \
+ "LICENSE=\par License:\n" \
+ "SofiaSIP=<a href=\"../index.html\">Sofia SIP</a>" \
+ "SU=@ref su_index \"SU\"" "su=@ref su_index \"su\"" \
+ "msg=@ref msg_index \"msg\"" \
+ "sip=@ref sip_index \"sip\"" \
+ "nua=@ref nua_index \"nua\"" \
+ "nta=@ref nta_index \"nta\"" \
+ "soa=@ref soa_index \"soa\"" \
+ "DEF=\def" \
+ "TAGS=\par Related Tags:" \
+ "TAG=\par \n" \
+ "EVENTS=\par Events:\n" \
+ "RESPONSES=\par Related Response Codes:\n" \
+ "CFILE=\file" \
+ "IFILE=\file" \
+ "HI=\hideinitializer " \
+ "HIDE=\hideinitializer " \
+ "SHOW=\showinitializer " \
+ "LGPL2=\par Lesser GNU Public License Version 2:\n \ref lgpl2\n \if 0\n" \
+ "ENDLGPL2=\endif \n" \
+ "GPL2=\par GNU Public License Version 2:\n \ref gpl2\n \if 0\n" \
+ "ENDGPL2=\endif \n" \
+ "ERRORS=\par Errors: " \
+ "ERROR=\par \n \b " \
+ "NEW_1_12_2=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.2.txt\">1.12.2</a>" \
+ "VERSION_1_12_2=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.2.txt\">1.12.2</a>" \
+ "NEW_1_12_4=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
+ "VERSION_1_12_4=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
+ "VERSION_1_12_5=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
+ "NEW_1_12_5=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+# Doxyfile 1.0.0 format
+#
+
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.version"
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.aliases"
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.rfc"
+
+OUTPUT_LANGUAGE      = English
+
+DETAILS_AT_TOP       = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES      = NO
+
+QUIET                = YES
+WARNINGS             = YES
+DISABLE_INDEX        = NO
+
+HAVE_DOT	     = YES
+CLASS_GRAPH          = NO
+INCLUDE_GRAPH	     = YES
+INCLUDED_BY_GRAPH    = NO
+COLLABORATION_GRAPH  = YES
+GROUP_GRAPHS         = NO
+EXTRACT_ALL          = NO
+EXTRACT_PRIVATE      = NO
+HIDE_UNDOC_RELATIONS = YES
+HIDE_UNDOC_MEMBERS   = YES
+HIDE_UNDOC_CLASSES   = YES
+HIDE_SCOPE_NAMES     = YES
+BRIEF_MEMBER_DESC    = YES
+REPEAT_BRIEF         = YES
+JAVADOC_AUTOBRIEF    = YES
+MAX_INITIALIZER_LINES = 0
+ENUM_VALUES_PER_LINE = 1
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION      = YES
+EXPAND_ONLY_PREDEF   = YES
+
+# HTML
+GENERATE_HTML        = YES
+HTML_OUTPUT          = .
+HTML_ALIGN_MEMBERS   = YES
+HTML_FOOTER	     = ../../libsofia-sip-ua/docs/sofia-footer.html
+
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+
+# LATEX
+GENERATE_LATEX       = NO
+LATEX_OUTPUT         = latex
+LATEX_CMD_NAME       = pdflatex
+USE_PDFLATEX         = YES
+PDF_HYPERLINKS       = YES
+COMPACT_LATEX        = YES
+PAPER_TYPE           = a4wide
+EXTRA_PACKAGES       = 
+LATEX_BATCHMODE      = YES
+
+FILE_PATTERNS        = *.h *.c 
+
+EXCLUDE_PATTERNS     = acconfig.h config.h confdefs.h \
+			test*.h test*.c torture*.c *test.c *torture.c \
+			*_tag_dll.c *_tag_ref.c
+
+IMAGE_PATH           = ../../libsofia-sip-ua/docs/pictures

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+PROJECT_NUMBER = @VERSION@

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+EXTRA_DIST = 	Doxyfile Doxyfile.aliases Doxyfile.conf \
+		docguide.docs \
+		mainpage.docs \
+		conformance.docs \
+		Doxyfile.version.in \
+		sofia-footer.html.in \
+		hide_emails.sh \
+		ChangeLog \
+	pictures/SIP_basic_incoming_operation.eps \
+	pictures/SIP_basic_incoming_operation.gif \
+	pictures/SIP_basic_incoming_operation.vsd \
+	pictures/SIP_basic_outgoing_operation.eps \
+	pictures/SIP_basic_outgoing_operation.gif \
+	pictures/SIP_basic_outgoing_operation.vsd \
+	pictures/SIP_incoming_call.eps \
+	pictures/SIP_incoming_call.gif \
+	pictures/SIP_incoming_call.vsd \
+	pictures/SIP_outgoing_call.eps \
+	pictures/SIP_outgoing_call.gif \
+	pictures/SIP_outgoing_call.vsd \
+	pictures/SIP_outgoing_operation_with_auth.eps \
+	pictures/SIP_outgoing_operation_with_auth.gif \
+	pictures/SIP_outgoing_operation_with_auth.vsd \
+	pictures/autotools.eps \
+	pictures/autotools.gif \
+	pictures/autotools.vsd \
+	pictures/nta-receiving-message.eps \
+	pictures/nta-receiving-message.gif 
+
+BUILT_SOURCES = Doxyfile.rfc
+
+# Including Doxyfile.rfc in dist breaks make manpages
+
+Doxyfile.rfc:
+	$(AWK) 'END { b="\\"; q="\\\""; \
+		print "# Autogenerated aliases for RFCs "from" .. "to ; \
+		print "ALIASES += " b; \
+		for (i=from; i < to; i++) { \
+		  print "RFC"i"=\"<a href="q site i type q">RFC "i"</a>\" "b; \
+		}}' \
+	site=http://www.faqs.org/rfcs/rfc type=.html \
+	from=700 to=4800 \
+	/dev/null > $@
+
+CLEANFILES = Doxyfile.rfc
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,474 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(srcdir)/../sofia.am $(srcdir)/Doxyfile.version.in \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/sofia-footer.html.in ChangeLog
+subdir = libsofia-sip-ua/docs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES = Doxyfile.version sofia-footer.html
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+EXTRA_DIST = Doxyfile Doxyfile.aliases Doxyfile.conf \
+		docguide.docs \
+		mainpage.docs \
+		conformance.docs \
+		Doxyfile.version.in \
+		sofia-footer.html.in \
+		hide_emails.sh \
+		ChangeLog \
+	pictures/SIP_basic_incoming_operation.eps \
+	pictures/SIP_basic_incoming_operation.gif \
+	pictures/SIP_basic_incoming_operation.vsd \
+	pictures/SIP_basic_outgoing_operation.eps \
+	pictures/SIP_basic_outgoing_operation.gif \
+	pictures/SIP_basic_outgoing_operation.vsd \
+	pictures/SIP_incoming_call.eps \
+	pictures/SIP_incoming_call.gif \
+	pictures/SIP_incoming_call.vsd \
+	pictures/SIP_outgoing_call.eps \
+	pictures/SIP_outgoing_call.gif \
+	pictures/SIP_outgoing_call.vsd \
+	pictures/SIP_outgoing_operation_with_auth.eps \
+	pictures/SIP_outgoing_operation_with_auth.gif \
+	pictures/SIP_outgoing_operation_with_auth.vsd \
+	pictures/autotools.eps \
+	pictures/autotools.gif \
+	pictures/autotools.vsd \
+	pictures/nta-receiving-message.eps \
+	pictures/nta-receiving-message.gif 
+
+BUILT_SOURCES = Doxyfile.rfc
+CLEANFILES = Doxyfile.rfc
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/docs/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/docs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+Doxyfile.version: $(top_builddir)/config.status $(srcdir)/Doxyfile.version.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-footer.html: $(top_builddir)/config.status $(srcdir)/sofia-footer.html.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/pictures
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	distclean distclean-generic distclean-libtool distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+	uninstall-info-am
+
+
+# Including Doxyfile.rfc in dist breaks make manpages
+
+Doxyfile.rfc:
+	$(AWK) 'END { b="\\"; q="\\\""; \
+		print "# Autogenerated aliases for RFCs "from" .. "to ; \
+		print "ALIASES += " b; \
+		for (i=from; i < to; i++) { \
+		  print "RFC"i"=\"<a href="q site i type q">RFC "i"</a>\" "b; \
+		}}' \
+	site=http://www.faqs.org/rfcs/rfc type=.html \
+	from=700 to=4800 \
+	/dev/null > $@
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1158 @@
+/*  -*- html -*- */
+/**
+
+ at page sofia_sip_conformance SIP and SDP Protocol Features in Sofia-SIP
+
+This document describes how Sofia-SIP stack supports specifications listed
+below.
+
+<table border=0>
+<tr valign="top">
+<td>
+<a href="#3261">RFC 3261</a> <br>
+<a href="#2617">RFC 2617</a> <br>
+<a href="#3262">RFC 3262</a> <br>
+<a href="#3263">RFC 3263</a> <br>
+<a href="#3265">RFC 3265</a> <br>
+<a href="#2806">RFC 2806</a> <br>
+<a href="#2976">RFC 2976</a> <br>
+<a href="#3311">RFC 3311</a> <br>
+<a href="#3313">RFC 3313</a> <br>
+<a href="#3323">RFC 3323</a> <br>
+<a href="#3326">RFC 3326</a> <br>
+</td><td>
+<a href="#3325">RFC 3325</a> <br>
+<a href="#3327">RFC 3327</a> <br>
+<a href="#3329">RFC 3329</a> <br>
+<a href="#3361">RFC 3361</a> <br>
+<a href="#3420">RFC 3420</a> <br>
+<a href="#3428">RFC 3428</a> <br>
+<a href="#3486">RFC 3486</a> <br>
+<a href="#3515">RFC 3515</a> <br>
+<a href="#3608">RFC 3608</a> <br>
+<a href="#3680">RFC 3680</a> <br>
+<a href="#3824">RFC 3824</a> <br>
+</td><td>
+<a href="#3840">RFC 3840</a> <br>
+<a href="#3841">RFC 3841</a> <br>
+<a href="#3842">RFC 3842</a> <br>
+<a href="#3856">RFC 3856</a> <br>
+<a href="#3857">RFC 3857</a> <br>
+<a href="#3858">RFC 3858</a> <br>
+<a href="#3891">RFC 3891</a> <br>
+<a href="#3892">RFC 3892</a> <br>
+<a href="#3903">RFC 3903</a> <br>
+<a href="#4028">RFC 4028</a> <br>
+<a href="#4566">RFC 4566</a> <br>
+</td><td>
+<a href="#2327">RFC 2327</a> <br>
+<a href="#3264">RFC 3264</a> <br>
+<a href="#3266">RFC 3266</a> <br>
+<a href="#3312">RFC 3312</a> <br>
+<a href="#3388">RFC 3388</a> <br>
+<a href="#3407">RFC 3407</a> <br>
+<a href="#3524">RFC 3524</a> <br>
+<a href="#3556">RFC 3556</a> <br>
+<a href="#3605">RFC 3605</a> <br>
+<a href="#3890">RFC 3890</a> <br>
+</td></tr>
+</table>
+
+<table border=1 cellpadding=4 cellspacing=0>
+<tr>
+   <th>Feature</th>
+   <th>Supported</td>
+   <th>Notes</td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+       <a name="3261"></a>
+	@RFC3261: Basic SIP Protocol
+    </th>
+    <td>
+	The SIP registration and dialog level implementation enables the
+	application to operate as a SIP UA, SIP proxy or a redirect server
+	according to the @RFC3261.
+
+	The @RFC3261 functionality is divided into five layers:
+	-# <a href="sip/index.html">message syntax and encoding</a>
+	-# <a href="tport/index.html">transport</a>
+	-# <a href="nta/index.html">transaction</a>
+	-# transaction user (UAS and UAC cores, proxy core)
+	-# SIP elements: <a href="nua/index.html">user agent</a>
+           client and server, proxies,
+	   registrars
+    </td>
+    <td>
+        &nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+       <a name="3261.19"></a> <a name="3261.20"></a>
+	@RFC3261 Sections&nbsp;19&nbsp;and&nbsp;20:<br>
+	Syntax and encoding
+    </td>
+    <td>
+	The supported @RFC3261 methods are: @b REGISTER, @b OPTIONS, @b
+	INVITE, @b ACK, @b CANCEL, @b BYE, as well as methods
+	<a href="#2976"><b>INFO</b></a>,
+	<a href="#3262"><b>PRACK</b></a>,
+        <a href="#3265"><b>SUBSCRIBE</b></a>,
+        <a href="#3265"><b>NOTIFY</b></a>,
+        <a href="#3311"><b>UPDATE</b></a>,
+        <a href="#3428"><b>MESSAGE</b></a>,
+        <a href="#3515"><b>REFER</b></a>,
+	and
+	<a href="#3903"><b>PUBLISH</b></a>.
+
+	Sofia-SIP supports the following SIP headers as specified in
+        @RFC3261 or its extensions (generating, parsing and syntax
+        checking):
+
+	@ref sip_accept "Accept",
+	@ref sip_accept_encoding "Accept-Encoding",
+	@ref sip_accept_language "Accept-Language",
+	@ref sip_allow "Allow",
+	@ref sip_authentication_info "Authentication-Info",
+	@ref sip_authorization "Authorization",
+	@ref sip_call_id "Call-ID" ("i"),
+	@ref sip_call_info "Call-Info",
+	@ref sip_contact "Contact" ("m"),
+	@ref sip_content_disposition "Content-Disposition",
+        @ref sip_content_encoding "Content-Encoding" ("e"),
+	@ref sip_content_language "Content-Language",
+	@ref sip_content_length "Content-Length" ("l"),
+	@ref sip_content_type "Content-Type" ("c"),
+	@ref sip_cseq "CSeq",
+	@ref sip_date "Date",
+	@ref sip_error_info "Error-Info",
+	@ref sip_expires "Expires",
+	@ref sip_from "From" ("f"),
+	@ref sip_in_reply_to "In-Reply-To",
+	@ref sip_max_forwards "Max-Forwards",
+	@ref sip_min_expires "Min-Expires",
+	@ref sip_mime_version "MIME-Version",
+	@ref sip_organization "Organization",
+	@ref sip_priority "Priority",
+	@ref sip_proxy_authenticate "Proxy-Authenticate",
+	@ref sip_proxy_authorization "Proxy-Authorization",
+	@ref sip_proxy_require "Proxy-Require",
+	@ref sip_record_route "Record-Route",
+	@ref sip_require "Require",
+	@ref sip_retry_after "Retry-After",
+	@ref sip_route "Route",
+	@ref sip_server "Server",
+	@ref sip_subject "Subject" ("s"),
+	@ref sip_supported "Supported" ("k"),
+	@ref sip_timestamp "Timestamp",
+	@ref sip_to "To" ("t"),
+	@ref sip_unsupported "Unsupported",
+	@ref sip_user_agent "User-Agent",
+	@ref sip_via "Via" ("v"),
+	@ref sip_warning "Warning", and
+	@ref sip_www_authenticate "WWW-Authenticate".
+
+	Unknown headers (extension headers) are supported and can be passed
+	to/received from application as name-value pairs.
+
+	It is possible to extend SIP parser in run-time with header-specific
+        parsers.
+    </td>
+    <td>
+    	- Unsupported headers:
+	  Alert-Info,
+	  Reply-To
+	- Automatic escaping of reserved characters has not been
+	  implemented.
+	- Using NUL (zero byte) in doublequoted strings has not been implemented
+   </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3261.18"></a>
+	@RFC3261 Section 18:<br>
+	UDP and TCP transports
+    </th>
+    <td>
+        UDP and TCP on both IP4 and IP6 are supported.
+
+        The UDP size limit of 1300 bytes is enforced by default. If limit is
+        exceeded, TCP is tried instead. If TCP connection is refused, UDP is
+        tried if message size is less than 64 kilobytes. Limit is adjustable
+        via parameter NTATAG_UDP_MTU().
+
+	TCP connections are reused by client. However, server closes
+	connections after idle time of 30 minutes (by default). The idle
+	time limit is adjustable with TPTAG_IDLE() (given as argument to
+	nta_agent_add_tport() or nta_agent_create()).
+
+	Server tries to use same TCP connection to return response as the
+	request was received.
+
+	Only one SIP message is accepted per UDP message, as per @RFC3261.
+    </td>
+    <td>
+	There is experimental support for SCTP, too.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3261.17"></a>
+	@RFC3261 Section 17:<br> Transactions
+    </th>
+    <td>
+        Transaction state engines function as specified in @RFC3261 section
+	17. There is special handling of methods @b INVITE, @b ACK, and @b
+	CANCEL. There are two modes for transaction state engines,
+	User-Agent and Proxy modes.
+
+	Default values for SIP timers are those specified by @RFC3261. The
+	defaults for T1, T1x64, T2 and T4 can be changed via
+        configuration tags defined in <nta_tag.h>.
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3261.26"></a>
+	@RFC3261 Section 26:<br> Security
+    </th>
+    <td>
+        TLS and SIPS URIs has been implemented. Currently, TLS does not
+	require certificate from client nor it does check it if one is
+	provided.
+    </td>
+    <td>
+	Missing:
+	- TLS certificate checking
+	- S/MIME
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="2617"></a>
+	@RFC2617: HTTP Digest Authentication
+    </th>
+    <td>
+	Sofia-SIP an authentication client and server modules implementing
+        HTTP Digest authentication.
+
+	HTTP Digest is a simple challenge-response authentication
+	scheme defined in @RFC2617 based on the UA sending a checksum
+	calculated over specific values in response to a challenge sent by
+	the server (proxy or UA).
+
+        Checksum calculation supports MD5 (@RFC1321). The algorithm for
+        calculating MD5 digest hash can be MD5, MD5sess or be
+        @RFC2069-compatible algorithm. The quality-of-protection (qop)
+        parameters "auth", "auth-int" and none (missing) are supported. The
+        "opaque" parameter is supported.
+
+	The SIP authentication headers supported (generating, parsing and
+	syntax checking) are:
+	@ref sip_authorization "Authorization",
+	@ref sip_authentication_info "Authentication-Info",
+	@ref sip_proxy_authenticate "Proxy-Authenticate",
+	@ref sip_proxy_authentication_info "Proxy-Authentication-Info",
+	@ref sip_proxy_authorization "Proxy-Authorization", and
+	@ref sip_www_authenticate "WWW-Authenticate".
+
+	SIP interface to the modules is implemented as defined in @RFC3261
+	(sections 8.1.3.5, 22.2, 22.3, 22.4).
+
+	An @RFC2617 header
+	@ref sip_proxy_authentication_info "Proxy-Authentication-Info"
+        is not listed in @RFC3261 but it is nevertheless supported by
+        Sofia-SIP.
+    </td>
+    <td>
+	Missing:
+        - Using nextnonce
+	- Mutual authentication
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3262"></a>
+	@RFC3262: PRACK and 100rel
+    </th>
+    <td>
+	PRACK method is supported within dialog as defined in RFC3262.
+        Semantics of reliable provisional responses are supported:
+        - including 100rel Required header in provisional responses if
+          request had 100rel
+	- generation of PRACK based on 100rel option tag in Require header of
+	  a provisional response, and
+        - automatic re-transmission of provisional responses.
+
+	The SIP headers supported (generating, parsing and syntax checking)
+	are @ref sip_rseq "RSeq" and @ref sip_rack "RAck".
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3263"></a>
+	@RFC3263: Locating SIP Servers
+    </th>
+    <td>
+	Support for SIP server address resolution from SIP or SIPS URI using
+	NAPTR, SRV, A or AAAA records in DNS as defined in @RFC3263.
+    </td>
+    <td>
+	- Resolving any other types of URIs than SIP or SIPS URIs, e.g., IM:
+	or PRES: URIs.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3265"></a>
+	@RFC3265: SIP Event Notifications
+    </th>
+    <td>
+	SIP extensions for subscribing and processing asynchronous event
+	notifications as defined in @RFC3265.
+
+	Includes dialog level support for sending and refreshing SUBSCRIBE
+	and receiving NOTIFY messages.
+
+	The SIP headers explicitly supported (generating, parsing and
+	syntax checking) are
+        @ref sip_event "Event" ("o"),
+	@ref sip_allow_events "Allow-Events", and
+        @ref sip_subscription_state "Subscription-State"
+
+	Note: currently there is no support for forked SUBSCRIBE requests.
+    </td>
+    <td>
+	Application must take care of:
+	- Subscribing, generating or processing specific event types
+          and interpreting the content of event data is up to application
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="2806"></a>
+	@RFC2806: tel URI
+    </th>
+    <td>
+	Sofia-SIP supports handling of any URI type. Sofia-SIP parses tel:
+        URIs.
+    </td>
+    <td>
+	Missing:
+	- Resolving the tel: URIs
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="2976"></a>
+	@RFC2976: INFO
+    </th>
+    <td>
+	INFO method is supported within a dialog natively.
+    </td>
+    <td>
+	Not implemented:
+	- Generating or processing contents of INFO requests
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3311"></a>
+	@RFC3311: UPDATE
+    </th>
+    <td>
+	UPDATE method as defined in RFC3311. UPDATE allows a client to
+	update parameters of a session (such as the set of media streams and
+	their codecs) even within early dialogs.
+
+	Offer-Answer negotiation with UPDATE is implemented in nua.
+    </td>
+    <td>
+	Application must take care of:
+        - Initiating UPDATE requests
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3313"></a>
+	@RFC3313: Media Authentication
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#3261.19">generic support</a> for
+	extension headers and parameters. P-Media-Authorization header is
+	supported as an @ref sip_unknown "extension header".
+    </td>
+    <td>
+        Application must take care of:
+	- Passing the authorization token to QoS reservation request
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3323"></a>
+	@RFC3323: Privacy
+    </th>
+    <td>
+	@ref sip_privacy "Privacy" header is supported (generating, parsing
+        and syntax checking).
+
+	Call-Id header is generated from cryptographically random id without
+	host name or IP address. By default, @ref sip_contact "Contact" and
+	@ref sip_via "Via" headers contain only IP address that can be
+	dynamically allocated.
+
+	Application can enter any SIP URI and display name to From header,
+	e.g., @code Anonymous <sip:anonymous at example.org> @endcode.
+    </td>
+    <td>
+        Application must take care of:
+	- Properly populating the URIs and display names within SIP headers
+	- Not including any optional headers that could reveal identity
+	- Generating of Privacy header with appropriate values
+	- Generating of Proxy-Require: privacy
+	- Using anonymous callback URIs etc.
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3326"></a>
+	@RFC3326: Reason
+    </th>
+    <td>
+	Sofia-SIP supports @ref sip_reason "Reason" header (generating,
+	parsing and syntax checking).
+    </td>
+    <td>
+        Application must take care of:
+	- Generating or processing Reason headers
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3325"></a>
+	@RFC3325: Asserted Identity
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#3261.19">generic support</a> for
+	extension headers and parameters. P-Asserted-Identity and
+	P-Preferred-Identity are supported as supported as @ref
+	sip_unknown "extension headers".
+    </td>
+    <td>
+	Not implemented:
+        - <a href="#3323">id privacy</a>
+	- Recognizing trust domains and enforcing handling of headers
+	  based on those
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3327"></a>
+	@RFC3327: Path
+    </th>
+    <td>
+	User-agent engine can add "path" option tag to Supported header of
+	REGISTER requests.
+
+	Sofia-SIP explicitly supports @ref sip_path "Path" header
+	(generating, parsing and syntax checking).
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3329"></a>
+	@RFC3329:
+	Security Agreement
+    </th>
+    <td>
+	Some support of the SIP Security Mechanism Agreement procedures. The
+	client is able to insert Security-Client and Security-Verify header
+	with fake @e d-ver value.
+
+	Sofia-SIP explicitly supports (generating, parsing
+	and syntax checking)
+	@ref sip_security_client "Security-Client",
+	@ref sip_security_server "Security-Server", and
+	@ref sip_security_verify "Security-Verify" headers.
+
+	Security-mechanism supported is "digest".
+    </td>
+    <td>
+	Correct @e d-ver value is not calculated.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3361"></a>
+	@RFC3361: DHCPv4 option for locating SIP servers.
+    </th>
+    <td>
+	Sofia-SIP supports outbound proxy.
+    </td>
+    <td>
+	Application must take care of:
+	- passing outbound proxy name or address from DHCP client
+          to Sofia-SIP stack.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3420"></a>
+	@RFC3420: message/sipfrag
+    </th>
+    <td>
+	Sofia-SIP passes the received SIP message headers to application
+	which can create a message/sipfrag payload.
+    </td>
+    <td>
+        Application must take care of:
+	- processing the SIP message fragments
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3428"></a>
+	@RFC3428: MESSAGE
+    </th>
+    <td>
+	MESSAGE method is supported natively.
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3486"></a>
+	@RFC3486: Compressing SIP
+    </th>
+    <td>
+	Sofia-SIP provides support for using comp=sigcomp parameters in @ref
+	sip_via "Via" header and @ref url_t "SIP URIs", indicating
+	support for compression.
+    </td>
+    <td>
+	SigComp itself is not supported.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3515"></a>
+	@RFC3515: REFER
+    </th>
+    <td>
+	REFER method is supported natively. Sofia-SIP processes incoming
+        REFER requests and generates NOTIFY with correct
+	@ref sip_event "Event" header automatically.
+
+	Further notifications can be automatically generated actions when
+	nua_invite() is given referrer's nua handle in NUTAG_NOTIFY_REFER().
+
+	Sofia-SIP explicitly supports (generating, parsing and syntax
+	checking) @ref sip_refer_to "Refer-To" ("r") SIP header.
+
+	See also support for
+	<a href="#3891">RFC 3891</a> and
+        <a href="#3892">RFC 3892</a>.
+    </td>
+    <td>
+        &nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3608"></a>
+	@RFC3608: Service-Route
+    </th>
+    <td>
+	Sofia-SIP supports @ref sip_service_route "Service-Route" that can
+	be used to provide a mechanism by which a registrar may inform a
+	registering UA of a service route. User-Agent will optionally use
+	the route provided in @ref sip_service_route "Service-Route" header.
+
+	The SIP header explicitly supported (generating, parsing and
+	syntax checking) is @ref sip_service_route "Service-Route".
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3680"></a>
+	@RFC3680: "reg" event
+    </th>
+    <td>
+	Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+	subscribing SIP event packages and receiving notifications for them.
+	Subscriptions are refreshed before expiration when needed and
+	subscriptions are terminated on request. Sofia-SIP takes care of
+        notified subscription states.
+
+	UA can SUBSCRIBE to a registration state event package after sending
+	initial REGISTER to, e.g., 3GPP network and use it to follow its
+        registration status.
+    </td>
+    <td>
+	Application must take care of:
+	- Generating subscriptions for "reg" event
+	- Processing notifications for "reg" event
+	  - Handling of XML document in notifications
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3824"></a>
+	@RFC3824: ENUM
+    </th>
+    <td>
+	Tel URIs are supported in any headers including URI parameters,
+	e.g., To, From, Contact headers, and Request-URI of the outgoing SIP
+	request provided that the next hop is given as SIP or SIPS URI.
+    </td>
+    <td>
+	Stack can not resolve E.164 number to address of next
+	hop. A proxy in the network must resolve E.164 numbers with ENUM.
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3840"></a>
+	@RFC3840: Callee Capabilities
+    </th>
+    <td>
+	Feature parameters can be added to SIP profiles and sent within
+	Contact header of REGISTER request as header parameters.
+
+	UAC can optionally generate media tags for Contact header using
+	local media profile.
+
+	Feature parameters can also be sent within any other SIP request as
+	extension parameters of Contact header.
+    </td>
+    <td>
+	Application must take care of:
+        - Processing the feature parameters received in the Contact header
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3841"></a>
+	@RFC3841: Caller Preferences
+    </th>
+    <td>
+	Built-in support for user-agent behavior.
+
+	UAC can optionally generate Accept-Contact header using local media
+	profile.
+
+	SIP parser parses the Accept-Contact and Reject-Contact headers.
+
+        ACK and CANCEL request messages sent have same values
+	for Accept-Contact/Reject-Contact or Request-Disposition
+	headers as the original request had.
+
+	There are functions for calculating score for contacts.
+
+	The SIP headers explicitly supported (generating,
+	parsing and syntax checking) are:
+	@ref sip_request_disposition "Request-Disposition" ("d"),
+	@ref sip_accept_contact "Accept-Contact" ("a"),
+	@ref sip_reject_contact "Reject-Contact" ("j"),
+    </td>
+    <td>
+	Application must take care of:
+        - UAS processing incoming Accept-Contact or Reject-Contact headers
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3842"></a>
+	@RFC3842: Message waiting event
+    </th>
+    <td>
+	Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+	subscribing SIP event packages and receiving notifications for them.
+	Subscriptions are refreshed before expiration when needed and
+	subscriptions are terminated on request. Sofia-SIP takes care of
+        notified subscription states.
+    </td>
+    <td>
+	Application must take care of:
+	- Generating subscriptions for "message-summary" event
+          - Including correct @ref sip_event "Event" and
+            @ref sip_accept "Accept" headers in the request (if needed)
+	- Processing notifications for "message-summary" event
+	  - Handling of summary information in notifications
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3856"></a>
+	@RFC3856: Presence
+    </th>
+    <td>
+	Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+	subscribing SIP event packages and receiving notifications for them.
+	Subscriptions are refreshed before expiration when needed and
+	subscriptions are terminated on request. Sofia-SIP takes care of
+        notified subscription states.
+
+	Note: Usage of pres: URI is supported only if the next hop URI to
+	where to send SUBSCRIBE is a SIP URI (e.g. of outbound proxy).
+	Resolving of pres: URIs by DNS is not supported.
+    </td>
+    <td>
+	Application must take care of:
+	- Generating subscriptions for "presence" event
+          - Including correct @ref sip_event "Event" and
+            @ref sip_accept "Accept" headers in the request (if needed)
+	- Processing notifications for "presence" event
+	  - Handling of presence information in notifications
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3857"></a> <a name="3858"></a>
+	@RFC3857: "winfo" event template package<br>
+	@RFC3858: winfo format
+    </th>
+    <td>
+	Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+	subscribing SIP event packages and receiving notifications for them.
+	Subscriptions are refreshed before expiration when needed and
+	subscriptions are terminated on request. Sofia-SIP takes care of
+        notified subscription states.
+    </td>
+    <td>
+        Application must take care of:
+	- Generating subscriptions for winfo events
+          - Including correct @ref sip_event "Event" and
+            @ref sip_accept "Accept" headers in the request (if needed)
+	- Processing notifications for winfo events:
+	  - Processing watcherxinfo XML documents
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3891"></a>
+	@RFC3891: Replaces
+    </th>
+    <td>
+	@ref sip_replaces "Replaces" header is explicitly supported
+	(generating, parsing and syntax checking).
+    </td>
+    <td>
+        Application must take care of:
+	- generating @ref sip_replaces "Replaces" header from a dialog and
+          matching a dialog with a Replaces header received
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3892"></a>
+	@RFC3892: Referred-By
+    </th>
+    <td>
+	@ref sip_referred_by "Referred-By" header is explicitly supported
+	(generating, parsing and syntax checking).
+
+	Referred-by token can be sent and received in
+	text-based SIP message body.
+    </td>
+    <td>
+        Application must take care of:
+	- Generating or processing @ref sip_referred_by "Referred-By" headers
+	- Generating (and encrypting) or verifying (and decrypting) of
+	  Referred-by tokens
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3903"></a>
+	@RFC3903: PUBLISH
+    </th>
+    <td>
+	PUBLISH method is supported natively. The SIP headers
+	explicitly supported (generating, parsing and syntax checking) are
+	@ref sip_etag "SIP-ETag" and @ref sip_if_match "SIP-If-Match".
+
+	The <a href="nua/index.html">user-agent engine</a> keep published
+	data refreshed until nua_unpublish() is called.
+    </td>
+    <td>
+        Application must take care of:
+        - Including correct @ref sip_event "Event" in the request
+        - Permanently storing SIP-ETag
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="4028"></a>
+	@RFC4028: Session Timers
+    </th>
+    <td>
+	The SIP session-timer ("timer") extension is supported.
+
+        The session-expires value and refreshing party is negotiated in
+	<a href="nua/index.html">user-agent engine</a>. When user-agent
+	engine is responsible for refreshes, it will initiate re-INVITE or
+	UPDATE transaction at regular intervals. If there has been no SIP
+	activity in session during the refresh period, it will try to
+	automatically terminate the call by sending a @b BYE request.
+
+        The SIP headers explicitly supported (generating, parsing and
+	syntax checking) are @ref sip_session_expires "Session-Expires" ("x") and
+	@ref sip_min_se "Min-SE".
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+</table>
+
+<table border=1 cellpadding=4 cellspacing=0>
+<tr>
+   <th>Feature</th>
+   <th>Supported</td>
+   <th>Notes</td>
+</tr>
+
+<tr valign=top>
+    <th align="left" align="left">
+	<a name="2327"></a>
+	@RFC2327: SDP (Session Description Protocol)
+    </th>
+    <td>
+	Generic support (generating, parsing and syntax checking) for SDP.
+	The SDP
+        @ref sdp_version_t "v=",
+        @ref sdp_origin_t "o=",
+	@ref sdp_connection_t "c=",
+	@ref sdp_bandwidth_t "b=",
+	@ref sdp_time_t "t=",
+	@ref sdp_repeat_t "r=",
+	@ref sdp_zone_t "z=",
+	@ref sdp_key_t "k=",
+	@ref sdp_attribute_t "a=", and
+	@ref sdp_media_t "m="
+        lines are separated and parsed. The "e=", "p=", "s=", and "i=" lines
+	are separated.
+
+	The attributes "a=sendrecv", "a=sendonly", "a=recvonly",
+	"a=inactive", @ref sdp_rtpmap_s "a=rtpmap", and "a=fmtp" are parsed.
+
+	The implementation tries to follow draft-ietf-mmusic-sdp-new-25,
+	draft Internet Standard for SDP in progress.
+    </td>
+    <td>
+    - see also <a href="#4566">RFC 4566</a>
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3264"></a>
+	@RFC3264: SDP Offer/Answer Negotiation
+    </th>
+    <td>
+	Generating and processing offers or answers.
+    </td>
+    <td>
+	- "a=fmtp" parameters are not taken into account
+          when generating or processing answer
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3266"></a>
+	@RFC3266: IP6 in SDP
+    </th>
+    <td>
+	Representation of IP6 addresses within SDP message.
+    </td>
+    <td>
+    - see also <a href="#4566">RFC 4566</a>
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3312"></a>
+	@RFC3312: Preconditions
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+
+        Sofia-SIP supports handling SIP feature tags in
+	@ref sip_proxy_require "Proxy-Require",
+        @ref sip_require "Require",
+        @ref sip_supported "Supported" ("k"),
+        and
+        @ref sip_unsupported "Unsupported" header.
+    </td>
+    <td>
+	Application must take care of:
+	- Semantics and handling of preconditions
+	- Reservation of resources
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3388"></a>
+	@RFC3388: Grouping of Media Lines
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+
+	@RFC3388 defines mid, group, LS and FID are predefined strings to be
+	used within attribute line
+    </td>
+    <td>
+        Application must take care of:
+	- Generating or processing the attribute lines
+	- Grouping the media for transport accordingly
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3407"></a>
+	@RFC3407: Capability Declaration
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+    </td>
+    <td>
+        Application must take care of:
+	- Defining sqn, cdsc, cpar etc. strings needed in a= line
+	- Generating or processing the attribute lines
+	- Capability negotiation itself
+    </td>
+</tr>
+
+
+<tr valign=top>
+    <th align="left">
+	<a name="3524"></a>
+	@RFC3524: SRF
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+    </td>
+    <td>
+        Application must take care of:
+	- Defining SRF string needed in a= line
+	- Generating or processing the attribute lines
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3556"></a>
+	@RFC3556: Bandwidth
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+    </td>
+    <td>
+        Application must take care of:
+	- Generating or processing RS and RR bandwidth modifiers
+	- Semantics of bandwidth allocation
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3605"></a>
+	@RFC3605: RTCP attribute
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+    </td>
+    <td>
+        Application must take care of:
+	- Discovering port numbers
+	- Generating or processing the RTCP attribute lines
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3890"></a>
+	@RFC3890: TIAS
+    </th>
+    <td>
+	Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+	lines that conform to SDP syntax.
+    </td>
+    <td>
+        Application must take care of:
+	- Generating or processing TIAS bandwidth modifiers
+	- Generating or processing the maxprate attribute lines
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="4566"></a>
+	@RFC4566: SDP: Session Description Protocol
+    </th>
+    <td>
+    Obsoletes RFC2327 and RFC3266.
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+</table>
+
+*/
+
+/* Overflow:
+
+<tr valign=top>
+    <th align="left">
+	<a name="3320"></a>
+	@RFC3320: SigComp
+    </th>
+    <td>
+    	Support for using SigComp for compression and
+	decompression of SIP/SDP messages. By default, dynamic
+	compression is used.
+
+	Decompression using UDVM
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3321"></a>
+	@RFC3321: SigComp Extended operations
+    </th>
+    <td>
+	Support for SigComp extended operations.
+    </td>
+    <td>
+	- Explicit Acknowledgment Scheme
+	- Shared Compression
+	- Checkpoint State
+	- Implicit Deletion for Dictionary Update
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3325"></a>
+	@RFC3325: Asserted Identity
+    </th>
+    <td>
+	Explicit support (generating, parsing and syntax checking) for the
+	following SIP headers: P-Asserted-Identity, P-Preferred-Identity
+    </td>
+    <td>
+	- Recognizing trust domains and enforcing handling of headers
+	  based on those
+    </td>
+</tr>
+
+<tr valign=top>
+    <th align="left">
+	<a name="3485"></a>
+	@RFC3485: SIP/SDP Dictionary
+    </th>
+    <td>
+	Support for SigComp static compression using SIP/SDP
+	dictionary.
+    </td>
+    <td>
+	&nbsp;
+    </td>
+</tr>
+
+
+
+
+	- Implicitly registered user identities
+
+<tr valign=top>
+    <th align="left">
+	<a name="3959"></a>
+	@RFC3959: early-session
+    </th>
+    <td>
+	Early-session value can be used within Content-Disposition,
+	Supported and Require headers.
+    </td>
+    <td>
+	- Generating of Content-Disposition, Supported and Require
+	- Handling of multipart bodies with early and session SDP
+    </td>
+</tr>
+
+*/
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*!
+
+ at page docguide Documentation Guidelines
+ 
+ at section doxygen Using Doxygen
+
+Doxygen is a document generation program, used by many C/C++ projects. Its
+home page is at <a href="http://www.doxygen.org">http://www.doxygen.org</a>. 
+The Sofia documentation is written using Doxygen.
+
+Doxygen works by extracting the documentation data both from the actual
+C/C++ source code and from the specially formatted comments. 
+The comments can contain some Javadoc-like 
+ at ref doxycommands "special commands". 
+
+In general the the style of the comments and documentation should follow the
+<a href="http://java.sun.com/j2se/javadoc/writingdoccomments/">
+javadoc style guide</a>.
+
+A Doxygen comment must either contain reference about the entity
+it is describing, e.g., command 
+\@file when describing files:
+ at verbatim
+/**
+ * @file foo.c 
+ * 
+ * Implementation of foo. The foo takes care of grokking xyzzy.
+ * 
+ * @author Jaska Jokunen <jaska.jokunen at company.com> \n
+ * 
+ * @date Created: Wed Oct 20 15:06:51 EEST 2004 jasjoku
+ */
+ at endverbatim
+
+Usually the entity that is documented comes straight after the documentation
+comment. For example, documenting a function happens like this:
+ at anchor orch
+ at verbatim
+
+/**
+ * Orches a candometer. If orching candometer is not possible, it
+ * tries to schadule hearping.
+ * 
+ * @param[in]  k        pointer to a candometer
+ * @param[in]  level    orching level
+ * @param[out] return_hearping return value for schaduled hearping
+ *
+ * @return
+ * The function orch() returns the candometer value, or #ERROR upon an error.
+ * If the returned value is 0, the newly schaduled hearping is returned in
+ * @a return_hearping.
+ */
+int orch(cando_t *k, int level, hearping_t *return_hearping)
+{
+  ...
+}
+ at endverbatim
+
+ at subsection doxyfile Doxyfile and Doxyfile.conf
+
+The doxygen options are specified through a configuration file,
+<i>Doxyfile</i>. As a convention, a module-specific Doxyfile includes 
+a common file libsofia-sip-ua/docs/Doxyfile.conf. This makes it possible 
+to keep the module-specific Doxyfiles as clean as possible:
+
+ at code
+PROJECT_NAME         = "ipt"
+OUTPUT_DIRECTORY     = ../docs/ipt
+
+INPUT 		     = ipt.docs . 
+
+ at INCLUDE = ../Doxyfile.conf
+
+TAGFILES            += ../docs/docs/doxytags=../docs
+TAGFILES            += ../docs/su/doxytags=../su
+GENERATE_TAGFILE     = ../docs/ipt/doxytags
+ at endcode
+
+From the file above, you can observe some conventions. The
+Doxygen-generated HTML documentation is collected in @b docs
+subdirectory at top level. A separate output directory is created for
+each submodule under it. Doxytags for the module are generated in the @e
+doxytags file in the output directory. 
+
+ at subsection module_docs Module documentation in \<module\>.docs
+
+Each module contains a documentation file containing at least the module
+mainpage called @e \<module\>.docs. There should be the module
+boilerplate information, for instance the following example is excerpt
+contents of file @e ipt.docs:
+
+ at verbatim
+/**
+ at MODULEPAGE "ipt" - Utility Module
+
+ at section ipt_meta Module Meta Information
+
+Utility library for IP Telephony applications.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section ipt_overview Overview
+
+This module contain some routines useful for IPT applications, like 
+- ...
+- ...
+*/
+ at endverbatim
+
+ at section doxycommands Common Doxygen Commands
+
+In this section we go through the most common Doxygen commands. All
+the commands are explained in the manual.
+The commands include 
+- @ref doxystyle "style commands (@@a, @@b, @@c, @@e, @@em, @@p)"
+- @ref doxyfuncs "function parameters and return values (@@param, @@return, @@retval)"
+
+ at subsection doxystyle Style Commands - @a, @b, @c, @e
+
+The text style can be changed with @@b @b (bold), @@c @c (code), or
+@@e @e (italic) commands. Function argument names use style command
+@@a. 
+
+For example, a sentence "The @b Content-Type header @a ct specifies the @e
+media-type of the message body, e.g., @c audio/amr would be AMR-encoded
+audio." is produced with commands like
+ at code
+The @b Content-Type header @a ct specifies the @e media-type of 
+the message body, e.g., @c audio/amr would be AMR-encoded audio.
+ at endcode 
+
+The style commands have synonyms, e.g., @@em and @@e mean same, as 
+well as @@c and @@p.
+
+ at subsection doxyfuncs Function Parameters and Return Values - @param, @return, @retval
+
+Parameters to a function are documented with @@param commands. (See
+the @ref orch "orch()" function above.) As a convention, the data flow
+direction [in], [out] or [in,out] is indicated in the brackets after the
+@@param command keyword.
+
+Return values can be documented in two alternative manners, either
+using @@return command (see @ref orch "orch()") or @@retval command. The
+latter is used if the function returns a small number of possible
+values, e.g., enumeration or success/failure indication.
+
+ at verbatim
+/**Schadule hearping.
+ * 
+ * The function schadule() schadules a hearping.
+ * 
+ * @param[in] h pointer to hearping
+ * 
+ * @retval 0  hearping was successful
+ * @retval -1 an error occurred
+ */
+int schadule(hearping_t *h)
+{
+  ...
+}
+ at endverbatim
+
+ at subsection doxyexamples Example Blocks - @code, @endcode
+
+An example code fragment can be included using @@code and @@endcode
+commands.
+ at verbatim
+/**Destroy a hearping.
+ * 
+ * The function hearping_destroy() deinitializes a hearping and
+ * reclaims the memory allocated for it. 
+ * 
+ * @param[in,out] h pointer to pointer to hearping
+ * 
+ * The function clears the pointer to hearping, so it must be called
+ * with a pointer to pointer:
+ * @code
+ *   hearping_destroy(&x->hearping);
+ * @endcode
+ */
+void hearping_destroy(hearping_t **h)
+{
+ at endverbatim
+
+ at subsection docpar Paragraphs
+
+The command @@par can be used to divide text into paragraphs. The text on
+the same line with @@par is used as a subtitle for the paragraph. The
+commands @@date, @@note, @@bug, @@todo, @@sa (See Also) and
+@@deprecated can be used to add common paragraphs to documentation entries.
+
+ at subsection docfiles Documenting Files
+
+In most files there is documentation entry for the file itself. It is
+usually at top after the LGPL reference, containing @@file command or alias
+@@CFILE/@@IFILE. There are Emacs macros for creating the boilerplate entry.
+
+ at subsection docgrouping Grouping Entries
+
+When the structure of the documentation does not follow directory or file
+structure, it is possible to use grouping commands @@defgroup and @@ingroup.
+The command @@defgroup creates a group, and @@ingroup adds an entry to an
+group. 
+
+ at subsection doclinking Creating Links
+
+Normally, Doxygen creates links to classes (and C structs) when it
+encounters the struct/class name.  It is also possible to add links to
+functions, type names and variables. If the function name is followed by
+pair of parenthesis (), Doxygen creates a link to it. If a type name or
+variable is prefixed with hash @#, Doxygen creates a link to it.
+
+It is also possible to create links with freely selected link to
+documentation entries with @@link and @@endlink commands. 
+
+When the link target is a named page, section, or subsection, it is possible
+to use the @@ref command.
+
+ at subsection doctext Writing Body Text
+
+The main body of the documentation is specified with @@mainpage command. The
+contents of the @@mainpage entry become the HTML home page of the
+documentation set. In each documentation set generated with Doxygen there
+can be only one @@mainpage command. Commands @@section, @@subsection, and
+@@subsubsection can be used to structure the body text.
+
+It is also possible to add individual HTML pages to the documentation. It
+happens with @@page command. These individual pages are like the home page
+added with @@mainpage, they can be accessed with the Related Pages link from
+the navigation bar.
+
+ at subsection docimages Adding Images
+
+Images are added with @@image command. As the different documentation
+formats support different image formats, the @@image has list the image file
+name for each supported documentation format. The following example uses
+bitmap image for HTML documentation and Encapsulate PostScript for
+print documents:
+ at code
+ at image html sip-parser.gif
+
+ at image latex sip-parser.eps
+ at endcode
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# description: Mangle email addresses in the HTML documentation
+# author: Kai Vehmanen <kai.vehmanen at nokia.com>
+# version: 20050908-3
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+
+find . -name '*.html' -print | while read i ; do 
+  (
+    echo "Hiding email addresses in ${i}."
+    sed -r -i 's/([:>;][a-z][-a-z.]*)(@[a-z][a-z]*)\.[a-z][a-z]*(["<\&])/\1\2-email.address.hidden\3/gi' $i
+ )
+done

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,740 @@
+/* -*- text -*- */
+
+/**@mainpage Sofia SIP User Agent Library - sofia-sip-ua
+
+ at section Introduction
+
+This document contains automatically generated reference documentation
+for Sofia-SIP components. Some introductory material and
+pointers to the example code are also included.
+
+For a list of module specific pages, see @ref subdirs 
+"source tree structure" or direct links to submodules:<br>
+<a href="nua/index.html">nua</a> 
+<a href="su/index.html">su</a> 
+<a href="features/index.html">features</a> 
+<a href="soa/index.html">soa</a> 
+<a href="sdp/index.html">sdp</a> 
+<a href="nta/index.html">nta</a> 
+<a href="tport/index.html">tport</a> 
+<a href="sresolv/index.html">sresolv</a> 
+<a href="sip/index.html">sip</a> 
+<a href="msg/index.html">msg</a> 
+<a href="url/index.html">url</a> 
+<a href="stun/index.html">stun</a> 
+<a href="iptsec/index.html">iptsec</a> 
+<a href="nea/index.html">nea</a> 
+<a href="nth/index.html">nth</a> 
+<a href="http/index.html">http</a> 
+<a href="bnf/index.html">bnf</a> 
+<a href="ipt/index.html">ipt</a> 
+
+ at section who Contact Information
+
+You can download latest Sofia SIP from the project 
+<a href="http://sofia-sip.sf.net">home page</a> at 
+<a href="sf.net">Sourceforge.net</a>.
+
+Please contact us if you have questions regarding this software:
+
+<ul> 
+<li>Pekka Pessi <Pekka.Pessi at nokia.com></li>
+<li>Kai Vehmanen <Kai.Vehmanen at nokia.com></li>
+</ul> 
+
+Or post to the Sofia-SIP mailing list:
+
+<ul>
+<li>mailto:sofia-sip-devel at lists.sourceforge.net</li>
+<li>http://lists.sourceforge.net/lists/listinfo/sofia-sip-devel</li>
+</ul>
+
+*/
+
+/**@page building Source Tree Structure
+
+ at section subdirs Directory Structure
+
+In libsofia-sip-ua, there are subdirectories
+
+Terminal and high-level libraries utilizing for both signaling and media:
+
+Common runtime library:
+ - <a href="su/index.html">"su" - sockets, memory management, threads</a>
+ - <a href="sresolv/index.html">"sresolv" - Asynchronous DNS resolver</a>
+ - <a href="ipt/index.html">"ipt" - IPT utility library</a>
+
+SIP Signaling:
+ - <a href="nua/index.html">"nua" - SIP User Agent library</a>
+ - <a href="nea/index.html">"nea" - SIP Event API</a>
+ - <a href="iptsec/index.html">"iptsec" - 
+    Digest authentication for HTTP and SIP</a>
+ - <a href="nta/index.html">"nta" - SIP transaction engine</a>
+ - <a href="tport/index.html">"tport" - Message transport</a>
+ - <a href="sip/index.html">"sip" - SIP messages and headers</a>
+ - <a href="msg/index.html">"msg" - Message handling </a>
+ - <a href="url/index.html">"url" - URL handling</a>
+ - <a href="bnf/index.html">"url" - low level parsing</a>
+
+HTTP subsystem:
+ - <a href="nth/index.html">"nth" - HTTP protocol engine</a>
+ - <a href="http/index.html">"http" - HTTP messages and headers</a>
+
+SDP processing:
+ - <a href="soa/index.html">"soa" - SDP Offer/Answer engine for SIP</a>
+ - <a href="sdp/index.html">"sdp" - SDP parser</a>
+
+Other:
+ - <a href="stun/index.html">"stun" - STUN library</a>
+
+Features provided by Sofia-SIP library:
+ - <a href="features/index.html">"features" - Features provided by Sofia SIP</a>
+
+Documentation:
+ - "docs" - Doxygen reference documentation
+
+*/
+
+/**
+ at page styleguide C Style Guide
+
+This document gives general guidelines on generic C style and code
+formatting within Sofia-SIP. The guidelines include identifier naming
+conventions, indenting convention, and tool usage directions.
+
+Please note that C style is always a matter of taste. 
+
+ at section naming Naming Conventions
+
+Generally, identifiers within each module are prefixed with the name of
+that module. For instance, the functions within http parser module @b http
+have prefix @c http_. Identifiers composed of multiple words have an
+underscore "_" between the words, the words themselves are in lower
+case. For instance, http_request_create().
+
+Macros should be in upper case. File names should be in lower case using
+underscore as delimiter if needed.
+
+Normal typedefs have suffix @c _t, however, function types have suffix @c
+_f. The enum names also sometimes have @c _e, struct names have @c _s and
+union names @c _u.
+
+It is recommended that type itself is typedef'ed, not a pointer to the
+type. It should be clear from variable declaration if the variable is a
+pointer or not.
+
+ at code
+typedef struct foo_s foo_t;
+typedef int f_fun(foo_t *f, char const *s);
+ at endcode
+
+Struct and union members should have common prefix. For instance,
+ at code
+struct foo_s {
+  int    f_len;
+  char  *f_name;
+  fun_f *f_fun;
+};
+ at endcode
+
+This prefix makes it easier to find where members are used.
+
+ at section formatting Indenting and Formatting code
+
+Indentation in Sofia-SIP C code generally follows the @e K&R style with indent
+of 2 characters (so you can use the default "GNU" c-style in Emacs). The
+maximum line length should be 80 characters.
+
+For example,
+
+ at code
+void kluge(int foo)
+{
+  if (foo) {
+    bar();
+  }
+  else {
+    switch (baz()) {
+    case a:
+      eeny();
+      break;
+    case b:
+      meeny();
+      break;
+    default:
+      moe();
+      break;
+    }
+  }
+}
+ at endcode
+
+The default indentation can be achieved with GNU indent with options
+ at code
+-nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci2 -cli0 -cp33 -cs
+-d0 -di1 -nfc1 -nfca -hnl -i2 -ip0 -l79 -lp -npcs -nprs -npsl -saf -sai
+-saw -nsc -nsob -nss
+ at endcode
+
+Loops without condition use @c for @c (;;) instead of @c while @c (1). 
+
+ at code
+  for (;;) {
+    foo();
+    if (bar())
+      break;
+    baz();
+  }
+ at endcode
+
+There should be whitespace on both sides of infix operators, except
+<code>.</code> or <code>-></code>, which require no space, or
+<code>,</code> (comma) which requires space only after). There should be
+whitespace between a keyword and parenthesis following it, but no
+whitespace between an identifier and parenthesis following it. E.g.,
+
+ at code
+  while (i++ < n)
+    baz();
+  for (;;) {
+    x->x_foo();
+    if (bar())
+      break;
+    z.z_baz++;
+  }
+  return (13 * i);
+ at endcode
+
+ */
+
+/**
+ at page programming Programming Guide
+
+ at section porting Writing Portable Code
+
+Most of Sofia-SIP software is written as portable. All core modules are
+(or at least should be) written in ANSI C 89 with some ANSI C 99
+features. If there are platform specific parts, they are collected to
+separate C files and isolated from the rest of the software with a
+wrapper interface.
+
+SU module handles abstraction to OS specific functionality such as
+memory management, sockets, threads and time functions. 
+
+ at subsection ansi_99 ANSI C 99 features
+
+The following ANSI C 99 features are to be used in Sofia-SIP software:
+- Integer types
+- functions va_copy() and snprintf()
+
+The following ANSI C 99 features shall not be used in Sofia-SIP software:
+- definition of a variable in the middle of function code.
+  (so always define your variables in the beginning of the block)
+
+ at subsection port_ints Integer Types
+
+As you should know, the length of native storage size depends on hardware,
+OS and compiler. This means in practice that the length of int or long is
+not necessarily 32 bits. As a consequence, you need to make sure that the
+value you intend to store in the int, can actually fit in int on different
+platforms. As a rule of thumb, if the integer value can exceed 8 bits, you
+should use types that have a defined length.
+
+Nevertheless its OK to use native integer types if you bear in mind
+what was said above. The original reason for having only native
+data type was performance. The int type is always stored in the
+fastest (and usually biggest size) possible.
+
+Never assume anything on the length of the type. Alway use sizeof()
+operator to find out the length.
+
+C 99 standard defines the following fixed length data types:
+
+- int64_t
+- uint64_t
+- int32_t
+- uint32_t
+- int16_t
+- uint16_t
+- int8_t
+- uint8_t
+
+To use these data types you must include the <su_types.h> header, which
+takes care of including correct file. If @b su includes are not available,
+you must include the following code segment to each file where you plan to
+use them:
+
+ at code
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#error Define HAVE_STDINT_H as 1 if you have <stdint.h>, \
+ or HAVE_INTTYPES_H if you have <inttypes.h>
+#endif
+ at endcode
+
+ at subsection port_byte_sex Byte order
+
+The host byte order on different platforms vary. When you do only
+local processing, need not to worry about the byte order. But as
+soon as you start writing code that send or receives anything to
+the network, you need to start worrying.
+
+If you wish to convert the byte order, it is simply done by calling
+one the following functions:
+
+The htonl() function converts the unsigned integer hostlong from
+host byte order to network byte order.
+
+The htons() function converts the unsigned short integer hostshort
+from host byte order to network byte order.
+
+The ntohl() function converts the unsigned integer netlong from
+network byte order to host byte order.
+
+The ntohs() function converts the unsigned short integer netshort
+from network byte order to host byte order.
+
+You need to include <netinet/in.h> or <su.h> to use these functions.
+
+ at subsection port_struct Packing structures
+
+By default, compilers usually arrange structures so that they are
+quick to access. This means that most fields in the structure start
+at the 32 bit boundary. If you need to conserve memory, you may use
+structure packing.
+
+To tell the compiler that you only need certain amount of bits to
+store a variable, you can use bit-fields. Compiler may or may not
+pack the bit-fields.
+
+ at code
+struct foo {
+  unsigned bar:5;
+  unsigned foo:2;
+  unsigned :0;
+  int      something;
+}
+ at endcode
+
+If compiler decides to pack this structure, this code generates a
+structure that has @a bar and @a foo in the first seven bits, and then
+ at a something beginning from the next 32 bit boundary. 
+
+One problem arises when using packed bit-fields: on ARM it is
+generally not possible to access a 32 bit field that does not start from
+the 32-bit boundary. Hence the example has the :0 padding member in the
+structure. Seems handy but beware: initialization of this structure fails
+on some ARM gcc compilers. (Ask Kai Vehmanen for details).
+
+A way to force packing of a structure is to use preprocessor
+directive @c @#pragma(pack). This directive is compiler specific, so if
+you plan to write truly portable code, you cannot use it. We have
+used it in some parts of the Sofia-SIP though. Only alternative is to
+write functions that fetch the desired bits from a 32 bit field
+with bit operations; not very handy and error prone.
+
+The same aligment problem also arises if you cast for example char
+buffer to a int32_t. You can only read int32_t from the 32bit boundary
+on ARM platform. So be careful.
+
+As a conclusion, when using bit-fields and stucture packing, beware
+of the pitfalls. If you don't really need to use them (as in parsing
+binary protocols), don't use them.
+
+ at section file_organization File and Directory Structure
+
+A Sofia-SIP library module can be defined as a subdirectory under the
+libsofia-sip-ua directory hierarchy that contains a file \<modulename\>.docs 
+(where the \<modulename\> of course referes to the actual name of 
+the module). 
+
+In case you like to start developing a new module, please
+contact Sofia-SIP development team so that they can help you to set up
+the basic module for you.
+
+An overview of the contents of a module directory:
+  - file \<modulename\>.docs \n
+    Main documentation file for the module. See @ref module_docs
+    for more information
+  - subdirectory pictures \n
+    Contains any pictures/images
+    that are needed by the module documentation. The
+    file formats to use are GIF (for html pages) and
+    EPS (for latex). If some program (e.g. MS Visio) is 
+    used to create the pictures, also the original
+    files must be stored here.\n
+    (Note that old modules may have "images" subdirectory instead of
+    "pictures")
+  - files Makefile.am \n
+    See section @ref build "dealing with GNU Autotools" below.
+  - (optionally) source code file(s) of the module and module tests. 
+    The source code file(s) can also be located in subdirectories if necesary.
+    
+
+ at section oo_with_c Writing Object-Oriented Code
+
+While C does not provide any special object-oriented features on its own, it
+is possible to program in object-oriented way using C, too. Sofia code make
+use of many object-oriented features while being written entirely in C.
+
+ at subsection oo_hiding Data Hiding
+
+Data hiding is a practice that makes separation between two modules very
+clear. Outside code cannot directly access the data within a module, but it
+has to use functions provided for that purpose. Data hiding also makes it
+easier to define a protocol between two objects - all communication happens
+using function calls.
+
+How to implement data hiding in C? Easiest answer is to only declare data
+structures in the header files, not to define them. We have a typedef #msg_t
+for @link msg_s struct msg_s @endlink in <sofia-sip/msg.h>, but the actual
+structure is defined in "msg_internal.h". Programs outside @b msg module
+does not have access to the @link msg_s struct msg_s @endlink, but they have
+to to access the #msg_t object through method functions provided in
+<sofia-sip/msg.h>. The @b msg implementation is also free to change the
+internal layout of the structure, only keeping the function interface
+unmodified.
+
+ at subsection oo_interface Interfaces
+
+Abstract interface is another object-oriented practice used in Sofia. Parser
+headers, defined in <sofia-sip/msg_types.h>, is a good example of abstract
+interface. The type for message headers, #msg_header_t, is defined using two
+C structures @link msg_common_s struct msg_common_s @endlink
+(#msg_common_t), and @link msg_hclass_s struct msg_hclass_s @endlink
+(#msg_hclass_t).
+
+Abstract interface is achieved using virtual function table in #msg_hclass_t
+structure, bit like C++ typically implements abstract classes and virtual
+functions. For implemenation of each header, the function table is
+initialized with functions responsible for decoding, encoding and
+manipulating the header structure. Unlike C++, the class of the object
+(#msg_hclass_t) is represented by a real data structure which also contains
+header-specific data, like header name.
+
+ at dontinclude sip_basic.c
+ at skipline msg_hclass_t sip_contact_class
+ at skip {{
+ at until }};
+
+ at subsection oo_derived Inheritance and Derived Objects
+
+Inheritance is a object-oriented practice that has limited use in Sofia. 
+Most common example of inheritance is use of #su_home_t. Many objects are
+derived from #su_home_t, which means that they can use the various
+home-based memory management functions from <su_alloc.h>. 
+
+In this sence, inheritance means that a pointer to a derived object can be
+casted as a pointer to a base object. In other words, the derived object
+must have the base object at the beginning of its memory area:
+
+ at code
+struct derived 
+{
+  struct base base[1];
+  int         extra;
+  char       *data;
+};
+ at endcode
+
+There are three alternatives to cast a pointer to derived to a pointer to
+base:
+ at code
+struct base *base1 = (struct base *)derived;
+struct base *base2 = &derived->base;
+struct base *base3 = derived->base;
+ at endcode
+The third alternative works because base was used as a 1-element array.
+
+ at subsection oo_templates Templates
+
+There are a few template types implemented as macros in Sofia libraries. 
+They include hash table, defined in <sofia-sip/htable.h>, which can be used
+to define hash tables types and accessor functions for different object, and
+red-black tree, defined in <sofia-sip/rbtree.h>.
+
+ at section memory Memory Management
+
+The home-based memory management is useful when a lot of memory blocks are 
+allocated for given task. The allocations are done via the memory home, 
+which keeps a reference to each allocated memory block. When the memory 
+home is then freed, it will free all memory blocks to which it has 
+reference. This simplifies application logic because application code does 
+not need to keep track of the allocated memory and free every allocated block 
+separately.
+
+See documentation of <su_alloc.h> and @ref su_alloc "memory managment tutorial"
+for more information of memory management services.
+
+ at subsection contextdata Memory management of context data
+
+A typical example of use of a memory home is to have a memory home structure
+(#su_home_t) as part of operation context information structure.
+
+ at code
+  /* context info structure */
+  struct context {
+    su_home_t  ctx_home[1];      /* memory home */
+    other_t   *ctx_other_stuff;  /* example of memory areas */
+    ...
+  };
+
+  /* context pointer */
+  struct context *ctx;
+
+  /* Allocate memory for context structure and initialize memory home */
+  ctx = su_home_clone(NULL, sizeof (struct context));
+
+  /* Allocate memory and register it with memory home */
+  ctx->ctx_other_stuff = su_zalloc(ctx->ctx_home, sizeof(other_t));
+
+  ... processing and allocating more memory ...
+
+  /* Release registered memory areas, home, and context structure */
+  su_home_zap(ctx->ctx_home);
+
+ at endcode
+
+ at subsection combining Combining allocations
+
+Another place where home-based memory management makes programmers
+life easier is case where a sub-procedure makes multiple memory allocations 
+and, in case the sub-procedure fails, all the allocations must be released 
+and, in case the sub-procedure is succesfull, all allocations must be
+controlled by upper level memory management.
+
+ at code
+  /* example sub-procedure. top_home is upper-level memory home */
+  int sub_procedure( su_home_t *top_home, ... )
+  {
+    su_home_t temphome[1] = { SU_HOME_INIT(temphome) };
+
+    ... allocations and other processing ...
+
+    /* was processing successfull ? */
+    if (success) {
+      /* ok -> move registered allocated memory to upper level memory home */
+      su_home_move( top_home, temphome );
+    }
+    /* destroy temporary memory home (and registered allocations) */
+    /* Note than in case processing was succesfull the memory     */
+    /* registrations were already moved to upper level home.      */ 
+    su_home_deinit(temphome);
+
+    /* return ok/not-ok */
+    return success;
+  }
+ at endcode
+
+ at section testing Testing Your Code
+
+See <tstdef.h> for example of how to write module tests with macros provided
+by Sofia.
+
+Here are some ideas of what you should test:
+- "Smoke test" \n
+  See that the module compiles, links and executes.
+- Module API functions should be tested with\n
+  - valid args
+  - not valid args
+- Aim for 100% line coverage\n
+  (If there is a line of code that you have not tested, you don't know 
+  if its working.) \n
+  For selected part of code you should also aim for 
+  100% branch/path coverage.\n
+  But be anyway reasonable with these because in practise complete
+  coverage is next to impossible to achive (so 80% is ok in practise).
+- Create test to check assumptions and/or tricks used in code.\n
+  For example if you rely on some compiler feature, create a test that
+  will fail with a compiler that does not have that feature.
+
+ at subsection check Running Module Tests
+
+Automake, which is used to build Sofia SIP, has builtin
+support for unit tests. To add an automatically run test to your module,
+you just have to add the following few lines to your module's Makefile.am
+(of course, you have to write the test programs, too):
+
+ at code
+TESTS = test_foo test_bar
+
+check_PROGRAMS = test_foo test_bar
+
+test_foo_SOURCES = foo.c foo.h
+test_foo_LDADD = -L. -lmy
+
+test_bar_SOURCES = bar.c bar.h
+test_foo_LDADD = -L. -lmy
+ at endcode
+
+Each test program should either return zero for success or a non-zero
+error code in its main function. Now when you run "make check",
+ at b my_test_foo and @b my_test_bar will be built and then run. 
+Make will print a
+summary of how the tests went. As these tests are run from the build 
+system, the tests must be non-interactive (no questions asked) and not 
+rely on any files that are not in version control system.
+
+Sofia SIP's top-level makefile contains a recursive check target, so 
+you can use "cd sofia-sip ; make check" to run all the existing tests
+with a single command.
+
+ at section build Dealing with GNU Autotools
+
+Sofia-SIP build system is based on the GNU tools automake, autoconf and
+libtool. This toolset has become the de-facto way of building Linux
+software. Because of this there is a lot of publicly available documentation
+about these tools, and of course, lots and lots of examples.
+
+A good introduction to these tools is available at
+<a href="http://developer.gnome.org/doc/books/WGA/generating-makefiles.html">
+developer.gnome.org</a>. <a href="http://sources.redhat.com/autobook">Autobook</a>
+provides more detailed documentation for autoconf and automake.
+The <a href="http://www.gnu.org/manual/make/">GNU make manual</a> 
+is also a good source of information.
+
+ at subsection autogen_sh autogen.sh
+
+At top-level there is a shell script called @b autogen.sh. It calls a
+convenient tool called @b autoreconf which will generate configure script
+for you. It also fixes the mode bits: the mode bits are not stored in
+<a href="http://darcs.net">darcs</a> version control system.
+
+ at code
+$ sh autogen.sh
+$ ./configure ... with your configure options ...
+ at endcode
+
+ at subsection configure_ac configure.ac
+
+The @b configure.ac file (older autoconf versions used also @b configure.in)
+contains the primary configuration for autoconf. configure.ac contains
+checks for all external libraries, non-standard language and compiler
+features that are needed to build the target module.
+
+This file is created by the developer of the module.
+
+ at subsection sofia_m4 m4 files
+
+Sofia-SIP's own autoconf macros are stored in the top-level direcry called @b
+m4. These macros, along with all other macros used by @b configure.ac, are
+copied into the module-specific @b aclocal.m4 file by an utility called
+aclocal.
+
+Contact Sofia-SIP development team, if you need changes to these files.
+
+ at subsection aclocal_m4 aclocal.m4
+
+The aclocal.m4 contains the definitions of the autoconf macros used in 
+ at b configure.ac.
+
+This file is generated by aclocal command.
+
+ at subsection Makefile_am Makefile.am
+
+Makefile.am is where you define what programs and libraries should 
+be built, and also what source files are needed to create them.
+When you run automake, it creates the file Makefile.in.
+
+This file is created by the developer of the module.
+
+ at subsection configure configure
+
+When you run configure script, it performs all the checks defined in 
+ at b configure.ac and then replaces all @b xxx.in files with equivalent 
+ at b xxx files. All @c @@FOO@@ variables in the source @b *.in files are 
+replaced with values found during the configuration process. For instance
+the variable @c @@srcdir@@ in @b Makefile.in is replaced in @b Makefile 
+with the source directory path (useful when compiling outside the main 
+source tree).
+
+This file is generated by autoconf command.
+
+ at subsection config_status config.status
+
+This script stores the last parameters given to configre command.
+If necessary you can rerun the last given configure script (with given
+parameters) by using command "./config.status -r" or 
+"./config.status --recheck".
+
+This file is generated by configure script.
+
+ at subsection config_cache config.cache
+
+This file contains results of the various checks that configure script 
+performed. In case the configure script failed, you might try to
+delete this file and run the configure script again.
+
+This file is generated by configure script.
+
+ at subsection Makefile Makefile
+
+The @b Makefile contains the actual rules how to build the target 
+libraries and program. It is used by the @c make program. @b Makefile 
+is generated from @b Makefile.in when you run @c autoconf command.
+Ensure that "make dist" and "make install" targets work.
+
+This file is generated by config.status and configure scripts.
+
+ at subsection config_h config.h
+
+This file contains C language defines of various confurable issues.
+
+This file is generated by config.status and configure script.
+
+ at subsection sofia_sip_configure_h sofia-sip/su_configure.h
+
+This file contains C language defines describing how the Sofia SIP UA
+library is configured.
+
+This file is generated by config.status and configure script.
+
+*/
+
+/**
+ at page debug_logs Debugging Logs
+
+The Sofia-SIP components can output various debugging information. The
+detail of the debugging output is determined by the debugging level. The
+level is usually module-specific and it can be modified by module-specific
+environment variable. There is also a default level for all modules,
+controlled by environment variable #SOFIA_DEBUG.
+
+The environment variables controlling the logging and other debug output are
+as follows:
+- #SOFIA_DEBUG	Default debug level (0..9)
+- #NUA_DEBUG	User Agent engine (<a href="nua/index.html">nua</a>) debug level (0..9)
+- #SOA_DEBUG	SDP Offer/Answer engine (<a href="soa/index.html">soa</a>) debug level (0..9)
+- #NEA_DEBUG	Event engine (<a href="nea/index.html">nea</a>) debug level (0..9)
+- #IPTSEC_DEBUG	HTTP/SIP autentication module debug level (0..9)
+- #NTA_DEBUG	Transaction engine debug level (0..9)
+- #TPORT_DEBUG	Transport event debug level (0..9)
+  - #TPORT_LOG	If set, print out all parsed SIP messages on transport layer
+  - #TPORT_DUMP	Filename for dumping unparsed messages from transport
+- #SU_DEBUG	<a href="nea/index.html">su</a> module debug level (0..9)
+
+The defined debug output levels are:
+- 0 SU_DEBUG_0() - fatal errors, panic
+- 1 SU_DEBUG_1() - critical errors, minimal progress at subsystem level
+- 2 SU_DEBUG_2() - non-critical errors
+- 3 SU_DEBUG_3() - warnings, progress messages
+- 5 SU_DEBUG_5() - signaling protocol actions (incoming packets, ...)
+- 7 SU_DEBUG_7() - media protocol actions (incoming packets, ...)
+- 9 SU_DEBUG_9() - entering/exiting functions, very verbatim progress
+
+In addition to the macros mentioned above, there is also functions for 
+printing logging messages:
+- su_llog(), su_vllog()
+- su_perror(), su_perror2()
+
+The log level can be set (to a level defined in a configuration file, for
+instance) with following functions
+- su_log_set_level(), su_log_soft_set_level()
+
+The log output can be redirected to, e.g., system log or loggin server, with
+su_log_redirect().
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4 @@
+<hr />
+Sofia-SIP @VERSION@ -
+Copyright (C) 2006 Nokia Corporation. All rights reserved.
+Licensed under the terms of the GNU Lesser General Public License.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,32 @@
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed features.
+  Added libfeatures.la into .so. Renamed sofia_has_* as sofia_sip_has_*. Using
+  features in nua_cli.c
+
+    M ./libsofia-sip-ua/Makefile.am +1
+    M ./libsofia-sip-ua/features/Makefile.am -2 +2
+    M ./libsofia-sip-ua/features/sofia_sip_features.c -14 +14
+    M ./libsofia-sip-ua/features/sofia_sip_features.docs -10 +10
+    M ./libsofia-sip-ua/features/sofia_sip_features.h.in -10 +10
+    M ./libsofia-sip-ua/stun/stun.c -2 +2
+    M ./utils/Makefile.am -1 +2
+    M ./utils/nua_cli.c -2 +29
+
+  * Added "features" module.
+
+     ./libsofia-sip-ua/nua/sofia_config.c -> ./libsofia-sip-ua/sofia/sofia_sip_features.c
+     ./libsofia-sip-ua/nua/sofia_config.h.in -> ./libsofia-sip-ua/sofia/sofia_sip_features.h.in
+     ./libsofia-sip-ua/sofia -> ./libsofia-sip-ua/features
+    M ./configure.ac -2 +3
+    M ./libsofia-sip-ua/Makefile.am -1 +1
+    A ./libsofia-sip-ua/features/Doxyfile
+    A ./libsofia-sip-ua/features/Makefile.am
+    M ./libsofia-sip-ua/features/sofia_sip_features.c -21 +78
+    A ./libsofia-sip-ua/features/sofia_sip_features.docs
+    M ./libsofia-sip-ua/features/sofia_sip_features.h.in -15 +20
+    M ./libsofia-sip-ua/nua/Makefile.am -4 +3
+    A ./libsofia-sip-ua/sofia/
+    M ./libsofia-sip-ua/stun/stun.c -1 +6
+    M ./libsofia-sip-ua/stun/stun.h +2
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+PROJECT_NAME         = "features"
+OUTPUT_DIRECTORY     = ../docs/html/features
+
+INPUT 		     = features.docs sofia-sip .
+
+ at INCLUDE             = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/docs.doxytags=..
+TAGFILES            += ../docs/su.doxytags=../su
+TAGFILES            += ../docs/ipt.doxytags=../ipt
+TAGFILES            += ../docs/bnf.doxytags=../bnf
+TAGFILES            += ../docs/url.doxytags=../url
+TAGFILES            += ../docs/msg.doxytags=../msg
+TAGFILES            += ../docs/sip.doxytags=../sip
+TAGFILES            += ../docs/sresolv.doxytags=../sresolv
+TAGFILES            += ../docs/tport.doxytags=../tport
+TAGFILES            += ../docs/nta.doxytags=../nta
+TAGFILES            += ../docs/sdp.doxytags=../sdp
+
+GENERATE_TAGFILE     = ../docs/features.doxytags
+
+ALIASES             +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,34 @@
+#
+# Makefile.am for sofia features module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES =		$(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libfeatures.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+# This is used by platforms not supporting autoconf
+nobase_include_sofia_HEADERS = sofia-sip/sofia_features.h
+
+libfeatures_la_SOURCES = features.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile features.docs
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,588 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia features module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libfeatures_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/features
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libfeatures_la_LIBADD =
+am_libfeatures_la_OBJECTS = features.lo
+libfeatures_la_OBJECTS = $(am_libfeatures_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libfeatures_la_SOURCES)
+DIST_SOURCES = $(libfeatures_la_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libfeatures.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+# This is used by platforms not supporting autoconf
+nobase_include_sofia_HEADERS = sofia-sip/sofia_features.h
+libfeatures_la_SOURCES = features.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile features.docs
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/features/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/features/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libfeatures.la: $(libfeatures_la_OBJECTS) $(libfeatures_la_DEPENDENCIES) 
+	$(LINK)  $(libfeatures_la_LDFLAGS) $(libfeatures_la_OBJECTS) $(libfeatures_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/features.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE features.c
+ * Provide features available through the sofia-sip library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Oct 24 14:51:32 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#include <sofia-sip/su_configure.h>
+#include <tport_tls.h>
+#include "sofia-sip/sofia_features.h"
+
+/** The name and version of software package providing Sofia-SIP-UA library.
+ * @showinitializer
+ */
+char const * const sofia_sip_name_version = SOFIA_SIP_NAME_VERSION;
+
+/** The name and version of software package providing S/MIME functionality, 
+ *  NULL if none.
+ */
+char const * sofia_sip_has_smime;
+
+
+/** The name and version of software package providing TLS functionality, 
+ *  NULL if none. 
+ * 
+ * TLS over TCP is used as transport for SIP messages when using SIPS
+ * scheme. Using TLS over TCP with SIP is described in @RFC3261.
+ */
+#if HAVE_OPENSSL
+char const * sofia_sip_has_tls = tls_version;
+#else
+char const * sofia_sip_has_tls;
+#endif
+
+/** The name and version of software package providing DTLS functionality, 
+ *  NULL if none. 
+ *
+ * DTLS or TLS over datagram transport (UDP) can be used as transport for
+ * SIP messages.
+ */
+char const * sofia_sip_has_dtls;
+
+/** The name and version of software package providing TLS over SCTP functionality, 
+ *  NULL if none. 
+ *
+ * TLS over SCTP can be used as transport for SIP messages.
+ */
+char const * sofia_sip_has_tls_sctp;
+
+#if HAVE_SOFIA_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+/** The name and version of software package providing SigComp functionality, 
+ *  NULL if none. 
+ *
+ * SigComp can be used to compress SIP messages.
+ */
+#if HAVE_SOFIA_SIGCOMP
+char const * sofia_sip_has_sigcomp = sigcomp_package_version;
+#else
+char const * sofia_sip_has_sigcomp;
+#endif
+
+/** The name and version of software package providing STUN functionality, 
+ *  NULL if none. 
+ *
+ * STUN is a protocol used to traverse NATs with UDP.
+ */
+#if HAVE_SOFIA_STUN
+extern char const stun_version[];
+char const * sofia_sip_has_stun = stun_version;
+#else
+char const * sofia_sip_has_stun;
+#endif
+
+/** The name and version of software package providing TURN functionality, 
+ *  NULL if none. 
+ *
+ * TURN is a protocol used to traverse NATs or firewalls with TCP or UDP.
+ */
+char const * sofia_sip_has_turn;
+
+/** The name and version of software package providing UPnP functionality, 
+ *  NULL if none. 
+ *
+ * UPnP (Universal Plug and Play) can be used to traverse NATs or firewalls.
+ */
+char const * sofia_sip_has_upnp;
+
+/** The name and version of software package providing SCTP functionality, 
+ *  NULL if none.
+ *
+ * SCTP can be used as transport for SIP messages. The software providing it
+ * can be, for example, LKSCTP (Linux kernel SCTP) for Linux.
+ */
+char const * sofia_sip_has_sctp;
+/* We don't have viable SCTP transport interface */
+
+/** The name and version of software package providing IPv6 functionality, 
+ *  NULL if none.
+ *
+ * IPv6 can be used to send SIP messages.
+ */
+#if SU_HAVE_IN6
+char const * sofia_sip_has_ipv6 = "IPv6";
+#else
+char const * sofia_sip_has_ipv6;
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,41 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "features" Module
+
+ at section features_meta Module Meta Information
+
+The @b features module provides application information about the various
+features possibly available through the @ref subdirs "sofia-sip-ua" binary API.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP  Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at section features_overview Overview
+
+The #sofia_sip_name_version contains the name and release of currently
+installed @a libsofia-sip-ua.so library. The macro #SOFIA_SIP_NAME_VERSION
+contains the name and release of currently available include files.
+
+The Sofia SIP binary API hides some protocols used under the SIP stack. 
+While the binary API stays the same, the features are not necessarily there. 
+These features are mainly related to encryption, compression and underlying
+transports.
+
+- #sofia_sip_has_smime
+- #sofia_sip_has_tls
+- #sofia_sip_has_dtls
+- #sofia_sip_has_tls_sctp
+- #sofia_sip_has_sigcomp
+- #sofia_sip_has_stun
+- #sofia_sip_has_turn
+- #sofia_sip_has_upnp
+- #sofia_sip_has_sctp
+- #sofia_sip_has_ipv6
+
+*/
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+/* This -*- C -*- file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* @configure_input@ */
+
+/**@file sofia-sip/sofia_features.h
+ * @brief Sofia-SIP Library Features
+ *
+ * Macros and string constants listing features supported or not supported
+ * by sofia-sip-ua library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef SOFIA_SIP_FEATURES_H
+/** Defined when <sofia-sip/sofia_features.h> has been included. */
+#define SOFIA_SIP_FEATURES_H
+
+/** Current Sofia version. @showinitializer */
+#define SOFIA_SIP_VERSION  "@PACKAGE_VERSION@"
+/** Current Sofia package name and version. @showinitializer */
+#define SOFIA_SIP_NAME_VERSION   "@PACKAGE_NAME at -@PACKAGE_VERSION@"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SOFIAPUBVAR char const * const sofia_sip_name_version;
+SOFIAPUBVAR char const * sofia_sip_has_smime;
+SOFIAPUBVAR char const * sofia_sip_has_tls;
+SOFIAPUBVAR char const * sofia_sip_has_dtls;
+SOFIAPUBVAR char const * sofia_sip_has_tls_sctp;
+SOFIAPUBVAR char const * sofia_sip_has_sigcomp;
+SOFIAPUBVAR char const * sofia_sip_has_stun;
+SOFIAPUBVAR char const * sofia_sip_has_turn;
+SOFIAPUBVAR char const * sofia_sip_has_upnp;
+
+SOFIAPUBVAR char const * sofia_sip_has_sctp;
+SOFIAPUBVAR char const * sofia_sip_has_ipv6;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Renamed http_test.c as test_http.c
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+PROJECT_NAME         = "http"
+OUTPUT_DIRECTORY     = ../docs/html/http
+
+INPUT 		     = http.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += \
+	../docs/su.doxytags=../su \
+	../docs/ipt.doxytags=../ipt \
+	../docs/bnf.doxytags=../bnf \
+	../docs/url.doxytags=../url \
+	../docs/msg.doxytags=../msg
+
+GENERATE_TAGFILE    = ../docs/http.doxytags
+
+ALIASES += \
+	"HTTP_HEADER=@ingroup http_headers\n at defgroup" \

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+#
+# Makefile.am for http module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libhttp.la
+
+check_PROGRAMS = 	test_http
+
+TESTS = 		test_http
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+PUBLIC_H = 		sofia-sip/http.h sofia-sip/http_header.h \
+			sofia-sip/http_parser.h sofia-sip/http_tag_class.h \
+			sofia-sip/http_status.h sofia-sip/http_hclasses.h
+
+BUILT_H = 		sofia-sip/http_protos.h sofia-sip/http_tag.h 
+BUILT_C = 		http_tag.c http_tag_ref.c http_parser_table.c
+
+BUILT_SOURCES = 	$(BUILT_H) $(BUILT_C)
+
+nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H) 
+
+libhttp_la_SOURCES = 	$(INTERNAL_H) \
+			http_parser.c http_header.c \
+			http_basic.c http_extra.c \
+			http_status.c http_tag_class.c \
+			$(BUILT_C)
+
+COVERAGE_INPUT = 	$(libhttp_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libhttp.la \
+			../bnf/libbnf.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../su/libsu.la
+
+test_http_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile http.docs \
+			sofia-sip/http_protos.h.in \
+			sofia-sip/http_tag.h.in \
+			http_parser_table.c.in \
+			http_tag.c.in
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = DLLREF=1
+
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+
+AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
+
+sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
+sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
+http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
+http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/http_protos.h: sofia-sip/http.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
+
+sofia-sip/http_tag.h: sofia-sip/http.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
+
+http_tag.c: sofia-sip/http.h
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
+
+http_parser_table.c: sofia-sip/http.h
+	$(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
+		MC_HASH_SIZE=127 $<

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,747 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for http module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libhttp_la_SOURCES) test_http.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_http$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/http
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libhttp_la_LIBADD =
+am__objects_1 = http_tag.lo http_tag_ref.lo http_parser_table.lo
+am_libhttp_la_OBJECTS = http_parser.lo http_header.lo http_basic.lo \
+	http_extra.lo http_status.lo http_tag_class.lo \
+	$(am__objects_1)
+libhttp_la_OBJECTS = $(am_libhttp_la_OBJECTS)
+test_http_SOURCES = test_http.c
+test_http_OBJECTS = test_http.$(OBJEXT)
+test_http_LDADD = $(LDADD)
+test_http_DEPENDENCIES = libhttp.la ../bnf/libbnf.la ../msg/libmsg.la \
+	../url/liburl.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libhttp_la_SOURCES) test_http.c
+DIST_SOURCES = $(libhttp_la_SOURCES) test_http.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libhttp.la
+TESTS = test_http
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+PUBLIC_H = sofia-sip/http.h sofia-sip/http_header.h \
+			sofia-sip/http_parser.h sofia-sip/http_tag_class.h \
+			sofia-sip/http_status.h sofia-sip/http_hclasses.h
+
+BUILT_H = sofia-sip/http_protos.h sofia-sip/http_tag.h 
+BUILT_C = http_tag.c http_tag_ref.c http_parser_table.c
+BUILT_SOURCES = $(BUILT_H) $(BUILT_C)
+nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H) 
+libhttp_la_SOURCES = $(INTERNAL_H) \
+			http_parser.c http_header.c \
+			http_basic.c http_extra.c \
+			http_status.c http_tag_class.c \
+			$(BUILT_C)
+
+COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libhttp.la \
+			../bnf/libbnf.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../su/libsu.la
+
+test_http_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile http.docs \
+			sofia-sip/http_protos.h.in \
+			sofia-sip/http_tag.h.in \
+			http_parser_table.c.in \
+			http_tag.c.in
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+TAG_DLL_FLAGS = DLLREF=1
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/http/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/http/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libhttp.la: $(libhttp_la_OBJECTS) $(libhttp_la_DEPENDENCIES) 
+	$(LINK)  $(libhttp_la_LDFLAGS) $(libhttp_la_OBJECTS) $(libhttp_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_http$(EXEEXT): $(test_http_OBJECTS) $(test_http_DEPENDENCIES) 
+	@rm -f test_http$(EXEEXT)
+	$(LINK) $(test_http_LDFLAGS) $(test_http_OBJECTS) $(test_http_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_extra.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_header.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_parser_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_status.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag_class.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_http.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
+sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
+http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
+http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/http_protos.h: sofia-sip/http.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
+
+sofia-sip/http_tag.h: sofia-sip/http.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
+
+http_tag.c: sofia-sip/http.h
+	$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
+
+http_parser_table.c: sofia-sip/http.h
+	$(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
+		MC_HASH_SIZE=127 $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+accept                  Accept                   
+accept_charset          Accept-Charset           
+accept_encoding         Accept-Encoding          
+accept_language         Accept-Language          
+accept_ranges           Accept-Ranges            
+age                     Age                      
+allow                   Allow                    
+authorization           Authorization            
+cache_control           Cache-Control            
+connection              Connection               
+content_encoding        Content-Encoding         
+content_language        Content-Language         
+content_length          Content-Length           
+content_location        Content-Location         
+content_md5             Content-MD5              
+content_range           Content-Range            
+content_type            Content-Type             
+date                    Date                     
+etag                    ETag                     
+expect                  Expect                   
+expires                 Expires                  
+from                    From                     
+host                    Host                     
+if_match                If-Match                 
+if_modified_since       If-Modified-Since        
+if_none_match           If-None-Match            
+if_range                If-Range                 
+if_unmodified_since     If-Unmodified-Since      
+last_modified           Last-Modified            
+location                Location                 
+max_forwards            Max-Forwards             
+mime_version            MIME-Version
+pragma                  Pragma                   
+pr_authenticate         Proxy-Authenticate       
+pr_authorization        Proxy-Authorization      
+range                   Range                    
+referer                 Referer                  
+retry_after             Retry-After              
+server                  Server                   
+te                      TE                       
+trailer                 Trailer                  
+transfer_encoding       Transfer-Encoding        
+upgrade                 Upgrade                  
+user_agent              User-Agent               
+vary                    Vary                     
+via                     Via                      
+warning                 Warning                  
+www_authenticate        WWW-Authenticate         

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+; Template for http.def
+
+LIBRARY      "http"
+
+DESCRIPTION  'HTTP Win32 Dynamic Link Library'
+
+EXPORTS
+    ; Explicit exports can go here
+
+	http_default_mclass
+
+	sip_#xxxxxx#_class
+	sip_#xxxxxx#_p
+	sip_#xxxxxx#_dup
+	sip_#xxxxxx#_copy
+	sip_#xxxxxx#_make
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,40 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "http" - HTTP Parser Module
+ *
+ * @section http_meta Module Meta Information
+ *
+ * The @b http module contains interface to the HTTP parser and the header
+ * and message objects.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section http_overview Overview
+ *
+ * Each HTTP header has a structure defined for it in <http.h>. All the
+ * variables, objects and functions related to a particular HTTP header are
+ * documented in a <a href="modules.html">submodule</a> for the header. In
+ * addition to the header structure, there is defined a @em header @em class
+ * structure and some standard functions for each header in the
+ * <http_header.h> include file. For header @c X, there are types,
+ * functions, macros and header class as follows:
+ *
+ *  - @c http_X_t is the structure used to store parsed header,
+ *  - @c HTTP_X_INIT() initializes a static instance of http_X_t,
+ *  - @c http_X_p() tests if header object is instance of header X,
+ *  - @c http_X_make() is a macro that creates a header X object by 
+         decoding given string,
+ *  - @c http_X_dup() duplicates (deeply copies) the header X (macro), 
+ *  - @c http_X_copy() is a macro that copies the header X (macro),
+ *  - @c #msg_hclass_t http_X_class[] contains the @em header @em class 
+ *    for header X.
+ * 
+ * In addition to this interface, the parser provider interface is
+ * documented in the <a href="../sip/group__sip__parser.html">SIP Parser module</a>.
+ * The parser provider interface makes it possible to extend HTTP parser with
+ * new headers or extend existing ones.
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1634 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_basic.c
+ * @brief HTTP basic header
+ *
+ * The file @b http_basic.c contains implementation of header classes for
+ * basic HTTP headers, like request and status lines, payload, @b Call-ID, @b
+ * CSeq, @b Contact, @b Content-Length, @b Date, @b Expires, @b From, @b
+ * Route, @b Record-Route, @b To, and @b Via.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date  Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su_alloc.h>
+
+#include <sofia-sip/http_parser.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/msg_mime_protos.h>
+#include <sofia-sip/msg_date.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_request HTTP request line.
+ *
+ * The HTTP request line contains the method, URL, and an optional HTTP
+ * protocol version. The missing version indicates version 0.9 without any
+ * request headers.
+ */
+
+/**
+ * Parse request line of a HTTP message.
+ *
+ * The function @c http_request_d() parses the request line from a a HTTP
+ * message.
+ */
+issize_t http_request_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_request_t *rq = h->sh_request;
+  char *uri, *version;
+
+  if (msg_firstline_d(s, &uri, &version) < 0 ||
+      (rq->rq_method = http_method_d(&s, &rq->rq_method_name)) < 0 || *s ||
+      url_d(rq->rq_url, uri) < 0 ||
+      (http_version_d(&version, &rq->rq_version) < 0 || version[0]))
+    return -1;
+
+  return 0;
+}
+
+/**
+ * Encode a HTTP request line.
+ *
+ * The function @c http_request_e() prints a HTTP request line.
+ */
+issize_t http_request_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+  http_request_t const *rq = h->sh_request;
+
+  return snprintf(b, bsiz, "%s " URL_FORMAT_STRING "%s%s" CRLF,
+		  rq->rq_method_name,
+		  URL_PRINT_ARGS(rq->rq_url),
+		  rq->rq_version ? " " : "",
+		  rq->rq_version ? rq->rq_version : "");
+}
+
+isize_t http_request_dup_xtra(http_header_t const *h, isize_t offset)
+{
+  http_request_t const *rq = h->sh_request;
+
+  offset += url_xtra(rq->rq_url);
+  if (!rq->rq_method)
+    offset += MSG_STRING_SIZE(rq->rq_method_name);
+  if (rq->rq_version)
+    offset += http_version_xtra(rq->rq_version);
+
+  return offset;
+}
+
+/** Duplicate one request header. */
+char *http_request_dup_one(http_header_t *dst, http_header_t const *src,
+			   char *b, isize_t xtra)
+{
+  http_request_t *rq = dst->sh_request;
+  http_request_t const *o = src->sh_request;
+  char *end = b + xtra;
+
+  URL_DUP(b, end, rq->rq_url, o->rq_url);
+
+  if (!(rq->rq_method = o->rq_method))
+    MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
+  else
+    rq->rq_method_name = o->rq_method_name;
+  http_version_dup(&b, &rq->rq_version, o->rq_version);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/** Create a request line object.
+ *
+ * Note that version string is not copied; it @b MUST remain constant during
+ * lifetime of the @c http_request_t object. You can use constants
+ * http_version_1_1 or http_version_1_0 declared in <http_header.h>.
+ */
+http_request_t *http_request_create(su_home_t *home,
+				    http_method_t method, char const *name,
+				    url_string_t const *url,
+				    char const *version)
+{
+  size_t xtra;
+  http_request_t *rq;
+
+  if (method)
+    name = http_method_name(method, name);
+
+  if (!name)
+    return NULL;
+
+  xtra = url_xtra(url->us_url) + (method ? 0 : strlen(name) + 1);
+
+  rq = msg_header_alloc(home, http_request_class, (isize_t)xtra)->sh_request;
+
+  if (rq) {
+    char *b = (char *)(rq + 1), *end = b + xtra;
+
+    rq->rq_method      = method;
+    rq->rq_method_name = name;
+    if (!method)
+      MSG_STRING_DUP(b, rq->rq_method_name, name);
+
+    URL_DUP(b, end, rq->rq_url, url->us_url);
+
+    rq->rq_version = version ? version : HTTP_VERSION_CURRENT;
+    assert(b == end);
+  }
+
+  return rq;
+}
+
+msg_hclass_t http_request_class[] =
+HTTP_HEADER_CLASS(request, NULL, rq_common, single_critical, request);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_status HTTP status line.
+ *
+ * The HTTP status line contains the HTTP protocol version, a reason code
+ * (100..599) and reason phrase.
+ */
+
+/** Parse status line */
+issize_t http_status_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_status_t *st = h->sh_status;
+  char *status, *phrase;
+  uint32_t code;
+
+  if (msg_firstline_d(s, &status, &phrase) < 0 ||
+      http_version_d(&s, &st->st_version) < 0 || *s ||
+      msg_uint32_d(&status, &code) == -1 || 
+      status[0])
+    return -1;
+
+  st->st_status = code;
+  st->st_phrase = phrase;
+
+  return 0;
+}
+
+issize_t http_status_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+  http_status_t const *st = h->sh_status;
+  char const *phrase = st->st_phrase;
+
+  if (phrase == NULL)
+    phrase = "";
+
+  if (st->st_version)
+    return snprintf(b, bsiz, "%s %03u %s" CRLF,
+		    st->st_version,
+		    st->st_status,
+		    phrase);
+  else
+    return snprintf(b, bsiz, "%03u %s" CRLF,
+		    st->st_status,
+		    phrase);
+}
+
+/** Extra size of a http_status_t object. */
+isize_t http_status_dup_xtra(http_header_t const *h, isize_t offset)
+{
+  if (h->sh_status->st_version)
+    offset += http_version_xtra(h->sh_status->st_version);
+  offset += MSG_STRING_SIZE(h->sh_status->st_phrase);
+  return offset;
+}
+
+/** Duplicate one status header. */
+char *http_status_dup_one(http_header_t *dst, http_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  http_status_t *st = dst->sh_status;
+  http_status_t const *o = src->sh_status;
+  char *end = b + xtra;
+
+  if (o->st_version)
+    http_version_dup(&b, &st->st_version, o->st_version);
+  st->st_status = o->st_status;
+  MSG_STRING_DUP(b, st->st_phrase, o->st_phrase);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Create a status line object.
+ *
+ * Note that version is not copied; it @b MUST remain constant during
+ * lifetime of the @c http_status_t object.
+ */
+http_status_t *http_status_create(su_home_t *home,
+				  unsigned status,
+				  char const *phrase,
+				  char const *version)
+{
+  http_status_t *st;
+
+  if (phrase == NULL && (phrase = http_status_phrase(status)) == NULL)
+    return NULL;
+
+  if ((st = msg_header_alloc(home, http_status_class, 0)->sh_status)) {
+    st->st_status = status;
+    st->st_phrase = phrase;
+    st->st_version = version ? version : HTTP_VERSION_CURRENT;
+  }
+
+  return st;
+}
+
+msg_hclass_t http_status_class[] =
+HTTP_HEADER_CLASS(status, NULL, st_common, single_critical, status);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept Accept header.
+ *
+ * We use MIME Accept header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_charset Accept-Charset header.
+ *
+ * We use MIME Accept-Charset header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_encoding Accept-Encoding header.
+ *
+ * We use MIME Accept-Encoding header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_language Accept-Language header.
+ *
+ * We use MIME Accept-Language header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_ranges Accept-Ranges header. */
+
+#define http_accept_ranges_d msg_list_d
+#define http_accept_ranges_e msg_list_e
+msg_hclass_t http_accept_ranges_class[] =
+HTTP_HEADER_CLASS_LIST(accept_ranges, "Accept-Ranges", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_age Age header. */
+
+#define http_age_d msg_numeric_d
+#define http_age_e msg_numeric_e
+#define http_age_dup_xtra msg_default_dup_xtra
+#define http_age_dup_one  msg_default_dup_one
+msg_hclass_t http_age_class[] =
+HTTP_HEADER_CLASS(age, "Age", x_common, single, age);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_allow Allow header. */
+
+#define http_allow_d msg_list_d
+#define http_allow_e msg_list_e
+msg_hclass_t http_allow_class[] =
+HTTP_HEADER_CLASS_LIST(allow, "Allow", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_authentication_info Authentication-Info header.
+ * @sa RFC 2617
+ */
+
+#define http_authentication_info_d msg_list_d
+#define http_authentication_info_e msg_list_e
+#define http_authentication_info_dup_xtra msg_list_dup_xtra
+#define http_authentication_info_dup_one msg_list_dup_one
+
+msg_hclass_t http_authentication_info_class[] =
+HTTP_HEADER_CLASS(authentication_info, "Authentication-Info", 
+		  ai_params, list, authentication_info);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_authorization Authorization header.
+ *
+ * We use MIME Authorization header.
+ */
+
+#define http_authorization_d msg_auth_d
+#define http_authorization_e msg_auth_e
+
+msg_hclass_t http_authorization_class[] =
+HTTP_HEADER_CLASS_AUTH(authorization, "Authorization", single);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_cache_control Cache-Control header. */
+
+#define http_cache_control_d msg_list_d
+#define http_cache_control_e msg_list_e
+
+msg_hclass_t http_cache_control_class[] =
+  HTTP_HEADER_CLASS_LIST(cache_control, "Cache-Control", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_connection Connection header. */
+
+#define http_connection_d msg_list_d
+#define http_connection_e msg_list_e
+msg_hclass_t http_connection_class[] =
+HTTP_HEADER_CLASS_LIST(connection, "Connection", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_encoding Content-Encoding header.
+ *
+ * We use MIME Content-Encoding header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_language Content-Language header.
+ *
+ * We use MIME Content-Language header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_length Content-Length header.
+ *
+ * We use MIME Content-Length header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_location Content-Location header.
+ *
+ * We use MIME Content-Location header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_md5 Content-MD5 header.
+ *
+ * We use MIME Content-MD5 header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_range Content-Range header.
+ *
+ * The Content-Range entity-header is sent with a partial entity-body to
+ * specify where in the full entity-body the partial body should be
+ * applied. Its syntax is defined in [H14.16] as follows:
+ *
+ * @code
+ *     Content-Range = "Content-Range" ":" content-range-spec
+ *     content-range-spec      = byte-content-range-spec
+ *     byte-content-range-spec = bytes-unit SP
+ *                               byte-range-resp-spec "/"
+ *                               ( instance-length | "*" )
+ *
+ *     byte-range-resp-spec    = (first-byte-pos "-" last-byte-pos)
+ *                                    | "*"
+ *     instance-length         = 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup http_content_range
+ * @typedef typedef struct http_content_range_s http_content_range_t;
+ *
+ * The structure #http_content_range_t contains representation of 
+ * @b Content-Range header.
+ *
+ * The #http_content_range_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t      cr_common[1];
+ *   msg_error_t      *cr_next;
+ *   off_t             cr_first;   // First-byte-pos
+ *   off_t             cr_last;    // Last-byte-pos
+ *   off_t             cr_length;  // Instance-length
+ * } http_content_range_t;
+ * @endcode
+ */
+
+issize_t http_content_range_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_content_range_t *cr = h->sh_content_range;
+
+  if (strncasecmp(s, "bytes", 5))
+    return -1;
+  s += 5; skip_lws(&s);
+  if (s[0] == '*') {
+    cr->cr_first = cr->cr_last = (http_off_t)-1;
+    s++; skip_lws(&s);
+  } else {
+    if (msg_delta_d((char const **)&s, &cr->cr_first) < 0)
+      return -1;
+    if (s[0] != '-')
+      return -1;
+    s++; skip_lws(&s);
+    if (msg_delta_d((char const **)&s, &cr->cr_last) < 0)
+      return -1;
+  }
+
+  if (s[0] != '/')
+    return -1;
+  s++; skip_lws(&s);
+
+  if (s[0] == '*') {
+    cr->cr_length = (http_off_t)-1;
+    s++; skip_lws(&s);
+  } else {
+    if (msg_delta_d((char const **)&s, &cr->cr_length) < 0)
+      return -1;
+  }
+
+  return s[0] ? -1 : 0;
+}
+
+issize_t http_content_range_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+  http_content_range_t const *cr = h->sh_content_range;
+
+  if (cr->cr_first == (http_off_t)-1) {
+    if (cr->cr_length == (http_off_t)-1)
+      return snprintf(b, bsiz, "bytes */*");
+    else
+      return snprintf(b, bsiz, "bytes */%lu", cr->cr_length);
+  }
+  else {
+    if (cr->cr_length == (http_off_t)-1)
+      return snprintf(b, bsiz, "bytes %lu-%lu/*", cr->cr_first, cr->cr_last);
+    else
+      return snprintf(b, bsiz, "bytes %lu-%lu/%lu",
+		      cr->cr_first, cr->cr_last, cr->cr_length);
+  }
+}
+
+msg_hclass_t http_content_range_class[] =
+HTTP_HEADER_CLASS(content_range, "Content-Range", cr_common, single, default);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_content_type Content-Type header.
+ *
+ * We use MIME Content-Type header.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_date Date header.
+ *
+ * The Date header field reflects the time when the request or response was
+ * first sent.  Its syntax is defined in [H14.18] as
+ * follows:
+ *
+ * @code
+ *    Date          =  "Date" HCOLON HTTP-date
+ *    HTTP-date      =  rfc1123-date
+ *    rfc1123-date  =  wkday "," SP date1 SP time SP "GMT"
+ *    date1         =  2DIGIT SP month SP 4DIGIT
+ *                     ; day month year (e.g., 02 Jun 1982)
+ *    time          =  2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                     ; 00:00:00 - 23:59:59
+ *    wkday         =  "Mon" / "Tue" / "Wed"
+ *                     / "Thu" / "Fri" / "Sat" / "Sun"
+ *    month         =  "Jan" / "Feb" / "Mar" / "Apr"
+ *                     / "May" / "Jun" / "Jul" / "Aug"
+ *                     / "Sep" / "Oct" / "Nov" / "Dec"
+ * @endcode
+ *
+ */
+
+/**@ingroup http_date
+ * @typedef typedef struct http_date_s http_date_t;
+ *
+ * The structure #http_date_t contains representation of @b Date header.
+ *
+ * The #http_date_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t    d_common[1];        // Common fragment info
+ *   msg_error_t    *d_next;             // Link to next (dummy)
+ *   http_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } http_date_t;
+ * @endcode
+ */
+
+issize_t http_date_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_date_t *date = h->sh_date;
+
+  if (msg_date_d((char const **)&s, &date->d_time) < 0 || *s)
+    return -1;
+  else
+    return 0;
+}
+
+
+issize_t http_date_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+  http_date_t const *date = h->sh_date;
+
+  return msg_date_e(b, bsiz, date->d_time);
+}
+
+/**@ingroup http_date
+ * @brief Create an @b Date header object.
+ *
+ * The function http_date_create() creates a Date header object with the
+ * date @a date. If @date is 0, current time (as returned by msg_now()) is
+ * used.
+ *
+ * @param home   memory home
+ * @param date   date expressed as seconds since Mon, 01 Jan 1900 00:00:00
+ *
+ * @return
+ * The function http_date_create() returns a pointer to newly created
+ * @b Date header object when successful, or NULL upon an error.
+ */
+http_date_t *http_date_create(su_home_t *home, http_time_t date)
+{
+  http_header_t *h = msg_header_alloc(home, http_date_class, 0);
+
+  if (h) {
+    if (date == 0)
+      date = msg_now();
+    h->sh_date->d_time = date;
+  }
+
+  return h->sh_date;
+}
+
+
+msg_hclass_t http_date_class[] =
+HTTP_HEADER_CLASS(date, "Date", d_common, single, default);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_etag ETag header. */
+
+#define http_etag_d msg_generic_d
+#define http_etag_e msg_generic_e
+msg_hclass_t http_etag_class[] =
+HTTP_HEADER_CLASS_G(etag, "ETag", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_expect Expect header. */
+
+#define http_expect_d msg_generic_d
+#define http_expect_e msg_generic_e
+msg_hclass_t http_expect_class[] =
+HTTP_HEADER_CLASS_G(expect, "Expect", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_expires Expires header.
+ *
+ * The Expires header field gives the date and time after which the message
+ * content expires. Its syntax is defined in RFC 1428 section 14.21 as
+ * follows:
+ *
+ * @code
+ *    Expires     =  "Expires:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_expires
+ * @typedef typedef struct http_expires_s http_expires_t;
+ *
+ * The structure #http_expires_t contains representation of @b Expires
+ * header.
+ *
+ * The #http_expires_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t    d_common[1];        // Common fragment info
+ *   msg_error_t    *d_next;             // Link to next (dummy)
+ *   http_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } http_expires_t;
+ * @endcode
+ */
+
+#define http_expires_d http_date_d
+#define http_expires_e http_date_e
+
+msg_hclass_t http_expires_class[] =
+HTTP_HEADER_CLASS(expires, "Expires", d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_from From header. 
+ *
+ * @code
+ *    From   = "From" ":" mailbox
+ * @endcode
+ */
+
+
+#define http_from_d msg_generic_d
+#define http_from_e msg_generic_e
+msg_hclass_t http_from_class[] =
+HTTP_HEADER_CLASS_G(from, "From", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_host Host header.
+ *
+ * @code
+ *    Host = "Host" ":" host [ ":" port ]
+ * @endcode
+ */
+
+/** Parse Host header */
+issize_t http_host_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_host_t *host = h->sh_host;
+
+  if (msg_hostport_d(&s, &host->h_host, &host->h_port) < 0 || *s)
+    return -1;
+
+  return 0;
+}
+
+/** Print Host header */
+issize_t http_host_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+
+  MSG_STRING_E(b, end, h->sh_host->h_host);
+  if (h->sh_host->h_port) {
+    MSG_CHAR_E(b, end, ':');
+    MSG_STRING_E(b, end, h->sh_host->h_port);
+  }
+
+  return b - b0;
+}
+
+/** Extra size of a http_host_t object. */
+static
+isize_t http_host_dup_xtra(http_header_t const *h, isize_t offset)
+{
+  offset += MSG_STRING_SIZE(h->sh_host->h_host);
+  offset += MSG_STRING_SIZE(h->sh_host->h_port);
+  return offset;
+}
+
+/** Duplicate one Host header. */
+static
+char *http_host_dup_one(http_header_t *dst, http_header_t const *src,
+			char *b, isize_t xtra)
+{
+  http_host_t *h = dst->sh_host;
+  http_host_t const *o = src->sh_host;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, h->h_host, o->h_host);
+  MSG_STRING_DUP(b, h->h_port, o->h_port);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/**Create a Host object. */
+http_host_t *http_host_create(su_home_t *home,
+			      char const *host,
+			      char const *port)
+{
+  http_host_t h[1];
+
+  http_host_init(h);
+
+  h->h_host = host, h->h_port = port;
+
+  if (host) {
+    return http_host_dup(home, h);
+  }
+  else
+    return NULL;
+}
+
+msg_hclass_t http_host_class[] =
+HTTP_HEADER_CLASS(host, "Host", h_common, single, host);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_match If-Match header. */
+
+#define http_if_match_d msg_list_d
+#define http_if_match_e msg_list_e
+msg_hclass_t http_if_match_class[] =
+HTTP_HEADER_CLASS_LIST(if_match, "If-Match", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_modified_since If-Modified-Since header.
+ *
+ * The If-Modified-Since header field The If-Modified-Since request-header
+ * field is used with a method to make it conditional: if the requested
+ * variant has not been modified since the time specified in this field, an
+ * entity will not be returned from the server; instead, a 304 (not
+ * modified) response will be returned without any message-body. Its syntax
+ * is defined in RFC 2616 secion 14.25 as follows:
+ *
+ * @code
+ *    If-Modified-Since =  "If-Modified-Since" ":" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_if_modified_since
+ * @typedef typedef struct http_if_modified_since_s http_if_modified_since_t;
+ *
+ * The structure #http_if_modified_since_t contains representation of 
+ * @b If-Modified-Since header.
+ *
+ * The #http_if_modified_since_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t    d_common[1];        // Common fragment info
+ *   msg_error_t    *d_next;             // Link to next (dummy)
+ *   http_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } http_if_modified_since_t;
+ * @endcode
+ */
+
+#define http_if_modified_since_d http_date_d
+#define http_if_modified_since_e http_date_e
+
+msg_hclass_t http_if_modified_since_class[] =
+HTTP_HEADER_CLASS(if_modified_since, "If-Modified-Since", 
+		  d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_none_match If-None-Match header. */
+
+#define http_if_none_match_d msg_list_d
+#define http_if_none_match_e msg_list_e
+msg_hclass_t http_if_none_match_class[] =
+HTTP_HEADER_CLASS_LIST(if_none_match, "If-None-Match", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_range If-Range header. 
+ *
+ * The @b If-Range header is used when a client has a partial copy of an
+ * entity in its cache, and wishes to have an up-to-date copy of the entire
+ * entity. Informally, its meaning is `if the entity is unchanged, send
+ * me the part(s) that I am missing; otherwise, send me the entire new
+ * entity'. Its syntax is defined in RFC 2616 as follows:
+ *
+ * @code
+ *   If-Range = "If-Range" ":" ( entity-tag / HTTP-date )
+ * @endcode
+ */    
+
+/** Parse If-Range header */
+issize_t http_if_range_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_if_range_t *ifr = (http_if_range_t *)h;
+
+  if (s[0] == '"' || strncasecmp(s, "W/\"", 3) == 0) {
+    ifr->ifr_tag = s;
+    return 0;
+  } else {
+    return msg_date_d((char const **)&s, &ifr->ifr_time);
+  }
+}
+
+/** Print If-Range header */
+issize_t http_if_range_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+  http_if_range_t const *ifr = (http_if_range_t const *)h;
+  char *b0 = b, *end = b + bsiz;
+
+  if (ifr->ifr_tag) {
+    MSG_STRING_E(b, end, ifr->ifr_tag);
+    return b - b0;
+  } else {
+    return msg_date_e(b, bsiz, ifr->ifr_time);
+  }
+}
+
+/** Extra size of a http_if_range_t object. */
+static
+isize_t http_if_range_dup_xtra(http_header_t const *h, isize_t offset)
+{
+  http_if_range_t const *ifr = (http_if_range_t const *)h;
+  offset += MSG_STRING_SIZE(ifr->ifr_tag);
+  return offset;
+}
+
+/** Duplicate one If-Range header. */
+static
+char *http_if_range_dup_one(http_header_t *dst, http_header_t const *src,
+			    char *b, isize_t xtra)
+{
+  http_if_range_t *ifr = dst->sh_if_range;
+  http_if_range_t const *o = src->sh_if_range;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, ifr->ifr_tag, o->ifr_tag);
+
+  ifr->ifr_time = o->ifr_time;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_if_range_class[] =
+HTTP_HEADER_CLASS(if_range, "If-Range", ifr_common, single, if_range);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_if_unmodified_since If-Unmodified-Since header.
+ *
+ * The @b If-Unmodified-Since header is used with a method to make it
+ * conditional. If the requested resource has not been modified since the
+ * time specified in this field, the server SHOULD perform the requested
+ * operation as if the If-Unmodified-Since header were not present. Its
+ * syntax is defined in RFC 2616 14.28 as follows:
+ *
+ * @code
+ *    If-Unmodified-Since     =  "If-Unmodified-Since:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_if_unmodified_since
+ * @typedef typedef http_date_t http_if_unmodified_since_t;
+ *
+ * The structure #http_if_unmodified_since_t contains representation of 
+ * @b If-Unmodified-Since header.
+ *
+ * The #http_if_unmodified_since_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t    d_common[1];        // Common fragment info
+ *   msg_error_t    *d_next;             // Link to next (dummy)
+ *   http_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } http_if_unmodified_since_t;
+ * @endcode
+ */
+
+#define http_if_unmodified_since_d http_date_d
+#define http_if_unmodified_since_e http_date_e
+
+msg_hclass_t http_if_unmodified_since_class[] =
+HTTP_HEADER_CLASS(if_unmodified_since, "If-Unmodified-Since", 
+		  d_common, single, default);
+
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_last_modified Last-Modified header.
+ *
+ * The Last-Modified header field gives the date and time after which the
+ * message content last_modified. Its syntax is defined in [] as follows:
+ *
+ * @code
+ *    Last-Modified     =  "Last-Modified:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_last_modified
+ * @typedef typedef struct http_last_modified_s http_last_modified_t;
+ *
+ * The structure #http_last_modified_t contains representation of @b
+ * Last-Modified header.
+ *
+ * The #http_last_modified_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t    d_common[1];        // Common fragment info
+ *   msg_error_t    *d_next;             // Link to next (dummy)
+ *   http_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } http_last_modified_t;
+ * @endcode
+ */
+
+#define http_last_modified_d http_date_d
+#define http_last_modified_e http_date_e
+
+msg_hclass_t http_last_modified_class[] =
+HTTP_HEADER_CLASS(last_modified, "Last-Modified", d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_location Location Header
+ *
+ * The Location header is used to redirect the recipient to a location other
+ * than the Request-URI for completion of the request or identification of a
+ * new resource. Its syntax is defined in RFC 2616 section 14.30 as follows:
+ *
+ * @code
+ *    Location       = "Location" ":" absoluteURI
+ * @endcode
+ *
+ */
+
+/**@ingroup http_location
+ *
+ * @typedef typedef struct http_location_s http_location_t;
+ *
+ * The structure http_location_t contains representation of @b Location
+ * header.
+ *
+ * The http_location_t is defined as follows:
+ * @code
+ * typedef struct http_location_s
+ * {
+ *   msg_common_t         loc_common[1];
+ *   msg_error_t         *loc_next;
+ *   url_t                loc_url[1];
+ * } http_location_t;
+ * @endcode
+ */
+
+/** Decode (parse) a Location header */
+issize_t http_location_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  http_location_t *loc = (http_location_t *)h;
+
+  return url_d(loc->loc_url, s);
+}
+
+/** Encode (print) a Location header */
+issize_t http_location_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  http_location_t const *loc = (http_location_t *)h;
+
+  return url_e(b, bsiz, loc->loc_url);
+}
+
+/** Calculate extra storage used by Location header field */
+isize_t http_location_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  http_location_t const *loc = (http_location_t *)h;
+
+  offset += url_xtra(loc->loc_url);
+
+  return offset;
+}
+
+/** Duplicate a Location header field */
+char *http_location_dup_one(msg_header_t *dst, msg_header_t const *src,
+			    char *b, isize_t xtra)
+{
+  http_location_t *loc = (http_location_t *)dst;
+  http_location_t const *o = (http_location_t const *)src;
+  char *end = b + xtra;
+
+  URL_DUP(b, end, loc->loc_url, o->loc_url);
+
+  assert(b <= end);
+
+  return b;
+}
+
+msg_hclass_t http_location_class[] =
+HTTP_HEADER_CLASS(location, "Location", loc_common, single, location);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_max_forwards Max-Forwards header. */
+
+#define http_max_forwards_d msg_numeric_d
+#define http_max_forwards_e msg_numeric_e
+msg_hclass_t http_max_forwards_class[] =
+HTTP_HEADER_CLASS(max_forwards, "Max-Forwards", mf_common, single, numeric);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_pragma Pragma header. */
+
+#define http_pragma_d msg_list_d
+#define http_pragma_e msg_list_e
+msg_hclass_t http_pragma_class[] =
+HTTP_HEADER_CLASS_LIST(pragma, "Pragma", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_proxy_authenticate Proxy-Authenticate header. */
+
+#define http_proxy_authenticate_d msg_auth_d
+#define http_proxy_authenticate_e msg_auth_e
+
+msg_hclass_t http_proxy_authenticate_class[] =
+HTTP_HEADER_CLASS_AUTH(proxy_authenticate, "Proxy-Authenticate", append);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_proxy_authorization Proxy-Authorization header. */
+
+#define http_proxy_authorization_d msg_auth_d
+#define http_proxy_authorization_e msg_auth_e
+
+msg_hclass_t http_proxy_authorization_class[] =
+HTTP_HEADER_CLASS_AUTH(proxy_authorization, "Proxy-Authorization", append);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_range Range header.
+ *
+ * The Range header is used to GET one or more sub-ranges of an entity
+ * instead of the entire entity. Its syntax is defined in RFC 2616 section
+ * 14.35 as follows:
+ *
+ * @code
+ *    Range = "Range" ":" ranges-specifier
+ *    ranges-specifier = byte-ranges-specifier
+ *    byte-ranges-specifier = bytes-unit "=" byte-range-set
+ *    byte-range-set  = 1#( byte-range-spec | suffix-byte-range-spec )
+ *    byte-range-spec = first-byte-pos "-" [last-byte-pos]
+ *    first-byte-pos  = 1*DIGIT
+ *    last-byte-pos   = 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup http_range
+ *
+ * @typedef typedef struct http_range_s http_range_t;
+ *
+ * The structure http_range_t contains representation of @b Range header.
+ *
+ * The http_range_t is defined as follows:
+ * @code
+ * typedef struct http_range_s
+ * {
+ *   msg_common_t         rng_common[1];
+ *   msg_error_t         *rng_next;
+ *   char const          *rng_unit;
+ *   char const  * const *rng_specs;
+ * } http_range_t;
+ * @endcode
+ */
+
+static issize_t range_spec_scan(char *start);
+
+/** Decode (parse) a Range header */
+issize_t http_range_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  http_range_t *rng = (http_range_t *)h;
+
+  rng->rng_unit = s;
+  skip_token(&s);
+  if (s == rng->rng_unit)
+    return -1;
+  if (IS_LWS(*s)) {
+    *s++ = '\0';
+    skip_lws(&s);
+  }
+  if (*s != '=')
+    return -1;
+  *s++ = '\0';
+  skip_lws(&s);
+
+  /* XXX - use range-scanner */
+  return msg_commalist_d(home, &s, &rng->rng_specs, range_spec_scan);
+}
+
+/** Scan and compact a range spec. */
+static
+issize_t range_spec_scan(char *start)
+{
+  size_t tlen;
+  char *s, *p;
+
+  s = p = start;
+
+  if (s[0] == ',')
+    return 0;
+
+  /* Three forms: 1*DIGIT "-" 1*DIGIT | 1*DIGIT "-" | "-" 1*DIGIT */
+
+  if (*s != '-') {
+    tlen = span_digit(s);
+    if (tlen == 0)
+      return -1;
+    p += tlen; s += tlen;
+    skip_lws(&s);
+  }
+
+  if (*s != '-')
+    return -1;
+
+  if (p != s)
+    *p = *s;
+  p++, s++; skip_lws(&s);
+
+  if (IS_DIGIT(*s)) {
+    tlen = span_digit(s);
+    if (tlen == 0)
+      return -1;
+    if (p != s)
+      memmove(p, s, tlen);
+    p += tlen; s += tlen;
+    skip_lws(&s);
+  }
+
+  if (p != s)
+    *p = '\0';
+
+  return s - start;
+}
+
+
+/** Encode (print) a Range header */
+issize_t http_range_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  http_range_t const *rng = (http_range_t *)h;
+  char *b0 = b, *end = b + bsiz;
+
+  MSG_STRING_E(b, end, rng->rng_unit);
+  MSG_CHAR_E(b, end, '=');
+  MSG_COMMALIST_E(b, end, rng->rng_specs, MSG_IS_COMPACT(flags));
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra storage used by Range header field */
+isize_t http_range_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  http_range_t const *rng = (http_range_t *)h;
+
+  MSG_PARAMS_SIZE(offset, rng->rng_specs);
+  offset += MSG_STRING_SIZE(rng->rng_unit);
+
+  return offset;
+}
+
+/** Duplicate a Range header field */
+char *http_range_dup_one(msg_header_t *dst, msg_header_t const *src,
+			 char *b, isize_t xtra)
+{
+  http_range_t *rng = (http_range_t *)dst;
+  http_range_t const *o = (http_range_t const *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup((char const * const **)&rng->rng_specs,
+		     o->rng_specs, b, xtra);
+  MSG_STRING_DUP(b, rng->rng_unit, o->rng_unit);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_range_class[] =
+HTTP_HEADER_CLASS(range, "Range", rng_specs, single, range);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_referer Referer header.
+ *
+ * The Referer header is used to redirect the recipient to a referer other
+ * than the Request-URI for completion of the request or identification of a
+ * new resource. Its syntax is defined in RFC 2616 section 14.30 as follows:
+ *
+ * @code
+ *    Referer       = "Referer" ":" absoluteURI
+ * @endcode
+ *
+ */
+
+/**@ingroup http_referer
+ *
+ * @typedef typedef struct http_referer_s http_referer_t;
+ *
+ * The structure http_referer_t contains representation of @b Referer
+ * header.
+ *
+ * The http_referer_t is defined as follows:
+ * @code
+ * typedef struct http_referer_s
+ * {
+ *   msg_common_t         loc_common[1];
+ *   msg_error_t         *loc_next;
+ *   url_t                loc_url[1];
+ * } http_referer_t;
+ * @endcode
+ */
+
+#define http_referer_d http_location_d
+#define http_referer_e http_location_e
+
+msg_hclass_t http_referer_class[] =
+HTTP_HEADER_CLASS(referer, "Referer", loc_common, single, location);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_mime_version MIME-Version header.
+ *
+ * We use MIME MIME-Version header.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_retry_after Retry-After header.
+ *
+ * The Retry-After response-header field can be used with a 503 (Service
+ * Unavailable) response to indicate how long the service is expected to be
+ * unavailable to the requesting client. This field MAY also be used with
+ * any 3xx (Redirection) response to indicate the minimum time the
+ * user-agent is asked wait before issuing the redirected request. Its
+ * syntax is defined in RFC 2616 section 14.37 as follows:
+ *
+ * @code
+ *    Retry-After   =  "Retry-After" ":" ( HTTP-date / delta-seconds )
+ * @endcode
+ *
+ */
+
+/**@ingroup http_retry_after
+ * @typedef typedef struct http_retry_after_s http_retry_after_t;
+ *
+ * The structure #http_retry_after_t contains representation of @b
+ * Retry-After header.
+ *
+ * The #http_retry_after_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t         ra_common[1]; // Common fragment info
+ *   msg_error_t         *ra_next;      // Link to next (dummy)
+ *   http_time_t          ra_date;      // When to retry
+ *   http_time_t          ra_delta;     // Seconds to before retry
+ * } http_retry_after_t;
+ * @endcode
+ */
+
+issize_t http_retry_after_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_retry_after_t *ra = h->sh_retry_after;
+
+  if (msg_date_delta_d((char const **)&s,
+		       &ra->ra_date,
+		       &ra->ra_delta) < 0 || *s)
+    return -1;
+  else
+    return 0;
+}
+
+issize_t http_retry_after_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+  http_retry_after_t const *ra = h->sh_retry_after;
+
+  if (ra->ra_date)
+    return msg_date_e(b, bsiz, ra->ra_date + ra->ra_delta);
+  else
+    return msg_delta_e(b, bsiz, ra->ra_delta);
+}
+
+msg_hclass_t http_retry_after_class[] =
+HTTP_HEADER_CLASS(retry_after, "Retry-After", ra_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_server Server header. */
+
+#define http_server_d msg_generic_d
+#define http_server_e msg_generic_e
+msg_hclass_t http_server_class[] =
+HTTP_HEADER_CLASS_G(server, "Server", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_te TE header.
+ *
+ * The TE request-header field indicates what extension transfer-codings it
+ * is willing to accept in the response and whether or not it is willing to
+ * accept trailer fields in a chunked transfer-coding. Its value may consist
+ * of the keyword "trailers" and/or a comma-separated list of extension
+ * transfer-coding names with optional accept parameters. Its syntax is
+ * defined in [H14.39] as follows:
+ *
+ * @code
+ *     TE        = "TE" ":" #( t-codings )
+ *     t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+ * @endcode
+ *
+ */
+
+/**@ingroup http_te
+ * @typedef typedef strucy http_te_s http_te_t;
+ *
+ * The structure http_te_t contains representation of @b TE header.
+ *
+ * The http_te_t is defined as follows:
+ * @code
+ * typedef struct http_te_s {
+ * } http_te_t;
+ * @endcode
+ */
+
+static inline
+void http_te_update(http_te_t *te)
+{
+  te->te_q = msg_header_find_param(te->te_common, "q");
+}
+
+issize_t http_te_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_header_t **hh = &h->sh_succ, *h0 = h;
+  http_te_t *te = (http_te_t *)h;
+
+  assert(h); assert(sizeof(*h));
+
+  for (;*s;) {
+    /* Ignore empty entries (comma-whitespace) */
+    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+    if (!h) {      /* Allocate next header structure */
+      if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+	break;
+      *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+      te = te->te_next = (http_te_t *)h;
+    }
+
+    /* "TE:" #(transfer-extension ; *(parameters))) */
+    if (msg_token_d(&s, &te->te_extension) == -1)
+      return -1;
+
+    if (*s == ';' && msg_params_d(home, &s, &te->te_params) == -1)
+      return -1;
+
+    if (*s != '\0' && *s != ',')
+      return -1;
+
+    if (te->te_params)
+      http_te_update(te);
+
+    h = NULL;
+  }
+
+  return 0;
+}
+
+issize_t http_te_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  http_te_t const *te = (http_te_t *)h;
+
+  assert(http_is_te(h));
+
+  MSG_STRING_E(b, end, te->te_extension);
+  MSG_PARAMS_E(b, end, te->te_params, flags);
+
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+isize_t http_te_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  http_te_t const *te = (http_te_t const *)h;
+
+  MSG_PARAMS_SIZE(offset, te->te_params);
+  offset += MSG_STRING_SIZE(te->te_extension);
+
+  return offset;
+}
+
+/** Duplicate one http_te_t object */
+char *http_te_dup_one(msg_header_t *dst, msg_header_t const *src,
+		      char *b, isize_t xtra)
+{
+  http_te_t *te = (http_te_t *)dst;
+  http_te_t const *o = (http_te_t const *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&te->te_params, o->te_params, b, xtra);
+  MSG_STRING_DUP(b, te->te_extension, o->te_extension);
+  if (te->te_params) http_te_update(te);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_te_class[] =
+HTTP_HEADER_CLASS(te, "TE", te_params, append, te);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_trailer Trailer header. */
+
+#define http_trailer_d msg_list_d
+#define http_trailer_e msg_list_e
+msg_hclass_t http_trailer_class[] =
+HTTP_HEADER_CLASS_LIST(trailer, "Trailer", list_critical);
+
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_transfer_encoding Transfer-Encoding header. */
+
+#define http_transfer_encoding_d msg_list_d
+#define http_transfer_encoding_e msg_list_e
+msg_hclass_t http_transfer_encoding_class[] =
+HTTP_HEADER_CLASS_LIST(transfer_encoding, "Transfer-Encoding", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_upgrade Upgrade header. */
+
+#define http_upgrade_d msg_list_d
+#define http_upgrade_e msg_list_e
+msg_hclass_t http_upgrade_class[] =
+HTTP_HEADER_CLASS_LIST(upgrade, "Upgrade", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_user_agent User-Agent header. */
+
+#define http_user_agent_d msg_generic_d
+#define http_user_agent_e msg_generic_e
+msg_hclass_t http_user_agent_class[] =
+HTTP_HEADER_CLASS_G(user_agent, "User-Agent", single);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_vary Vary header. */
+
+#define http_vary_d msg_list_d
+#define http_vary_e msg_list_e
+msg_hclass_t http_vary_class[] =
+HTTP_HEADER_CLASS_LIST(vary, "Vary", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_via Via header.
+ *
+ * @code
+ *    Via =  "Via" ":" 1#( received-protocol received-by [ comment ] )
+ *    received-protocol = [ protocol-name "/" ] protocol-version
+ *    protocol-name     = token
+ *    protocol-version  = token
+ *    received-by       = ( host [ ":" port ] ) | pseudonym
+ *    pseudonym         = token
+ * @endcode
+ */
+
+issize_t http_via_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+  http_header_t **hh = &h->sh_succ, *h0 = h;
+  http_via_t *v = h->sh_via;
+
+  assert(h && h->sh_class);
+
+  for (;*s;) {
+    /* Ignore empty entries (comma-whitespace) */
+    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+    if (!h) {      /* Allocate next header structure */
+      if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+	return -1;
+      *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+      v = v->v_next = h->sh_via;
+    }
+
+    if (http_version_d(&s, &v->v_version) == -1) /* Parse protocol version */
+      return -1;
+    if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1) /* Host (and port) */
+      return -1;
+    if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1) /* Comment */
+      return -1;
+    if (*s != '\0' && *s != ',') /* Extra before next header field? */
+      return -1;
+
+    h = NULL;
+  }
+
+  if (h)		/* List without valid header via */
+    return -1;
+
+  return 0;
+}
+
+issize_t http_via_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+  int const compact = MSG_IS_COMPACT(flags);
+  char *b0 = b, *end = b + bsiz;
+  http_via_t const *v = h->sh_via;
+
+  MSG_STRING_E(b, end, v->v_version);
+  MSG_CHAR_E(b, end, ' ');
+  MSG_STRING_E(b, end, v->v_host);
+  if (v->v_port) {
+    MSG_CHAR_E(b, end, ':');
+    MSG_STRING_E(b, end, v->v_port);
+  }
+  if (v->v_comment) {
+    if (!compact) MSG_CHAR_E(b, end, ' ');
+    MSG_CHAR_E(b, end, '(');
+    MSG_STRING_E(b, end, v->v_comment);
+    MSG_CHAR_E(b, end, ')');
+  }
+
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+static isize_t http_via_dup_xtra(http_header_t const *h, isize_t offset)
+{
+  http_via_t const *v = h->sh_via;
+
+  offset += MSG_STRING_SIZE(v->v_version);
+  offset += MSG_STRING_SIZE(v->v_host);
+  offset += MSG_STRING_SIZE(v->v_port);
+  offset += MSG_STRING_SIZE(v->v_comment);
+
+  return offset;
+}
+
+/** Duplicate one http_via_t object */
+static char *http_via_dup_one(http_header_t *dst, http_header_t const *src,
+			      char *b, isize_t xtra)
+{
+  http_via_t *v = dst->sh_via;
+  http_via_t const *o = src->sh_via;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, v->v_version, o->v_version);
+  MSG_STRING_DUP(b, v->v_host, o->v_host);
+  MSG_STRING_DUP(b, v->v_port, o->v_port);
+  MSG_STRING_DUP(b, v->v_comment, o->v_comment);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_via_class[] =
+HTTP_HEADER_CLASS(via, "Via", v_common, prepend, via);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_warning Warning header. */
+
+#define http_warning_d msg_warning_d
+#define http_warning_e msg_warning_e
+#define http_warning_dup_xtra msg_warning_dup_xtra
+#define http_warning_dup_one msg_warning_dup_one
+
+msg_hclass_t http_warning_class[] =
+  HTTP_HEADER_CLASS(warning, "Warning", w_common, append, warning);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_www_authenticate WWW-Authenticate header. */
+
+#define http_www_authenticate_d msg_auth_d
+#define http_www_authenticate_e msg_auth_e
+
+msg_hclass_t http_www_authenticate_class[] =
+HTTP_HEADER_CLASS_AUTH(www_authenticate, "WWW-Authenticate", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_error Erroneous headers.
+ *
+ * We use erroneous header object from @b msg module.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_unknown Unknown headers.
+ *
+ * We use unknown header object from @b msg module.
+ */
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_separator Header separator.
+ *
+ * We use header separator object from @b msg module.
+ */
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_payload Message payload.
+ *
+ * We use message body object from @b msg module.
+ */
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,469 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_extra.c 
+ *
+ * Extra HTTP headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include "sofia-sip/http_parser.h"
+
+/* ========================================================================== */
+
+/**@HTTP_HEADER http_proxy_connection Proxy-Connection extension header. */
+
+#define http_proxy_connection_d msg_list_d
+#define http_proxy_connection_e msg_list_e
+msg_hclass_t http_proxy_connection_class[] =
+HTTP_HEADER_CLASS_LIST(proxy_connection, "Proxy-Connection", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_cookie Cookie extension header.
+ *
+ * The Cookie header is used to transmit state information from server
+ * back to the http client. Its syntax is defined in RFC 2109 section 4.3.4
+ * as follows:
+ *
+ * @code
+ *   cookie         = "Cookie:" cookie-version
+ *                    1*((";" | ",") cookie-value)
+ *   cookie-value   = NAME "=" VALUE [";" path] [";" domain]
+ *   cookie-version = "$Version" "=" value
+ *   NAME           = attr
+ *   VALUE          = value
+ *   path           = "$Path" "=" value
+ *   domain         = "$Domain" "=" value
+ * @endcode
+ *
+ */
+
+/**@ingroup http_cookie
+ *
+ * @typedef typedef struct http_cookie_s http_cookie_t;
+ *
+ * The structure http_cookie_t contains representation of @b Cookie
+ * header. Please note that a single http_cookie_t can contain many
+ * cookies.
+ *
+ * The http_cookie_t is defined as follows:
+ * @code
+ * typedef struct http_cookie_s
+ * {
+ * } http_cookie_t;
+ * @endcode
+ */
+
+/**Update Cookie parameters.
+ *
+ * The function http_cookie_update() updates a @b Cookie parameter
+ * shortcuts.
+ *
+ * @param sc pointer to a @c http_cookie_t object
+ */
+static inline
+void http_cookie_update(http_cookie_t *c)
+{
+  size_t i;
+
+  c->c_name = NULL;
+  c->c_version = NULL, c->c_domain = NULL, c->c_path = NULL;
+
+  if (!c->c_params)
+    return;
+
+  if (!(MSG_PARAM_MATCH(c->c_version, c->c_params[0], "$Version")))
+    return;
+  if (!c->c_params[1] || c->c_params[1][0] == '$')
+    return;
+
+  c->c_name = c->c_params[1];
+
+  for (i = 2; ; i++) {
+    msg_param_t p = c->c_params[i];
+    if (!p || *p++ != '$')
+      break;
+    switch (p[0]) {
+    case 'd': case 'D':
+      MSG_PARAM_MATCH(c->c_domain, p, "Domain");
+      break;
+    case 'p': case 'P':
+      MSG_PARAM_MATCH(c->c_path, p, "Path");
+      break;
+    }
+  }
+}
+
+/* Scan a cookie parameter */
+static issize_t cookie_scanner(char *s)
+{
+  char *p = s;
+  size_t tlen;
+
+  skip_token(&s);
+
+  if (s == p)		/* invalid parameter name */
+    return -1;
+
+  tlen = s - p;
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+  if (*s == '=') {
+    char *v;
+    s++;
+    skip_lws(&s);
+
+    v = s;
+
+    /* get value */
+    if (*s == '"') {
+      size_t qlen = span_quoted(s);
+      if (!qlen)
+	return -1;
+      s += qlen;
+    }
+    else {
+      s += strcspn(s, ",;" LWS);
+      if (s == v) 
+	return -1;
+    }
+
+    if (p + tlen + 1 != v) {
+      memmove(p + tlen + 1, v, s - v);
+      p[tlen] = '=';
+      p[tlen + 1 + (s - v)] = '\0';
+    }
+  }
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+  return s - p;
+}
+
+/** Decode (parse) a Cookie header */
+issize_t http_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  http_cookie_t *c = (http_cookie_t *)h;
+
+  assert(h); assert(sizeof(*h));
+
+  for (;*s;) {
+    /* Ignore empty entries (comma-whitespace) */
+    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+    if (msg_any_list_d(home, &s, (msg_param_t **)&c->c_params,
+		       cookie_scanner, ';') == -1)
+      return -1;
+
+    if (*s != '\0' && *s != ',')
+      return -1;
+
+    if (!c->c_params)
+      return -1;
+  }
+
+  http_cookie_update(c);
+
+  return 0;
+}
+
+/** Encode (print) a Cookie header */
+issize_t http_cookie_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  http_cookie_t const *c = (http_cookie_t *)h;
+  size_t i;
+
+  if (c->c_params) {
+    for (i = 0; c->c_params[i]; i++) {
+      if (i > 0) MSG_CHAR_E(b, end, ';');
+      MSG_STRING_E(b, end, c->c_params[i]);
+    }
+  }
+
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra storage used by Cookie header field */
+isize_t http_cookie_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  http_cookie_t const *c = (http_cookie_t *)h;
+
+  MSG_PARAMS_SIZE(offset, c->c_params);
+
+  return offset;
+}
+
+/** Duplicate a Cookie header field */
+char *http_cookie_dup_one(msg_header_t *dst, msg_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  http_cookie_t *c = (http_cookie_t *)dst;
+  http_cookie_t const *o = (http_cookie_t const *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+  http_cookie_update(c);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_cookie_class[] =
+HTTP_HEADER_CLASS(cookie, "Cookie", c_params, append, cookie);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_set_cookie Set-Cookie extension header.
+ *
+ * The Set-Cookie header is used to transmit state information from server
+ * back to the http client. Its syntax is defined in RFC 2109 section 4.2.2
+ * as follows:
+ *
+ * @code
+ * set-cookie      =       "Set-Cookie:" cookies
+ * cookies         =       1#cookie
+ * cookie          =       NAME "=" VALUE *(";" cookie-av)
+ * NAME            =       attr
+ * VALUE           =       value
+ * cookie-av       =       "Comment" "=" value
+ *                 |       "Domain" "=" value
+ *                 |       "Max-Age" "=" value
+ *                 |       "Path" "=" value
+ *                 |       "Secure"
+ *                 |       "Version" "=" 1*DIGIT
+ *
+ * @endcode
+ *
+ */
+
+/**@ingroup http_set_cookie
+ *
+ * @typedef typedef struct http_set_cookie_s http_set_cookie_t;
+ *
+ * The structure http_set_cookie_t contains representation of @b Set-Cookie
+ * header.
+ *
+ * The http_set_cookie_t is defined as follows:
+ * @code
+ * typedef struct http_set_cookie_s
+ * {
+ * } http_set_cookie_t;
+ * @endcode
+ */
+
+/**Update Set-Cookie parameters.
+ *
+ * The function http_set_cookie_update() updates a @b Set-Cookie parameter
+ * shortcuts.
+ *
+ * @param sc pointer to a @c http_set_cookie_t object
+ */
+static inline
+void http_set_cookie_update(http_set_cookie_t *sc)
+{
+  size_t i;
+
+  sc->sc_name = NULL;
+  sc->sc_version = NULL, sc->sc_domain = NULL, sc->sc_path = NULL;
+  sc->sc_comment = NULL, sc->sc_max_age = NULL, sc->sc_secure = 0;
+
+  if (!sc->sc_params)
+    return;
+
+  sc->sc_name = sc->sc_params[0];
+
+  for (i = 1; sc->sc_params[i]; i++) {
+    msg_param_t p = sc->sc_params[i];
+    switch (p[0]) {
+    case 'c': case 'C':
+      MSG_PARAM_MATCH(sc->sc_comment, p, "Comment");
+      break;
+    case 'd': case 'D':
+      MSG_PARAM_MATCH(sc->sc_domain, p, "Domain");
+      break;
+    case 'm': case 'M':
+      MSG_PARAM_MATCH(sc->sc_max_age, p, "Max-Age");
+      break;
+    case 'p': case 'P':
+      MSG_PARAM_MATCH(sc->sc_path, p, "Path");
+      break;
+    case 's': case 'S':
+      MSG_PARAM_MATCH_P(sc->sc_secure, p, "Secure");
+      break;
+    case 'v': case 'V':
+      MSG_PARAM_MATCH(sc->sc_version, p, "Version");
+      break;
+    }
+  }
+
+}
+
+#include <sofia-sip/msg_date.h>
+
+/* Scan a cookie parameter */
+static issize_t set_cookie_scanner(char *s)
+{
+  char *rest;
+
+#define LOOKING_AT(s, what) \
+  (strncasecmp((s), what, strlen(what)) == 0 && (rest = s + strlen(what)))
+
+  /* Special cases from Netscape spec */
+  if (LOOKING_AT(s, "expires=")) {
+    msg_time_t value; 
+    msg_date_d((char const **)&rest, &value);
+  } else if (LOOKING_AT(s, "path=/")) {
+    for (;;) {
+      rest += span_unreserved(rest);
+      if (*rest != '/')
+	break;
+      rest++;
+    }
+  } else {
+    return msg_attribute_value_scanner(s);
+  }
+#undef LOOKING_AT
+
+  if (IS_LWS(*rest)) { 
+    *rest++ = '\0'; skip_lws(&rest); 
+  }
+
+  return rest - s;
+}
+
+/** Decode (parse) Set-Cookie header */
+issize_t http_set_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_header_t **hh = &h->sh_succ, *h0 = h;
+  http_set_cookie_t *sc = (http_set_cookie_t *)h;
+  msg_param_t *params;
+
+  assert(h); assert(sizeof(*h));
+
+  for (;*s;) {
+    /* Ignore empty entries (comma-whitespace) */
+    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+    if (!h) {      /* Allocate next header structure */
+      if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+	return -1;
+      *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+      sc = sc->sc_next = (http_set_cookie_t *)h;
+    }
+
+    /* "Set-Cookie:" 1#(NAME "=" VALUE *(";" cookie-av))) */
+    params = su_zalloc(home, MSG_PARAMS_NUM(1) * sizeof(msg_param_t));
+    if (!params)
+      return -1;
+
+    params[0] = s, sc->sc_params = params;
+    s += strcspn(s, ",;" LWS);
+
+    if (*s) {
+      *s++ = '\0';
+      skip_lws(&s);
+      if (*s && msg_any_list_d(home, &s, (msg_param_t **)&sc->sc_params,
+			       set_cookie_scanner, ';') == -1)
+	return -1;
+    }
+
+    if (*s != '\0' && *s != ',')
+      return -1;
+
+    if (sc->sc_params)
+      http_set_cookie_update(sc);
+
+    h = NULL;
+  }
+
+  return 0;
+}
+
+/** Encode (print) Set-Cookie header */
+issize_t http_set_cookie_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  http_set_cookie_t const *sc = (http_set_cookie_t *)h;
+  size_t i;
+
+  if (sc->sc_params) {
+    for (i = 0; sc->sc_params[i]; i++) {
+      if (i > 0) MSG_CHAR_E(b, end, ';');
+      MSG_STRING_E(b, end, sc->sc_params[i]);
+    }
+  }
+
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra storage used by Set-Cookie header field */
+isize_t http_set_cookie_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  http_set_cookie_t const *sc = (http_set_cookie_t *)h;
+
+  MSG_PARAMS_SIZE(offset, sc->sc_params);
+
+  return offset;
+}
+
+/** Duplicate a Set-Cookie header field */
+char *http_set_cookie_dup_one(msg_header_t *dst, msg_header_t const *src,
+			      char *b, isize_t xtra)
+{
+  http_set_cookie_t *sc = (http_set_cookie_t *)dst;
+  http_set_cookie_t const *o = (http_set_cookie_t const *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&sc->sc_params, o->sc_params, b, xtra);
+  http_set_cookie_update(sc);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+msg_hclass_t http_set_cookie_class[] =
+HTTP_HEADER_CLASS(set_cookie, "Set-Cookie", sc_params, append, set_cookie);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,307 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_header.c
+ *
+ * HTTP header handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+#define HTTP_STATIC_INLINE
+
+#include "sofia-sip/http_parser.h"
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+/** Complete a HTTP request. */
+int http_request_complete(msg_t *msg)
+{
+  size_t len = 0;
+  http_t *http = http_object(msg);
+  http_payload_t const *pl;
+  su_home_t *home = msg_home(msg);
+
+  if (!http)
+    return -1;
+  if (!http->http_request)
+    return -1;
+  if (!http->http_host)
+    return -1;
+
+    for (pl = http->http_payload; pl; pl = pl->pl_next)
+      len += pl->pl_len;
+
+  if (len > UINT32_MAX)
+    return -1;
+
+  if (!http->http_content_length) {
+    http->http_content_length = http_content_length_create(home, (uint32_t)len);
+  }
+  else {
+    if (http->http_content_length->l_length != len) {
+      http->http_content_length->l_length = (uint32_t)len;
+      msg_fragment_clear(http->http_content_length->l_common);
+    }
+  }
+  
+  if (!http->http_separator)
+    http->http_separator = http_separator_create(home);
+
+  return 0;
+}
+
+/** Remove schema, host, port, and fragment from HTTP/HTTPS URL */
+int http_strip_hostport(url_t *url)
+{
+  if (url->url_type == url_http || url->url_type == url_https) {
+    url->url_type = url_unknown;
+    url->url_scheme = NULL;
+    url->url_user = NULL;
+    url->url_password = NULL;
+    url->url_host = NULL;
+    url->url_port = NULL;
+    if (url->url_path == NULL) {
+      url->url_root = '/';
+      url->url_path = "";
+    }
+  }
+
+  url->url_fragment = NULL;
+
+  return 0;
+}
+
+/** Add a Content-Length and separator to a message */
+int http_message_complete(msg_t *msg, http_t *http)
+{ 
+#if 1
+  if (!http->http_content_length) {
+    http_content_length_t *l;
+    http_payload_t *pl;
+    size_t len = 0;
+    
+    for (pl = http->http_payload; pl; pl = pl->pl_next)
+      len += pl->pl_len;
+
+    if (len > UINT32_MAX)
+      return -1;
+
+    l = http_content_length_create(msg_home(msg), (uint32_t)len);
+
+    if (msg_header_insert(msg, http, (http_header_t *)l) < 0)
+      return -1;
+  }
+#endif
+
+  if (!http->http_separator) {
+    http_separator_t *sep = http_separator_create(msg_home(msg));
+    if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Add headers from the request to the response message. */
+int http_complete_response(msg_t *msg, 
+			   int status, char const *phrase, 
+			   http_t const *request)
+{
+  su_home_t *home = msg_home(msg);
+  http_t *http = msg_object(msg);
+
+  if (!http || !request || !request->http_request)
+    return -1;
+
+  if (!http->http_status)
+    http->http_status = http_status_create(home, status, phrase, NULL);
+
+  if (!http->http_status)
+    return -1;
+
+  if (!http->http_separator) {
+    http_separator_t *sep = http_separator_create(msg_home(msg));
+    if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Copy a HTTP header. */
+http_header_t *http_header_copy(su_home_t *home, http_header_t const *h)
+{
+  if (h == NULL || h == HTTP_NONE)
+    return NULL;
+  return msg_header_copy_as(home, h->sh_class, h);
+}
+
+/** Duplicate a HTTP header. */
+http_header_t *http_header_dup(su_home_t *home, http_header_t const *h)
+{
+  if (h == NULL || h == HTTP_NONE)
+    return NULL;
+  return msg_header_dup_as(home, h->sh_class, h);
+
+}
+
+/** Decode a HTTP header. */
+http_header_t *http_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+  return msg_header_d(home, msg, b);
+}
+
+/** Encode a HTTP header. */
+int http_header_e(char b[], int bsiz, http_header_t const *h, int flags)
+{
+  return msg_header_e(b, bsiz, h, flags);
+}
+
+/** Encode HTTP header contents. */
+int http_header_field_e(char b[], int bsiz, http_header_t const *h, int flags)
+{
+  assert(h); assert(h->sh_class);
+
+  return h->sh_class->hc_print(b, bsiz, h, flags);
+}
+
+http_header_t *http_header_format(su_home_t *home, 
+				  msg_hclass_t *hc,
+				  char const *fmt,
+				  ...)
+{
+  http_header_t *h;
+  va_list ap;
+
+  va_start(ap, fmt);
+
+  h = http_header_vformat(home, hc, fmt, ap);
+
+  va_end(ap);
+
+  return h;
+}
+
+/** Add a duplicate of header object to a HTTP message. */
+int http_add_dup(msg_t *msg,
+		 http_t *http,
+		 http_header_t const *o)
+{
+  if (o == HTTP_NONE)
+    return 0;
+
+  if (msg == NULL || o == NULL)
+    return -1;
+
+  return msg_header_insert(msg, http, msg_header_dup(msg_home(msg), o));
+}
+
+int http_add_make(msg_t *msg,
+		 http_t *http,
+		 msg_hclass_t *hc,
+		 char const *s)
+{
+  if (s == NULL)
+    return 0;
+
+  if (msg == NULL)
+    return -1;
+
+  return msg_header_insert(msg, http, msg_header_make(msg_home(msg), hc, s));
+}
+
+int http_add_format(msg_t *msg,
+		    http_t *http,
+		    msg_hclass_t *hc,
+		    char const *fmt,
+		    ...)
+{
+  http_header_t *h;
+  va_list ap;
+
+  if (fmt == NULL)
+    return 0;
+
+  if (msg == NULL)
+    return -1;
+
+  va_start(ap, fmt);
+  h = http_header_vformat(msg_home(msg), hc, fmt, ap);
+  va_end(ap);
+
+  return msg_header_insert(msg, http, h);
+}
+
+/** Compare two HTTP URLs. */
+int http_url_cmp(url_t const *a, url_t const *b)
+{
+  int rv;
+
+  if ((rv = url_cmp(a, b)))
+    return rv;
+
+  if (a->url_path != b->url_path) {
+    if (a->url_path == NULL) return -1;
+    if (b->url_path == NULL) return +1;
+    if ((rv = strcmp(a->url_path, b->url_path)))
+      return rv;
+  }
+
+  /* Params? */
+
+  /* Query */
+  if (a->url_headers != b->url_headers) {
+    if (a->url_headers == NULL) return -1;
+    if (b->url_headers == NULL) return +1;
+    if ((rv = strcmp(a->url_headers, b->url_headers)))
+      return rv;
+  }
+
+  return 0;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,573 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_parser.c
+ *
+ * HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct  5 14:01:24 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include "sofia-sip/http_parser.h"
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+#include <sofia-sip/msg_mclass.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+
+/** HTTP version 1.1. */
+char const http_version_1_1[] = "HTTP/1.1";
+/** HTTP version 1.0. */
+char const http_version_1_0[] = "HTTP/1.0";
+/** HTTP version 0.9 is an empty string. */
+char const http_version_0_9[] = "";
+
+msg_mclass_t *http_default_mclass(void)
+{
+  extern msg_mclass_t http_mclass[];
+
+  return http_mclass;
+}
+
+static
+issize_t http_extract_chunk(msg_t *, http_t *, char b[], isize_t bsiz, int eos);
+
+/** Calculate length of line ending (0, 1 or 2) */
+#define CRLF_TEST(s) \
+  (((s)[0]) == '\r' ? (((s)[1]) == '\n') + 1 : ((s)[0])=='\n')
+
+/** Extract the HTTP message body, including separator line. 
+ *
+ * @retval -1    error
+ * @retval 0     cannot proceed
+ * @retval other number of bytes extracted
+ */
+issize_t http_extract_body(msg_t *msg, http_t *http, char b[], isize_t bsiz, int eos)
+{
+  issize_t m = 0;
+  size_t body_len;
+
+  int flags = http->http_flags;
+
+  if (eos && bsiz == 0) {
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+    return 0;
+  }
+
+  if (flags & MSG_FLG_TRAILERS) {
+    /* The empty line after trailers */
+    if (!eos && (bsiz == 0 || (bsiz == 1 && b[0] == '\r')))
+      return 0;
+
+    m = CRLF_TEST(b); 
+
+    assert(m > 0 || eos); /* We should be looking at an empty line */
+
+    /* We have completed trailers */
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+
+    return m;
+  }
+
+  if (flags & MSG_FLG_CHUNKS)
+    return http_extract_chunk(msg, http, b, bsiz, eos);
+
+  if (!(flags & MSG_FLG_BODY)) {
+    /* We are looking at a potential empty line */
+    m = msg_extract_separator(msg, http, b, bsiz, eos);
+
+    if (m == 0)			/* Not yet */
+      return 0;
+
+    http->http_flags |= MSG_FLG_BODY;
+    b += m, bsiz -= m;
+  }
+
+  /* body_len is determined by rules in RFC2616 sections 4.3 and 4.4 */
+
+  /* 1XX, 204, 304 do not have message-body, ever */
+  if (http->http_status) {
+    int status = http->http_status->st_status;
+
+    if (status < 200 || status == 204 || status == 304)
+      flags |= HTTP_FLG_NO_BODY;
+  }
+
+  if (flags & HTTP_FLG_NO_BODY) {
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+    return m;
+  }
+
+  if (http->http_transfer_encoding) {
+    if (/* NOTE - there is really no Transfer-Encoding: identity in RFC 2616
+	 * but it was used in drafts...
+	 */
+	http->http_transfer_encoding->k_items &&
+	http->http_transfer_encoding->k_items[0] &&
+	strcasecmp(http->http_transfer_encoding->k_items[0], 
+		   "identity") != 0) {
+      http->http_flags |= MSG_FLG_CHUNKS;
+
+      if (http->http_flags & MSG_FLG_STREAMING)
+	msg_set_streaming(msg, msg_start_streaming);
+
+      if (m)
+	return m;
+
+      return http_extract_chunk(msg, http, b, bsiz, eos);
+    }
+  }
+
+
+  if (http->http_content_length)
+    body_len = http->http_content_length->l_length;
+  /* We cannot parse multipart/byteranges ... */
+  else if (http->http_content_type && http->http_content_type->c_type &&
+	   strcasecmp(http->http_content_type->c_type, "multipart/byteranges") 
+	   == 0)
+    return -1;
+  else if (MSG_IS_MAILBOX(flags)) /* message fragments */
+    body_len = 0;
+  else if (http->http_request) 
+    body_len = 0;
+  else if (eos)
+    body_len = bsiz;
+  else 
+    return 0;			/* XXX */
+
+  if (body_len == 0) {
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+    return m;
+  }
+
+  if (http->http_flags & MSG_FLG_STREAMING)
+    msg_set_streaming(msg, msg_start_streaming);
+
+  if (m)
+    return m;
+
+  m = msg_extract_payload(msg, http, NULL, body_len, b, bsiz, eos);
+  if (m == -1)
+    return -1;
+
+  /* We have now all message fragments in place */
+  http->http_flags |= MSG_FLG_FRAGS;
+  if (bsiz >= body_len) {
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+  }
+
+  return m;
+}
+
+/** Extract a chunk. 
+ *
+ * @retval -1    error
+ * @retval 0     cannot proceed
+ * @retval other number of bytes extracted
+ */
+issize_t http_extract_chunk(msg_t *msg, http_t *http, char b[], isize_t bsiz, int eos)
+{
+  size_t n;
+  unsigned crlf, chunk_len;
+  char *b0 = b, *s;
+  union {
+    msg_header_t *header;  
+    msg_payload_t *chunk;
+  } h = { NULL };
+  size_t bsiz0 = bsiz;
+
+  if (bsiz == 0)
+    return 0;
+
+  /* We should be looking at an empty line followed by the chunk header */
+  while ((crlf = CRLF_TEST(b))) {
+    if (bsiz == 1 && crlf == 1 && b[0] == '\r' && !eos)
+      return 0;
+
+    if (crlf == bsiz) {
+      if (eos) {
+	msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+	return (b - b0) + crlf;
+      }
+      else
+	return 0;
+    }
+    assert(crlf < bsiz);
+
+    /* Skip crlf */
+    b += crlf; bsiz -= crlf;  
+  }
+
+  /* Now, looking at the chunk header */
+  n = strcspn(b, CRLF); 
+  if (!eos && n == bsiz) 
+    return 0;
+  crlf = CRLF_TEST(b + n);
+  
+  if (n == 0) {
+    if (crlf == bsiz && eos) {
+      msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+      return crlf;
+    }
+    else
+      return -1;		/* XXX - should we be more liberal? */
+  }
+
+  if (!eos && n + crlf == bsiz && (crlf == 0 || (crlf == 1 && b[n] == '\r')))
+    return 0;
+
+  chunk_len = strtoul(b, &s, 16);
+  if (s == b)
+    return -1;
+  skip_ws(&s);
+  if (s != b + n && s[0] != ';') /* Extra stuff that is not parameter */
+    return -1;
+
+  if (chunk_len == 0) {  /* We found last-chunk */
+    b += n + crlf, bsiz -= n + crlf;
+
+    crlf = bsiz > 0 ? CRLF_TEST(b) : 0;
+
+    if ((eos && bsiz == 0) || crlf == 2 || 
+	(crlf == 1 && (bsiz > 1 || b[0] == '\n'))) {
+      /* Shortcut - We got empty trailers */
+      b += crlf;
+      msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+    } else {
+      /* We have to parse trailers */
+      http->http_flags |= MSG_FLG_TRAILERS;
+    }
+
+    return b - b0;
+  }
+  else {
+    issize_t chunk;
+
+    b += n + crlf, bsiz -= n + crlf;
+
+    /* Extract chunk */
+    chunk = msg_extract_payload(msg, http, 
+				&h.header, chunk_len + (b - b0),
+				b0, bsiz0, eos);
+
+    if (chunk != -1 && h.header) {
+      assert(h.chunk->pl_data);
+      h.chunk->pl_data += (b - b0);
+      h.chunk->pl_len -= (b - b0);
+    }
+  
+    return chunk;
+  }
+}
+
+/** Parse HTTP version.
+ *
+ *  The function http_version_d() parses a HTTP method.
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int http_version_d(char **ss, char const **ver)
+{
+  char *s = *ss;
+  char const *result;
+  int const version_size = sizeof(http_version_1_1) - 1;
+
+  if (strncasecmp(s, http_version_1_1, version_size) == 0 && 
+      !IS_TOKEN(s[version_size])) {
+    result = http_version_1_1;
+    s += version_size;
+  }
+  else if (strncasecmp(s, http_version_1_0, version_size) == 0 && 
+	   !IS_TOKEN(s[version_size])) {
+    result = http_version_1_0;
+    s += version_size;
+  }
+  else if (s[0] == '\0') {
+    result = http_version_0_9;
+  } else {
+    /* Version consists of one or two tokens, separated by / */
+    size_t l1 = 0, l2 = 0, n;
+
+    result = s;
+
+    l1 = span_token(s);
+    for (n = l1; IS_LWS(s[n]); n++)
+      s[n] = '\0';
+    if (s[n] == '/') {
+      for (n = n + 1; IS_LWS(s[n]); n++);
+      l2 = span_token(s + n);
+      n += l2;
+    }
+
+    if (l1 == 0)
+      return -1;
+
+    /* If there is extra ws between tokens, compact version */
+    if (l2 > 0 && n > l1 + 1 + l2) {
+      s[l1] = '/';
+      memmove(s + l1 + 1, s + n - l2, l2);
+      s[l1 + 1 + l2] = 0;
+
+      /* Compare again with compacted version */ 
+      if (strcasecmp(s, http_version_1_1) == 0)
+	result = http_version_1_1;
+      else if (strcasecmp(s, http_version_1_0) == 0)
+	result = http_version_1_0;
+    }
+
+    s += n;
+  }
+
+  while (IS_LWS(*s)) *s++ = '\0';
+  
+  *ss = s;
+
+  if (ver) 
+    *ver = result;
+
+  return 0;
+}
+
+/** Calculate extra space required by version string */
+isize_t http_version_xtra(char const *version)
+{
+  if (version == http_version_1_1)
+    return 0;
+  else if (version == http_version_1_0)
+    return 0;
+  else
+    return MSG_STRING_SIZE(version);
+}
+
+/** Duplicate a transport string */
+void http_version_dup(char **pp, char const **dd, char const *s)
+{
+  if (s == http_version_1_1)
+    *dd = s;
+  else if (s == http_version_1_0)
+    *dd = s;
+  else
+    MSG_STRING_DUP(*pp, *dd, s);
+}
+
+/** Well-known HTTP method names. */
+static char const * const methods[] = {
+  "<UNKNOWN>",
+  http_method_name_get,
+  http_method_name_post,
+  http_method_name_head,
+  http_method_name_options,
+  http_method_name_put,
+  http_method_name_delete,
+  http_method_name_trace,
+  http_method_name_connect,
+  NULL,
+  /* If you add something here, add also them to http_method_d! */
+};
+
+char const http_method_name_get[]     = "GET";
+char const http_method_name_post[]    = "POST";
+char const http_method_name_head[]    = "HEAD";
+char const http_method_name_options[] = "OPTIONS";
+char const http_method_name_put[]     = "PUT";
+char const http_method_name_delete[]  = "DELETE";
+char const http_method_name_trace[]   = "TRACE";
+char const http_method_name_connect[] = "CONNECT";
+
+char const *http_method_name(http_method_t method, char const *name)
+{
+  if (method > 0 && (size_t)method < sizeof(methods)/sizeof(methods[0]))
+    return methods[method];
+  else if (method == 0)
+    return name;
+  else
+    return NULL;
+}
+
+/**Parse a HTTP method name.
+ *
+ * The function @c http_method_d() parses a HTTP method, and returns a code
+ * corresponding to the method.  It stores the address of the first non-LWS
+ * character after method name in @c *ss.
+ *
+ * @param ss    pointer to pointer to string to be parsed
+ * @param nname pointer to value-result parameter formethod name
+ *
+ * @note
+ * If there is no whitespace after method name, the value in @a *nname
+ * may not be NUL-terminated.  The calling function @b must NUL terminate
+ * the value by setting the @a **ss to NUL after first examining its value.
+ *
+ * @return The function @c http_method_d returns the method code if method
+ * was identified, 0 (@c http_method_unknown) if method is not known, or @c -1
+ * (@c http_method_invalid) if an error occurred.
+ *
+ * If the value-result argument @a nname is not @c NULL, http_method_d()
+ * stores a pointer to the method name to it.
+ */
+http_method_t http_method_d(char **ss, char const **nname)
+{
+  char *s = *ss, c = *s;
+  char const *name;
+  int code = http_method_unknown;
+  size_t n = 0;
+
+#define MATCH(s, m) (strncasecmp(s, m, n = sizeof(m) - 1) == 0)
+
+  if (c >= 'a' && c <= 'z') 
+    c += 'A' - 'a';
+
+  switch (c) {
+  case 'C': if (MATCH(s, "CONNECT")) code = http_method_connect; break;
+  case 'D': if (MATCH(s, "DELETE")) code = http_method_delete; break;
+  case 'G': if (MATCH(s, "GET")) code = http_method_get; break;
+  case 'H': if (MATCH(s, "HEAD")) code = http_method_head; break;
+  case 'O': if (MATCH(s, "OPTIONS")) code = http_method_options; break;
+  case 'P': if (MATCH(s, "POST")) code = http_method_post; 
+            else
+            if (MATCH(s, "PUT")) code = http_method_put; break;
+  case 'T': if (MATCH(s, "TRACE")) code = http_method_trace; break;
+  }
+
+#undef MATCH
+
+  if (!code || IS_NON_WS(s[n])) {
+    /* Unknown method */
+    code = http_method_unknown;
+    name = s;
+    for (n = 0; IS_UNRESERVED(s[n]); n++)
+      ;
+    if (s[n]) {
+      if (!IS_LWS(s[n]))
+	return http_method_invalid;
+      if (nname)
+	s[n++] = '\0';
+    }
+  }
+  else {
+    name = methods[code];
+  }
+
+  while (IS_LWS(s[n]))
+    n++;
+
+  *ss = (s + n);
+  if (nname) *nname = name;
+
+  return code;
+}
+
+/** Get method enum corresponding to method name */
+http_method_t http_method_code(char const *name)
+{
+  /* Note that http_method_d() does not change string if nname is NULL */
+  return http_method_d((char **)&name, NULL);
+}
+
+/**Parse HTTP query string.
+ *
+ * The function http_query_parse() searches for the given keys in HTTP @a
+ * query. For each key, a query element (in the form name=value) is searched
+ * from the query string. If a query element has a beginning matching with
+ * the key, a copy of the rest of the element is returned in corresponding
+ * return_value argument. 
+ *
+ * @note The @a query string will be modified.
+ *
+ * @return
+ * The function http_query_parse() returns number keys that matched within
+ * the @a query string.
+ */
+issize_t http_query_parse(char *query,
+			  /* char const *key, char **return_value, */
+			  ...)
+{
+  va_list ap;
+  char *q, *q_next;
+  char *name, *value, **return_value;
+  char const *key;
+  size_t namelen, valuelen, keylen;
+  isize_t N;
+  int has_value;
+
+  if (!query)
+    return -1;
+
+  for (q = query, N = 0; *q; q = q_next) {
+    namelen = strcspn(q, "=&");
+    valuelen = namelen + strcspn(q + namelen, "&");
+
+    q_next = q + valuelen;
+    if (*q_next) 
+      *q_next++ = '\0';
+
+    value = q + namelen; 
+    has_value = (*value) != '\0'; /* is the part in form of name=value? */
+    if (has_value)
+      *value++ = '\0';
+
+    name = url_unescape(q, q); 
+
+    if (has_value) {
+      namelen = strlen(name);
+      name[namelen] = '=';
+      url_unescape(name + namelen + 1, value);
+    }
+
+    va_start(ap, query);
+
+    while ((key = va_arg(ap, char const *))) {
+      return_value = va_arg(ap, char **);
+      keylen = strlen(key);
+
+      if (strncmp(key, name, keylen) == 0) {
+	*return_value = name + keylen;
+	N++;
+      }
+    }
+
+    va_end(ap);
+  }
+
+  return N;
+} 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+/** -*- C -*-
+ * @IFILE http_parser_table.c.in
+ *
+ * Template for <http_parser_table.c>.
+ *
+ * @date Created: Tue Oct  1 20:37:52 2002 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE http_parser_table.c 
+ * @brief HTTP parser table
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Oct  1 20:37:52 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/http_parser.h>
+#include <sofia-sip/msg_mclass.h>
+
+#define HTTP_PARSER_FLAGS (MSG_FLG_CHUNKING)
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_status.c   HTTP status codes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 18 18:58:21 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <sofia-sip/http_status.h>
+
+char const
+  http_100_continue[]             = "Continue",
+  http_101_switching[]            = "Switching Protocols",
+  http_200_ok[]                   = "OK",
+  http_201_created[]              = "Created",
+  http_202_accepted[]             = "Accepted",
+  http_203_non_auth_info[]        = "Non-Authoritative Information",
+  http_204_no_content[]           = "No Content",
+  http_205_reset_content[]        = "Reset Content",
+  http_206_partial_content[]      = "Partial Content",
+  http_300_multiple_choices[]     = "Multiple Choices",
+  http_301_moved_permanently[]    = "Moved Permanently",
+  http_302_found[]                = "Found",
+  http_303_see_other[]            = "See Other",
+  http_304_not_modified[]         = "Not Modified",
+  http_305_use_proxy[]            = "Use Proxy",
+  http_307_temporary_redirect[]   = "Temporary Redirect",
+  http_400_bad_request[]          = "Bad Request",
+  http_401_unauthorized[]         = "Unauthorized",
+  http_402_payment_required[]     = "Payment Required",
+  http_403_forbidden[]            = "Forbidden",
+  http_404_not_found[]            = "Not Found",
+  http_405_not_allowed[]          = "Method Not Allowed",
+  http_406_not_acceptable[]       = "Not Acceptable",
+  http_407_proxy_auth[]           = "Proxy Authentication Required",
+  http_408_timeout[]              = "Request Timeout",
+  http_409_conflict[]             = "Conflict",
+  http_410_gone[]                 = "Gone",
+  http_411_no_length[]            = "Length Required",
+  http_412_precondition[]         = "Precondition Failed",
+  http_413_entity_too_large[]     = "Request Entity Too Large",
+  http_414_uri_too_long[]         = "Request-URI Too Long",
+  http_415_media_type[]           = "Unsupported Media Type",
+  http_416_requested_range[]      = "Requested Range Not Satisfiable",
+  http_417_expectation[]          = "Expectation Failed",
+  http_426_upgrade[]              = "Upgrade Required",
+  http_500_internal_server[]      = "Internal Server Error",
+  http_501_not_implemented[]      = "Not Implemented",
+  http_502_bad_gateway[]          = "Bad Gateway",
+  http_503_no_service[]           = "Service Unavailable",
+  http_504_gateway_timeout[]      = "Gateway Timeout",
+  http_505_http_version[]         = "HTTP Version Not Supported";
+
+char const *http_status_phrase(int status)
+{
+  if (status < 100 || status > 699) 
+    return NULL;
+
+  switch (status) {
+  case 100: return http_100_continue;
+  case 101: return http_101_switching;
+  case 200: return http_200_ok;
+  case 201: return http_201_created;
+  case 202: return http_202_accepted;
+  case 203: return http_203_non_auth_info;
+  case 204: return http_204_no_content;
+  case 205: return http_205_reset_content;
+  case 206: return http_206_partial_content;
+  case 300: return http_300_multiple_choices;
+  case 301: return http_301_moved_permanently;
+  case 302: return http_302_found;
+  case 303: return http_303_see_other;
+  case 304: return http_304_not_modified;
+  case 305: return http_305_use_proxy;
+  case 307: return http_307_temporary_redirect;
+  case 400: return http_400_bad_request;
+  case 401: return http_401_unauthorized;
+  case 402: return http_402_payment_required;
+  case 403: return http_403_forbidden;
+  case 404: return http_404_not_found;
+  case 405: return http_405_not_allowed;
+  case 406: return http_406_not_acceptable;
+  case 407: return http_407_proxy_auth;
+  case 408: return http_408_timeout;
+  case 409: return http_409_conflict;
+  case 410: return http_410_gone;
+  case 411: return http_411_no_length;
+  case 412: return http_412_precondition;
+  case 413: return http_413_entity_too_large;
+  case 414: return http_414_uri_too_long;
+  case 415: return http_415_media_type;
+  case 416: return http_416_requested_range;
+  case 417: return http_417_expectation;
+  case 426: return http_426_upgrade;
+  case 500: return http_500_internal_server;
+  case 501: return http_501_not_implemented;
+  case 502: return http_502_bad_gateway;
+  case 503: return http_503_no_service;
+  case 504: return http_504_gateway_timeout;
+  case 505: return http_505_http_version;
+  }
+
+  return " ";
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,68 @@
+/**@HTTP 
+ * @IFILE http_tag.c.in
+ *
+ * Template for <http_tag.c>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file http_tag.c  HTTP Tag classes
+ *
+ * This file is autogenerated from <http_tag.c.in>.
+ *
+ * #AUTO#
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "http"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_protos.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/http_tag_class.h>
+
+tag_typedef_t httptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t httptag_http = HTTPMSGTAG_TYPEDEF(http);
+tag_typedef_t httptag_version = STRTAG_TYPEDEF(version);
+tag_typedef_t httptag_header = 
+	{{ TAG_NAMESPACE, "header", httphdrtag_class, 0 }};
+tag_typedef_t httptag_header_str = STRTAG_TYPEDEF(header_str);
+
+
+tag_typedef_t httptag_#xxxxxx# = HTTPHDRTAG_TYPEDEF(#xxxxxx#);
+tag_typedef_t httptag_#xxxxxx#_str = HTTPSTRTAG_TYPEDEF(#xxxxxx#);
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,222 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_tag_class.c  HTTP tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/http_parser.h>
+
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/http_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+tag_class_t httphdrtag_class[1] = 
+  {{
+    sizeof(httphdrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msghdrtag_xtra,
+    /* tc_dup */      msghdrtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msghdrtag_snprintf,
+    /* tc_filter */   httptag_filter,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     msghdrtag_scan,
+  }};
+
+tag_class_t httpstrtag_class[1] = 
+  {{
+    sizeof(httpstrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     t_str_xtra,
+    /* tc_dup */      t_str_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_str_snprintf,
+    /* tc_filter */   NULL /* msgtag_str_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     msghdrtag_scan,
+  }};
+
+tag_class_t httpmsgtag_class[1] = 
+  {{
+    sizeof(httpmsgtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msgobjtag_xtra,
+    /* tc_dup */      msgobjtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msgobjtag_snprintf,
+    /* tc_filter */   NULL /* httptag_http_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     t_str_scan
+  }};
+
+/** Filter a HTTP header structure. */
+tagi_t *httptag_filter(tagi_t *dst,
+		      tagi_t const f[],
+		      tagi_t const *src, 
+		      void **bb)
+{
+  tagi_t stub[2] = {{ NULL }};
+  tag_type_t sctt, tt = f->t_tag;
+  msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
+
+  assert(src);
+
+  sctt = src->t_tag;
+
+  if (sctt && sctt->tt_class == httpmsgtag_class) {
+    http_t const *http;
+    msg_mclass_t const *mc;
+    http_header_t const *h, **hh;
+
+    http = (http_t const *)src->t_value;
+    mc = (void *)http->http_common->h_class;
+    hh = (void *)msg_hclass_offset(mc, http, hc);
+
+    if (http == NULL ||
+	(char *)hh >= ((char *)http + http->http_size) ||
+	(char *)hh < (char *)&http->http_request)
+      return dst;
+
+    h = *hh;
+
+    if (h == NULL)
+      return dst;
+
+    stub[0].t_tag = tt;
+    stub[0].t_value = (tag_value_t)h;
+    src = stub; sctt = tt;
+  }
+
+  if (tt != sctt)
+    return dst;
+
+  if (!src->t_value)
+    return dst;
+  else if (dst) {
+    return t_dup(dst, src, bb);
+  }
+  else {
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst + 1;
+  }
+}
+
+/** Duplicate headers from taglist and add them to the HTTP message. 
+ *
+ * Return the number of headers added to the HTTP message.
+ */
+int http_add_tl(msg_t *msg, http_t *http,
+	       tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t const *t;
+  ta_list ta;
+  int retval = 0;
+
+  if (msg == NULL)
+    return -1;
+  if (http == NULL)
+    http = msg_object(msg);
+
+  ta_start(ta, tag, value);
+
+  for (t = ta_args(ta); t; t = tl_next(t)) {
+    if (!(tag = t->t_tag) || !(value = t->t_value))
+      continue;
+
+    if (HTTPTAG_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      http_header_t *h = (http_header_t *)value, **hh;
+
+      if (h == HTTP_NONE) { /* Remove header(s) */
+	if (hc == NULL)
+	  break;
+
+	hh = msg_hclass_offset(msg_mclass(msg), http, hc);
+	if (!hh)
+	  break;
+
+	while (*hh) {
+	  msg_header_remove(msg, http, *hh);
+	}
+      }
+      else if (h == NULL) {
+	continue;
+      } else {
+	if (tag == httptag_header)
+	  hc = h->sh_class;
+
+	if (msg_header_add_dup_as(msg, http, hc, h) < 0)
+	  break;
+      }
+    }
+    else if (HTTPTAG_STR_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      char const *s = (char const *)value;
+      if (s && msg_header_add_make(msg, http, hc, s) < 0)
+	break;
+    }
+    else if (tag == httptag_header_str) {
+      if (msg_header_add_str(msg, http, (char const *)value) < 0)
+	break;
+    } 
+    else 
+      continue;
+
+    retval++;
+  }
+
+  ta_end(ta);
+
+  if (t) 
+    return -1;
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,482 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_H
+/** Defined when <sofia-sip/http.h> has been included. */
+#define HTTP_H
+
+/**@file sofia-sip/http.h 
+ * 
+ * HTTP message, methods, headers.
+ * 
+ * @sa <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created      : Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Constants 
+ */
+
+#define HTTP_NONE ((http_header_t *)MSG_HEADER_NONE)
+#define HTTP_DEFAULT_PORT (80)
+#define HTTP_DEFAULT_SERV "80"
+
+/** HTTP protocol identifier */
+#define HTTP_PROTOCOL_TAG   ((void *)0x48545450)	/* 'HTTP' */
+
+/** HTTP parser flags */
+enum {
+  HTTP_FLG_NO_BODY = (1 << 15)
+};
+
+/** IDs for well-known HTTP methods. */
+typedef enum {
+  http_method_invalid = -1,	/**< Invalid method name */
+  http_method_unknown = 0,	/**< Unknown method, use @c method_name */
+  http_method_get,		/**< GET */
+  http_method_post,		/**< POST */
+  http_method_head,		/**< HEAD */
+  http_method_options,		/**< OPTIONS */
+  http_method_put,		/**< PUT */
+  http_method_delete,		/**< DELETE */
+  http_method_trace,		/**< TRACE */
+  http_method_connect,		/**< CONNECT */
+} http_method_t;
+
+#define HTTP_METHOD(s)          http_method_unknown, #s
+#define HTTP_NO_METHOD          http_method_unknown, NULL
+#define HTTP_METHOD_GET	        http_method_get, "GET"
+#define HTTP_METHOD_POST	http_method_post, "POST"
+#define HTTP_METHOD_HEAD	http_method_head, "HEAD"
+#define HTTP_METHOD_OPTIONS	http_method_options, "OPTIONS"
+#define HTTP_METHOD_PUT	        http_method_put, "PUT"
+#define HTTP_METHOD_DELETE	http_method_delete, "DELETE"
+#define HTTP_METHOD_TRACE	http_method_trace, "TRACE"
+#define HTTP_METHOD_CONNECT	http_method_connect, "CONNECT"
+
+/* ----------------------------------------------------------------------
+ * 2) Type declarations
+ */
+
+/** HTTP message object. */
+typedef struct http_s               http_t;
+
+/** Any HTTP header - union of all possible HTTP headers. */
+typedef union http_header_u         http_header_t;
+
+typedef struct http_request_s 	    http_request_t;
+typedef struct http_status_s  	    http_status_t;
+typedef msg_accept_t                http_accept_t;
+typedef msg_accept_charset_t        http_accept_charset_t;
+typedef msg_accept_encoding_t       http_accept_encoding_t;
+typedef msg_accept_language_t       http_accept_language_t;
+typedef msg_list_t                  http_accept_ranges_t;
+typedef msg_numeric_t               http_age_t;
+typedef msg_list_t                  http_allow_t;
+typedef msg_auth_info_t             http_authentication_info_t;
+typedef msg_auth_t                  http_authorization_t;
+typedef msg_list_t                  http_cache_control_t;
+typedef msg_list_t                  http_connection_t;
+typedef msg_content_encoding_t      http_content_encoding_t;
+typedef msg_content_language_t      http_content_language_t;
+typedef msg_content_length_t        http_content_length_t;
+typedef msg_content_location_t      http_content_location_t;
+typedef msg_generic_t               http_content_md5_t;
+typedef struct http_content_range_s http_content_range_t;
+typedef msg_content_type_t          http_content_type_t;
+typedef struct http_date_s          http_date_t;
+typedef msg_generic_t               http_etag_t;
+typedef msg_generic_t               http_expect_t;
+typedef http_date_t                 http_expires_t;
+typedef msg_generic_t               http_from_t;
+typedef struct http_host_s          http_host_t;
+typedef msg_list_t                  http_if_match_t;
+typedef http_date_t                 http_if_modified_since_t;
+typedef msg_list_t                  http_if_none_match_t;
+typedef struct http_if_range_s      http_if_range_t;
+typedef http_date_t                 http_if_unmodified_since_t;
+typedef http_date_t                 http_last_modified_t;
+typedef struct http_location_s      http_location_t;
+typedef struct http_max_forwards_s  http_max_forwards_t;
+typedef msg_generic_t               http_mime_version_t;
+typedef msg_list_t                  http_pragma_t;
+typedef msg_auth_t                  http_proxy_authenticate_t;
+typedef msg_auth_t                  http_proxy_authorization_t;
+typedef struct http_range_s         http_range_t;
+typedef struct http_location_s      http_referer_t;
+typedef struct http_retry_after_s   http_retry_after_t;
+typedef msg_generic_t               http_server_t;
+typedef struct http_te_s            http_te_t;
+typedef msg_list_t                  http_trailer_t;
+typedef msg_list_t                  http_transfer_encoding_t;
+typedef msg_list_t                  http_upgrade_t;
+typedef msg_generic_t               http_user_agent_t;
+typedef msg_list_t                  http_vary_t;
+typedef struct http_via_s           http_via_t;
+typedef msg_warning_t               http_warning_t;
+typedef msg_auth_t                  http_www_authenticate_t;
+
+typedef msg_list_t                  http_proxy_connection_t;
+
+typedef struct http_set_cookie_s    http_set_cookie_t;
+typedef struct http_cookie_s        http_cookie_t;
+
+/** Erroneous header. */
+typedef msg_error_t                 http_error_t;
+/** Unknown header. */
+typedef msg_generic_t               http_unknown_t;
+/** Separator line between headers and message contents */ 
+typedef msg_separator_t             http_separator_t;
+/** Entity-body */ 
+typedef msg_payload_t               http_payload_t;
+/** Time in seconds since 01-Jan-1900. */
+typedef unsigned long               http_time_t;
+/** Range offset. */
+typedef unsigned long               http_off_t;
+
+
+/* ----------------------------------------------------------------------
+ * 3) Structure definitions
+ */
+
+/** HTTP request line */
+struct http_request_s {
+  msg_common_t      rq_common[1];
+  http_error_t     *rq_next;
+  http_method_t     rq_method;	    	/** Method enum. */
+  char const       *rq_method_name; 	/** Method name. */
+  url_t             rq_url[1];	    	/** URL. */
+  char const       *rq_version;     	/** Protocol version. */
+};
+
+/** HTTP status line */
+struct http_status_s {
+  msg_common_t      st_common[1];
+  http_error_t     *st_next;
+  char const       *st_version;
+  int               st_status;
+  char const       *st_phrase;
+};
+
+/**@ingroup http_authentication_info
+ * @brief Structure for @b Authentication-Info header.
+ *
+ * @deprecated Use struct msg_auth_info_s instead.
+ */
+struct http_authentication_info_s
+{
+  msg_common_t        ai_common[1]; /**< Common fragment info */
+  msg_error_t        *ai_next;	    /**< Dummy link to next */
+  msg_param_t const  *ai_params;    /**< List of authentication info */
+};
+
+/** Content-Range */
+struct http_content_range_s {
+  msg_common_t      cr_common[1];
+  http_error_t     *cr_next;
+  http_off_t        cr_first;	/**< First-byte-pos */
+  http_off_t        cr_last;	/**< Last-byte-pos */
+  http_off_t        cr_length;	/**< Instance-length */
+};
+
+/** Date, Expires, If-Modified-Since, If-Unmodified-Since, Last-Modified */
+struct http_date_s {
+  msg_common_t      d_common[1];
+  http_error_t     *d_next;
+  http_time_t       d_time;	/**< Seconds since Jan 1, 1900 */
+};
+
+/** Host */
+struct http_host_s {
+  msg_common_t         h_common[1];
+  http_error_t        *h_next;
+  char const          *h_host;
+  char const          *h_port;
+};
+
+/** If-Range */
+struct http_if_range_s {
+  msg_common_t         ifr_common[1];
+  http_error_t        *ifr_next;
+  char const          *ifr_tag;	 /**< Tag */
+  http_time_t          ifr_time; /**< Timestamp */
+};
+
+/** Location, Referer */
+struct http_location_s {
+  msg_common_t         loc_common[1];
+  http_error_t        *loc_next;
+  url_t                loc_url[1];
+};
+
+/** Max-Forwards */
+struct http_max_forwards_s {
+  msg_common_t         mf_common[1];
+  http_error_t        *mf_next;
+  unsigned long        mf_count;
+};
+
+/** Range */
+struct http_range_s
+{
+  msg_common_t         rng_common[1];
+  http_error_t        *rng_next;
+  char const          *rng_unit;
+  char const         **rng_specs;
+};
+
+/** Retry-After. */
+struct http_retry_after_s {
+  msg_common_t         ra_common[1];  	/**< Common fragment info */
+  http_error_t        *ra_next;	      	/**< Link to next (dummy) */
+  http_time_t          ra_date;       	/**< When to retry */
+  http_time_t          ra_delta;        /**< Seconds to before retry */
+};
+
+/** TE */
+struct http_te_s {
+  msg_common_t         te_common[1];	/**< Common fragment info */
+  http_te_t           *te_next;		/**< Link to next t-coding */
+  char const          *te_extension;	/**< Transfer-Extension */
+  msg_param_t const   *te_params;	/**< List of parameters */
+  char const          *te_q;		/**< Q-value */
+};
+
+/** Via */
+struct http_via_s {
+  msg_common_t         v_common[1];
+  http_via_t          *v_next;
+  char const          *v_version;
+  char const          *v_host;
+  char const          *v_port;
+  char const          *v_comment;
+};
+
+/** Cookie */
+struct http_cookie_s {
+  msg_common_t         c_common[1];
+  http_cookie_t       *c_next;
+  msg_param_t const   *c_params;
+  char const          *c_version;
+  char const          *c_name;
+  char const          *c_domain;
+  char const          *c_path;
+};
+
+/** Set-Cookie */
+struct http_set_cookie_s {
+  msg_common_t         sc_common[1];
+  http_set_cookie_t   *sc_next;
+  msg_param_t const   *sc_params;
+  char const          *sc_name;
+  char const          *sc_version;
+  char const          *sc_domain;
+  char const          *sc_path;
+  char const          *sc_comment;
+  char const          *sc_max_age;
+  unsigned             sc_secure;
+};
+
+/**HTTP message object.
+ *
+ * This structure contains a HTTP message object.  It is used to access the
+ * headers and payload within the message.  The generic transport aspects of
+ * the message, like network address, is accessed using a @b msg_t object
+ * directly.
+ */
+struct http_s {
+  msg_common_t               http_common[1];    /**< For recursive inclusion */
+  msg_pub_t                 *http_next;	     /**< Dummy pointer to next part */
+  void                      *http_user;	               /**< Application data */
+  unsigned                   http_size;	         /**< Size of this structure */
+  int                        http_flags;                          /**< Flags */
+  http_error_t              *http_error;              /**< Erroneous headers */
+  
+  http_request_t            *http_request;                /**< Request line  */
+  http_status_t             *http_status;                   /**< Status line */
+
+  /* === Headers start here */
+  http_accept_t             *http_accept;                        /**< Accept */
+  http_accept_charset_t     *http_accept_charset;        /**< Accept-Charset */
+  http_accept_encoding_t    *http_accept_encoding;      /**< Accept-Encoding */
+  http_accept_language_t    *http_accept_language;      /**< Accept-Language */
+  http_accept_ranges_t      *http_accept_ranges;          /**< Accept-Ranges */
+  http_allow_t              *http_allow;                          /**< Allow */
+  http_authentication_info_t*http_authentication_info;/**<Authentication-Info*/
+  http_authorization_t      *http_authorization;          /**< Authorization */
+  http_age_t                *http_age;                              /**< Age */
+  http_cache_control_t      *http_cache_control;          /**< Cache-Control */
+  http_connection_t         *http_connection;                /**< Connection */
+  http_date_t               *http_date;                            /**< Date */
+  http_etag_t               *http_etag;                            /**< ETag */
+  http_expect_t             *http_expect;                        /**< Expect */
+  http_expires_t            *http_expires;                      /**< Expires */
+  http_from_t               *http_from;                            /**< From */
+  http_host_t               *http_host;                            /**< Host */
+  http_if_match_t           *http_if_match;                    /**< If-Match */
+  http_if_modified_since_t  *http_if_modified_since;  /**< If-Modified-Since */
+  http_if_none_match_t      *http_if_none_match;          /**< If-None-Match */
+  http_if_range_t           *http_if_range;                    /**< If-Range */
+  http_if_unmodified_since_t*http_if_unmodified_since;/**<If-Unmodified-Since*/
+  http_last_modified_t      *http_last_modified;          /**< Last-Modified */
+  http_location_t           *http_location;                    /**< Location */
+  http_max_forwards_t       *http_max_forwards;            /**< Max-Forwards */
+  http_pragma_t             *http_pragma;                        /**< Pragma */
+  http_proxy_authenticate_t *http_proxy_authenticate;/**< Proxy-Authenticate */
+  http_proxy_authorization_t*http_proxy_authorization;/**<Proxy-Authorization*/
+  http_range_t              *http_range;                          /**< Range */
+  http_referer_t            *http_referer;                      /**< Referer */
+  http_retry_after_t        *http_retry_after;              /**< Retry-After */
+  http_server_t             *http_server;                        /**< Server */
+  http_te_t                 *http_te;                                /**< TE */
+  http_trailer_t            *http_trailer;                      /**< Trailer */
+  http_transfer_encoding_t  *http_transfer_encoding;  /**< Transfer-Encoding */
+  http_upgrade_t            *http_upgrade;                      /**< Upgrade */
+  http_user_agent_t         *http_user_agent;                /**< User-Agent */
+  http_vary_t               *http_vary;                            /**< Vary */
+  http_via_t                *http_via;                              /**< Via */
+  http_warning_t            *http_warning;                      /**< Warning */
+  http_www_authenticate_t   *http_www_authenticate;    /**< WWW-Authenticate */
+
+  http_proxy_connection_t   *http_proxy_connection;    /**< Proxy-Connection */
+  http_set_cookie_t         *http_set_cookie;                /**< Set-Cookie */
+  http_cookie_t             *http_cookie;                        /**< Cookie */
+
+  http_mime_version_t       *http_mime_version;            /**< MIME-Version */
+  http_content_encoding_t   *http_content_encoding;    /**< Content-Encoding */
+  http_content_language_t   *http_content_language;    /**< Content-Language */
+  http_content_length_t     *http_content_length;        /**< Content-Length */
+  http_content_location_t   *http_content_location;    /**< Content-Location */
+  http_content_md5_t        *http_content_md5;              /**< Content-MD5 */
+  http_content_range_t      *http_content_range;          /**< Content-Range */
+  http_content_type_t       *http_content_type;            /**< Content-Type */
+
+  /* === Headers end here */
+  http_header_t             *http_unknown;             /**< Unknown headers. */
+  http_separator_t          *http_separator;     
+				  /**< Separator between message and payload */
+  http_payload_t            *http_payload;	    /**< Message entity-body */
+};
+
+/**Union representing any HTTP header.
+ * 
+ * Each different header is an array of size 1.
+ * 
+ * @deprecated
+ */
+union http_header_u {
+  msg_common_t                sh_common[1]; 
+  struct {
+    msg_common_t              shn_common;
+    http_header_t            *shn_next;
+  }                           sh_header_next[1];
+
+  msg_auth_t                  sh_auth[1];
+  msg_generic_t               sh_generic[1];
+  msg_numeric_t               sh_numeric[1];
+
+  http_request_t              sh_request[1];
+  http_status_t               sh_status[1];
+  http_error_t                sh_error[1];
+  http_unknown_t              sh_unknown[1];
+  http_separator_t            sh_separator[1];
+  http_payload_t              sh_payload[1];
+
+  /* Proper headers */
+  http_via_t                 sh_via[1];
+  http_host_t                sh_host[1];
+  http_from_t                sh_from[1];
+  http_referer_t             sh_referer[1];
+  http_connection_t          sh_connection[1];
+
+  http_accept_t              sh_accept[1];
+  http_accept_charset_t      sh_accept_charset[1];
+  http_accept_encoding_t     sh_accept_encoding[1];
+  http_accept_language_t     sh_accept_language[1];
+  http_accept_ranges_t       sh_accept_ranges[1];
+  http_allow_t               sh_allow[1];
+  http_te_t                  sh_te[1];
+
+  http_authentication_info_t sh_authentication_info[1];
+  http_authorization_t       sh_authorization[1];
+  http_www_authenticate_t    sh_www_authenticate[1];
+  http_proxy_authenticate_t  sh_proxy_authenticate[1];
+  http_proxy_authorization_t sh_proxy_authorization[1];
+
+  http_age_t                 sh_age[1];
+  http_cache_control_t       sh_cache_control[1];
+  http_date_t                sh_date[1];
+  http_expires_t             sh_expires[1];
+  http_if_match_t            sh_if_match[1];
+  http_if_modified_since_t   sh_if_modified_since[1];
+  http_if_none_match_t       sh_if_none_match[1];
+  http_if_range_t            sh_if_range[1];
+  http_if_unmodified_since_t sh_if_unmodified_since[1];
+
+  http_etag_t                sh_etag[1];
+  http_expect_t              sh_expect[1];
+  http_last_modified_t       sh_last_modified[1];
+  http_location_t            sh_location[1];
+  http_max_forwards_t        sh_max_forwards[1];
+  http_pragma_t              sh_pragma[1];
+  http_range_t               sh_range[1];
+  http_retry_after_t         sh_retry_after[1];
+  http_trailer_t             sh_trailer[1];
+  http_upgrade_t             sh_upgrade[1];
+  http_vary_t                sh_vary[1];
+  http_warning_t             sh_warning[1];
+
+  http_user_agent_t          sh_user_agent[1];
+  http_server_t              sh_server[1];
+
+  http_mime_version_t        sh_mime_version[1];
+  http_content_language_t    sh_content_language[1];
+  http_content_location_t    sh_content_location[1];
+  http_content_md5_t         sh_content_md5[1];
+  http_content_range_t       sh_content_range[1];
+  http_content_encoding_t    sh_content_encoding[1];
+  http_transfer_encoding_t   sh_transfer_encoding[1];
+  http_content_type_t        sh_content_type[1];
+  http_content_length_t      sh_content_length[1];
+
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_HCLASSES_H
+/** Defined when <sofia-sip/http_hclasses.h> has been included. */
+#define HTTP_HCLASSES_H
+
+/**@file sofia-sip/http_hclasses.h
+ * @brief HTTP header classes.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* Use directly these header classes */
+
+#define http_accept_class              msg_accept_class
+#define http_accept_charset_class      msg_accept_charset_class
+#define http_accept_encoding_class     msg_accept_encoding_class
+#define http_accept_language_class     msg_accept_language_class
+#define http_content_encoding_class    msg_content_encoding_class
+#define http_content_length_class      msg_content_length_class
+#define http_content_md5_class         msg_content_md5_class
+#define http_content_type_class        msg_content_type_class
+#define http_content_id_class          msg_content_id_class
+#define http_content_location_class    msg_content_location_class
+#define http_content_language_class    msg_content_language_class
+#define http_mime_version_class        msg_mime_version_class
+
+#define http_error_class               msg_error_class
+#define http_unknown_class             msg_unknown_class
+#define http_separator_class           msg_separator_class
+#define http_payload_class             msg_payload_class
+
+SOFIA_END_DECLS
+
+#ifndef HTTP_PROTOS_H
+#define HTTP_HCLASSES_ONLY
+#include <sofia-sip/http_protos.h>
+#undef HTTP_HCLASSES_ONLY
+#endif
+
+#endif /* !defined HTTP_HCLASSES_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_HEADER_H
+/** Defined when <sofia-sip/http_header.h> has been included.*/
+#define HTTP_HEADER_H
+
+/**@file sofia-sip/http_header.h 
+ *
+ * HTTP library prototypes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date  Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Macros
+ */
+
+/** Initialize a HTTP header structure. */
+#define HTTP_HEADER_INIT(h, http_class, size)			\
+  ((void)memset((h), 0, (size)),				\
+   (void)(((msg_common_t *)(h))->h_class = (http_class)),	\
+   (h))
+
+#define HTTP_METHOD_NAME(method, name) \
+ ((method) == http_method_unknown ? (name) : http_method_name(method, name))
+
+/* ----------------------------------------------------------------------
+ * 2) Variables
+ */
+
+SOFIAPUBVAR char const http_method_name_get[];
+SOFIAPUBVAR char const http_method_name_post[];
+SOFIAPUBVAR char const http_method_name_head[];
+SOFIAPUBVAR char const http_method_name_options[];
+SOFIAPUBVAR char const http_method_name_put[];
+SOFIAPUBVAR char const http_method_name_delete[];
+SOFIAPUBVAR char const http_method_name_trace[];
+SOFIAPUBVAR char const http_method_name_connect[];
+
+/** HTTP 0.9 */
+SOFIAPUBVAR char const http_version_0_9[];
+
+/** HTTP 1.0 */
+SOFIAPUBVAR char const http_version_1_0[];
+
+/** HTTP 1.1 version. */ 
+SOFIAPUBVAR char const http_version_1_1[];
+
+#define HTTP_VERSION_CURRENT http_version_1_1
+
+/* ----------------------------------------------------------------------
+ * 3) Prototypes 
+ */
+
+/** HTTP parser description. */
+SOFIAPUBFUN msg_mclass_t *http_default_mclass(void);
+
+/** Complete a HTTP request. */
+SOFIAPUBFUN int http_request_complete(msg_t *msg);
+
+/** Complete a HTTP message. */
+SOFIAPUBFUN int http_message_complete(msg_t *msg, http_t *http);
+
+/** Add a duplicate of header object to a HTTP message. */
+SOFIAPUBFUN int http_add_dup(msg_t *, http_t *, http_header_t const *);
+
+/** Add a header to the HTTP message. */
+SOFIAPUBFUN int http_add_make(msg_t *msg, http_t *http,
+			      msg_hclass_t *hc, char const *s);
+
+/** Add a header to the HTTP message. */
+SOFIAPUBFUN int http_add_format(msg_t *msg, http_t *http, msg_hclass_t *hc,
+				char const *fmt, ...);
+
+/** Add tagged headers to the HTTP message */
+SOFIAPUBFUN int http_add_tl(msg_t *msg, http_t *http,
+			    tag_type_t tag, tag_value_t value, ...);
+
+/** Remove schema, host, and port from URL */
+SOFIAPUBFUN int http_strip_hostport(url_t *url);
+
+/** Add required headers to the response message */
+SOFIAPUBFUN int http_complete_response(msg_t *msg,
+				       int status, char const *phrase, 
+				       http_t const *request);
+
+/** Return string corresponding to the method. */
+SOFIAPUBFUN char const *http_method_name(http_method_t method,
+					 char const *name);
+
+/** Return enum corresponding to the method name */
+SOFIAPUBFUN http_method_t http_method_code(char const *name);
+
+#if !SU_HAVE_INLINE
+SOFIAPUBFUN http_t *http_object(msg_t *msg);
+SOFIAPUBFUN int http_header_insert(msg_t *msg, http_t *http, http_header_t *h);
+SOFIAPUBFUN int http_header_remove(msg_t *msg, http_t *http, http_header_t *h);
+SOFIAPUBFUN char const *http_header_name(http_header_t const *h, int compact);
+SOFIAPUBFUN void *http_header_data(http_header_t *h);
+SOFIAPUBFUN http_content_length_t *http_content_length_create(su_home_t *home, 
+							      uint32_t n);
+SOFIAPUBFUN http_payload_t *http_payload_create(su_home_t *home, 
+						void const *data, usize_t len);
+SOFIAPUBFUN http_separator_t *http_separator_create(su_home_t *home);
+#endif
+
+SOFIAPUBFUN http_header_t *http_header_format(su_home_t *home, msg_hclass_t *,
+					      char const *fmt, ...);
+
+
+/** Create a request line object. */
+SOFIAPUBFUN http_request_t *http_request_create(su_home_t *home,
+						http_method_t method,
+						const char *name,
+						url_string_t const *url,
+						char const *version);
+
+/** Create a status line object. */
+SOFIAPUBFUN http_status_t *http_status_create(su_home_t *home,
+					      unsigned status,
+					      char const *phrase,
+					      char const *version);
+
+/** Create an @b Host header object. */
+SOFIAPUBFUN http_host_t *http_host_create(su_home_t *home, 
+					  char const *host,
+					  char const *port);
+
+/** Create an @b Date header object. */
+SOFIAPUBFUN http_date_t *http_date_create(su_home_t *home, http_time_t t);
+
+/** Create an @b Expires header object. */
+SOFIAPUBFUN http_expires_t *http_expires_create(su_home_t *home,
+						http_time_t delta);
+
+/** Compare two HTTP URLs. */
+SOFIAPUBFUN int http_url_cmp(url_t const *a, url_t const *b);
+
+/** Parse query part in HTTP URL. */
+SOFIAPUBFUN issize_t http_query_parse(char *query,
+				      /* char const *key, char **return_value, */
+				      ...);
+
+/* ----------------------------------------------------------------------
+ * 4) Inlined functions 
+ */
+
+#if SU_HAVE_INLINE
+/** Get HTTP structure from msg. */
+su_inline
+http_t *http_object(msg_t *msg)
+{
+  return (http_t *)msg_public(msg, HTTP_PROTOCOL_TAG);
+}
+
+/** Insert a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c http_header_insert() inserts header or list of headers
+ * into a HTTP message.  It also inserts them into the the message fragment
+ * chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status).  The Via
+ * headers are inserted after the request or status, and rest of the headers
+ * after request, status, or Via headers.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param http HTTP message structure to which header is added
+ * @param h   list of header(s) to be added
+ */
+su_inline 
+int http_header_insert(msg_t *msg, http_t *http, http_header_t *h)
+{
+  return msg_header_insert(msg, (msg_pub_t *)http, (msg_header_t *)h);
+}
+
+/** Remove a header from a HTTP message. */ 
+su_inline
+int http_header_remove(msg_t *msg, http_t *http, http_header_t *h)
+{
+  return msg_header_remove(msg, (msg_pub_t *)http, (msg_header_t *)h);
+}
+
+/** Return name of the header. */
+su_inline
+char const *http_header_name(http_header_t const *h, int compact)
+{
+  if (compact && h->sh_class->hc_short[0])
+    return h->sh_class->hc_short;
+  else
+    return h->sh_class->hc_name;
+}
+
+/** Return data after header structure. */
+su_inline
+void *http_header_data(http_header_t *h)
+{
+  return h && h != HTTP_NONE ? h->sh_class->hc_size + (char *)h : NULL;
+}
+
+su_inline 
+http_content_length_t *http_content_length_create(su_home_t *home, uint32_t n)
+{
+  return msg_content_length_create(home, n);
+}
+
+su_inline 
+http_payload_t *http_payload_create(su_home_t *home, void const *data, isize_t len)
+{
+  return msg_payload_create(home, data, len);
+}
+
+su_inline 
+http_separator_t *http_separator_create(su_home_t *home)
+{
+  return msg_separator_create(home);
+}
+#endif
+
+SOFIA_END_DECLS
+
+#ifndef HTTP_PROTOS_H
+#include <sofia-sip/http_protos.h>
+#endif
+
+#endif /* !defined(HTTP_HEADER_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_PARSER_H
+/**Defined when <sofia-sip/http_parser.h> has been included.*/
+#define HTTP_PARSER_H 
+/**@file sofia-sip/http_parser.h
+ * @brief Typedefs and prototypes used by HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+
+#ifndef MSG_PARSER_H
+#include <sofia-sip/msg_parser.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+#ifndef HTTP_HEADER_H
+#include <sofia-sip/http_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------------
+ * 1) Macros for defining boilerplate functions and structures for each header
+ */
+
+#define HTTP_HCLASS_TAG     HTTP_PROTOCOL_TAG
+#define HTTP_HCLASS_TEST(x) ((x) && (x)->hc_tag == HTTP_PROTOCOL_TAG)
+#define HTTP_HDR_TEST(x)    ((x)->sh_class && HTTP_HCLASS_TEST((x)->sh_class))
+
+/** Define a header class for a HTTP header. */
+#define HTTP_HEADER_CLASS(c, l, params, kind, dup) \
+  MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup, http_no)
+
+/** This is used by headers with no extra data in copy */
+#define HTTP_HEADER_CLASS_G(c, l, kind) \
+  MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic, http_no)
+
+/** Define a header class for a msg_list_t kind of header */
+#define HTTP_HEADER_CLASS_LIST(c, l, kind) \
+  MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list, http_no)
+
+/** Define a authorization header class */
+#define HTTP_HEADER_CLASS_AUTH(c, l, kind) \
+  MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth, http_no)
+
+#define http_numeric_dup_xtra msg_default_dup_xtra
+#define http_numeric_dup_one  msg_default_dup_one
+
+#define http_default_dup_xtra msg_default_dup_xtra
+#define http_default_dup_one  msg_default_dup_one
+
+#define http_no_update NULL
+
+/* ---------------------------------------------------------------------------
+ * 2) Prototypes for HTTP-specific decoding/encoding functions
+ */
+
+/* Version strings */
+SOFIAPUBFUN int http_version_d(char **ss, char const **ver);
+SOFIAPUBFUN isize_t http_version_xtra(char const *version);
+SOFIAPUBFUN void http_version_dup(char **pp, char const **dd, char const *s);
+
+/* Method */
+SOFIAPUBFUN http_method_t http_method_d(char **ss, char const **nname);
+SOFIAPUBFUN char const *http_method_name(http_method_t method,
+					 char const *name);
+
+/** Extract HTTP message body */
+SOFIAPUBFUN issize_t http_extract_body(msg_t *, http_t *, 
+				       char b[], isize_t bsiz, int eos);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_PARSER_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,311 @@
+/** -*- C -*-
+ * @file sofia-sip/http_protos.h.in
+ *
+ * Template for <http_protos.h>.
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_PROTOS_H
+/** Defined when <sofia-sip/http_protos.h> has been included. */
+#define HTTP_PROTOS_H
+
+/**@file sofia-sip/http_protos.h 
+ *
+ * Macros for each HTTP header.
+ *
+ * #AUTO#
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include <sofia-sip/su_config.h>
+
+#ifndef HTTP_HEADER_H
+#include <sofia-sip/http_header.h>
+#endif
+#ifndef HTTP_HCLASSES_H
+#include <sofia-sip/http_hclasses.h>
+#endif
+
+#define http_header_make(h, c, s) \
+  ((http_header_t *)msg_header_make((h), (c), (s)))
+#define http_header_vformat(h, c, f, a) \
+  ((http_header_t *)msg_header_vformat((h), (c), (f), (a)))
+
+SOFIA_BEGIN_DECLS
+
+/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
+
+/**@addtogroup http_#xxxxxx#*/ /** @{ */
+
+enum { 
+  /** Hash of #xxxxxxx_xxxxxxx#. @internal*/
+  http_#xxxxxx#_hash = #hash# 
+};
+
+/**Header class for HTTP #xxxxxxx_xxxxxxx#.
+ * 
+ * The header class http_#xxxxxx#_class defines how a HTTP
+ * #xxxxxxx_xxxxxxx# is parsed and printed.  It also
+ * contains methods used by HTTP parser and other functions
+ * to manipulate the http_#xxxxxx#_t header structure.
+ * 
+ */
+SOFIAPUBVAR msg_hclass_t http_#xxxxxx#_class[];
+
+#ifndef HTTP_HCLASSES_ONLY
+
+/** Decode (parse) a #xxxxxxx_xxxxxxx#. @internal */
+SOFIAPUBFUN msg_parse_f http_#xxxxxx#_d;
+
+/** Encode (print) a #xxxxxxx_xxxxxxx#. @internal */
+SOFIAPUBFUN msg_print_f http_#xxxxxx#_e;
+
+/**Initializer for structure http_#xxxxxx#_t.
+ * 
+ * A static http_#xxxxxx#_t structure must be initialized
+ * with the HTTP_#XXXXXX#_INIT() macro. For instance,
+ * @code 
+ * 
+ *  http_#xxxxxx#_t http_#xxxxxx# = HTTP_#XXXXXX#_INIT;
+ * 
+ * @endcode
+ * @HI
+ */
+#define HTTP_#XXXXXX#_INIT() HTTP_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure http_#xxxxxx#_t.
+ * 
+ * An http_#xxxxxx#_t structure can be initialized with the
+ * http_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ * 
+ *  http_#xxxxxx#_t http_#xxxxxx#;
+ * 
+ *  http_#xxxxxx#_init(&http_#xxxxxx#);
+ * 
+ * @endcode
+ * @HI
+ */
+#if SU_HAVE_INLINE
+su_inline http_#xxxxxx#_t *http_#xxxxxx#_init(http_#xxxxxx#_t x[1])
+{
+  return HTTP_HEADER_INIT(x, http_#xxxxxx#_class, sizeof(http_#xxxxxx#_t));
+}
+#else
+#define http_#xxxxxx#_init(x) \
+  HTTP_HEADER_INIT(x, http_#xxxxxx#_class, sizeof(http_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of http_#xxxxxx#_t.
+ * 
+ * The function http_is_#xxxxxx#() returns true (nonzero) if
+ * the header class is an instance of #xxxxxxx_xxxxxxx#
+ * object and false (zero) otherwise.
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @return
+ * The function http_is_x#xxxxxx#() returns true (nonzero) if
+ * the header object is an instance of header #xxxxxx# and
+ * false (zero) otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline 
+int http_is_#xxxxxx#(http_header_t const *header)
+{
+  return header && header->sh_class->hc_hash == http_#xxxxxx#_hash;
+}
+#else
+#define http_is_#xxxxxx#(h) \
+ ((h) && ((msg_common_t *)(h))->h_class->hc_hash == http_#xxxxxx#_hash)
+#endif
+
+/**Duplicate (deep copy) @c http_#xxxxxx#_t.
+ * 
+ * The function http_#xxxxxx#_dup() duplicates a header
+ * structure @a hdr.  If the header structure @a hdr
+ * contains a reference (@c hdr->x_next) to a list of
+ * headers, all the headers in the list are duplicated, too.
+ * 
+ * @param home  memory home used to allocate new structure
+ * @param hdr   header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant
+ * strings attached to the header are copied, too.  The
+ * function uses given memory @a home to allocate all the
+ * memory areas used to copy the header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = http_#xxxxxx#_dup(home, http->http_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function http_#xxxxxx#_dup() returns a pointer to the
+ * newly duplicated http_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_dup(su_home_t *home, 
+				   http_#xxxxxx#_t const *hdr)
+     __attribute__((__malloc__));
+
+/**Copy a http_#xxxxxx#_t header structure.
+ * 
+ * The function http_#xxxxxx#_copy() copies a header structure @a
+ * hdr.  If the header structure @a hdr contains a reference (@c
+ * hdr->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home
+ * to allocate all the memory areas used to copy the header
+ * structure @a hdr.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param hdr     pointer to the header structure to be duplicated
+ * 
+ * When copying, only the header structure and parameter lists
+ * attached to it are duplicated.  The new header structure
+ * retains all the references to the strings within the old @a
+ * header, including the encoding of the old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = http_#xxxxxx#_copy(home, http->http_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function http_#xxxxxx#_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_copy(su_home_t *home, 
+				    http_#xxxxxx#_t const *hdr)
+     __attribute__((__malloc__));
+
+/**Make a header structure http_#xxxxxx#_t.
+ * 
+ * The function http_#xxxxxx#_make() makes a new
+ * http_#xxxxxx#_t header structure.  It allocates a new
+ * header structure, and decodes the string @a s as the
+ * value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @note This function is usually implemented as a macro calling
+ * http_header_make().
+ * 
+ * @return
+ * The function http_#xxxxxx#_make() returns a pointer to
+ * newly maked http_#xxxxxx#_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_make(su_home_t *home, char const *s)
+     __attribute__((__malloc__));
+
+/**Make a #xxxxxxx_xxxxxxx# from formatting result.
+ * 
+ * The function http_#xxxxxx#_format() makes a new
+ * #xxxxxxx_xxxxxxx# object using formatting result as its
+ * value.  The function first prints the arguments according to
+ * the format @a fmt specified.  Then it allocates a new header
+ * structure, and uses the formatting result as the header
+ * value.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_format().
+ * 
+ * @return
+ * The function http_#xxxxxx#_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((__malloc__, __format__ (printf, 2, 3)));
+
+
+/* Inlined functions */
+#if SU_HAVE_INLINE
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+  http_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = http_header_vformat(home, http_#xxxxxx#_class, fmt, ap);
+  va_end(ap);
+ 
+  return (http_#xxxxxx#_t *)h;
+}
+
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_dup(su_home_t *home, http_#xxxxxx#_t const *o) 
+{ 
+  return (http_#xxxxxx#_t *)
+    msg_header_dup_as(home, http_#xxxxxx#_class, (msg_header_t const *)o);
+}
+
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_copy(su_home_t *home, http_#xxxxxx#_t const *o) 
+{ 
+  return (http_#xxxxxx#_t *)
+    msg_header_copy_as(home, http_#xxxxxx#_class, (msg_header_t const *)o); 
+}
+
+su_inline 
+http_#xxxxxx#_t *http_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+  return (http_#xxxxxx#_t *)http_header_make(home, http_#xxxxxx#_class, s);
+}
+#endif
+
+#endif /* !define HTTP_HCLASSES_ONLY */
+
+/** @} */
+
+
+SOFIA_END_DECLS
+#endif /* !defined(HTTP_PROTOS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_STATUS_H 
+#define HTTP_STATUS_H 
+
+/**@file sofia-sip/http_status.h 
+ *
+ * HTTP status codes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 18 18:55:09 2001 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN char const *http_status_phrase(int status);
+
+#define HTTP_100_CONTINUE	       100, http_100_continue
+#define HTTP_101_SWITCHING	       101, http_101_switching
+#define HTTP_200_OK		       200, http_200_ok
+#define HTTP_201_CREATED	       201, http_201_created
+#define HTTP_202_ACCEPTED	       202, http_202_accepted
+#define HTTP_203_NON_AUTH_INFO	       203, http_203_non_auth_info
+#define HTTP_204_NO_CONTENT	       204, http_204_no_content
+#define HTTP_205_RESET_CONTENT	       205, http_205_reset_content
+#define HTTP_206_PARTIAL_CONTENT       206, http_206_partial_content
+#define HTTP_300_MULTIPLE_CHOICES      300, http_300_multiple_choices
+#define HTTP_301_MOVED_PERMANENTLY     301, http_301_moved_permanently
+#define HTTP_302_FOUND		       302, http_302_found
+#define HTTP_303_SEE_OTHER	       303, http_303_see_other
+#define HTTP_304_NOT_MODIFIED	       304, http_304_not_modified
+#define HTTP_305_USE_PROXY	       305, http_305_use_proxy
+#define HTTP_307_TEMPORARY_REDIRECT    307, http_307_temporary_redirect
+#define HTTP_400_BAD_REQUEST	       400, http_400_bad_request
+#define HTTP_401_UNAUTHORIZED	       401, http_401_unauthorized
+#define HTTP_402_PAYMENT_REQUIRED      402, http_402_payment_required
+#define HTTP_403_FORBIDDEN	       403, http_403_forbidden
+#define HTTP_404_NOT_FOUND	       404, http_404_not_found
+#define HTTP_405_NOT_ALLOWED	       405, http_405_not_allowed
+#define HTTP_406_NOT_ACCEPTABLE	       406, http_406_not_acceptable
+#define HTTP_407_PROXY_AUTH	       407, http_407_proxy_auth
+#define HTTP_408_TIMEOUT	       408, http_408_timeout
+#define HTTP_409_CONFLICT	       409, http_409_conflict
+#define HTTP_410_GONE		       410, http_410_gone
+#define HTTP_411_NO_LENGTH	       411, http_411_no_length
+#define HTTP_412_PRECONDITION	       412, http_412_precondition
+#define HTTP_413_ENTITY_TOO_LARGE      413, http_413_entity_too_large
+#define HTTP_414_URI_TOO_LONG	       414, http_414_uri_too_long
+#define HTTP_415_MEDIA_TYPE	       415, http_415_media_type
+#define HTTP_416_REQUESTED_RANGE       416, http_416_requested_range
+#define HTTP_417_EXPECTATION	       417, http_417_expectation
+#define HTTP_426_UPGRADE               426, http_426_upgrade
+#define HTTP_500_INTERNAL_SERVER       500, http_500_internal_server
+#define HTTP_501_NOT_IMPLEMENTED       501, http_501_not_implemented
+#define HTTP_502_BAD_GATEWAY	       502, http_502_bad_gateway
+#define HTTP_503_NO_SERVICE	       503, http_503_no_service
+#define HTTP_504_GATEWAY_TIMEOUT       504, http_504_gateway_timeout
+#define HTTP_505_HTTP_VERSION	       505, http_505_http_version
+
+SOFIAPUBVAR char const http_100_continue[];
+SOFIAPUBVAR char const http_101_switching[];
+SOFIAPUBVAR char const http_200_ok[];
+SOFIAPUBVAR char const http_201_created[];
+SOFIAPUBVAR char const http_202_accepted[];
+SOFIAPUBVAR char const http_203_non_auth_info[];
+SOFIAPUBVAR char const http_204_no_content[];
+SOFIAPUBVAR char const http_205_reset_content[];
+SOFIAPUBVAR char const http_206_partial_content[];
+SOFIAPUBVAR char const http_300_multiple_choices[];
+SOFIAPUBVAR char const http_301_moved_permanently[];
+SOFIAPUBVAR char const http_302_found[];
+SOFIAPUBVAR char const http_303_see_other[];
+SOFIAPUBVAR char const http_304_not_modified[];
+SOFIAPUBVAR char const http_305_use_proxy[];
+SOFIAPUBVAR char const http_307_temporary_redirect[];
+SOFIAPUBVAR char const http_400_bad_request[];
+SOFIAPUBVAR char const http_401_unauthorized[];
+SOFIAPUBVAR char const http_402_payment_required[];
+SOFIAPUBVAR char const http_403_forbidden[];
+SOFIAPUBVAR char const http_404_not_found[];
+SOFIAPUBVAR char const http_405_not_allowed[];
+SOFIAPUBVAR char const http_406_not_acceptable[];
+SOFIAPUBVAR char const http_407_proxy_auth[];
+SOFIAPUBVAR char const http_408_timeout[];
+SOFIAPUBVAR char const http_409_conflict[];
+SOFIAPUBVAR char const http_410_gone[];
+SOFIAPUBVAR char const http_411_no_length[];
+SOFIAPUBVAR char const http_412_precondition[];
+SOFIAPUBVAR char const http_413_entity_too_large[];
+SOFIAPUBVAR char const http_414_uri_too_long[];
+SOFIAPUBVAR char const http_415_media_type[];
+SOFIAPUBVAR char const http_416_requested_range[];
+SOFIAPUBVAR char const http_417_expectation[];
+SOFIAPUBVAR char const http_426_upgrade[];
+SOFIAPUBVAR char const http_500_internal_server[];
+SOFIAPUBVAR char const http_501_not_implemented[];
+SOFIAPUBVAR char const http_502_bad_gateway[];
+SOFIAPUBVAR char const http_503_no_service[];
+SOFIAPUBVAR char const http_504_gateway_timeout[];
+SOFIAPUBVAR char const http_505_http_version[];
+
+SOFIA_END_DECLS
+
+#endif /* HTTP_STATUS_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,236 @@
+/**@file sofia-sip/http_tag.h.in
+ *
+ * Template for <http_tag.h>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_TAG_H
+/** Defined when <sofia-sip/http_tag.h> has been included. */
+#define HTTP_TAG_H
+
+/**@file sofia-sip/http_tag.h
+ * @brief Tag class for HTTP headers
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define HTTPTAG(c, x)         httptag_##c, httptag_##c##_v(x)
+#define HTTPTAG_REF(c, x)     httptag_##c##_ref, httptag_##c##_vr(&(x))
+#define HTTPTAG_STR(c, s)     httptag_##c##_str, tag_str_v(s)
+#define HTTPTAG_STR_REF(c, s) httptag_##c##_str_ref, tag_str_vr(&(s))
+
+/** Test if tag type marks a http_t structure. @HIDE */
+#define HTTPTAG_P(tt)     ((tt)->tt_class == httphdrtag_class)
+/** Test if tag type marks a HTTP header string. @HIDE */
+#define HTTPTAG_STR_P(tt) ((tt)->tt_class == httpstrtag_class)
+/** Test if tag type marks a HTTP header structure. @HIDE */
+#define HTTPTAG_HTTP_P(tt) ((tt)->tt_class == httpmsgtag_class)
+
+/** Test if tag item contains http_t structure. @HIDE */
+#define HTTPTAGI_P(t)     (HTTPTAG_P((t)->t_tag))
+/** Test if tag item contains a HTTP header string. @HIDE */
+#define HTTPTAGI_STR_P(t) (HTTPTAG_STR_P((t)->t_tag))
+/** Test if tag item contains a HTTP header structure. @HIDE */
+#define HTTPTAGI_HTTP_P(t) (HTTPTAG_HTTP_P((t)->t_tag))
+
+SOFIAPUBVAR tag_class_t httphdrtag_class[1];
+SOFIAPUBVAR tag_class_t httpstrtag_class[1];
+SOFIAPUBVAR tag_class_t httpmsgtag_class[1];
+
+/** Filter tag matching any http tag. */
+#define HTTPTAG_ANY()         httptag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t httptag_any;
+
+/**Tag list item for @c http_t object.
+ *
+ * The HTTPTAG_HTTP() macro is used to include a tag item for a http_t object
+ * in the tag list.
+ *
+ * @param x pointer to a http_t message object, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_HTTP(x)       httptag_http, httptag_http_v((x))
+
+/** Tag for @c http_t */
+SOFIAPUBVAR tag_typedef_t httptag_http;
+
+#define HTTPTAG_HTTP_REF(x)   httptag_http_ref, httptag_http_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_http_ref;
+
+#if SU_HAVE_INLINE
+static inline
+tag_value_t httptag_http_v(http_t const *v) { return (tag_value_t)v; }
+static inline 
+tag_value_t httptag_http_vr(http_t const **vp) { return (tag_value_t)vp; }
+#else
+#define httptag_http_v(v)   (tag_value_t)(v)
+#define httptag_http_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for http protocol version.
+ *
+ * The HTTPTAG_VERSION() macro is used to include a tag item for a HTTP
+ * protocol version in the tag list.
+ *
+ * @param x pointer to a http_t message object, or NULL.
+ */
+#define HTTPTAG_VERSION(x)       httptag_http, (tag_value_t)x
+
+extern tag_typedef_t httptag_version;
+
+/** Reference to HTTPTAG_VERSION */
+#define HTTPTAG_VERSION_REF(x)   httptag_http_ref, (tag_value_t)&(x)
+
+extern tag_typedef_t httptag_version_ref;
+
+/**Tag list item for header string.
+ *
+ * The HTTPTAG_HEADER() macro is used to include a tag item containing an
+ * unknown HTTP header in the tag list, e.g., 
+ * @code 
+ * http_header_t *hdr;
+ *
+ * HTTPTAG_HEADER(hdr).
+ * @endcode
+ *
+ * @param x pointer to a header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_HEADER(x)       httptag_header, httptag_header_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t httptag_header;
+
+#define HTTPTAG_HEADER_REF(x)   httptag_header_ref, httptag_header_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_header_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+httptag_header_v(http_header_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+httptag_header_vr(http_header_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define httptag_header_v(v)   (tag_value_t)(v)
+#define httptag_header_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * The HTTPTAG_HEADER_STR() macro is used to include a tag item containing a
+ * header string in the tag list.
+ *
+ * @param x pointer to a string, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_HEADER_STR(x)       httptag_header_str, tag_str_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t httptag_header_str;
+
+#define HTTPTAG_HEADER_STR_REF(x)   httptag_header_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_header_str_ref;
+
+
+/**@ingroup http_#xxxxxx#
+ *
+ * Tag list item for pointer to a #xxxxxxx_xxxxxxx# object.
+ *
+ * The HTTPTAG_#XXXXXX#() macro is used to include a tag item with a
+ * pointer to a http_#xxxxxx#_t object in a tag list.
+ *
+ * @param x pointer to a http_#xxxxxx#_t header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_#XXXXXX#(x)        	  HTTPTAG(#xxxxxx#, x)
+
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#;
+
+/**@ingroup http_#xxxxxx#
+ *
+ * Tag list item for string with #xxxxxxx_xxxxxxx# value.
+ *
+ * The HTTPTAG_#XXXXXX#_STR() macro is used to include a tag item with a 
+ * string containing value of a http_#xxxxxx#_t header in a tag list.
+ *
+ * @param s pointer to a string containing http_#xxxxxx#_t value, or NULL.
+ *
+ * The HTTPTAG_#XXXXXX#_STR string can be converted to a
+ * http_#xxxxxx#_t header structure by giving the string @a s has
+ * second argument to function http_#xxxxxx#_make().
+ *
+ * @HIDE
+ */
+#define HTTPTAG_#XXXXXX#_STR(s)    	  HTTPTAG_STR(#xxxxxx#, s)
+
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_str;
+
+#define HTTPTAG_#XXXXXX#_REF(x)        	  HTTPTAG_REF(#xxxxxx#, x)
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_ref;
+
+#define HTTPTAG_#XXXXXX#_STR_REF(x)        HTTPTAG_STR_REF(#xxxxxx#, x)
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_str_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+httptag_#xxxxxx#_v(http_#xxxxxx#_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+httptag_#xxxxxx#_vr(http_#xxxxxx#_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define httptag_#xxxxxx#_v(v)   (tag_value_t)(v)
+#define httptag_#xxxxxx#_vr(vp) (tag_value_t)(vp)
+#endif
+
+SOFIA_END_DECLS
+#endif /* !defined(HTTP_TAG_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_TAG_CLASS_H
+/**Defined when http_tag_class.h have been included*/
+#define HTTP_TAG_CLASS_H 
+
+/**@file sofia-sip/http_tag_class.h
+ * @brief Tag classes for HTTP headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef MSG_TAG_CLASS_H
+#include <sofia-sip/msg_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Define a named tag type for HTTP header @a t. */
+#define HTTPHDRTAG_NAMED_TYPEDEF(n, t) \
+{{ TAG_NAMESPACE, #n, httphdrtag_class, \
+  (tag_value_t)http_##t##_class }}
+
+/** Define a tag type for HTTP header @a t. */
+#define HTTPHDRTAG_TYPEDEF(t) HTTPHDRTAG_NAMED_TYPEDEF(t, t)
+
+/** Define a string tag type for HTTP header @a t. */
+#define HTTPSTRTAG_TYPEDEF(t) \
+{{ TAG_NAMESPACE, #t "_str", httpstrtag_class, \
+  (tag_value_t)http_##t##_class }}
+
+/** Define a tag type for HTTP message @a t. */
+#define HTTPMSGTAG_TYPEDEF(t) \
+  {{ TAG_NAMESPACE, #t, httpmsgtag_class, \
+     (tag_value_t)HTTP_PROTOCOL_TAG }}
+
+/**@internal Filter HTTP header tag items. */ 
+SOFIAPUBFUN tagi_t *httptag_filter(tagi_t *dst, tagi_t const f[],
+				   tagi_t const *src, 
+				   void **bb);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_TAG_CLASS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1513 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_http.c
+ *
+ * Testing functions for HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Mar  6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t  */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include <sofia-sip/http_parser.h>
+
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/url_tag.h>
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/msg_addr.h>
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+
+char const *name = "test_http";
+
+static int tag_test(void);
+static int tag_test2(void);
+static int http_header_handling_test(void);
+static int http_header_test(void);
+static int http_parser_test(void);
+static int test_http_encoding(void);
+static int http_chunk_test(void);
+static int http_tag_test(void);
+static int test_query_parser(void);
+
+static msg_t *read_message(char const string[]);
+msg_mclass_t *test_mclass = NULL;
+
+void usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-v]\n",
+	  name);
+}
+
+char *lastpart(char *path)
+{
+  if (strchr(path, '/'))
+    return strrchr(path, '/') + 1;
+  else
+    return path;
+}
+
+int tstflags;
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  name = lastpart(argv[0]);  /* Set our name */
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  if (!test_mclass)
+    test_mclass = http_default_mclass();
+
+  retval |= tag_test(); fflush(stdout);
+  retval |= tag_test2(); fflush(stdout);
+  retval |= http_header_handling_test(); fflush(stdout);
+  retval |= http_header_test(); fflush(stdout);
+  retval |= http_tag_test(); fflush(stdout);
+  retval |= http_parser_test(); fflush(stdout);
+  retval |= test_http_encoding(); fflush(stdout);
+  retval |= http_chunk_test(); fflush(stdout);
+  retval |= test_query_parser(); fflush(stdout);
+
+  return retval;
+}
+
+msg_t *read_message(char const buffer[])
+{
+  int i, n, m;
+  msg_t *msg;
+  msg_iovec_t iovec[2];
+
+  n = strlen(buffer);
+  if (n == 0)
+    return NULL;
+
+  msg = msg_create(test_mclass, MSG_DO_EXTRACT_COPY);
+
+  for (i = 0; i < n;) {
+    if (msg_recv_iovec(msg, iovec, 2, 10, 0) < 0) {
+      perror("msg_recv_iovec");
+      return NULL;
+    }
+    *(char *)(iovec->mv_base) = buffer[i++];
+    msg_recv_commit(msg, 1, i == n);
+
+    m = msg_extract(msg);
+    if (m < 0) {
+      fprintf(stderr, "test_http: parsing error\n");
+      return NULL;
+    }
+    if (m > 0)
+      break;
+  }
+
+  if (i != n) {
+    fprintf(stderr, "test_http: parser error (len=%u, read=%u)\n", n, i);
+    msg_destroy(msg), msg = NULL;
+  }
+
+  return msg;
+}
+
+/* Read message byte-by-byte */
+msg_t *read_message_byte_by_byte(char const buffer[])
+{
+  int i, n, m;
+  msg_t *msg;
+  msg_iovec_t iovec[msg_n_fragments];
+
+  n = strlen(buffer);
+  if (n == 0)
+    return NULL;
+
+  msg = msg_create(test_mclass, MSG_DO_EXTRACT_COPY);
+
+  for (i = 0; i < n;) {
+    /* This prevent msg_recv_iovec() from allocating extra slack */
+    int msg_buf_exact(msg_t *, int);
+    msg_buf_exact(msg, 10 + 1);	
+
+    if (msg_recv_iovec(msg, iovec, msg_n_fragments, 10, 0) < 0) {
+      perror("msg_recv_iovec");
+      return NULL;
+    }
+    assert(iovec->mv_len > 0);
+    *(char *)(iovec->mv_base) = buffer[i++];
+    msg_recv_commit(msg, 1, i == n);
+
+    m = msg_extract(msg);
+    if (m < 0) {
+      fprintf(stderr, "test_http: parsing error\n");
+      return NULL;
+    }
+    if (m > 0)
+      break;
+  }
+
+  if (i != n) {
+    fprintf(stderr, "test_http: parser error (len=%u, read=%u)\n", n, i);
+    msg_destroy(msg), msg = NULL;
+  }
+
+  return msg;
+}
+
+static
+int header_size(http_header_t *h)
+{
+  int offset = 0;
+
+  for (; h; h = h->sh_next) {
+    offset += SU_ALIGN(offset) + h->sh_class->hc_size;
+    offset = h->sh_class->hc_dxtra(h, offset);
+  }
+
+  return offset;
+}
+
+#define XTRA(xtra, h) SU_ALIGN(xtra) + header_size((http_header_t*)h)
+
+/** Test header filtering and duplicating */
+static int tag_test(void)
+{
+  su_home_t *home = su_home_new(sizeof *home);
+  http_request_t *request =
+    http_request_make(home, "GET /test/path HTTP/1.1");
+  http_via_t *via = http_via_make(home, "1.1 http.example.com, 1.0 fred");
+  http_host_t *host = http_host_make(home, "http.example.com:8080");
+  http_max_forwards_t *mf = http_max_forwards_make(home, "16");
+  url_t *url = url_hdup(home, (url_t *)"http://host:80/test/path");
+
+  tagi_t *lst, *dup;
+  int xtra;
+
+  BEGIN();
+
+  su_home_check(home);
+
+  TEST_1(home); TEST_1(request); TEST_1(host);
+  TEST_1(via); TEST_1(via->v_next);
+
+  lst = tl_list(HTTPTAG_REQUEST(request),
+		HTTPTAG_HOST(host),
+		HTTPTAG_VIA(via),
+		HTTPTAG_MAX_FORWARDS(mf),
+		URLTAG_URL(url),
+		TAG_NULL());
+
+  xtra = 0;
+  xtra += XTRA(xtra, request);
+  xtra += XTRA(xtra, host);
+  xtra += XTRA(xtra, via);
+  xtra += XTRA(xtra, mf);
+  xtra += SU_ALIGN(xtra) + sizeof(*url) + url_xtra(url);
+
+  TEST_SIZE(tl_xtra(lst, 0), xtra);
+  TEST_SIZE(tl_len(lst), 6 * sizeof(tagi_t));
+
+  dup = tl_adup(NULL, lst);
+
+  TEST_1(dup != NULL);
+  TEST_SIZE(tl_len(dup), 6 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(dup, 0), xtra);
+
+  if (tstflags & tst_verbatim)
+    tl_print(stdout, "dup:\n", dup);
+
+  su_free(NULL, dup);
+  tl_vfree(lst);
+
+  su_home_unref(home);
+
+  END();
+}
+
+/** Test advanced tag features */
+static int tag_test2(void)
+{
+  BEGIN();
+
+#if 0
+  tagi_t
+    *lst, *dup, *filter1, *filter2, *filter3, *filter4,
+    *b1, *b2, *b3, *b4;
+
+  msg_t *msg;
+  http_t *http;
+  su_home_t *home;
+  int xtra;
+
+  home = su_home_new(sizeof *home);
+
+  msg = read_message("HTTP/2.0 401 Unauthorized\r\n"
+		     "Content-Length: 0\r\n"
+		     "\r\n");
+
+  http = msg_object(msg);
+
+  TEST_1(home && msg && http);
+
+  TEST_1(http_status_p((http_header_t *)http->http_status));
+  TEST_1(http_content_length_p((http_header_t *)http->http_content_length));
+
+  lst = tl_list(HTTPTAG_VIA(http->http_via),
+		HTTPTAG_RECORD_ROUTE(http->http_record_route),
+		TAG_SKIP(2),
+		HTTPTAG_CSEQ(http->http_cseq),
+		HTTPTAG_PAYLOAD(http->http_payload),
+		TAG_NULL());
+  filter1 = tl_list(HTTPTAG_VIA(0),
+		    TAG_NULL());
+  filter2 = tl_list(HTTPTAG_CALL_ID(0),
+		    HTTPTAG_FROM(0),
+		    HTTPTAG_ROUTE(0),
+		    HTTPTAG_CSEQ(0),
+		    TAG_NULL());
+  filter3 = tl_list(HTTPTAG_CSEQ(0),
+		    HTTPTAG_CONTENT_LENGTH(0),
+		    TAG_NULL());
+  filter4 = tl_list(HTTPTAG_STATUS(0),
+		    HTTPTAG_VIA(0),
+		    HTTPTAG_RECORD_ROUTE(0),
+		    HTTPTAG_FROM(0),
+		    HTTPTAG_TO(0),
+		    HTTPTAG_CALL_ID(0),
+		    HTTPTAG_CSEQ(0),
+		    HTTPTAG_WWW_AUTHENTICATE(0),
+		    HTTPTAG_PROXY_AUTHENTICATE(0),
+		    HTTPTAG_CONTENT_LENGTH(0),
+		    TAG_NULL());
+
+  TEST_1(lst && filter1 && filter2 && filter3 && filter4);
+
+  b1 = tl_afilter(home, filter1, lst);
+  TEST(tl_len(b1), 2 * sizeof(tagi_t));
+  TEST_1(((http_via_t *)b1->t_value)->v_next);
+  xtra = http_header_size((http_header_t *)http->http_via);
+  xtra += SU_ALIGN(xtra);
+  xtra += http_header_size((http_header_t *)http->http_via->v_next);
+  TEST(tl_xtra(b1, 0), xtra);
+
+  dup = tl_adup(home, lst);
+
+  TEST(tl_len(dup), tl_len(lst));
+  TEST(tl_xtra(dup, 0), tl_xtra(lst, 0));
+
+  tl_vfree(lst);
+
+  lst = tl_list(HTTPTAG_HTTP(http), TAG_NULL());
+
+  b2 = tl_afilter(home, filter2, lst);
+  TEST(tl_len(b2), 4 * sizeof(tagi_t));
+  xtra = 0;
+  xtra += XTRA(xtra, http->http_call_id);
+  xtra += XTRA(xtra, http->http_from);
+  xtra += XTRA(xtra, http->http_cseq);
+  TEST(tl_xtra(b2, 0), xtra);
+
+  b3 = tl_afilter(home, filter3, lst);
+
+  TEST(tl_len(b3), 3 * sizeof(tagi_t));
+  TEST(tl_xtra(b3, 0),
+       sizeof(http_content_length_t) + sizeof(http_cseq_t));
+
+
+  b4 = tl_afilter(home, filter4, lst);
+  TEST(tl_len(b4), 11 * sizeof(tagi_t));
+  xtra = 0;
+  xtra += XTRA(xtra, http->http_status);
+  xtra += XTRA(xtra, http->http_via);
+  xtra += XTRA(xtra, http->http_via->v_next);
+  xtra += XTRA(xtra, http->http_record_route);
+  xtra += XTRA(xtra, http->http_from);
+  xtra += XTRA(xtra, http->http_to);
+  xtra += XTRA(xtra, http->http_call_id);
+  xtra += XTRA(xtra, http->http_cseq);
+  xtra += XTRA(xtra, http->http_www_authenticate);
+  xtra += XTRA(xtra, http->http_proxy_authenticate);
+  xtra += XTRA(xtra, http->http_content_length);
+  TEST(tl_xtra(b4, 0), xtra);
+
+  tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3); tl_vfree(filter4);
+  tl_vfree(lst);
+
+  su_home_check(home);
+
+  su_free(home, b4);
+  su_free(home, b3);
+  su_free(home, b2);
+  su_free(home, dup);
+  su_free(home, b1);
+
+  su_home_check(home);
+
+  su_home_unref(home);
+#endif
+
+  END();
+}
+
+/** Test parser and header manipulation */
+static int http_header_handling_test(void)
+{
+  msg_t *msg;
+  http_t *http;
+  su_home_t *home;
+
+  http_request_t            http_request[1];
+  http_status_t             http_status[1];
+  http_unknown_t            http_unknown[1];
+  http_separator_t          http_separator[1];
+  http_payload_t            http_payload[1];
+  http_via_t                http_via[1];
+  http_host_t               http_host[1];
+  http_from_t               http_from[1];
+  http_referer_t            http_referer[1];
+  http_connection_t         http_connection[1];
+  http_accept_t             http_accept[1];
+  http_accept_charset_t     http_accept_charset[1];
+  http_accept_encoding_t    http_accept_encoding[1];
+  http_accept_language_t    http_accept_language[1];
+  http_accept_ranges_t      http_accept_ranges[1];
+  http_allow_t              http_allow[1];
+  http_te_t                 http_te[1];
+  http_authorization_t      http_authorization[1];
+  http_www_authenticate_t   http_www_authenticate[1];
+  http_proxy_authenticate_t http_proxy_authenticate[1];
+  http_proxy_authorization_t http_proxy_authorization[1];
+  http_age_t                http_age[1];
+  http_cache_control_t      http_cache_control[1];
+  http_date_t               http_date[1];
+  http_expires_t            http_expires[1];
+  http_if_match_t           http_if_match[1];
+  http_if_modified_since_t  http_if_modified_since[1];
+  http_if_none_match_t      http_if_none_match[1];
+  http_if_range_t           http_if_range[1];
+  http_if_unmodified_since_t http_if_unmodified_since[1];
+  http_etag_t               http_etag[1];
+  http_expect_t             http_expect[1];
+  http_last_modified_t      http_last_modified[1];
+  http_location_t           http_location[1];
+  http_max_forwards_t       http_max_forwards[1];
+  http_pragma_t             http_pragma[1];
+  http_range_t              http_range[1];
+  http_retry_after_t        http_retry_after[1];
+  http_trailer_t            http_trailer[1];
+  http_upgrade_t            http_upgrade[1];
+  http_vary_t               http_vary[1];
+  http_warning_t            http_warning[1];
+  http_user_agent_t         http_user_agent[1];
+  http_server_t             http_server[1];
+  http_mime_version_t       http_mime_version[1];
+  http_content_language_t   http_content_language[1];
+  http_content_location_t   http_content_location[1];
+  http_content_md5_t        http_content_md5[1];
+  http_content_range_t      http_content_range[1];
+  http_content_encoding_t   http_content_encoding[1];
+  http_transfer_encoding_t  http_transfer_encoding[1];
+  http_content_type_t       http_content_type[1];
+  http_content_length_t     http_content_length[1];
+
+  BEGIN();
+
+  http_request_init(http_request);
+  http_status_init(http_status);
+  http_unknown_init(http_unknown);
+  http_separator_init(http_separator);
+  http_payload_init(http_payload);
+  http_via_init(http_via);
+  http_host_init(http_host);
+  http_from_init(http_from);
+  http_referer_init(http_referer);
+  http_connection_init(http_connection);
+
+  http_accept_init(http_accept);
+  http_accept_charset_init(http_accept_charset);
+  http_accept_encoding_init(http_accept_encoding);
+  http_accept_language_init(http_accept_language);
+  http_accept_ranges_init(http_accept_ranges);
+  http_allow_init(http_allow);
+  http_te_init(http_te);
+
+  http_authorization_init(http_authorization);
+  http_www_authenticate_init(http_www_authenticate);
+  http_proxy_authenticate_init(http_proxy_authenticate);
+  http_proxy_authorization_init(http_proxy_authorization);
+
+  http_age_init(http_age);
+  http_cache_control_init(http_cache_control);
+  http_date_init(http_date);
+  http_expires_init(http_expires);
+  http_if_match_init(http_if_match);
+  http_if_modified_since_init(http_if_modified_since);
+  http_if_none_match_init(http_if_none_match);
+  http_if_range_init(http_if_range);
+  http_if_unmodified_since_init(http_if_unmodified_since);
+
+  http_etag_init(http_etag);
+  http_expect_init(http_expect);
+  http_last_modified_init(http_last_modified);
+  http_location_init(http_location);
+  http_max_forwards_init(http_max_forwards);
+  http_pragma_init(http_pragma);
+  http_range_init(http_range);
+  http_retry_after_init(http_retry_after);
+  http_trailer_init(http_trailer);
+  http_upgrade_init(http_upgrade);
+  http_vary_init(http_vary);
+  http_warning_init(http_warning);
+
+  http_user_agent_init(http_user_agent);
+  http_server_init(http_server);
+
+  http_mime_version_init(http_mime_version);
+  http_content_language_init(http_content_language);
+  http_content_location_init(http_content_location);
+  http_content_md5_init(http_content_md5);
+  http_content_range_init(http_content_range);
+
+  http_content_encoding_init(http_content_encoding);
+  http_transfer_encoding_init(http_transfer_encoding);
+
+  http_content_type_init(http_content_type);
+  http_content_length_init(http_content_length);
+
+  home = su_home_new(sizeof *home);
+
+  {
+    int i;
+
+    struct { http_method_t number; char const *name; } methods[] = {
+      { http_method_get, "GET" },
+      { http_method_post, "POST" },
+      { http_method_head, "HEAD" },
+      { http_method_options, "OPTIONS" },
+      { http_method_put, "PUT" },
+      { http_method_delete, "DELETE" },
+      { http_method_trace, "TRACE" },
+      { http_method_connect, "CONNECT" },
+      { 0, NULL }
+    };
+
+    for (i = 0; methods[i].name; i++) {
+      TEST_1(strcmp(methods[i].name,
+		   http_method_name(methods[i].number, "")) == 0);
+    }
+  }
+
+  msg = read_message(
+    "PUT /Foo HTTP/1.1\r\n"
+    "Host: [::1]:8080\r\n"
+    "From: webmaster at w3.org\r\n"
+    "Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)\r\n"
+    "Referer: http://www.w3.org/hypertext/DataSources/Overview.html\r\n"
+    "Connection: close\r\n"
+    "Accept: audio/*; q=0.2, audio/basic\r\n"
+    "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8\r\n"
+    "Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0\r\n"
+    "Accept-Language: da, en-gb;q=0.8, en;q=0.7\r\n"
+    "Accept-Ranges: bytes\r\n"
+    "Age: 212\r\n"
+    "Allow: GET, HEAD, PUT\r\n"
+    "Cache-Control: private, community=\"UCI\"\r\n"
+    "Content-Encoding: identity\r\n"
+    "Content-Language: da\r\n"
+    "Content-Type: text/html\r\n"
+    "Content-Location: http://localhost/Foo\r\n"
+    "Content-Length: 28\r\n"
+    "Content-MD5: f48BLMCjkX5M5PgWoelogA==\r\n"
+    "Content-Range: bytes 0-27/*\r\n"
+    "\r\n"
+    "<html><body></body></html>\r\n");
+
+  http = msg_object(msg);
+
+  TEST_1(home && msg && http);
+
+  TEST_1(http_is_request((http_header_t *)http->http_request));
+  TEST_1(http->http_via); TEST_1(http->http_via->v_next);
+  TEST_1(http->http_via->v_next->v_next == NULL);
+
+  TEST_1(http->http_host);
+  TEST_1(http->http_from);
+  TEST_1(http->http_referer);
+  TEST_1(http->http_connection);
+  TEST_1(http->http_accept);
+  TEST_1(http->http_accept_charset);
+  TEST_1(http->http_accept_encoding);
+  TEST_1(http->http_accept_language);
+  TEST_1(http->http_accept_ranges);
+  TEST_1(http->http_age);
+  TEST_1(http->http_allow);
+  TEST_1(http->http_cache_control);
+  TEST_1(http->http_content_encoding);
+  TEST_1(http->http_content_language);
+  TEST_1(http->http_content_type);
+  TEST_1(http->http_content_location);
+  TEST_1(http->http_content_length);
+  TEST_1(http->http_content_md5);
+  TEST_1(http->http_content_range);
+
+  /* Quiet lots of warnings */
+#define _msg_header_offset msg_header_offset
+#define msg_header_offset(msg, http, h)			\
+  _msg_header_offset(msg, http, (http_header_t *)h)
+
+  TEST_P(msg_header_offset(msg, http, http_request), &http->http_request);
+  TEST_P(msg_header_offset(msg, http, http_status), &http->http_status);
+  TEST_P(msg_header_offset(msg, http, http_unknown), &http->http_unknown);
+  TEST_P(msg_header_offset(msg, http, http_separator), &http->http_separator);
+  TEST_P(msg_header_offset(msg, http, http_payload), &http->http_payload);
+  TEST_P(msg_header_offset(msg, http, http_via), &http->http_via);
+
+  TEST_P(msg_header_offset(msg, http, http_via), &http->http_via);
+  TEST_P(msg_header_offset(msg, http, http_host), &http->http_host);
+  TEST_P(msg_header_offset(msg, http, http_from), &http->http_from);
+  TEST_P(msg_header_offset(msg, http, http_referer), &http->http_referer);
+  TEST_P(msg_header_offset(msg, http, http_connection),
+	 &http->http_connection);
+
+  TEST_P(msg_header_offset(msg, http, http_accept), &http->http_accept);
+  TEST_P(msg_header_offset(msg, http, http_accept_charset),
+	 &http->http_accept_charset);
+  TEST_P(msg_header_offset(msg, http, http_accept_encoding),
+	 &http->http_accept_encoding);
+  TEST_P(msg_header_offset(msg, http, http_accept_language),
+	 &http->http_accept_language);
+  TEST_P(msg_header_offset(msg, http, http_accept_ranges),
+	 &http->http_accept_ranges);
+  TEST_P(msg_header_offset(msg, http, http_allow),
+	 &http->http_allow);
+  TEST_P(msg_header_offset(msg, http, http_te),
+	 &http->http_te);
+
+  TEST_P(msg_header_offset(msg, http, http_authorization),
+	 &http->http_authorization);
+  TEST_P(msg_header_offset(msg, http, http_www_authenticate),
+	 &http->http_www_authenticate);
+  TEST_P(msg_header_offset(msg, http, http_proxy_authenticate),
+	 &http->http_proxy_authenticate);
+  TEST_P(msg_header_offset(msg, http, http_proxy_authorization),
+	 &http->http_proxy_authorization);
+
+  TEST_P(msg_header_offset(msg, http, http_age),
+	 &http->http_age);
+  TEST_P(msg_header_offset(msg, http, http_cache_control),
+	 &http->http_cache_control);
+  TEST_P(msg_header_offset(msg, http, http_date),
+	 &http->http_date);
+  TEST_P(msg_header_offset(msg, http, http_expires),
+	 &http->http_expires);
+  TEST_P(msg_header_offset(msg, http, http_if_match),
+	 &http->http_if_match);
+  TEST_P(msg_header_offset(msg, http, http_if_modified_since),
+	 &http->http_if_modified_since);
+  TEST_P(msg_header_offset(msg, http, http_if_none_match),
+	 &http->http_if_none_match);
+  TEST_P(msg_header_offset(msg, http, http_if_range),
+	 &http->http_if_range);
+  TEST_P(msg_header_offset(msg, http, http_if_unmodified_since),
+	 &http->http_if_unmodified_since);
+
+  TEST_P(msg_header_offset(msg, http, http_etag),
+	 &http->http_etag);
+  TEST_P(msg_header_offset(msg, http, http_expect),
+	 &http->http_expect);
+  TEST_P(msg_header_offset(msg, http, http_last_modified),
+	 &http->http_last_modified);
+  TEST_P(msg_header_offset(msg, http, http_location),
+	 &http->http_location);
+  TEST_P(msg_header_offset(msg, http, http_max_forwards),
+	 &http->http_max_forwards);
+  TEST_P(msg_header_offset(msg, http, http_pragma),
+	 &http->http_pragma);
+  TEST_P(msg_header_offset(msg, http, http_range),
+	 &http->http_range);
+  TEST_P(msg_header_offset(msg, http, http_retry_after),
+	 &http->http_retry_after);
+  TEST_P(msg_header_offset(msg, http, http_trailer),
+	 &http->http_trailer);
+  TEST_P(msg_header_offset(msg, http, http_upgrade),
+	 &http->http_upgrade);
+  TEST_P(msg_header_offset(msg, http, http_vary),
+	 &http->http_vary);
+  TEST_P(msg_header_offset(msg, http, http_warning),
+	 &http->http_warning);
+
+  TEST_P(msg_header_offset(msg, http, http_user_agent),
+	 &http->http_user_agent);
+  TEST_P(msg_header_offset(msg, http, http_server),
+	 &http->http_server);
+
+  TEST_P(msg_header_offset(msg, http, http_mime_version),
+	 &http->http_mime_version);
+  TEST_P(msg_header_offset(msg, http, http_content_language),
+	 &http->http_content_language);
+  TEST_P(msg_header_offset(msg, http, http_content_location),
+	 &http->http_content_location);
+  TEST_P(msg_header_offset(msg, http, http_content_md5),
+	 &http->http_content_md5);
+  TEST_P(msg_header_offset(msg, http, http_content_range),
+	 &http->http_content_range);
+
+  TEST_P(msg_header_offset(msg, http, http_content_encoding),
+	 &http->http_content_encoding);
+  TEST_P(msg_header_offset(msg, http, http_transfer_encoding),
+	 &http->http_transfer_encoding);
+
+  TEST_P(msg_header_offset(msg, http, http_content_type),
+	 &http->http_content_type);
+  TEST_P(msg_header_offset(msg, http, http_content_length),
+	 &http->http_content_length);
+
+  TEST_SIZE(http_via_class->hc_params,
+	    offsetof(http_via_t, v_common));
+  TEST_SIZE(http_host_class->hc_params,
+	    offsetof(http_host_t, h_common));
+  TEST_SIZE(http_from_class->hc_params,
+	    offsetof(http_from_t, g_common));
+  TEST_SIZE(http_referer_class->hc_params,
+	    offsetof(http_referer_t, loc_common));
+  TEST_SIZE(http_connection_class->hc_params,
+	    offsetof(http_connection_t, k_items));
+
+  TEST_SIZE(http_accept_class->hc_params,
+	    offsetof(http_accept_t, ac_params));
+  TEST_SIZE(http_accept_charset_class->hc_params,
+	    offsetof(http_accept_charset_t, aa_params));
+  TEST_SIZE(http_accept_encoding_class->hc_params,
+	    offsetof(http_accept_encoding_t, aa_params));
+  TEST_SIZE(http_accept_language_class->hc_params,
+	    offsetof(http_accept_language_t, aa_params));
+  TEST_SIZE(http_accept_ranges_class->hc_params,
+	    offsetof(http_accept_ranges_t, k_items));
+  TEST_SIZE(http_allow_class->hc_params,
+	    offsetof(http_allow_t, k_items));
+  TEST_SIZE(http_te_class->hc_params,
+	    offsetof(http_te_t, te_params));
+
+  TEST_SIZE(http_authorization_class->hc_params,
+	    offsetof(http_authorization_t, au_params));
+  TEST_SIZE(http_www_authenticate_class->hc_params,
+	    offsetof(http_www_authenticate_t, au_params));
+  TEST_SIZE(http_proxy_authenticate_class->hc_params,
+	    offsetof(http_proxy_authenticate_t, au_params));
+  TEST_SIZE(http_proxy_authorization_class->hc_params,
+	    offsetof(http_proxy_authorization_t, au_params));
+
+  TEST_SIZE(http_age_class->hc_params,
+	    offsetof(http_age_t, x_common));
+  TEST_SIZE(http_cache_control_class->hc_params,
+	    offsetof(http_cache_control_t, k_items));
+  TEST_SIZE(http_date_class->hc_params,
+	    offsetof(http_date_t, d_common));
+  TEST_SIZE(http_expires_class->hc_params,
+	    offsetof(http_expires_t, d_common));
+  TEST_SIZE(http_if_match_class->hc_params,
+	    offsetof(http_if_match_t, k_items));
+  TEST_SIZE(http_if_modified_since_class->hc_params,
+	    offsetof(http_if_modified_since_t, d_common));
+  TEST_SIZE(http_if_none_match_class->hc_params,
+	    offsetof(http_if_none_match_t, k_items));
+  TEST_SIZE(http_if_range_class->hc_params,
+	    offsetof(http_if_range_t, ifr_common));
+  TEST_SIZE(http_if_unmodified_since_class->hc_params,
+	    offsetof(http_if_unmodified_since_t, d_common));
+
+  TEST_SIZE(http_etag_class->hc_params,
+	    offsetof(http_etag_t, g_common));
+  TEST_SIZE(http_expect_class->hc_params,
+	    offsetof(http_expect_t, g_common));
+  TEST_SIZE(http_last_modified_class->hc_params,
+	    offsetof(http_last_modified_t, d_common));
+  TEST_SIZE(http_location_class->hc_params,
+	    offsetof(http_location_t, loc_common));
+  TEST_SIZE(http_max_forwards_class->hc_params,
+	    offsetof(http_max_forwards_t, mf_common));
+  TEST_SIZE(http_pragma_class->hc_params,
+	    offsetof(http_pragma_t, k_items));
+  TEST_SIZE(http_range_class->hc_params,
+	    offsetof(http_range_t, rng_specs));
+  TEST_SIZE(http_retry_after_class->hc_params,
+	    offsetof(http_retry_after_t, ra_common));
+  TEST_SIZE(http_trailer_class->hc_params,
+	    offsetof(http_trailer_t, k_items));
+  TEST_SIZE(http_upgrade_class->hc_params,
+	    offsetof(http_upgrade_t, k_items));
+  TEST_SIZE(http_vary_class->hc_params,
+	    offsetof(http_vary_t, k_items));
+  TEST_SIZE(http_warning_class->hc_params,
+	    offsetof(http_warning_t, w_common));
+
+  TEST_SIZE(http_user_agent_class->hc_params,
+	    offsetof(http_user_agent_t, g_common));
+  TEST_SIZE(http_server_class->hc_params,
+	    offsetof(http_server_t, g_common));
+
+  TEST_SIZE(http_mime_version_class->hc_params,
+	    offsetof(http_mime_version_t, g_common));
+  TEST_SIZE(http_content_language_class->hc_params,
+	    offsetof(http_content_language_t, k_items));
+  TEST_SIZE(http_content_location_class->hc_params,
+	    offsetof(http_content_location_t, g_common));
+  TEST_SIZE(http_content_md5_class->hc_params,
+	    offsetof(http_content_md5_t, g_common));
+  TEST_SIZE(http_content_range_class->hc_params,
+	    offsetof(http_content_range_t, cr_common));
+
+  TEST_SIZE(http_content_encoding_class->hc_params,
+	    offsetof(http_content_encoding_t, k_items));
+  TEST_SIZE(http_transfer_encoding_class->hc_params,
+	    offsetof(http_transfer_encoding_t, k_items));
+
+  TEST_SIZE(http_content_type_class->hc_params,
+	    offsetof(http_content_type_t, c_params));
+  TEST_SIZE(http_content_length_class->hc_params,
+	    offsetof(http_content_length_t, l_common));
+
+  su_home_unref(home);
+
+  END();
+}
+
+int count(msg_common_t *h)
+{
+  http_header_t *sh = (http_header_t *)h;
+  unsigned n;
+
+  for (n = 0; sh; sh = sh->sh_next)
+    n++;
+
+  return n;
+}
+
+int len(msg_common_t *h)
+{
+  msg_header_t *sh = (msg_header_t *)h;
+  unsigned n;
+
+  for (n = 0; sh; sh = sh->sh_next) {
+    if (n) n +=2;
+    n += msg_header_field_e(NULL, 0, sh, 0);
+  }
+
+  return n;
+}
+
+static int http_header_test(void)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  BEGIN();
+
+  {
+    http_request_t *rq;
+
+    TEST_1(rq = http_request_make(home, "GET / HTTP/1.0"));
+
+    TEST(rq->rq_method, http_method_get);
+    TEST_S(rq->rq_method_name, "GET");
+    TEST_S(rq->rq_url->url_path, "");
+    TEST_1(rq->rq_url->url_root);
+    TEST_S(url_as_string(home, rq->rq_url), "/");
+    TEST_P(rq->rq_version, http_version_1_0);
+
+    TEST_1(rq = http_request_make(home, "GET / HTTP/1.2"));
+
+    TEST(rq->rq_method, http_method_get);
+    TEST_S(rq->rq_method_name, "GET");
+    TEST_S(rq->rq_url->url_path, "");
+    TEST_1(rq->rq_url->url_root);
+    TEST_S(url_as_string(home, rq->rq_url), "/");
+    TEST_S(rq->rq_version, "HTTP/1.2");
+
+    TEST_1(rq = http_request_make(home, "GET /foo"));
+    TEST(rq->rq_method, http_method_get);
+    TEST_S(rq->rq_method_name, "GET");
+    TEST_S(rq->rq_url->url_path, "foo");
+    TEST_1(rq->rq_url->url_root);
+    TEST_S(url_as_string(home, rq->rq_url), "/foo");
+    TEST_S(rq->rq_version, "");
+    TEST_P(rq->rq_version, http_version_0_9);
+  }
+
+  {
+    http_status_t *st;
+
+    st = http_status_make(home, "HTTP/1.0 100 Continue"); TEST_1(st);
+    TEST_S(st->st_version, "HTTP/1.0");
+    TEST_P(st->st_version, http_version_1_0);
+    TEST(st->st_status, 100);
+    TEST_S(st->st_phrase, "Continue");
+
+    st = http_status_make(home, "HTTP/1.1 200"); TEST_1(st);
+    TEST_S(st->st_version, "HTTP/1.1");
+    TEST(st->st_status, 200);
+    TEST_S(st->st_phrase, "");
+
+    st = http_status_make(home, "HTTP/1.1  200  Ok"); TEST_1(st);
+    TEST_S(st->st_version, "HTTP/1.1");
+    TEST_P(st->st_version, http_version_1_1);
+    TEST(st->st_status, 200);
+    TEST_S(st->st_phrase, "Ok");
+
+    st = http_status_make(home, "HTTP  99  Ok "); TEST_1(st);
+    TEST_S(st->st_version, "HTTP");
+    TEST(st->st_status, 99);
+    TEST_S(st->st_phrase, "Ok");
+
+    st = http_status_make(home, "HTTP/1.2 200 Ok"); TEST_1(st);
+    TEST_S(st->st_version, "HTTP/1.2");
+    TEST(st->st_status, 200);
+    TEST_S(st->st_phrase, "Ok");
+  }
+
+  {
+    http_content_range_t *cr;
+
+    cr = http_content_range_make(home, "bytes 0 - 499 / *"); TEST_1(cr);
+    TEST64(cr->cr_first, 0);
+    TEST64(cr->cr_last, 499);
+    TEST64(cr->cr_length, (http_off_t)-1);
+
+    cr = http_content_range_make(home, "bytes 500-999/9913133"); TEST_1(cr);
+    TEST64(cr->cr_first, 500);
+    TEST64(cr->cr_last, 999);
+    TEST64(cr->cr_length, 9913133);
+
+    TEST_1(!http_content_range_make(home, "bytes = 0 - 499 / *,"));
+  }
+
+  {
+    http_cookie_t *c;
+
+    c = http_cookie_make(home, "$Version=1;"
+			 "foo=bar;$Domain=.nokia.com;$Path=\"\"");
+    TEST_1(c);
+    TEST_1(c->c_params);
+    TEST_S(c->c_version, "1");
+    TEST_S(c->c_name, "foo=bar");
+    TEST_S(c->c_domain, ".nokia.com");
+    TEST_S(c->c_path, "\"\"");
+
+    c = http_cookie_make(home, "$Version=1;"
+			 "foo=bar;$Domain=.nokia.com;$Path=\"\",  , "
+			 "bar=bazzz;$Domain=.research.nokia.com;$Path=\"\";"
+			 "hum=ham;$Domain=.nokia.fi;$Path=\"/sofia\""
+			 );
+
+    TEST_1(c);
+    TEST_1(c->c_params);
+    TEST_S(c->c_version, "1");
+    TEST_S(c->c_name, "foo=bar");
+    TEST_S(c->c_domain, ".nokia.com");
+    TEST_S(c->c_path, "\"\"");
+
+    c = http_cookie_make(home, "foo=bar=baz1");
+
+    TEST_1(c);
+    TEST_1(c->c_params);
+    TEST_S(c->c_params[0], "foo=bar=baz1");
+  }
+
+  {
+    http_set_cookie_t *sc;
+
+    sc = http_set_cookie_make(home, "foo=bar;Domain=.nokia.com;Path=\"\""
+			      ";Foo=bar;Version=1;Secure;Max-age=1212;"
+			      "Comment=\"Jummi Jammmi\"");
+    TEST_1(sc);
+    TEST_1(sc->sc_params);
+    TEST_S(sc->sc_name, "foo=bar");
+    TEST_S(sc->sc_version, "1");
+    TEST_S(sc->sc_domain, ".nokia.com");
+    TEST_S(sc->sc_max_age, "1212");
+    TEST_S(sc->sc_path, "\"\"");
+    TEST_S(sc->sc_comment, "\"Jummi Jammmi\"");
+    TEST(sc->sc_secure, 1);
+
+    sc = http_set_cookie_make(home, "foo=bar;Domain=.nokia.com;Path=\"\""
+			      ";Foo=bar;Version=1");
+
+    TEST_1(sc);
+    TEST_1(sc->sc_params);
+    TEST_S(sc->sc_name, "foo=bar");
+    TEST_S(sc->sc_version, "1");
+    TEST_S(sc->sc_domain, ".nokia.com");
+    TEST_P(sc->sc_max_age, NULL);
+    TEST_S(sc->sc_path, "\"\"");
+    TEST_S(sc->sc_comment, NULL);
+    TEST(sc->sc_secure, 0);
+
+
+    sc = http_set_cookie_make(home,
+			      "CUSTOMER=WILE_E_COYOTE; "
+			      "path=/; "
+			      "expires=Wednesday, 09-Nov-99 23:12:40 GMT");
+    
+    TEST_1(sc);
+    TEST_1(sc->sc_params);
+    TEST_S(sc->sc_name, "CUSTOMER=WILE_E_COYOTE");
+    TEST_S(sc->sc_version, NULL);
+    TEST_S(sc->sc_domain, NULL);
+    TEST_S(sc->sc_max_age, NULL);
+    TEST_S(sc->sc_path, "/");
+    TEST_S(sc->sc_comment, NULL);
+    TEST(sc->sc_secure, 0);
+  }
+
+  {
+    http_range_t *rng;
+
+    rng = http_range_make(home, "bytes = 0 - 499"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "0-499");
+    TEST_P(rng->rng_specs[1], NULL);
+
+    rng = http_range_make(home, "bytes=,500 - 999"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "500-999");
+    TEST_P(rng->rng_specs[1], NULL);
+
+    rng = http_range_make(home, "bytes= - 500"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "-500");
+    TEST_P(rng->rng_specs[1], NULL);
+
+    rng = http_range_make(home, "bytes=9500-"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "9500-");
+    TEST_P(rng->rng_specs[1], NULL);
+
+    rng = http_range_make(home, "bytes=0- 0 , -  1"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "0-0");
+    TEST_S(rng->rng_specs[1], "-1");
+    TEST_P(rng->rng_specs[2], NULL);
+
+    rng = http_range_make(home, "bytes=500-600 , 601 - 999 ,,"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "500-600");
+    TEST_S(rng->rng_specs[1], "601-999");
+    TEST_P(rng->rng_specs[2], NULL);
+
+    rng = http_range_make(home, "bytes=500-700,601-999"); TEST_1(rng);
+    TEST_S(rng->rng_unit, "bytes");
+    TEST_1(rng->rng_specs);
+    TEST_S(rng->rng_specs[0], "500-700");
+    TEST_S(rng->rng_specs[1], "601-999");
+    TEST_P(rng->rng_specs[2], NULL);
+  }
+
+  {
+    http_date_t *d;
+    char const *s;
+    char b[64];
+
+    d = http_date_make(home, s = "Wed, 15 Nov 1995 06:25:24 GMT"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 816416724);
+    TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+    TEST_S(b, s);
+    d = http_date_make(home, s = "Wed, 15 Nov 1995 04:58:08 GMT"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 816411488);
+    TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+    TEST_S(b, s);
+    d = http_date_make(home, s = "Tue, 15 Nov 1994 08:12:31 GMT"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 784887151);
+    TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+    TEST_S(b, s);
+    d = http_date_make(home, "Fri Jan 30 12:21:09 2004"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 1075465269);
+    d = http_date_make(home, "Fri Jan  1 12:21:09 2004"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 1072959669);
+    d = http_date_make(home, "Tuesday, 15-Nov-94 08:12:31 GMT"); TEST_1(d);
+    TEST(d->d_time, 2208988800UL + 784887151);
+  }
+
+  {
+    http_retry_after_t *ra;
+    char const *s;
+    char b[64];
+
+    ra = http_retry_after_make(home, s = "Wed, 15 Nov 1995 06:25:24 GMT");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 816416724);
+    TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+    TEST_S(b, s);
+    ra = http_retry_after_make(home, s = "Wed, 15 Nov 1995 04:58:08 GMT");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 816411488);
+    TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+    TEST_S(b, s);
+    ra = http_retry_after_make(home, s = "Tue, 15 Nov 1994 08:12:31 GMT");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 784887151);
+    TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+    TEST_S(b, s);
+    ra = http_retry_after_make(home, "Fri Jan 30 12:21:09 2004");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 1075465269);
+    ra = http_retry_after_make(home, "Fri Jan  1 12:21:09 2004");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 1072959669);
+    ra = http_retry_after_make(home, "Tuesday, 15-Nov-94 08:12:31 GMT");
+    TEST_1(ra);
+    TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 784887151);
+    ra = http_retry_after_make(home, "121");
+    TEST_1(ra);
+    TEST(ra->ra_date, 0);
+    TEST(ra->ra_delta, 121);
+  }
+
+  {
+    http_location_t *l;
+
+    TEST_1(l = http_location_make(home, "http://www.google.fi/cxfer?c=PREF%3D:TM%3D1105378671:S%3DfoewuOwfszMIFJbP&prev=/"));
+  }
+
+  su_home_deinit(home);
+
+  END();
+}
+
+static int http_parser_test(void)
+{
+  msg_t *msg;
+  http_t *http;
+
+  BEGIN();
+
+  {
+    char data[] =
+      "HTTP/1.1 200\r\n"
+      "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+      "Transfer-Encoding: chunked, gzip\r\n"
+      "Transfer-Encoding: deflate\r\n"
+      "TE: chunked, gzip\r\n"
+      "TE: deflate\r\n"
+      "Content-Encoding: identity, gzip\r\n"
+      "Content-Type: text/html\r\n"
+      "Content-Encoding: deflate\r\n"
+      "Set-Cookie: PREF=ID=1eab07c269cd7e5a:LD=fi:TM=1094601448:LM=1094601448:S=Ik6IEs3W3vamd8Xu; "
+      "expires=Sun, 17-Jan-2038 19:14:07 GMT ; path=/; domain=.google.fi\r\n"
+      "Set-Cookie: CUSTOMER=WILE_E_COYOTE; "
+      "path=/; "
+      "expires=Wednesday, 09-Nov-99 23:12:40 GMT\r\n"
+      "\r\n"
+      "4c\r\n"
+      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n"
+      "\r\n"
+      "<html>\r\n"
+      "\r\n"
+      "\r\n9\r\n"
+      "</html>\r\n"
+      "\r\n0\r\n"
+      "Date: Mon, 21 Oct 2002 13:10:41 GMT\r\n"
+      "\n";
+
+    TEST_1(msg = read_message_byte_by_byte(data));
+
+    http = msg_object(msg); TEST_1(http);
+
+    TEST_1(http->http_status);
+    TEST_1(http->http_payload);
+    TEST_1(http->http_payload->pl_next);
+    TEST_1(http->http_date);
+    TEST_1(http->http_te);
+    TEST_1(http->http_transfer_encoding);
+    TEST_1(http->http_transfer_encoding->k_items);
+    TEST_1(http->http_content_encoding);
+    TEST_1(http->http_content_encoding->k_items);
+    TEST_1(http->http_content_encoding->k_items);
+    TEST_S(http->http_content_encoding->k_items[0], "identity");
+    TEST_S(http->http_content_encoding->k_items[1], "gzip");
+    TEST_S(http->http_content_encoding->k_items[2], "deflate");
+    TEST_P(http->http_content_encoding->k_items[3], NULL);
+    TEST_1(http->http_set_cookie);
+    TEST_1(http->http_set_cookie->sc_next);
+
+    msg_destroy(msg);
+  }
+
+  END();
+}
+
+static int test_http_encoding(void)
+{
+  http_header_t *h, *h1;
+  msg_t *msg;
+  http_t *http;
+  su_home_t *home;
+  char b[160];
+  size_t n;
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  msg = read_message(
+    "GET http://bar.com/foo/ HTTP/1.1\r\n"
+    "Accept: text/html\r\n"
+    "Accept-Charset: iso-8859-1\r\n"
+    "Accept-Encoding: gzip\r\n"
+    "Accept-Language: fi\r\n"
+    "Authorization: Basic dXNlcjE6c2VjcmV0\r\n"
+    "Expect: 100-continue\r\n"
+    "From: user at nokia.com\r\n"
+    "Host: www.nokia.com:80\r\n"
+    "If-Match: \"entity_tag001\"\r\n"
+    "If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "If-None-Match: \"entity_tag001\", \"tag02\"\r\n"
+    "If-Range: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "If-Unmodified-Since: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "Location: a+a+://\r\n"
+    "Max-Forwards: 3\r\n"
+    "Proxy-Authorization: Basic dXNlcjE6c2VjcmV0\r\n"
+    "Range: bytes=100-599\r\n"
+    "Referer: http://www.microsoft.com/resources.asp\r\n"
+    "TE: trailers\r\n"
+    "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)\r\n"
+    "Cookie: $Version=\"1\";user=\"WILE_E_COYOTE\";$Path=\"/acme\"\r\n"
+    "Cache-Control: max-age=10\r\n"
+    "Pragma: no-cache\r\n"
+    "Transfer-Encoding: chunked, deflate\r\n"
+    "Upgrade: SHTTP/1.3, TLS/1.0\r\n"
+    "Via: HTTP/1.1 Proxy1\r\n"
+    "Proxy-Connection: keep-alive\r\n"
+    "Connection: close\r\n"
+    "Date: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "Trailer: Date, Connection\r\n"
+    "Warning: 2112 www.nokia.com \"Disconnected Operation\"\r\n"
+    /* This is here just because we cannot include two Retry-After
+       headers in a single message */
+    "Retry-After: 60\r\n"
+    "\r\n"
+    );
+  http = http_object(msg);
+
+  TEST_1(msg); TEST_1(http); TEST_1(!http->http_error);
+
+  for (h = (http_header_t *)http->http_request; h; h = h->sh_succ) {
+
+    if (h == (http_header_t*)http->http_payload)
+      break;
+
+    TEST_1(h1 = msg_header_dup(home, h));
+    n = msg_header_e(b, sizeof b, h1, 0);
+    if (n != h->sh_len)
+      TEST_SIZE(n, h->sh_len);
+    TEST_M(b, h->sh_data, n);
+    su_free(home, h1);
+  }
+
+  msg_destroy(msg), msg = NULL;
+
+  msg = read_message(
+    "HTTP/1.1 200 Ok\r\n"
+    "Accept-Ranges: none\r\n"
+    "Age: 2147483648\r\n"
+    "ETag: \"b38b9-17dd-367c5dcd\"\r\n"
+    "Location: http://localhost/redirecttarget.asp\r\n"
+    "Proxy-Authenticate: Basic realm=\"Nokia Internet Proxy\"\r\n"
+    "Retry-After: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "Server: Microsoft-IIS/5.0\r\n"
+    "Vary: Date\r\n"
+    "WWW-Authenticate: Digest realm=\"Nokia Intranet\", nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", opaque=\"+GNywA==\", algorithm=MD5, qop=\"auth-int\"\r\n"
+    "Set-Cookie: user=\"WILE_E_COYOTE\";Version=\"1\";Path=\"/acme\"\r\n"
+    "Allow: GET, HEAD\r\n"
+    /* This is here just because we cannot include two If-Range
+       headers in a single message */
+    "If-Range: \"tag02\"\r\n"
+    "Content-Encoding: gzip\r\n"
+    "Content-Language: en\r\n"
+    "Content-Length: 70\r\n"
+    "Content-Location: http://localhost/page.asp\r\n"
+    "Content-MD5: LLO7gLaGqGt4BI6HouiWng==\r\n"
+    "Content-Range: bytes 2543-4532/7898\r\n"
+    "Content-Type: text/html\r\n"
+    "Expires: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+    "\r\n"
+    "<html><head><title>Heippa!</title></head><body>Heippa!</body></html>"
+    "\r\n");
+  http = http_object(msg);
+
+  TEST_1(msg); TEST_1(http); TEST_1(!http->http_error);
+
+  for (h = (http_header_t *)http->http_status; h; h = h->sh_succ) {
+    if (h == (http_header_t*)http->http_payload)
+      break;
+
+    TEST_1(h1 = msg_header_dup(home, h));
+    n = msg_header_e(b, sizeof b, h1, 0);
+    TEST_SIZE(n, h->sh_len);
+    TEST_M(b, h->sh_data, n);
+    su_free(home, h1);
+  }
+
+  msg_destroy(msg), msg = NULL;
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+
+static int http_chunk_test(void)
+{
+  msg_t *msg;
+  http_t *http;
+
+  BEGIN();
+
+  {
+    char data[] =
+      "\nHTTP/1.1 200 OK\r\n"
+      "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+      "Transfer-Encoding: chunked\r\n"
+      "Content-Type: text/html\r\n"
+      "\r\n"
+      "4c\r\n"
+      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n"
+      "\r\n"
+      "<html>\r\n"
+      "\r\n"
+      "\r\n9\r\n"
+      "</html>\r\n"
+      "\r\n0\r\n"
+      "Date: Mon, 21 Oct 2002 13:10:41 GMT\r\n"
+      "\n";
+
+    TEST_1(msg = read_message_byte_by_byte(data));
+
+    http = msg_object(msg); TEST_1(http);
+
+    TEST_1(http->http_status);
+    TEST_1(http->http_payload);
+    TEST_1(http->http_payload->pl_next);
+    TEST_1(http->http_date);
+
+    msg_destroy(msg);
+  }
+
+  {
+    /* Use LF only as line delimiter */
+    char data[] =
+      "HTTP/1.1 200 OK\n"
+      "Server: Apache/1.3.11 (Unix) tomcat/1.0\n"
+      "Transfer-Encoding: chunked\n"
+      "Content-Type: text/html\n"
+      "\n"
+      "48\n"
+      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+      "\n"
+      "<html>\n"
+      "\n"
+      "\n8\n"
+      "</html>\n"
+      "\n0\n"
+      "Date: Mon, 21 Oct 2002 13:10:41 GMT\n"
+      "\n";
+
+    TEST_1(msg = read_message_byte_by_byte(data));
+
+    http = msg_object(msg); TEST_1(http);
+
+    TEST_1(http->http_status);
+    TEST_1(http->http_payload);
+    TEST_1(http->http_payload->pl_next);
+    TEST_1(http->http_date);
+
+    msg_destroy(msg);
+  }
+
+  {
+    /* Use CR only as line delimiter */
+    char data[] =
+      "HTTP/1.1 200 OK\r"
+      "Server: Apache/1.3.11 (Unix) tomcat/1.0\r"
+      "Transfer-Encoding: chunked\r"
+      "Content-Type: text/html\r"
+      "\r"
+      "48\r"
+      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r"
+      "\r"
+      "<html>\r"
+      "\r"
+      "\r8\r"
+      "</html>\r"
+      "\r0\r"
+      "Date: Mon, 21 Oct 2002 13:10:41 GMT\r"
+      "\r";
+
+    TEST_1(msg = read_message_byte_by_byte(data));
+
+    http = msg_object(msg); TEST_1(http);
+
+    TEST_1(http->http_status);
+    TEST_1(http->http_payload);
+    TEST_1(http->http_payload->pl_next);
+    TEST_1(http->http_date);
+
+    msg_destroy(msg);
+  }
+
+  END();
+}
+
+static int http_tag_test(void)
+{
+  BEGIN();
+
+  {
+    msg_t *msg;
+    http_t *http;
+
+    http_referer_t *r;
+    http_upgrade_t *u;
+
+    char data[] =
+      "HTTP/1.1 200 OK\r\n"
+      "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+      "\r\n";
+
+    TEST_1(msg = read_message_byte_by_byte(data));
+
+    http = msg_object(msg); TEST_1(http);
+
+    TEST_1(http->http_status);
+    TEST_1(http->http_server);
+
+    r = http_referer_make(NULL, "ftp://ftp.funet.fi"); TEST_1(r);
+    u = http_upgrade_make(NULL, "HTTP/1.1, TLS/1.1"); TEST_1(u);
+
+    TEST_1(u->k_items);
+    TEST_S(u->k_items[0], "HTTP/1.1");
+    TEST_S(u->k_items[1], "TLS/1.1");
+    TEST_1(!u->k_items[2]);
+
+    TEST(http_add_tl(msg, http,
+		     HTTPTAG_SERVER(HTTP_NONE->sh_server),
+		     HTTPTAG_USER_AGENT_STR(NULL),
+		     HTTPTAG_USER_AGENT(NULL),
+		     HTTPTAG_REFERER(r),
+		     HTTPTAG_MAX_FORWARDS_STR("1"),
+		     HTTPTAG_HEADER((http_header_t*)u),
+		     HTTPTAG_HEADER_STR("Vary: *\r\n\r\nfoo"),
+		     TAG_END()),
+	 5);
+
+    TEST_P(http->http_server, NULL);
+    TEST_1(http->http_referer);
+    TEST_1(http->http_max_forwards);
+    TEST_1(http->http_upgrade);
+    TEST_1(http->http_vary);
+    TEST_1(http->http_payload);
+
+    msg_destroy(msg);
+  }
+
+  END();
+}
+
+static
+int test_query_parser(void)
+{
+  BEGIN();
+
+  {
+    char query[] = "foo=bar&bar=baz";
+    char *foo = NULL, *bar = NULL, *baz = "default";
+
+    TEST_SIZE(http_query_parse(NULL, NULL), -1);
+
+    TEST_SIZE(http_query_parse(query,
+			       "foo=", &foo,
+			       "bar=", &bar,
+			       "baz=", &baz,
+			       NULL), 2);
+    TEST_S(foo, "bar");
+    TEST_S(bar, "baz");
+    TEST_S(baz, "default");
+  }
+
+  {
+    char q2[] = "f%6fo=b%61r&bar=baz&bazibazuki";
+
+    char *foo = NULL, *bar = NULL, *baz = NULL;
+
+    TEST_SIZE(http_query_parse(q2,
+			       "foo=", &foo,
+			       "bar=", &bar,
+			       "baz", &baz,
+			       NULL),
+	      3);
+
+    TEST_S(foo, "bar");
+    TEST_S(bar, "baz");
+    TEST_S(baz, "ibazuki");
+
+  }
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed token64_e() prototype in ipt/token64.[hc].
+
+    M ./libsofia-sip-ua/ipt/token64.c -1 +1
+    M ./libsofia-sip-ua/ipt/token64.h -1 +1
+
+2005-07-24  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* sha1.c: Added RFC 3174 copyright notice.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+PROJECT_NAME         = "ipt"
+OUTPUT_DIRECTORY     = ../docs/html/ips
+
+INPUT 		     = ipt.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/su.doxytags=../su
+GENERATE_TAGFILE     = ../docs/ipt.doxytags
+
+ALIASES +=
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,54 @@
+#
+# Makefile.am for ipt module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libipt.la
+
+check_PROGRAMS = 	torture_base64
+
+TESTS = 		torture_base64
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/rc4.h \
+			sofia-sip/base64.h \
+			sofia-sip/string0.h sofia-sip/token64.h \
+			sofia-sip/uniqueid.h
+
+libipt_la_SOURCES = 	base64.c string0.c token64.c
+
+EXTRA_DIST = 		sofia-sip/utf8.h \
+			utf8internal.h \
+			utf8.c ucs2.c ucs4.c rc4.c \
+			utf8test.c
+
+COVERAGE_INPUT = 	$(libipt_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libipt.la \
+			../sresolv/libsresolv.la \
+			../su/libsu.la
+
+torture_base64_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST +=		Doxyfile ipt.docs
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,694 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for ipt module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libipt_la_SOURCES) torture_base64.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = torture_base64$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/ipt
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libipt_la_LIBADD =
+am_libipt_la_OBJECTS = base64.lo string0.lo token64.lo
+libipt_la_OBJECTS = $(am_libipt_la_OBJECTS)
+torture_base64_SOURCES = torture_base64.c
+torture_base64_OBJECTS = torture_base64.$(OBJEXT)
+torture_base64_LDADD = $(LDADD)
+torture_base64_DEPENDENCIES = libipt.la ../sresolv/libsresolv.la \
+	../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libipt_la_SOURCES) torture_base64.c
+DIST_SOURCES = $(libipt_la_SOURCES) torture_base64.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libipt.la
+TESTS = torture_base64
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+			sofia-sip/rc4.h \
+			sofia-sip/base64.h \
+			sofia-sip/string0.h sofia-sip/token64.h \
+			sofia-sip/uniqueid.h
+
+libipt_la_SOURCES = base64.c string0.c token64.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = sofia-sip/utf8.h utf8internal.h utf8.c ucs2.c ucs4.c \
+	rc4.c utf8test.c Doxyfile ipt.docs
+COVERAGE_INPUT = $(libipt_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libipt.la \
+			../sresolv/libsresolv.la \
+			../su/libsu.la
+
+torture_base64_LDFLAGS = -static
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/ipt/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/ipt/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libipt.la: $(libipt_la_OBJECTS) $(libipt_la_DEPENDENCIES) 
+	$(LINK)  $(libipt_la_LDFLAGS) $(libipt_la_OBJECTS) $(libipt_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+torture_base64$(EXEEXT): $(torture_base64_OBJECTS) $(torture_base64_DEPENDENCIES) 
+	@rm -f torture_base64$(EXEEXT)
+	$(LINK) $(torture_base64_LDFLAGS) $(torture_base64_OBJECTS) $(torture_base64_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/base64.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/string0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/token64.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_base64.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,251 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE base64.c
+ *
+ * Implementation of BASE64 encoding and decoding functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "sofia-sip/base64.h"
+
+static unsigned char const code[] = 
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define B64NOP 128
+#define B64EOF  64
+
+/**Decode a BASE64-encoded string.
+ *
+ * The function base64_d() decodes a string @a b64s encoded with BASE64. It
+ * stores the result in the buffer @a buf of @a bsiz bytes.
+ *
+ * If the @a buf is NULL, the function just returns the length of decoded
+ * data. In any case, no decoded data is stored in @a buf beyond @a bsiz. 
+ * The function always returns the full length of decodable data.
+ * 
+ * @param buf  Buffer to store decoded data
+ * @param bsiz Size of @a buf
+ * @param b64s Base64-encoded string.
+ *
+ * @return Length of data that can be decoded in bytes. 
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, 
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein, November 1996.
+ *
+ * @par Example
+ * The following example code decodes a string of BASE64 data into a 
+ * memory area allocated from heap:
+ * @code
+ * int decoder(char const *encoded, void **return_decoded)
+ * {
+ *   int len = base64_d(NULL, 0, encoded);
+ *   void *decoded = malloc(len);
+ *   base64_d(decoded, len, encoded);
+ *   *return_decoded = decoded;
+ *   return len;
+ * }
+ * @endcode
+ */
+isize_t base64_d(char buf[], isize_t bsiz, char const *b64s) 
+{
+  static unsigned char decode[256] = "";
+  unsigned char const *s = (unsigned char const *)b64s;
+  unsigned char c, b1, b2 = B64EOF, b3 = B64EOF, b4 = B64EOF;
+  unsigned long w;
+  isize_t i, len = 0, total_len = 0;
+
+  if (b64s == NULL)
+    return 0;
+
+  if (decode['\0'] != B64EOF) {
+    /* Prepare decoding table */
+    for (i = 1; i < 256; i++)
+      decode[i] = B64NOP; 
+
+    for (i = 0; i < 64; i++) {
+      decode[code[i]] = (unsigned char)i;
+    }
+    decode['='] = B64EOF;
+    decode['\0'] = B64EOF;
+  }
+
+  /* Calculate length */
+  while ((c = decode[*s++]) != B64EOF) {
+    if (c != B64NOP)
+      len++;
+  }
+  
+  total_len = len = len * 3 / 4;
+
+  if (buf == NULL || bsiz == 0)
+    return total_len;
+
+  if (len > bsiz) 
+    len = bsiz;
+  
+  for (i = 0, s = (unsigned char const *)b64s; i < len; ) {
+      
+    while ((b1 = decode[*s++]) == B64NOP)
+      ;
+    if (b1 != B64EOF)
+      while ((b2 = decode[*s++]) == B64NOP)
+	;
+    if (b2 != B64EOF)
+      while ((b3 = decode[*s++]) == B64NOP)
+	;
+    if (b3 != B64EOF)
+      while ((b4 = decode[*s++]) == B64NOP)
+	;
+      
+    if (((b1 | b2 | b3 | b4) & (B64NOP|B64EOF)) == 0) {
+      /* Normal case, 4 B64 chars to 3 data bytes */
+      w = (b1 << 18) | (b2 << 12) | (b3 << 6) | b4;
+      buf[i++] = (unsigned char)(w >> 16);
+      buf[i++] = (unsigned char)(w >> 8);
+      buf[i++] = (unsigned char)(w);
+      continue;
+    }
+    else {
+      /* EOF */
+      if ((b1 | b2) & B64EOF) {
+	/* fputs("base64dec: strange eof ===\n", stderr); */
+	break;
+      }
+      buf[i++] = (b1 << 2) | (b2 >> 4);
+      if (b3 != B64EOF) {
+	buf[i++] = ((b2 & 15) << 4) | ((b3 >> 2) & 15);
+	if (b4 != B64EOF) {
+	  buf[i++] = ((b3 & 3) << 6) | b4;
+	}
+      }
+      break;
+    }
+  }
+
+#if 0
+  printf("base64_d returns, decoded %d bytes\n", total_len);
+  for (i = 0; i < len; i++)
+    printf("%02x", buf[i]);
+  printf("\n");
+#endif
+
+  return total_len;
+}
+
+/**Encode data with BASE64.
+ * 
+ * The function base64_e() encodes @a dsiz bytes of @a data into @a buf. 
+ *
+ * @note The function base64_e() uses at most @a bsiz bytes from @a buf.
+ *
+ * If @a bsiz is zero, the function just returns the length of BASE64
+ * encoding, excluding the final @c NUL.
+ *
+ * If encoded string is longer than that @a bsiz, the function terminates
+ * string with @c NUL at @a buf[bsiz-1], but returns the length of encoding as
+ * usual.
+ *
+ * @param buf  buffer for encoded data
+ * @param bsiz size of @a buffer
+ * @param data data to be encoded
+ * @param dsiz size of @a data
+ *
+ * @return The function base64_e() return length of encoded string,
+ * excluding the final NUL.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, 
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein, November 1996.
+ *
+ */
+isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz) 
+{
+  unsigned char *s = (unsigned char *)buf;
+  unsigned char *b = (unsigned char *)data;
+  unsigned long w;
+
+  isize_t i, n, slack = (unsigned)dsiz % 3;
+  isize_t dsize = dsiz - slack, bsize = bsiz;
+
+  if (bsize == 0)
+    s = NULL;
+  
+  for (i = 0, n = 0; i < dsize; i += 3, n += 4) {
+    w = (b[i] << 16) | (b[i+1] << 8) | b[i+2];
+
+    if (s) {
+      if (n + 4 < bsize) {
+	s[n + 0] = code[(w >> 18) & 63];
+	s[n + 1] = code[(w >> 12) & 63];
+	s[n + 2] = code[(w >> 6) & 63];
+	s[n + 3] = code[(w) & 63];
+      } else {
+	if (n + 1 < bsize) 
+	  s[n + 0] = code[(w >> 18) & 63];
+	if (n + 2 < bsize) 
+	  s[n + 1] = code[(w >> 12) & 63];
+	if (n + 3 < bsize)
+	  s[n + 2] = code[(w >> 6) & 63];
+	s[bsize - 1] = '\0';
+	s = NULL;
+      }
+    }
+  }			   
+  
+  if (slack) {
+    if (s) {
+      if (slack == 2)
+	w = (b[i] << 16) | (b[i+1] << 8);
+      else
+	w = (b[i] << 16);
+
+      if (n + 1 < bsize) 
+	s[n + 0] = code[(w >> 18) & 63];
+      if (n + 2 < bsize)
+	s[n + 1] = code[(w >> 12) & 63];
+      if (n + 3 < bsize)
+	s[n + 2] = (slack == 2) ? code[(w >> 6) & 63] : '=';
+      if (n + 3 < bsize)
+	s[n + 3] = '=';
+      if (n + 4 >= bsize)
+	s[bsize - 1] = '\0', s = NULL;
+    }
+    n += 4;
+  }
+
+  if (s)
+    s[n] = '\0';
+
+  return n;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "ipt" - Utility Module
+ * 
+ * @section ipt_meta Module Meta Information
+ *
+ * Utility library for IP Telephony applications.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section ipt_overview Overview
+ *
+ * This module contain some routines useful for IPT applications, like 
+ * - base64.h BASE64 encoding/decoding, 
+ * - token64.h encoding/decoding binary as SIP/HTTP token, 
+ * - utf8.h UTF8 encoding/decoding, 
+ * - sha1.h SHA1 hash routines, and
+ * - rc4.h arcfour random number generator.
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,264 @@
+/**@CFILE rc4.c Arcfour pseudorandom generator.
+ *
+ * @author Pekka Pessi <ppessi at hut.fi>
+ *
+ * Copyright (c) 1996 Pekka Pessi. All rights reserved.
+ *
+ * This source code is provided for unrestricted use. Users may copy or
+ * modify this source code without charge.
+ *
+ * THIS SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
+ * INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
+ * PRACTICE.
+ *
+ * This source code is provided with no support and without any obligation
+ * on the part of author to assist in its use, correction, modification or
+ * enhancement.
+ *
+ * AUTHOR SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF
+ * COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE OR ANY PART
+ * THEREOF.
+ *
+ * In no event will author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages, even if author has
+ * been advised of the possibility of such damages.
+ *
+ * @date Created: Sun Jun  9 12:43:17 1996 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/rc4.h"
+
+void rc4_init(const void *vseed, isize_t seed_len, rc4_t *state) {
+  short i; rc4_u8 j; rc4_u8 k;
+
+  const rc4_u8 *seed = (const rc4_u8 *)vseed;
+  rc4_u8 *array = state->rc4_array;
+
+  state->rc4_i = 0;     
+  state->rc4_j = 0;     
+
+  for (i = 0; i < 256; i++)              
+    array[i] = (rc4_u8) i;               
+
+  for (i = 0, j = 0, k = 0; 
+       i < 256; 
+       i++, k++, k >= seed_len ? k = 0 : 0) {
+    rc4_u8 a = array[i];
+    rc4_u8 b = array[j += a + seed[k]];
+
+    array[i] = b;
+    array[j] = a;
+  }       
+}
+
+void rc4(void *buffer, isize_t len, rc4_t *state) { 
+  rc4_u8 *buf = (rc4_u8 *)buffer;
+  rc4_u8 *array = state->rc4_array;
+  rc4_u8 i = state->rc4_i;     
+  rc4_u8 j = state->rc4_j;
+    
+  while (len-- > 0) {               
+    rc4_u8 a = array[++i];	
+    rc4_u8 b = array[j += a];
+
+    array[i] = b;
+    array[j] = a;
+
+    *buf++ ^= array[(a + b) & 255];         
+  }               
+
+  state->rc4_i = i;     
+  state->rc4_j = j;
+}
+
+#ifdef RC4_TESTING
+
+rc4_u8 key_0[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+rc4_u8 input_0[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+rc4_u8 output_0[] = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 };
+
+rc4_u8 key_1[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, };
+rc4_u8 input_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_1[] = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79, };
+
+rc4_u8 key_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 input_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_2[] = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a, };
+
+rc4_u8 key_3[] = { 0xef, 0x01, 0x23, 0x45, };
+rc4_u8 input_3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_3[] = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61, }; 
+rc4_u8 key_4[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, };
+rc4_u8 input_4[] = { 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
+  0x01, };
+
+rc4_u8 output_4[] = { 
+  0x75, 0x95, 0xc3, 0xe6, 0x11, 0x4a, 0x09, 0x78, 0x0c, 0x4a, 0xd4, 
+  0x52, 0x33, 0x8e, 0x1f, 0xfd, 0x9a, 0x1b, 0xe9, 0x49, 0x8f, 
+  0x81, 0x3d, 0x76, 0x53, 0x34, 0x49, 0xb6, 0x77, 0x8d, 0xca, 
+  0xd8, 0xc7, 0x8a, 0x8d, 0x2b, 0xa9, 0xac, 0x66, 0x08, 0x5d, 
+  0x0e, 0x53, 0xd5, 0x9c, 0x26, 0xc2, 0xd1, 0xc4, 0x90, 0xc1, 
+  0xeb, 0xbe, 0x0c, 0xe6, 0x6d, 0x1b, 0x6b, 0x1b, 0x13, 0xb6, 
+  0xb9, 0x19, 0xb8, 0x47, 0xc2, 0x5a, 0x91, 0x44, 0x7a, 0x95, 
+  0xe7, 0x5e, 0x4e, 0xf1, 0x67, 0x79, 0xcd, 0xe8, 0xbf, 0x0a, 
+  0x95, 0x85, 0x0e, 0x32, 0xaf, 0x96, 0x89, 0x44, 0x4f, 0xd3, 
+  0x77, 0x10, 0x8f, 0x98, 0xfd, 0xcb, 0xd4, 0xe7, 0x26, 0x56, 
+  0x75, 0x00, 0x99, 0x0b, 0xcc, 0x7e, 0x0c, 0xa3, 0xc4, 0xaa, 
+  0xa3, 0x04, 0xa3, 0x87, 0xd2, 0x0f, 0x3b, 0x8f, 0xbb, 0xcd, 
+  0x42, 0xa1, 0xbd, 0x31, 0x1d, 0x7a, 0x43, 0x03, 0xdd, 0xa5, 
+  0xab, 0x07, 0x88, 0x96, 0xae, 0x80, 0xc1, 0x8b, 0x0a, 0xf6, 
+  0x6d, 0xff, 0x31, 0x96, 0x16, 0xeb, 0x78, 0x4e, 0x49, 0x5a, 
+  0xd2, 0xce, 0x90, 0xd7, 0xf7, 0x72, 0xa8, 0x17, 0x47, 0xb6, 
+  0x5f, 0x62, 0x09, 0x3b, 0x1e, 0x0d, 0xb9, 0xe5, 0xba, 0x53, 
+  0x2f, 0xaf, 0xec, 0x47, 0x50, 0x83, 0x23, 0xe6, 0x71, 0x32, 
+  0x7d, 0xf9, 0x44, 0x44, 0x32, 0xcb, 0x73, 0x67, 0xce, 0xc8, 
+  0x2f, 0x5d, 0x44, 0xc0, 0xd0, 0x0b, 0x67, 0xd6, 0x50, 0xa0, 
+  0x75, 0xcd, 0x4b, 0x70, 0xde, 0xdd, 0x77, 0xeb, 0x9b, 0x10, 
+  0x23, 0x1b, 0x6b, 0x5b, 0x74, 0x13, 0x47, 0x39, 0x6d, 0x62, 
+  0x89, 0x74, 0x21, 0xd4, 0x3d, 0xf9, 0xb4, 0x2e, 0x44, 0x6e, 
+  0x35, 0x8e, 0x9c, 0x11, 0xa9, 0xb2, 0x18, 0x4e, 0xcb, 0xef, 
+  0x0c, 0xd8, 0xe7, 0xa8, 0x77, 0xef, 0x96, 0x8f, 0x13, 0x90, 
+  0xec, 0x9b, 0x3d, 0x35, 0xa5, 0x58, 0x5c, 0xb0, 0x09, 0x29, 
+  0x0e, 0x2f, 0xcd, 0xe7, 0xb5, 0xec, 0x66, 0xd9, 0x08, 0x4b, 
+  0xe4, 0x40, 0x55, 0xa6, 0x19, 0xd9, 0xdd, 0x7f, 0xc3, 0x16, 
+  0x6f, 0x94, 0x87, 0xf7, 0xcb, 0x27, 0x29, 0x12, 0x42, 0x64, 
+  0x45, 0x99, 0x85, 0x14, 0xc1, 0x5d, 0x53, 0xa1, 0x8c, 0x86, 
+  0x4c, 0xe3, 0xa2, 0xb7, 0x55, 0x57, 0x93, 0x98, 0x81, 0x26, 
+  0x52, 0x0e, 0xac, 0xf2, 0xe3, 0x06, 0x6e, 0x23, 0x0c, 0x91, 
+  0xbe, 0xe4, 0xdd, 0x53, 0x04, 0xf5, 0xfd, 0x04, 0x05, 0xb3, 
+  0x5b, 0xd9, 0x9c, 0x73, 0x13, 0x5d, 0x3d, 0x9b, 0xc3, 0x35, 
+  0xee, 0x04, 0x9e, 0xf6, 0x9b, 0x38, 0x67, 0xbf, 0x2d, 0x7b, 
+  0xd1, 0xea, 0xa5, 0x95, 0xd8, 0xbf, 0xc0, 0x06, 0x6f, 0xf8, 
+  0xd3, 0x15, 0x09, 0xeb, 0x0c, 0x6c, 0xaa, 0x00, 0x6c, 0x80, 
+  0x7a, 0x62, 0x3e, 0xf8, 0x4c, 0x3d, 0x33, 0xc1, 0x95, 0xd2, 
+  0x3e, 0xe3, 0x20, 0xc4, 0x0d, 0xe0, 0x55, 0x81, 0x57, 0xc8, 
+  0x22, 0xd4, 0xb8, 0xc5, 0x69, 0xd8, 0x49, 0xae, 0xd5, 0x9d, 
+  0x4e, 0x0f, 0xd7, 0xf3, 0x79, 0x58, 0x6b, 0x4b, 0x7f, 0xf6, 
+  0x84, 0xed, 0x6a, 0x18, 0x9f, 0x74, 0x86, 0xd4, 0x9b, 0x9c, 
+  0x4b, 0xad, 0x9b, 0xa2, 0x4b, 0x96, 0xab, 0xf9, 0x24, 0x37, 
+  0x2c, 0x8a, 0x8f, 0xff, 0xb1, 0x0d, 0x55, 0x35, 0x49, 0x00, 
+  0xa7, 0x7a, 0x3d, 0xb5, 0xf2, 0x05, 0xe1, 0xb9, 0x9f, 0xcd, 
+  0x86, 0x60, 0x86, 0x3a, 0x15, 0x9a, 0xd4, 0xab, 0xe4, 0x0f, 
+  0xa4, 0x89, 0x34, 0x16, 0x3d, 0xdd, 0xe5, 0x42, 0xa6, 0x58, 
+  0x55, 0x40, 0xfd, 0x68, 0x3c, 0xbf, 0xd8, 0xc0, 0x0f, 0x12, 
+  0x12, 0x9a, 0x28, 0x4d, 0xea, 0xcc, 0x4c, 0xde, 0xfe, 0x58, 
+  0xbe, 0x71, 0x37, 0x54, 0x1c, 0x04, 0x71, 0x26, 0xc8, 0xd4, 
+  0x9e, 0x27, 0x55, 0xab, 0x18, 0x1a, 0xb7, 0xe9, 0x40, 0xb0, 
+  0xc0, };
+
+#include <stdio.h>
+
+void printout(const char *title, rc4_u8 *data, int len) {
+  int i;
+
+  puts(title);
+
+  for (i = 0; i < len; i++) {
+    printf("0x%02x ", data[i]);
+  }
+  
+  putchar('\n');
+}
+
+int main() {
+  int failed = 0;
+
+  rc4_t state[1];
+
+  rc4_init(key_0, sizeof key_0, state);
+  rc4(input_0, sizeof input_0, state);
+  if (memcmp(input_0, output_0, sizeof input_0)) {
+    printout("Test 0 output", input_0, sizeof input_0);
+    failed = 1;
+  }
+
+  if (!failed) {
+    puts("RC4 seems to work\n");
+  }
+
+  rc4_prepare_key(key_1, sizeof key_1, state);
+  rc4(input_1, sizeof input_1, state);
+  if (memcmp(input_1, output_1, sizeof input_1)) {
+    printout("Test 1 output", input_1, sizeof input_1);
+    failed = 1;
+  }
+
+  rc4_prepare_key(key_2, sizeof key_2, state);
+  rc4(input_2, sizeof input_2, state);
+  if (memcmp(input_2, output_2, sizeof input_2)) {
+    printout("Test 2 output", input_2, sizeof input_2);
+    failed = 1;
+  }
+
+  rc4_prepare_key(key_3, sizeof key_3, state);
+  rc4(input_3, sizeof input_3, state);
+  if (memcmp(input_3, output_3, sizeof input_3)) {
+    printout("Test 3 output", input_3, sizeof input_3);
+    failed = 1;
+  }
+
+  rc4_prepare_key(key_4, sizeof key_4, state);
+  rc4(input_4, sizeof input_4, state);
+  if (memcmp(input_4, output_4, sizeof input_4)) {
+    printout("Test 4 output", input_4, sizeof input_4);
+    failed = 1;
+  }
+
+  exit(failed);
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+/**@file sofia-sip/base64.h
+ *
+ * @brief Base64 encoding and decoding functions.
+ *
+ * This module contains base64 encoding and decoding functions.  Base64
+ * encodes arbitrary octet strings as strings containing characters @c
+ * [A-Za-z0-9+/=]. Base64 is defined as part of MIME mail format, but it is
+ * used widely by other text-based protocols as well.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, 
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein, 
+ * November 1996.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Decode a BASE64-encoded string. */
+SOFIAPUBFUN isize_t base64_d(char buf[], isize_t bsiz, char const *b64s);
+/** Encode data with BASE64. */
+SOFIAPUBFUN isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz);
+
+/** Calculate size of n bytes encoded in base64 */
+#define BASE64_SIZE(n) ((((n) + 2) / 3) * 4)
+
+SOFIA_END_DECLS
+
+#endif /* !BASE_64 */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef RC4_H
+/** Defined when <sofia-sip/rc4.h> has been included. */
+#define RC4_H
+
+/**@file sofia-sip/rc4.h
+ * @brief Arcfour random number generator.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Sun Jun  9 14:32:58 1996 ppessi
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+/** Byte. */
+typedef uint8_t rc4_u8;
+
+/** RC4 context. 
+ * 
+ * The RC4 context is accessed and modified through rc4_init() and rc4()
+ * functions only.
+ */
+typedef struct {      
+  uint8_t rc4_i;        
+  uint8_t rc4_j;
+  uint8_t rc4_array[256];       
+} rc4_t;
+
+/** Key RC4 context. */
+SOFIAPUBFUN void rc4_init(const void *seed, isize_t seed_len, rc4_t *state);
+
+/** Generate RC4 stream. */ 
+SOFIAPUBFUN void rc4(void *buffer, isize_t len, rc4_t *state);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* !defined RC4_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STRING0_H
+/** Defined when <sofia-sip/string0.h> is included. */
+#define STRING0_H
+
+/**@file sofia-sip/string0.h
+ *
+ * @brief String comparison functions accepting NULL pointers
+ *
+ * This module contains string comparison functions that can be called
+ * with NULL pointer as argument.
+ *
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+#include <string.h>
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_INLINE
+su_inline
+#else
+SOFIAPUBFUN
+#endif
+int 
+  str0cmp(char const *a, char const *b),
+  str0ncmp(char const *a, char const *b, size_t n),
+  str0casecmp(char const *a, char const *b),
+  str0ncasecmp(char const *a, char const *b, size_t n);
+
+#if SU_HAVE_INLINE
+su_inline
+#else
+SOFIAPUBFUN
+#endif
+size_t
+strnspn(char const *s, size_t size, char const *term),
+  strncspn(char const *s, size_t ssize, char const *reject);
+
+#if SU_HAVE_INLINE
+int str0cmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcmp(a, b);
+}
+
+int str0ncmp(char const *a, char const *b, size_t n)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strncmp(a, b, n);
+}
+
+int str0casecmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcasecmp(a, b);
+}
+
+int str0ncasecmp(char const *a, char const *b, size_t n)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strncasecmp(a, b, n);
+}
+
+size_t strnspn(char const *s, size_t ssize, char const *term)
+{
+  size_t n;
+  size_t tsize = strlen(term);
+
+  if (tsize == 0) {
+    return 0;
+  }
+  else if (tsize == 1) {
+    char c, t = term[0];
+    for (n = 0; n < ssize && (c = s[n]) && c == t; n++)
+      ;
+  }
+  else if (tsize == 2) {
+    char c, t1 = term[0], t2 = term[1];
+    for (n = 0; n < ssize && (c = s[n]) && (c == t1 || c == t2); n++)
+      ;
+  }
+  else {
+    size_t i;
+    char c, t1 = term[0], t2 = term[1];
+    for (n = 0; n < ssize && (c = s[n]) && (c == t1 || c == t2); n++) {
+      for (i = 2; i < tsize; i++)
+	if (c == term[i])
+	  return n;
+    }
+  }
+
+  return n;
+}
+
+size_t strncspn(char const *s, size_t ssize, char const *reject)
+{
+  size_t n;
+  size_t rsize = strlen(reject);
+
+  if (rsize == 0) {
+    for (n = 0; n < ssize && s[n]; n++)
+      ;
+  }
+  else if (rsize == 1) {
+    char c, rej = reject[0];
+    for (n = 0; n < ssize && (c = s[n]) && c != rej; n++)
+      ;
+  }
+  else if (rsize == 2) {
+    char c, rej1 = reject[0], rej2 = reject[1];
+    for (n = 0; n < ssize && (c = s[n]) && c != rej1 && c != rej2; n++)
+      ;
+  }
+  else {
+    size_t i;
+    char c, rej1 = reject[0], rej2 = reject[1];
+    for (n = 0; n < ssize && (c = s[n]) && c != rej1 && c != rej2; n++) {
+      for (i = 2; i < rsize; i++)
+	if (c == reject[i])
+	  return n;
+    }
+  }
+
+  return n;
+}
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* !STRING0_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TOKEN64_H
+#define TOKEN64_H
+
+/**@file sofia-sip/token64.h
+ *
+ * @brief Token64 encoding.
+ *
+ * This module contains token64 encoding functions. Token64 encodes
+ * arbitrary octet strings as http header tokens containing only characters
+ * in range @c [-+A-Za-z0-9].
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN isize_t token64_e(char b[], isize_t bsiz,
+			      void const *data, isize_t dlen);
+
+/** Calculate size of n bytes encoded in token-64 */
+#define TOKEN64_SIZE(n) (((n + 2) / 3) * 4)
+
+SOFIA_END_DECLS
+
+#endif /* !TOKEN64_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef UNIQUEID_H
+/** Defined when <sofia-sip/uniqueid.h> has been included. */
+#define UNIQUEID_H 
+
+/**@file sofia-sip/uniqueid.h
+ *
+ * Compatibility functions to handle GloballyUniqueID.
+ *
+ * This file just includes <su_uniqueid.h>.
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ */
+
+/* Compatibility functionality */
+#define guid_t su_guid_t 
+#define guid_generate su_guid_generate
+#define guid_sprintf su_guid_sprintf
+#define guid_strlen su_guid_strlen
+#define randint su_randint
+#define randmem su_randmem
+
+#include <sofia-sip/su_uniqueid.h>
+
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/utf8.h
+ * Encoding/Decoding Functions for UCS Transformation Format UTF-8.
+ *
+ * UTF-8 encoding codes the ISO 10646 (Unicode, UCS2 and UCS4) characters as
+ * variable length (1 - 6 bytes) strings of 8-bit characters.
+ *
+ * @author Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:38 1998 pessi
+
+ * @sa <a href="ftp://ftp.ietf.org/rfc/rfc2279.txt">RFC 2279</a>, 
+ * <i>"UTF-8, a transformation format of ISO 10646"</i>,
+ * F. Yergeau. January 1998.
+ *
+ */
+
+#ifndef UTF8_H
+/** Defined when <sofia-sip/utf8.h> has been included */
+#define	UTF8_H
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef unsigned char  utf8;
+typedef unsigned short utf16;
+typedef unsigned char  ucs1;
+typedef unsigned short ucs2;
+typedef unsigned int   ucs4;
+
+SOFIAPUBFUN size_t utf8_width(const utf8 *);
+
+/* Latin-1 encoding/decoding */
+SOFIAPUBFUN size_t ucs18decode(char *dst, size_t dst_size, const utf8 *s);
+SOFIAPUBFUN size_t ucs1encode(utf8 *dst, const ucs1 *s, size_t n,
+			      const char quote[128]);
+SOFIAPUBFUN size_t ucs1declen(const utf8 *s);
+SOFIAPUBFUN size_t ucs1enclen(const ucs1 *s, size_t n, const char quote[128]);
+
+/* UCS2 (BMP) encoding/decoding */
+size_t ucs2decode(ucs2 *dst, size_t dst_size, const utf8 *s);
+size_t ucs2encode(utf8 *dst, const ucs2 *s, size_t n, const char quote[128]);
+size_t ucs2declen(const utf8 *s);
+size_t ucs2enclen(const ucs2 *s, size_t n, const char quote[128]);
+
+size_t ucs4decode(ucs4 *dst, size_t dst_size, const utf8 *s);
+size_t ucs4encode(utf8 *dst, const ucs4 *s, size_t n, const char quote[128]);
+size_t ucs4declen(const utf8 *s);
+size_t ucs4enclen(const ucs4 *s, size_t n, const char quote[128]);
+
+size_t ucs2len(ucs2 const *s);
+int ucs2cmp(ucs2 const *s1, ucs2 const *s2);
+int ucs2ncmp(ucs2 const *s1, ucs2 const *s2, size_t n);
+
+size_t ucs4len(ucs4 const *s);
+int ucs4cmp(ucs4 const *s1, ucs4 const *s2);
+int ucs4ncmp(ucs4 const *s1, ucs4 const *s2, size_t n);
+
+/*
+ * IS_UCS4_n tests whether UCS4 character should be represented 
+ * with 'n' byte utf8 string
+ */
+#define IS_UCS4_1(x) ((ucs4)(x) <= 0x7fu)
+#define IS_UCS4_2(x) (0x80u <= (ucs4)(x) && (ucs4)(x) <= 0x7ffu)
+#define IS_UCS4_3(x) (0x800u <= (ucs4)(x) && (ucs4)(x) <= 0xffffu)
+#define IS_UCS4_4(x) (0x10000u <= (ucs4)(x) && (ucs4)(x) <= 0x1fFFFFu)
+#define IS_UCS4_5(x) (0x200000u <= (ucs4)(x) && (ucs4)(x) <= 0x3ffFFFFu)
+#define IS_UCS4_6(x) (0x4000000u <= (ucs4)(x) && (ucs4)(x) <= 0x7fffFFFFu)
+
+/* Special test for ISO-8859-1 characters */
+#define IS_UCS4_I(x) (0x80u <= (ucs4)(x) && (ucs4)(x) <= 0xffu)
+
+/* Length of an UCS4 character in UTF8 encoding */
+#define UTF8_LEN4(x) (IS_UCS4_1(x) || IS_UCS4_2(x) && 2 || \
+		      IS_UCS4_3(x) && 3 || IS_UCS4_4(x) && 4 || \
+		      IS_UCS4_5(x) && 5 || IS_UCS4_6(x) && 6)
+
+/* Length of an UCS2 character in UTF8 encoding */
+#define UTF8_LEN2(x) (IS_UCS4_1(x) || IS_UCS4_2(x) && 2 || IS_UCS4_3(x) && 3)
+
+/*
+ * IS_UTF8_n tests the length of the next wide character
+ */
+#define IS_UTF8_1(c) (0x00 == ((c) & 0x80))
+#define IS_UTF8_2(c) (0xc0 == ((c) & 0xe0))
+#define IS_UTF8_3(c) (0xe0 == ((c) & 0xf0))
+#define IS_UTF8_4(c) (0xf0 == ((c) & 0xf8))
+#define IS_UTF8_5(c) (0xf8 == ((c) & 0xfc))
+#define IS_UTF8_6(c) (0xfc == ((c) & 0xfe))
+
+/* Extension byte? */
+#define IS_UTF8_X(c) (0x80 == ((c) & 0xc0))
+/* ISO-8859-1 character? */
+#define IS_UTF8_I(c) (0xc0 == ((c) & 0xfc))
+
+#define IS_UTF8_S1(s) \
+(IS_UTF8_1(s[0]))
+#define IS_UTF8_S2(s) \
+(IS_UTF8_2(s[0])&&((s)[1]&192)==128)
+#define IS_UTF8_SI(s) \
+(IS_UTF8_I(s[0])&&((s)[1]&192)==128)
+#define IS_UTF8_S3(s) \
+(IS_UTF8_3(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128)
+#define IS_UTF8_S4(s) \
+(IS_UTF8_4(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&((s)[3]&192)==128)
+#define IS_UTF8_S5(s) \
+(IS_UTF8_5(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&\
+ ((s)[3]&192)==128&&((s)[4]&192)==128)
+#define IS_UTF8_S6(s) \
+(IS_UTF8_6(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&((s)[3]&192)==128&&\
+ ((s)[4]&192)==128&&((s)[5]&192)==128)
+
+#define UCS4_S1(s) ((ucs4)(s[0]))
+#define UCS4_S2(s) ((ucs4)\
+		    (((s[0])&31)<<6)|((s[1])&63))
+#define UCS4_S3(s) ((ucs4)\
+	            (((s[0])&15)<<12)|(((s[1])&63)<<6)|((s[2])&63))
+#define UCS4_S4(s) ((ucs4)\
+	            (((s[0])&7)<<18)|(((s[1])&63)<<12)|(((s[2])&63)<<6)|\
+	            ((s[3])&63))
+#define UCS4_S5(s) ((ucs4)\
+	            (((s[0])&3)<<24)|(((s[1])&63)<<18)|(((s[2])&63)<<12)|\
+	            (((s[3])&63)<<6)|((s[4])&63))
+#define UCS4_S6(s) ((ucs4)\
+		    (((s[0])&1)<<30)|(((s[1])&63)<<24)|(((s[2])&63)<<18)|\
+		    (((s[3])&63)<<12)|(((s[4])&63)<<6)|((s[5])&63))
+
+#define UTF8_S1(s,c) ((s)[0]=(c))
+#define UTF8_S2(s,c) ((s)[0]=(((c)>>6)&31)|0xc0,\
+		      (s)[1]=((c)&63)|128)
+#define UTF8_S3(s,c) ((s)[0]=(((c)>>12)&15)|0xe0,\
+		      (s)[1]=((c>>6)&63)|128,\
+		      (s)[2]=((c)&63)|128)
+#define UTF8_S4(s,c) ((s)[0]=(((c)>>18)&7)|0xf0,\
+		      (s)[1]=((c>>12)&63)|128,\
+		      (s)[2]=((c>>6)&63)|128,\
+		      (s)[3]=((c)&63)|128)
+#define UTF8_S5(s,c) ((s)[0]=(((c)>>24)&3)|0xf8,\
+		      (s)[1]=((c>>18)&63)|128,\
+		      (s)[2]=((c>>12)&63)|128,\
+		      (s)[3]=((c>>6)&63)|128,\
+		      (s)[4]=((c)&63)|128)
+#define UTF8_S6(s,c) ((s)[0]=(((c)>>30)&1)|0xfc,\
+		      (s)[1]=((c>>24)&63)|128,\
+		      (s)[2]=((c>>18)&63)|128,\
+		      (s)[3]=((c>>12)&63)|128,\
+		      (s)[4]=((c>>6)&63)|128,\
+		      (s)[5]=((c)&63)|128)
+     
+SOFIA_END_DECLS
+
+#endif /* UTF8_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE string0.c
+ *
+ * Expand string0 functions non-inline.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sofia-sip/su_config.h>
+
+#undef SU_HAVE_INLINE
+#undef su_inline
+
+#define SU_HAVE_INLINE 1
+#define su_inline
+
+#include "sofia-sip/string0.h"

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE token64.c  
+ *
+ * Token encoding.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Apr  3 10:45:47 2002 ppessi 
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <assert.h>
+
+#include "sofia-sip/token64.h"
+
+static const char code[65] = 
+"0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/** Encode data as an http token. 
+ *
+ * @note
+ * A token is case-independent, so this is really not a good idea.
+ * Use msg_random_token() instead.
+ */
+isize_t token64_e(char b[], isize_t bsiz, void const *data, isize_t dlen)
+{
+  size_t i, n, slack;
+  unsigned char const *h = data;
+  char *s = b, *end = b + bsiz;
+  long w;
+
+  if (dlen <= 0) {
+    if (bsiz && b) *b = '\0';
+    return 0;
+  }
+
+  n = (8 * dlen + 5) / 6;
+  if (bsiz == 0 || b == NULL)
+    return n;
+
+  if (b + n >= end)
+    dlen = 6 * bsiz / 8;
+  else
+    end = b + n + 1;
+
+  slack = dlen % 3;
+  dlen -= slack;
+
+  for (i = 0; i < dlen; i += 3, s += 4) {
+    unsigned char h0 = h[i], h1 = h[i + 1], h2 = h[i + 2];
+    
+    s[0] = code[h0 >> 2];
+    s[1] = code[((h0 << 4)|(h1 >> 4)) & 63];
+    s[2] = code[((h1 << 4)|(h2 >> 6)) & 63];
+    s[3] = code[(h2) & 63];
+  }
+
+  if (slack) {
+    if (slack == 2)
+      w = (h[i] << 16) | (h[i+1] << 8);
+    else
+      w = (h[i] << 16);
+
+    if (s < end) *s++ = code[(w >> 18) & 63];
+    if (s < end) *s++ = code[(w >> 12) & 63];
+    if (s < end && slack == 2) *s++ = code[(w >> 6) & 63];
+  }
+
+  if (s < end)
+    *s++ = '\0';
+  else
+    end[-1] = '\0';
+
+  assert(end == s);
+
+  return n;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,187 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_base64.c
+ * @brief Test BASE64 encoding/decoding
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com> \n
+ *
+ * @date Created: Tue Feb  1 13:29:09 EET 2005 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sofia-sip/base64.h"
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+char const *name = "torture_base64";
+
+#include <sofia-sip/tstdef.h>
+
+char const constant[] = "not changed";
+
+int test_encoding(void)
+{
+  char buffer[32];
+
+  BEGIN();
+
+  TEST_SIZE(base64_e(buffer, sizeof buffer, "\0\020\203", 3), 4);
+  TEST_S(buffer, "ABCD");
+
+  strcpy(buffer + 5, "not changed");
+  TEST_SIZE(base64_e(buffer, 5, "\0\020\203", 3), 4);
+  TEST_S(buffer + 5, "not changed");
+  TEST_S(buffer, "ABCD");
+
+  strcpy(buffer + 4, "not changed");
+  TEST_SIZE(base64_e(buffer, 4, "\0\020\203", 3), 4);
+  TEST_S(buffer + 4, "not changed");
+  TEST_S(buffer, "ABC");
+
+  strcpy(buffer + 3, "not changed");
+  TEST_SIZE(base64_e(buffer, 3, "\0\020\203", 3), 4);
+  TEST_S(buffer + 3, "not changed");
+  TEST_S(buffer, "AB");
+
+  strcpy(buffer + 2, "not changed");
+  TEST_SIZE(base64_e(buffer, 2, "\0\020\203", 3), 4);
+  TEST_S(buffer + 2, "not changed");
+  TEST_S(buffer, "A");
+
+  strcpy(buffer + 1, "not changed");
+  TEST_SIZE(base64_e(buffer, 1, "\0\020\203", 3), 4);
+  TEST_S(buffer + 1, "not changed");
+  TEST_S(buffer, "");
+
+  strcpy(buffer + 5, "not changed");
+  TEST_SIZE(base64_e(buffer, 5, "\0\020", 2), 4);
+  TEST_S(buffer + 5, "not changed");
+  TEST_S(buffer, "ABA=");
+
+  strcpy(buffer + 4, "not changed");
+  TEST_SIZE(base64_e(buffer, 4, "\0\020", 2), 4);
+  TEST_S(buffer + 4, "not changed");
+  TEST_S(buffer, "ABA");
+
+  strcpy(buffer + 3, "not changed");
+  TEST_SIZE(base64_e(buffer, 3, "\0\020", 2), 4);
+  TEST_S(buffer + 3, "not changed");
+  TEST_S(buffer, "AB");
+
+  strcpy(buffer + 2, "not changed");
+  TEST_SIZE(base64_e(buffer, 2, "\0\020", 2), 4);
+  TEST_S(buffer + 2, "not changed");
+  TEST_S(buffer, "A");
+
+  strcpy(buffer + 1, "not changed");
+  TEST_SIZE(base64_e(buffer, 1, "\0\020", 2), 4);
+  TEST_S(buffer + 1, "not changed");
+  TEST_S(buffer, "");
+
+  strcpy(buffer + 5, "not changed");
+  TEST_SIZE(base64_e(buffer, 5, "\0", 1), 4);
+  TEST_S(buffer + 5, "not changed");
+  TEST_S(buffer, "AA==");
+
+  strcpy(buffer + 4, "not changed");
+  TEST_SIZE(base64_e(buffer, 4, "\0", 1), 4);
+  TEST_S(buffer + 4, "not changed");
+  TEST_S(buffer, "AA=");
+
+  strcpy(buffer + 3, "not changed");
+  TEST_SIZE(base64_e(buffer, 3, "\0", 1), 4);
+  TEST_S(buffer + 3, "not changed");
+  TEST_S(buffer, "AA");
+
+  strcpy(buffer + 2, "not changed");
+  TEST_SIZE(base64_e(buffer, 2, "\0", 1), 4);
+  TEST_S(buffer + 2, "not changed");
+  TEST_S(buffer, "A");
+
+  strcpy(buffer + 1, "not changed");
+  TEST_SIZE(base64_e(buffer, 1, "\0", 1), 4);
+  TEST_S(buffer + 1, "not changed");
+  TEST_S(buffer, "");
+
+  END();
+}
+
+int test_decoding(void)
+{
+  char buffer[32];
+
+  BEGIN();
+
+  strcpy(buffer + 0, "not changed");
+  TEST_SIZE(base64_d((void *)buffer, 0, "ABCD"), 3);
+  TEST_S(buffer + 0, "not changed");
+
+  TEST_SIZE(base64_d((void *)buffer, 3, "ABCD"), 3);
+  TEST_M(buffer, "\0\020\203", 3);
+
+  TEST_SIZE(base64_d(NULL, 3, "ABCD"), 3);
+
+  TEST_SIZE(base64_d((void *)buffer, 3, "A B C D !!"), 3);
+  TEST_M(buffer, "\0\020\203", 3);
+
+  END();
+}
+
+
+void usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-v]\n",
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_encoding(); fflush(stdout);
+  retval |= test_decoding(); fflush(stdout);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,192 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE ucs2.c UCS2 (Unicode, ISO Basic Multilingual Plane) string handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ *
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+/*
+ * Decode utf8 string into ucs2 string, 
+ * return number of ucs2 characters decoded
+ */
+size_t ucs2decode(ucs2 *dst, size_t dst_size, const utf8 *s)
+{
+  ucs2 v, *d = dst;
+
+  if (s) do {
+    if (dst_size == 0)
+      break;
+    if (IS_UTF8_S1(s))
+      v = UCS4_S1(s), s += 1;
+    else if (IS_UTF8_S2(s))
+      v = UCS4_S2(s), s += 2;
+    else if (IS_UTF8_S3(s))
+      v = UCS4_S3(s), s += 3;
+    else {
+      s++;
+      continue;			/* skip illegal characters */
+    }
+    *d++ = v;
+    dst_size--;
+  } while (*s);
+
+  if (dst_size)
+    *d = 0;
+
+  return d - dst;
+}
+
+/*
+ * Encode ucs2 string into utf8 string,
+ * return number of utf8 bytes encoded including final zero
+ *
+ * 'quote' may contain an optional quoting table containing 
+ * non-zero for all ASCII characters to quote
+ * 
+ */
+size_t ucs2encode(utf8 *dst, const ucs2 *s, size_t n, const char quote[128])
+{
+  utf8 *d = dst;
+  ucs2 c;
+
+  if (s) while (n-- > 0) {
+    c = *s++;
+
+    if (IS_UCS4_1(c)) {
+      if (quote && quote[c]) {
+	UTF8_S2(d, c);
+	d += 2;
+      }
+      else {
+	if (!c)			/* zero must be represented as UTF8_2 */
+	  break;
+	UTF8_S1(d, (utf8) c);
+	d += 1;
+      }
+    }
+    else if (IS_UCS4_2(c)) {
+      UTF8_S2(d, c);
+      d += 2;
+    }
+    else /* if (IS_UCS4_3(c)) */ {
+      UTF8_S3(d, c);
+      d += 3;
+    }
+  }
+
+  *d++ = 0;
+  return d - dst;
+}
+
+/*
+ * Length of UCS2 (BMP, Unicode) string decoded from UTF8
+ */
+size_t ucs2declen(const utf8 *s)
+{
+  size_t len = 0;
+  size_t errors = 0;		/* errors */
+
+  UTF8_ANALYZE(s, len, len, len, errors, errors);
+
+  if (errors)
+    return 0;
+
+  return len;
+}
+
+/*
+ * Length of UTF8 encoding of a UCS2 string, including final zero
+ */
+size_t ucs2enclen(const ucs2 *s, size_t n, const char quote[128])
+{
+  size_t len = 1;
+  ucs2 c;
+  
+  while (n-- > 0) {
+    c = *s++;
+    if (c < 0x80u)
+      if (quote && quote[c])
+	len += 2;
+      else {
+	if (!c) break;
+	len += 1;
+      }
+    else if (c < 0x800u)
+      len += 2;
+    else /* if (c < 0x10000u) */
+      len += 3;
+  }
+
+  return len;
+}
+
+/*
+ * Length of UCS2 string (number of non-zero UCS2 characters before zero)
+ */
+size_t ucs2len(ucs2 const *s)
+{
+  size_t len = 0;
+
+  if (s) while (*s++) 
+    len++;
+
+  return len;
+}
+
+/*
+ * Compare UCS2 (BMP, Unicode) string
+ */
+int ucs2cmp(ucs2 const *s1, ucs2 const *s2)
+{
+  int retval = s1 - s2;
+
+  if (s1 && s2) 
+    while ((retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+      ;
+
+  return retval;
+}
+
+/*
+ * Compare UCS2 (BMP, Unicode) string
+ */
+int ucs2ncmp(ucs2 const *s1, ucs2 const *s2, size_t n)
+{
+  int retval = 0;
+
+  if (s1 && s2) 
+    while (n-- > 0 && (retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+      ;
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE ucs4.c UCS-4 routines
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+/*
+ * Decode utf8 string into ucs4 string, 
+ * return number of ucs4 characters decoded
+ */
+size_t ucs4decode(ucs4 *dst, size_t dst_size, const utf8 *s)
+{
+  ucs4 v, *d = dst;
+
+  if (s) while (*s) {
+    if (dst_size == 0)
+      break;
+    if (IS_UTF8_S1(s))
+      v = UCS4_S1(s), s += 1;
+    else if (IS_UTF8_S2(s))
+      v = UCS4_S2(s), s += 2;
+    else if (IS_UTF8_S3(s))
+      v = UCS4_S3(s), s += 3;
+    else if (IS_UTF8_S4(s))
+      v = UCS4_S4(s), s += 4;
+    else if (IS_UTF8_S5(s))
+      v = UCS4_S5(s), s += 5;
+    else if (IS_UTF8_S6(s))
+      v = UCS4_S6(s), s += 6;
+    else {
+      s++;
+      continue;			/* skip illegal characters */
+    }
+    *d++ = v;
+    dst_size--;
+  };
+
+  if (dst_size)
+    *d = 0;
+
+  return d - dst;
+}
+
+/*
+ * Encode ucs4 string into utf8 string,
+ * return number of utf8 bytes encoded including final zero
+ *
+ * 'quote' may contain an optional quoting table containing 
+ * non-zero for all ASCII characters to quote
+ * 
+ */
+size_t ucs4encode(utf8 *dst, const ucs4 *s, size_t n, const char quote[128])
+{
+  utf8 *d = dst;
+  ucs4 c;
+
+  if (s) while (n-- > 0) {
+    c = *s++;
+
+    if (IS_UCS4_1(c)) {
+      if (quote && quote[c]) {
+	UTF8_S2(d, c);
+	d += 2;
+      }
+      else {
+	if (!c)			/* zero must be represented as UTF8_2 */
+	  break;
+	UTF8_S1(d, c);
+	d += 1;
+      }
+    }
+    else if (IS_UCS4_2(c)) {
+      UTF8_S2(d, c);
+      d += 2;
+    }
+    else if (IS_UCS4_3(c)) {
+      UTF8_S3(d, c);
+      d += 3;
+    }
+    else if (IS_UCS4_4(c)) {
+      UTF8_S4(d, c);
+      d += 4;
+    }
+    else if (IS_UCS4_5(c)) {
+      UTF8_S5(d, c);
+      d += 5;
+    }
+    else if (IS_UCS4_6(c)) {
+      UTF8_S6(d, c);
+      d += 6;
+    }
+    else {
+      /* skip illegal (negative) characters */
+    }
+  }
+
+  *d++ = 0;
+  return d - dst;
+}
+
+/*
+ * Length of UCS4 string decoded from UTF8
+ */
+size_t ucs4declen(const utf8 *s)
+{
+  size_t len = 0;
+  size_t errors = 0;		/* errors */
+
+  UTF8_ANALYZE(s, len, len, len, len, errors);
+
+  if (errors)
+    return 0;
+
+  return len;
+}
+
+/*
+ * Length of UTF8 encoding of a UCS4 string, including final zero
+ */
+size_t ucs4enclen(const ucs4 *s, size_t n, const char quote[128])
+{
+  size_t len = 1;
+  ucs4 c;
+  
+  while (n-- > 0) {
+    c = *s++;
+    if (c < 0x80u)
+      if (quote && quote[c])
+	len += 2;
+      else {
+	if (!c) break;
+	len += 1;
+      }
+    else if (c < 0x800u)
+      len += 2;
+    else if (c < 0x10000u)
+      len += 3;
+    else if (c < 0x200000u)
+      len += 4;
+    else if (c < 0x4000000u)
+      len += 5;
+    else if (c < 0x80000000u)
+      len += 6;
+  }
+
+  return len;
+}
+
+/*
+ * Length of UCS4 string (number of non-zero UCS4 characters before zero)
+ */
+size_t ucs4len(ucs4 const *s)
+{
+  size_t len = 0;
+
+  if (s) while (*s++) 
+    len++;
+
+  return len;
+}
+
+/*
+ * Compare UCS4 string
+ */
+int ucs4cmp(ucs4 const *s1, ucs4 const *s2)
+{
+  int retval;
+
+  while ((retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+    ;
+
+  return retval;
+}
+
+/*
+ * Compare UCS4 string prefix 
+ */
+int ucs4ncmp(ucs4 const *s1, ucs4 const *s2, size_t n)
+{
+  int retval = 0;
+
+  while (n-- > 0 && (retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+    ;
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE utf8.c 
+ *
+ * utf8 string handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+#ifndef _WIN32
+#include <assert.h>
+#endif
+
+/** Width of an UTF8 character cell (1, 2 or 4 bytes) */
+size_t utf8_width(const utf8 *s)
+{
+  size_t w8 = 0, w16 = 0, w32 = 0;
+  size_t errors = 0;		/* errors */
+
+  UTF8_ANALYZE(s, w8, w8, w16, w32, errors);
+
+  if (errors)
+    return 0;
+
+  return w32 ? 4 : (w16 ? 2 : 1);
+}
+
+/** Convert UTF8 string @a s to ISO-Latin-1 string @a dst. */
+size_t ucs18decode(char *dst, size_t dst_size, const utf8 *s)
+{
+#ifndef _WIN32
+  assert(!"implemented");
+#endif
+  return 0;
+}
+
+/** Convert ISO-Latin-1 string @a s to UTF8 string in @a dst. */
+size_t ucs1encode(utf8 *dst, const ucs1 *s, size_t n, const char quote[128])
+{
+#ifndef _WIN32
+  assert(!"implemented");
+#endif
+  return 0;
+}
+
+/** Calculate number of characters in UTF8 string @a s. */
+size_t ucs1declen(const utf8 *s)
+{
+#ifndef _WIN32
+  assert(!"implemented");
+#endif
+  return 0;
+}
+
+/** Calculate length of UTF8 encoding of string @a s. */
+size_t ucs1enclen(const ucs1 *s, size_t n, const char quote[128])
+{
+#ifndef _WIN32
+  assert(!"implemented");
+#endif
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef UTF8INTERNAL_H
+#define UTF8INTERNAL_H 
+
+/**@IFILE utf8internal.h 
+ * UTF-8 macros.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#define UTF8_ANALYZE(s, ascii, latin1, ucs2, ucs4, errors) \
+do {  \
+  if (s) while (*s) { \
+    utf8 c = *s++; \
+    if (IS_UTF8_1(c)) \
+      ascii++; \
+    else if (IS_UTF8_I(c)) { \
+      if (IS_UTF8_X(s[0])) \
+	latin1++, s++; \
+      else \
+	errors++; \
+    } \
+    else if (IS_UTF8_2(c)) { \
+      if (IS_UTF8_X(s[0])) \
+	ucs2++, s++; \
+      else \
+	errors++; \
+    } \
+    else if (IS_UTF8_3(c)) { \
+      if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1])) \
+	ucs2++, s++, s++; \
+      else \
+	errors++; \
+    } \
+    else if (IS_UTF8_4(c)) { \
+      if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) && IS_UTF8_X(s[2])) \
+	ucs4++, s++, s++, s++; \
+      else \
+	errors++; \
+    } \
+    else if (IS_UTF8_5(c)) { \
+      if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) &&  \
+	  IS_UTF8_X(s[2]) && IS_UTF8_X(s[3])) \
+	ucs4++, s++, s++, s++, s++; \
+      else \
+	errors++; \
+    } \
+    else if (IS_UTF8_6(c)) { \
+      if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) &&  \
+	  IS_UTF8_X(s[2]) && IS_UTF8_X(s[3]) && IS_UTF8_X(s[4])) \
+	ucs4++, s++, s++, s++, s++, s++; \
+      else \
+	errors++; \
+    } \
+    else \
+	errors++; \
+  } \
+} while(0)
+
+#endif /* UTF8INTERNAL_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE utf8test.c UTF8 encoding - decoding tests
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:38 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+  static ucs4 ucs4test0[] = { 
+    0x41u, 0xC1u, 0x841u, 0x10041u, 0x200041u, 0x4000041u, 0
+  };
+  static utf8 ucs4test1[] = 
+    "A" 
+    "\303\201"
+    "\340\241\201"
+    "\360\220\201\201"
+    "\370\210\200\201\201"
+    "\374\204\200\200\201\201";
+
+  static ucs2 ucs2test0[] = { 
+    0x41u, 0xC1u, 0x841u, 0
+  };
+  static utf8 ucs2test1[] = 
+    "A" 
+    "\303\201"
+    "\340\241\201";
+
+  ucs4 ucs4s[1024] = { 0 };
+  ucs2 ucs2s[1024] = { 0 }; 
+  utf8 utf8s[1024] = { 0 };
+
+  size_t len;
+  int result = 0;
+  int i;
+
+  puts("testing ucs4len(ucs4test0)");
+
+  len = ucs4len(ucs4test0);
+  if (len != 6) {
+    printf("ucs4len(ucs4test0) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs4declen(ucs4test1)");
+
+  len = ucs4declen(ucs4test1);
+  if (len != 6) {
+    printf("ucs4declen(ucs4test1) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs4enclen(ucs4test0, 6, NULL)");
+
+  len = ucs4enclen(ucs4test0, 6, NULL);
+  if (len != 22) {
+    printf("ucs4enclen(ucs4test0, 6, NULL) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs4enclen(ucs4test0, 5, NULL)");
+
+  len = ucs4enclen(ucs4test0, 5, NULL);
+  if (len != 16) {
+    printf("ucs4enclen(ucs4test0, 5, NULL) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs4encode(utf8s, ucs4test0, 6, NULL)");
+
+  if (ucs4encode(utf8s, ucs4test0, 6, NULL) != 22 ||
+      strcmp((char *)utf8s, (char*)ucs4test1)) {
+    printf("ucs4encode(utf8s, ucs4test0, 6, NULL) fails\n");
+    result = 1;
+    printf("\tutf8s=\"%s\"\n", utf8s);
+  }
+  else puts("OK");
+
+  puts("testing ucs4decode(ucs4s, sizeof(ucs4s), ucs4test1)");
+
+  if (ucs4decode(ucs4s, sizeof(ucs4s)/sizeof(*ucs4s), ucs4test1) != 6
+      || ucs4cmp(ucs4s, ucs4test0)) {
+    printf("ucs4decode(ucs4s, sizeof(ucs4s), ucs4test1) fails\n");
+    result = 1;
+    for (i = 0; i < 8; i++) {
+      printf("\tucs4s[%d]=0x%x\n", i, ucs4s[i]);
+    }
+  }
+  else puts("OK");
+
+  /* UCS2 */
+  
+  puts("testing ucs2len(ucs2test0)");
+
+  len = ucs2len(ucs2test0);
+  if (len != 3) {
+    printf("ucs2len(ucs2test0) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs2declen(ucs2test1)");
+
+  len = ucs2declen(ucs2test1);
+  if (len != 3) {
+    printf("ucs2declen(ucs2test1) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs2enclen(ucs2test0, 3, NULL)");
+
+  len = ucs2enclen(ucs2test0, 3, NULL);
+  if (len != 7) {
+    printf("ucs2enclen(ucs2test1, 3, NULL) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs2enclen(ucs2test0, 2, NULL)");
+
+  len = ucs2enclen(ucs2test0, 2, NULL);
+  if (len != 4) {
+    printf("ucs2enclen(ucs2test1, NULL) returns %u\n", len);
+    result = 1;
+  }
+  else puts("OK");
+
+  puts("testing ucs2encode(utf8s, ucs2test0, 3, NULL)");
+
+  if (ucs2encode(utf8s, ucs2test0, 3, NULL) != 7 ||
+      strcmp((char *)utf8s, (char*)ucs2test1)) {
+    printf("ucs2encode(utf8s, ucs2test0, 3, NULL) fails\n");
+    result = 1;
+    printf("\tutf8s=\"%s\"\n", utf8s);
+  }
+  else puts("OK");
+
+  puts("testing ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1)");
+
+  if (ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1) != 3 ||
+      ucs2cmp(ucs2s, ucs2test0)) {
+    printf("ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1) fails\n");
+    result = 1;
+    for (i = 0; i < 8; i++) {
+      printf("\tucs2s[%d]=0x%x\n", i, ucs2s[i]);
+    }
+  }
+  else puts("OK");
+
+
+  return result;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,24 @@
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Renamed auth_digest_test.c as test_auth_digest.c.
+
+2005-10-21  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Generate opaque only if opaque parameter has value "*".
+
+    M ./libsofia-sip-ua/iptsec/auth_module.c -14 +20
+
+2005-09-06  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* auth_digest_test.c: Using opaque to match credentials (as per
+	auth_digest_credentials()).
+
+	* auth_plugin.h, auth_module.c: Added auth_digest_credentials.
+
+2005-08-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* auth_module.c: Using unsigned as type of hash!
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,20 @@
+PROJECT_NAME         = "iptsec"
+OUTPUT_DIRECTORY     = ../docs/html/iptsec
+
+INPUT 		     = iptsec.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES           += ../docs/su.doxytags=../su
+TAGFILES           += ../docs/ipt.doxytags=../ipt
+TAGFILES           += ../docs/bnf.doxytags=../bnf
+TAGFILES           += ../docs/url.doxytags=../url
+TAGFILES           += ../docs/msg.doxytags=../msg
+TAGFILES           += ../docs/sip.doxytags=../sip
+TAGFILES           += ../docs/sresolv.doxytags=../sresolv
+TAGFILES           += ../docs/tport.doxytags=../tport
+TAGFILES           += ../docs/nta.doxytags=../nta
+
+GENERATE_TAGFILE    = ../docs/iptsec.doxytags
+
+ALIASES 	   += 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,80 @@
+#
+# Makefile.am for iptsec module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../bnf -I../bnf \
+	 		-I$(srcdir)/../ipt -I../ipt \
+	 		-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../nta -I../nta \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libiptsec.la
+
+check_PROGRAMS = 	test_auth_digest
+
+TESTS = 		test_auth_digest
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = 	auth_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/auth_common.h \
+			sofia-sip/auth_client.h sofia-sip/auth_digest.h \
+			sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
+			sofia-sip/auth_client_plugin.h \
+			$(NTLM_HEADER)
+
+libiptsec_la_SOURCES = 	iptsec_debug.h \
+			auth_client.c auth_common.c auth_digest.c \
+			auth_module.c auth_tag.c auth_tag_ref.c \
+			auth_plugin.c auth_plugin_delayed.c \
+			auth_module_http.c auth_module_sip.c \
+			$(NTLM_SOURCE) \
+			iptsec_debug.c
+
+NTLM_HEADER = 		sofia-sip/auth_ntlm.h
+if HAVE_NTLM
+NTLM_SOURCE = 		auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+endif
+
+EXTRA_libiptsec_la_SOURCES = \
+			auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+
+COVERAGE_INPUT = 	$(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libiptsec.la \
+			../http/libhttp.la \
+			../nta/libnta.la \
+			../sip/libsip.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../ipt/libipt.la \
+			../su/libsu.la
+
+test_auth_digest_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = 		Doxyfile iptsec.docs testpasswd \
+			auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,752 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for iptsec module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libiptsec_la_SOURCES) $(EXTRA_libiptsec_la_SOURCES) test_auth_digest.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_auth_digest$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/iptsec
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libiptsec_la_LIBADD =
+am__libiptsec_la_SOURCES_DIST = iptsec_debug.h auth_client.c \
+	auth_common.c auth_digest.c auth_module.c auth_tag.c \
+	auth_tag_ref.c auth_plugin.c auth_plugin_delayed.c \
+	auth_module_http.c auth_module_sip.c auth_ntlm.c \
+	auth_client_ntlm.c auth_plugin_ntlm.c iptsec_debug.c
+ at HAVE_NTLM_TRUE@am__objects_1 = auth_ntlm.lo auth_client_ntlm.lo \
+ at HAVE_NTLM_TRUE@	auth_plugin_ntlm.lo
+am_libiptsec_la_OBJECTS = auth_client.lo auth_common.lo auth_digest.lo \
+	auth_module.lo auth_tag.lo auth_tag_ref.lo auth_plugin.lo \
+	auth_plugin_delayed.lo auth_module_http.lo auth_module_sip.lo \
+	$(am__objects_1) iptsec_debug.lo
+libiptsec_la_OBJECTS = $(am_libiptsec_la_OBJECTS)
+test_auth_digest_SOURCES = test_auth_digest.c
+test_auth_digest_OBJECTS = test_auth_digest.$(OBJEXT)
+test_auth_digest_LDADD = $(LDADD)
+test_auth_digest_DEPENDENCIES = libiptsec.la ../http/libhttp.la \
+	../nta/libnta.la ../sip/libsip.la ../msg/libmsg.la \
+	../url/liburl.la ../bnf/libbnf.la ../ipt/libipt.la \
+	../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libiptsec_la_SOURCES) $(EXTRA_libiptsec_la_SOURCES) \
+	test_auth_digest.c
+DIST_SOURCES = $(am__libiptsec_la_SOURCES_DIST) \
+	$(EXTRA_libiptsec_la_SOURCES) test_auth_digest.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+	 		-I$(srcdir)/../ipt -I../ipt \
+	 		-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../nta -I../nta \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libiptsec.la
+TESTS = test_auth_digest
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = auth_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/auth_common.h \
+			sofia-sip/auth_client.h sofia-sip/auth_digest.h \
+			sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
+			sofia-sip/auth_client_plugin.h \
+			$(NTLM_HEADER)
+
+libiptsec_la_SOURCES = iptsec_debug.h \
+			auth_client.c auth_common.c auth_digest.c \
+			auth_module.c auth_tag.c auth_tag_ref.c \
+			auth_plugin.c auth_plugin_delayed.c \
+			auth_module_http.c auth_module_sip.c \
+			$(NTLM_SOURCE) \
+			iptsec_debug.c
+
+NTLM_HEADER = sofia-sip/auth_ntlm.h
+ at HAVE_NTLM_TRUE@NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+EXTRA_libiptsec_la_SOURCES = \
+			auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+
+COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libiptsec.la \
+			../http/libhttp.la \
+			../nta/libnta.la \
+			../sip/libsip.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../ipt/libipt.la \
+			../su/libsu.la
+
+test_auth_digest_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile iptsec.docs testpasswd \
+			auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/iptsec/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/iptsec/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libiptsec.la: $(libiptsec_la_OBJECTS) $(libiptsec_la_DEPENDENCIES) 
+	$(LINK)  $(libiptsec_la_LDFLAGS) $(libiptsec_la_OBJECTS) $(libiptsec_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_auth_digest$(EXEEXT): $(test_auth_digest_OBJECTS) $(test_auth_digest_DEPENDENCIES) 
+	@rm -f test_auth_digest$(EXEEXT)
+	$(LINK) $(test_auth_digest_LDFLAGS) $(test_auth_digest_OBJECTS) $(test_auth_digest_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_client.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_client_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_digest.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module_http.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module_sip.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin_delayed.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/iptsec_debug.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_auth_digest.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1023 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_client.c  Authenticators for SIP client
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_md5.h>
+
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/auth_client.h"
+#include "sofia-sip/auth_client_plugin.h"
+
+#include <sofia-sip/msg_types.h>
+#include <sofia-sip/msg_header.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+static auth_client_t *ca_create(su_home_t *home, 
+				char const *scheme,
+				char const *realm);
+
+static void ca_destroy(su_home_t *home, auth_client_t *ca);
+
+static int ca_challenge(auth_client_t *ca,
+			msg_auth_t const *auth, 
+			msg_hclass_t *credential_class,
+			char const *scheme,
+			char const *realm);
+
+static int ca_info(auth_client_t *ca,
+		   msg_auth_info_t const *ai,
+		   msg_hclass_t *credential_class);
+
+static int ca_credentials(auth_client_t *ca, 
+			  char const *scheme,
+			  char const *realm, 
+			  char const *user,
+			  char const *pass);
+
+static int ca_clear_credentials(auth_client_t *ca, 
+				char const *scheme,
+				char const *realm);
+
+
+/** Initialize authenticators.
+ *
+ * The function auc_challenge() merges the challenge @a ch to the list of
+ * authenticators @a auc_list.  
+ *
+ * @param[in,out] auc_list  list of authenticators to be updated
+ * @param[in,out] home      memory home used for allocating authenticators
+ * @param[in] ch        challenge to be processed
+ * @param[in] crcl      credential class
+ * 
+ * @retval 1 when challenge was updated
+ * @retval 0 when there was no new challenges
+ * @retval -1 upon an error
+ */
+int auc_challenge(auth_client_t **auc_list,
+		  su_home_t *home, 
+		  msg_auth_t const *ch,
+		  msg_hclass_t *crcl)
+{
+  auth_client_t **cca;
+  int retval = 0;
+
+  /* Go through each challenge in Authenticate or Proxy-Authenticate headers */
+  for (; ch; ch = ch->au_next) {
+    char const *scheme = ch->au_scheme;
+    char const *realm = msg_header_find_param(ch->au_common, "realm=");
+    int matched = 0, updated;
+
+    if (!scheme || !realm)
+      continue;
+
+    /* Update matching authenticator */
+    for (cca = auc_list; (*cca); cca = &(*cca)->ca_next) {
+      updated = ca_challenge((*cca), ch, crcl, scheme, realm);
+      if (updated < 0)
+	return -1;
+      if (updated == 0)
+	continue;		/* No match, next */
+      matched = 1;
+      if (updated > 1)
+	retval = 1;		/* Updated authenticator */
+    }
+
+    if (!matched) {
+      /* There was no matching authenticator, create a new one */
+      *cca = ca_create(home, scheme, realm);
+      if (ca_challenge((*cca), ch, crcl, scheme, realm) < 0) {
+	ca_destroy(home, *cca), *cca = NULL;
+	return -1;
+      }
+      retval = 1;		/* Updated authenticator */
+    }
+  }
+
+  return retval;
+}
+
+/** Update authentication client. 
+ *
+ * @retval -1 upon an error
+ * @retval 0 when challenge did not match
+ * @retval 1 when challenge did match but was not updated
+ * @retval 2 when challenge did match and updated client
+ */
+static
+int ca_challenge(auth_client_t *ca, 
+		 msg_auth_t const *ch,
+		 msg_hclass_t *credential_class,
+		 char const *scheme, 
+		 char const *realm)
+{
+  int stale = 0;
+
+  assert(ca); assert(ch);
+
+  if (!ca || !ch)
+    return -1;
+
+  if (strcmp(ca->ca_scheme, scheme))
+    return 0;
+  if (strcmp(ca->ca_realm, realm))
+    return 0;
+
+  if (ca->ca_credential_class && 
+      ca->ca_credential_class != credential_class)
+    return 0;
+
+  if (!ca->ca_auc)
+    return 1;
+
+  if (ca->ca_auc->auc_challenge)
+    stale = ca->ca_auc->auc_challenge(ca, ch);
+  if (stale < 0)
+    return -1;
+
+  if (!ca->ca_credential_class)
+    stale = 1, ca->ca_credential_class = credential_class;
+
+  return stale ? 2 : 1;
+}
+
+/** Store authentication info to authenticators.
+ *
+ * The function auc_info() feeds the authentication data from the
+ * authentication info @a info to the list of authenticators @a auc_list.
+ *
+ * @param[in,out] auc_list  list of authenticators to be updated
+ * @param[in] info      info to be processed
+ * @param[in] crcl      corresponding credential class
+ *
+ * The authentication info can be in either Authentication-Info or in
+ * Proxy-Authentication-Info headers.
+ * If the header is Authentication-Info, the @a crcl should be
+ * #sip_authorization_class or #http_authorization_class.
+ * Likewise, If the header is Proxy-Authentication-Info, the @a crcl should
+ * be #sip_proxy_authorization_class or #http_proxy_authorization_class.
+
+ * The authentication into usually contains next nonce or mutual
+ * authentication information. We handle only nextnonce parameter. 
+ *
+ * @bug
+ * The result can be quite unexpected if there are more than one
+ * authenticator with the given type (specified by @a crcl). In principle,
+ * SIP allows more than one challenge for a single request.
+ *
+ * @retval number of challenges to updated
+ * @retval 0 when there was no challenge to update
+ * @retval -1 upon an error
+ */
+int auc_info(auth_client_t **auc_list,
+	     msg_auth_info_t const *ai,
+	     msg_hclass_t *credential_class)
+{
+  auth_client_t *ca;
+  int retval = 0;
+
+  /* Go through each challenge in Authenticate or Proxy-Authenticate headers */
+
+  /* Update matching authenticator */
+  for (ca = *auc_list; ca; ca = ca->ca_next) {
+    int updated = ca_info(ca, ai, credential_class);
+    if (updated < 0)
+      return -1;
+    if (updated >= 1)
+      retval = 1;		/* Updated authenticator */
+  }
+
+  return retval;
+}
+
+/** Update authentication client with authentication info. 
+ *
+ * @retval -1 upon an error
+ * @retval 0 when challenge did not match
+ * @retval 1 when challenge did match but was not updated
+ * @retval 2 when challenge did match and updated client
+ */
+static
+int ca_info(auth_client_t *ca, 
+	    msg_auth_info_t const *ai,
+	    msg_hclass_t *credential_class)
+{
+  assert(ca); assert(ai);
+
+  if (!ca || !ai)
+    return -1;
+
+  if (!ca->ca_credential_class)
+    return 0;
+
+  if (ca->ca_credential_class != credential_class)
+    return 0;
+
+  if (!ca->ca_auc
+      || (size_t)ca->ca_auc->auc_plugin_size <= 
+         offsetof(auth_client_plugin_t, auc_info)
+      || !ca->ca_auc->auc_info)
+    return 0;
+
+  return ca->ca_auc->auc_info(ca, ai);
+}
+
+
+/**Feed authentication data to the authenticator.
+ *
+ * The function auc_credentials() is used to provide the authenticators in
+ * with authentication data (user name, secret).  The authentication data
+ * has format as follows:
+ *
+ * scheme:"realm":user:pass
+ *
+ * For instance, @c Basic:"nokia-proxy":ppessi:verysecret
+ *
+ * @todo The authentication data format sucks.
+ *
+ * @param[in,out] auc_list  list of authenticators 
+ * @param[in,out] home      memory home used for allocations
+ * @param[in] data          colon-separated authentication data
+ * 
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auc_credentials(auth_client_t **auc_list, su_home_t *home, 
+		    char const *data)
+{
+  int retval = 0, match;
+  char *s0, *s;
+  char *scheme = NULL, *user = NULL, *pass = NULL, *realm = NULL;
+
+  s0 = s = su_strdup(NULL, data);
+
+  /* Parse authentication data */
+  /* Data is string like "Basic:\"agni\":user1:secret" */
+  if (s && (s = strchr(scheme = s, ':')))
+    *s++ = 0;
+  if (s && (s = strchr(realm = s, ':')))
+    *s++ = 0;
+  if (s && (s = strchr(user = s, ':')))
+    *s++ = 0;
+  if (s && (s = strchr(pass = s, ':')))
+    *s++ = 0;
+
+  if (scheme && realm && user && pass) {
+    for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+      match = ca_credentials(*auc_list, scheme, realm, user, pass);
+      if (match < 0) {
+	retval = -1;
+	break;
+      }
+      if (match) 
+	retval++;
+    }
+  }
+
+  su_free(NULL, s0);
+
+  return retval;
+}
+
+/**Feed authentication data to the authenticator.
+ *
+ * The function auc_credentials() is used to provide the authenticators in
+ * with authentication tuple (scheme, realm, user name, secret).  
+ *
+ * scheme:"realm":user:pass
+ *
+ * @todo The authentication data format sucks.
+ *
+ * @param[in,out] auc_list  list of authenticators 
+ * @param[in] scheme        scheme to use (NULL, if any)
+ * @param[in] realm         realm to use (NULL, if any)
+ * @param[in] user          username 
+ * @param[in] pass          password
+ * 
+ * @retval number of matching clients
+ * @retval 0 when no matching client was found
+ * @retval -1 upon an error
+ */
+int auc_all_credentials(auth_client_t **auc_list, 
+			char const *scheme,
+			char const *realm, 
+			char const *user,
+			char const *pass)
+{
+  int retval = 0, match;
+
+#if HAVE_SC_CRED_H
+  /* XXX: add */
+#endif
+
+  if (user && pass) {
+    for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+      match = ca_credentials(*auc_list, scheme, realm, user, pass);
+      if (match < 0)
+	return -1;
+      if (match) 
+	retval++;
+    }
+  }
+
+  return retval;
+}
+
+int ca_credentials(auth_client_t *ca, 
+		   char const *scheme,
+		   char const *realm, 
+		   char const *user,
+		   char const *pass)
+{
+  assert(ca);
+
+  if (!ca || !ca->ca_scheme || !ca->ca_realm)
+    return -1;
+
+  if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
+      (realm != NULL && strcmp(realm, ca->ca_realm)))
+    return -1;
+
+  ca->ca_user = su_strdup(ca->ca_home, user);
+  ca->ca_pass = su_strdup(ca->ca_home, pass);
+
+  if (!ca->ca_user || !ca->ca_pass)
+    return -1;
+
+  return 1;
+}
+
+
+/** Copy authentication data from @a src to @a dst.
+ *
+ * @retval >0 if credentials were copied
+ * @retval 0 if there was no credentials to copy
+ * @retval <0 if an error occurred.
+ */
+int auc_copy_credentials(auth_client_t **dst,
+			 auth_client_t const *src)
+{
+  int retval = 0;
+
+  if (!dst)
+    return -1;
+
+  for (;*dst; dst = &(*dst)->ca_next) {
+    auth_client_t *d = *dst;
+    auth_client_t const *ca;
+
+    for (ca = src; ca; ca = ca->ca_next) {
+      char *u, *p;
+      if (!ca->ca_user || !ca->ca_pass)
+	continue;
+      if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme))
+	continue;
+      if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))
+	continue;
+
+      if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
+	  d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {
+	retval++;
+	break;
+      }
+
+      u = su_strdup(d->ca_home, ca->ca_user);
+      p = su_strdup(d->ca_home, ca->ca_pass);
+      if (!u || !p)
+	return -1;
+
+      if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);
+      if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);
+      d->ca_user = u, d->ca_pass = p;
+      retval++;
+      break;
+    }
+  }
+
+  return retval;
+}
+      	      
+
+/**Clear authentication data from the authenticator.
+ *
+ * The function auc_clear_credentials() is used to remove the credentials
+ * from the authenticators.
+ *
+ * @param[in,out] auc_list  list of authenticators 
+ * @param[in] scheme    scheme (if non-null, remove only matching credentials) 
+ * @param[in] realm     realm (if non-null, remove only matching credentials)
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auc_clear_credentials(auth_client_t **auc_list, 
+			 char const *scheme,
+			 char const *realm)
+{
+  int retval = 0;
+
+  for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+    int match = ca_clear_credentials(*auc_list, scheme, realm);
+    if (match < 0) {
+      retval = -1;
+      break;
+    }
+    if (match) 
+      retval++;
+  }
+
+  return retval;
+}
+
+static
+int ca_clear_credentials(auth_client_t *ca, 
+			 char const *scheme,
+			 char const *realm)
+{
+  assert(ca);
+
+  if (!ca || !ca->ca_scheme || !ca->ca_realm)
+    return -1;
+
+  if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
+      (realm != NULL && strcmp(realm, ca->ca_realm)))
+    return -1;
+
+  su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL;
+  su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL;
+
+  return 1;
+}
+
+/** Check if we have all required credentials.
+ * 
+ * @retval 1 when authorization can proceed
+ * @retval 0 when there is not enough credentials
+ */
+int auc_has_authorization(auth_client_t **auc_list)
+{
+  auth_client_t const *ca;
+
+  if (auc_list == NULL)
+    return 0;
+
+  /* Make sure every challenge has credentials */
+  for (ca = *auc_list; ca; ca = ca->ca_next) {
+    if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class)
+      return 0;
+  }
+
+  return 1;
+}
+
+/**Authorize a request.
+ *
+ * The function auc_authorization() is used to add correct authentication
+ * headers to a request. The authentication headers will contain the
+ * credentials generated by the list of authenticators.
+ *
+ * @param[in,out] auc_list  list of authenticators 
+ * @param[out] msg          message to be authenticated
+ * @param[out] pub          headers of the message
+ * @param[in] method        request method
+ * @param[in] url           request URI
+ * @param[in] body          message body (NULL if empty)
+ * 
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
+		      char const *method, 
+		      url_t const *url, 
+		      msg_payload_t const *body)
+{
+  auth_client_t *ca;
+  msg_mclass_t const *mc = msg_mclass(msg);
+
+  if (auc_list == NULL || msg == NULL)
+    return -1;
+
+  if (!auc_has_authorization(auc_list))
+    return 0;
+
+  if (pub == NULL)
+    pub = msg_object(msg);
+
+  /* Remove existing credentials */
+  for (ca = *auc_list; ca; ca = ca->ca_next) {
+    msg_header_t **hh = msg_hclass_offset(mc, pub, ca->ca_credential_class);
+
+    while (hh && *hh)
+      msg_header_remove(msg, pub, *hh);
+  }
+
+  /* Insert new credentials */
+  for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+    su_home_t *home = msg_home(msg);
+    msg_header_t *h = NULL;
+
+    ca = *auc_list;
+
+    if (!ca->ca_auc)
+      continue;
+
+    if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0
+	|| msg_header_insert(msg, pub, h) < 0)
+      return -1;
+  }
+
+  return 1;
+}
+
+/**Generate headers authorizing a request.
+ *
+ * The function auc_authorization_headers() is used to generate
+ * authentication headers for a request. The list of authentication headers
+ * will contain the credentials generated by the list of authenticators.
+ *
+ * @param[in] auc_list      list of authenticators 
+ * @param[in] home          memory home used to allocate headers
+ * @param[in] method        request method
+ * @param[in] url           request URI
+ * @param[in] body          message body (NULL if empty)
+ * @param[out] return_headers  authorization headers return value
+ * 
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorization_headers(auth_client_t **auc_list, 
+			      su_home_t *home,
+			      char const *method, 
+			      url_t const *url, 
+			      msg_payload_t const *body,
+			      msg_header_t **return_headers)
+{
+  auth_client_t *ca;
+
+  /* Make sure every challenge has credentials */
+  if (!auc_has_authorization(auc_list))
+    return 0;
+
+  /* Create new credential headers */
+  for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+    msg_header_t *h = NULL;
+
+    ca = *auc_list;
+
+    if (!ca->ca_auc)
+      continue;
+
+    if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0)
+      return -1;
+
+    *return_headers = h;
+
+    while (*return_headers)
+      return_headers = &(*return_headers)->sh_next;
+  }
+
+  return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Basic scheme */
+
+static int auc_basic_authorization(auth_client_t *ca,
+				   su_home_t *h,
+				   char const *method, 
+				   url_t const *url, 
+				   msg_payload_t const *body,
+				   msg_header_t **);
+
+const auth_client_plugin_t ca_basic_plugin = 
+{ 
+  /* auc_plugin_size: */ sizeof ca_basic_plugin,
+  /* auc_size: */        sizeof (auth_client_t),
+  /* auc_name: */       "Basic",
+  /* auc_challenge: */   NULL,
+  /* auc_authorize: */   auc_basic_authorization,
+  /* auc_info: */        NULL
+};
+
+/**Create a basic authorization header.
+ *
+ * The function auc_basic_authorization() creates a basic authorization
+ * header from username @a user and password @a pass. The authorization
+ * header type is determined by @a hc - it can be sip_authorization_class,
+ * sip_proxy_authorization_class, http_authorization_class, or
+ * http_proxy_authorization_class, for instance.
+ *
+ * @param home memory home used to allocate memory for the new header
+ * @param hc   header class for the header to be created
+ * @param user user name
+ * @param pass password
+ * 
+ * @return
+ * The function auc_basic_authorization() returns a pointer to newly created 
+ * authorization header, or NULL upon an error.
+ */
+int auc_basic_authorization(auth_client_t *ca, 
+			    su_home_t *home,
+			    char const *method, 
+			    url_t const *url, 
+			    msg_payload_t const *body,
+			    msg_header_t **return_headers)
+{
+  msg_hclass_t *hc = ca->ca_credential_class;
+  char const *user = ca->ca_user;
+  char const *pass = ca->ca_pass;
+  size_t ulen, plen, uplen, b64len, basiclen;
+  char *basic, *base64, *userpass;
+  char buffer[71];
+
+  if (user == NULL || pass == NULL)
+    return -1;
+
+  ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen;
+  b64len = BASE64_SIZE(uplen);
+  basiclen = strlen("Basic ") + b64len;
+
+  if (sizeof(buffer) > basiclen + 1)
+    basic = buffer;
+  else
+    basic = malloc(basiclen + 1);
+
+  /*
+   * Basic authentication consists of username and password separated by
+   * colon and then base64 encoded.
+   */
+  strcpy(basic, "Basic ");
+  base64 = basic + strlen("Basic ");
+  userpass = base64 + b64len - uplen;
+  memcpy(userpass, user, ulen);
+  userpass[ulen] = ':';
+  memcpy(userpass + ulen + 1, pass, plen);
+  userpass[uplen] = '\0';
+  
+  base64_e(base64, b64len + 1, userpass, uplen);
+
+  base64[b64len] = '\0';
+
+  *return_headers = msg_header_make(home, hc, basic);
+
+  if (buffer != basic)
+    free(basic);
+
+  return *return_headers ? 0 : -1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Digest scheme */
+
+typedef struct auth_digest_client_s
+{
+  auth_client_t cda_client;
+
+  int           cda_ncount;
+  char const   *cda_cnonce;
+  auth_challenge_t cda_ac[1];
+} auth_digest_client_t;
+
+static int auc_digest_challenge(auth_client_t *ca, 
+				msg_auth_t const *ch);
+static int auc_digest_authorization(auth_client_t *ca, 
+				    su_home_t *h,
+				    char const *method, 
+				    url_t const *url, 
+				    msg_payload_t const *body,
+				    msg_header_t **);
+static int auc_digest_info(auth_client_t *ca, 
+			   msg_auth_info_t const *ai);
+
+static const auth_client_plugin_t ca_digest_plugin = 
+{ 
+  /* auc_plugin_size: */ sizeof ca_digest_plugin,
+  /* auc_size: */        sizeof (auth_digest_client_t),
+  /* auc_name: */       "Digest", 
+  /* auc_challenge: */   auc_digest_challenge,
+  /* auc_authorize: */   auc_digest_authorization,
+  /* auc_info: */        auc_digest_info
+};
+
+/** Store a digest authorization challenge.
+ */
+static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
+{
+  su_home_t *home = ca->ca_home;
+  auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+  auth_challenge_t ac[1] = {{ sizeof ac }};
+  int stale;
+
+  if (auth_digest_challenge_get(home, ac, ch->au_params) < 0)
+    goto error;
+
+  /* Check that we can handle the challenge */
+  if (!ac->ac_md5 && !ac->ac_md5sess)
+    goto error;
+  if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
+    goto error;
+
+  stale = ac->ac_stale || str0cmp(ac->ac_nonce, cda->cda_ac->ac_nonce);
+
+  if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale)) {
+    su_guid_t guid[1];
+    char *cnonce;
+    if (cda->cda_cnonce != NULL)
+      /* Free the old one if we are updating after stale=true */
+      su_free(home, (void *)cda->cda_cnonce);
+    su_guid_generate(guid);
+    cda->cda_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
+    base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
+    cda->cda_ncount = 0;
+  }
+
+  auth_digest_challenge_free_params(home, cda->cda_ac);
+
+  *cda->cda_ac = *ac;
+
+  return stale ? 2 : 1;
+
+ error:
+  auth_digest_challenge_free_params(home, ac);
+  return -1;
+}
+
+static int auc_digest_info(auth_client_t *ca,
+			   msg_auth_info_t const *ai)
+{
+  auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+  su_home_t *home = ca->ca_home;
+  char const *nextnonce = NULL;
+  issize_t n;
+
+  n = auth_get_params(home, ai->ai_params,
+		      "nextnonce=", &nextnonce,
+		      NULL);
+
+  if (n <= 0)
+    return n;
+
+  cda->cda_ac->ac_nonce = nextnonce;
+
+  return 1;
+}
+
+/**Create a digest authorization header.
+ *
+ * Creates a digest authorization header from username @a user and password
+ * @a pass, client nonce @a cnonce, client nonce count @a nc, request method
+ * @a method, request URI @a uri and message body @a data. The authorization
+ * header type is determined by @a hc - it can be either
+ * sip_authorization_class or sip_proxy_authorization_class, as well as
+ * http_authorization_class or http_proxy_authorization_class.
+ *
+ * @return
+ * Returns a pointer to newly created authorization header, or NULL upon an
+ * error.
+ */
+static
+int auc_digest_authorization(auth_client_t *ca, 
+			     su_home_t *home,
+			     char const *method, 
+			     url_t const *url, 
+			     msg_payload_t const *body,
+			     msg_header_t **return_headers)
+{
+  auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+  msg_hclass_t *hc = ca->ca_credential_class;
+  char const *user = ca->ca_user;
+  char const *pass = ca->ca_pass;
+  auth_challenge_t const *ac = cda->cda_ac;
+  char const *cnonce = cda->cda_cnonce;
+  unsigned nc = ++cda->cda_ncount;
+  char *uri = url_as_string(home, url);
+  void const *data = body ? body->pl_data : "";
+  usize_t dlen = body ? body->pl_len : 0;
+
+  msg_header_t *h;
+  auth_hexmd5_t sessionkey, response;
+  auth_response_t ar[1] = {{ 0 }};
+  char ncount[17];
+
+  ar->ar_size = sizeof(ar);
+  ar->ar_username = user;
+  ar->ar_realm = ac->ac_realm;
+  ar->ar_nonce = ac->ac_nonce;
+  ar->ar_algorithm = NULL;
+  ar->ar_md5 = ac->ac_md5;
+  ar->ar_md5sess = ac->ac_md5sess;
+  ar->ar_opaque = ac->ac_opaque;
+  ar->ar_qop = NULL;
+  ar->ar_auth = ac->ac_auth;
+  ar->ar_auth_int = ac->ac_auth_int;
+  ar->ar_uri = uri;
+
+  /* If there is no qop, we MUST NOT include cnonce or nc */
+  if (!ar->ar_auth && !ar->ar_auth_int)
+    cnonce = NULL;
+
+  if (cnonce) {
+    snprintf(ncount, sizeof(ncount), "%08x", nc);
+    ar->ar_cnonce = cnonce;
+    ar->ar_nc = ncount;
+  }
+
+  auth_digest_sessionkey(ar, sessionkey, pass);
+  auth_digest_response(ar, response, sessionkey, method, data, dlen);
+
+  h = msg_header_format(home, hc, 
+			"Digest "
+			"username=\"%s\", "
+			"realm=\"%s\", "
+			"nonce=\"%s"
+			"%s%s"
+			"%s%s"
+			"%s%s, "
+			"uri=\"%s\", "
+			"response=\"%s\""
+			"%s%s"
+			"%s%s",
+			ar->ar_username, 
+			ar->ar_realm,
+			ar->ar_nonce,
+			cnonce ? "\",  cnonce=\"" : "", 
+			cnonce ? cnonce : "",
+			ar->ar_opaque ? "\",  opaque=\"" : "", 
+			ar->ar_opaque ? ar->ar_opaque : "",
+			ar->ar_algorithm ? "\", algorithm=" : "",
+			ar->ar_algorithm ? ar->ar_algorithm : "",
+			ar->ar_uri,
+			response,
+			ar->ar_auth || ar->ar_auth_int ? ", qop=" : "", 
+			ar->ar_auth_int ? "auth-int" : 
+			(ar->ar_auth ? "auth" : ""),
+			cnonce ? ", nc=" : "", 
+			cnonce ? ncount : "");
+
+  su_free(home, uri);
+
+  if (!h)
+    return -1;
+  *return_headers = h;
+  return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+#define MAX_AUC 20
+
+static auth_client_plugin_t const *ca_plugins[MAX_AUC] = 
+{
+  &ca_digest_plugin, &ca_basic_plugin, NULL
+};
+
+/** Register an authentication client plugin */
+int auc_register_plugin(auth_client_plugin_t const *plugin)
+{
+  int i;
+
+  if (plugin == NULL ||
+      plugin->auc_name == NULL ||
+      plugin->auc_authorize == NULL)
+    return errno = EFAULT, -1;
+
+  if (plugin->auc_size < (int) sizeof (auth_client_t))
+    return errno = EINVAL, -1;
+
+  for (i = 0; i < MAX_AUC; i++) {
+    if (ca_plugins[i] == NULL || 
+	strcmp(plugin->auc_name, ca_plugins[i]->auc_name) == 0) {
+      ca_plugins[i] = plugin;
+      return 0;
+    }
+  }
+
+  return errno = ENOMEM, -1;
+}
+
+/** Allocate an (possibly extended) auth_client_t structure. */
+static
+auth_client_t *ca_create(su_home_t *home,
+			 char const *scheme,
+			 char const *realm)
+{
+  auth_client_plugin_t const *auc = NULL;
+  auth_client_t *ca;
+  size_t aucsize = (sizeof *ca), realmlen, size;
+  char *s;
+  int i;
+
+  if (scheme == NULL || realm == NULL)
+    return (void)(errno = EFAULT), NULL;
+
+  realmlen = strlen(realm) + 1;
+
+  for (i = 0; i < MAX_AUC; i++) {
+    auc = ca_plugins[i];
+    if (!auc || strcasecmp(auc->auc_name, scheme) == 0)
+      break;
+  }
+
+  aucsize = auc ? (size_t)auc->auc_size : (sizeof *ca);
+  size = aucsize + realmlen;
+  if (!auc)
+    size += strlen(scheme) + 1;
+
+  ca = su_home_clone(home, (isize_t)size);
+  if (!ca)
+    return ca;
+
+  s = (char *)ca + aucsize;
+  ca->ca_auc = auc;
+  ca->ca_realm = strcpy(s, realm);
+  ca->ca_scheme = auc ? auc->auc_name : strcpy(s + realmlen, scheme);
+
+  return ca;
+}
+
+void ca_destroy(su_home_t *home, auth_client_t *ca)
+{
+  su_free(home, ca);
+}
+
+
+#if HAVE_SOFIA_SIP
+#include <sofia-sip/sip.h>
+
+/**Authorize a SIP request.
+ *
+ * The function auc_authorize() is used to add correct authentication
+ * headers to a SIP request. The authentication headers will contain the
+ * credentials generated by the list of authenticators.
+ *
+ * @param[in,out] auc_list  list of authenticators 
+ * @param[in,out] msg       message to be authenticated
+ * @param[in,out] sip       sip headers of the message
+ * 
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorize(auth_client_t **auc_list, msg_t *msg, sip_t *sip)
+{
+  sip_request_t *rq = sip ? sip->sip_request : NULL;
+
+  if (!rq)
+    return 0;
+
+  return auc_authorization(auc_list, msg, (msg_pub_t *)sip, 
+			   rq->rq_method_name, 
+			   /*
+			     RFC 3261 defines the protection domain based
+			     only on realm, so we do not bother get a
+			     correct URI to auth module.
+			   */
+			   rq->rq_url, 
+			   sip->sip_payload);
+}
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_client_ntlm.c  NTLM authenticator for SIP client
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed May 24 21:44:39 EEST 2006
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_md5.h>
+
+#include "sofia-sip/auth_ntlm.h"
+#include "sofia-sip/auth_client.h"
+#include "sofia-sip/auth_client_plugin.h"
+
+#include <sofia-sip/msg_header.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+typedef struct auth_ntlm_client_s
+{
+  auth_client_t ntlm_client;
+
+  int           ntlm_ncount;
+  char const   *ntlm_cnonce;
+  auth_challenge_t ntlm_ac[1];
+} auth_ntlm_client_t;
+
+static int auc_ntlm_challenge(auth_client_t *ca, 
+				msg_auth_t const *ch);
+static int auc_ntlm_authorization(auth_client_t *ca, 
+				    su_home_t *h,
+				    char const *method, 
+				    url_t const *url, 
+				    msg_payload_t const *body,
+				    msg_header_t **);
+
+auth_client_plugin_t const _ntlm_client_plugin = 
+{ 
+  sizeof ca_ntlm_plugin,
+  sizeof (auth_ntlm_client_t),
+  "NTLM", 
+  auc_ntlm_challenge,
+  auc_ntlm_authorization
+};
+
+auth_client_plugin_t const * const ntlm_client_plugin = _ntlm_client_plugin;
+
+/** Store a ntlm authorization challenge.
+ */
+static int auc_ntlm_challenge(auth_client_t *ca, msg_auth_t const *ch)
+{
+  su_home_t *home = ca->ca_home;
+  auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca;
+  auth_challenge_t ac[1] = {{ sizeof ac }};
+  int stale;
+
+  if (auth_ntlm_challenge_get(home, ac, ch->au_params) < 0)
+    goto error;
+
+  /* Check that we can handle the challenge */
+  if (!ac->ac_md5 && !ac->ac_md5sess)
+    goto error;
+  if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
+    goto error;
+
+  stale = ac->ac_stale || str0cmp(ac->ac_nonce, ntlm->ntlm_ac->ac_nonce);
+
+  if (ac->ac_qop && (ntlm->ntlm_cnonce == NULL || ac->ac_stale)) {
+    su_guid_t guid[1];
+    char *cnonce;
+    if (ntlm->ntlm_cnonce != NULL)
+      /* Free the old one if we are updating after stale=true */
+      su_free(home, (void *)ntlm->ntlm_cnonce);
+    su_guid_generate(guid);
+    ntlm->ntlm_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
+    base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
+    ntlm->ntlm_ncount = 0;
+  }
+
+  auth_ntlm_challenge_free_params(home, ntlm->ntlm_ac);
+
+  *ntlm->ntlm_ac = *ac;
+
+  return stale ? 2 : 1;
+
+ error:
+  auth_ntlm_challenge_free_params(home, ac);
+  return -1;
+}
+
+
+/**Create a NTLM authorization header.
+ *
+ * Creates a ntlm authorization header from username @a user and password
+ * @a pass, client nonce @a cnonce, client nonce count @a nc, request method
+ * @a method, request URI @a uri and message body @a data. The authorization
+ * header type is determined by @a hc - it can be either
+ * sip_authorization_class or sip_proxy_authorization_class, as well as
+ * http_authorization_class or http_proxy_authorization_class.
+ *
+ * @param home 	  memory home used to allocate memory for the new header
+ * @param hc   	  header class for the header to be created
+ * @param user 	  user name
+ * @param pass 	  password
+ * @param ac      challenge structure
+ * @param cnonce  client nonce
+ * @param nc      client nonce count 
+ * @param method  request method
+ * @param uri     request uri
+ * @param data    message body
+ * @param dlen    length of message body
+ *
+ * @return
+ * Returns a pointer to newly created authorization header, or NULL upon an
+ * error.
+ */
+int auc_ntlm_authorization(auth_client_t *ca, 
+			     su_home_t *home,
+			     char const *method, 
+			     url_t const *url, 
+			     msg_payload_t const *body,
+			     msg_header_t **return_headers)
+{
+  auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca;
+  msg_hclass_t *hc = ca->ca_credential_class;
+  char const *user = ca->ca_user;
+  char const *pass = ca->ca_pass;
+  auth_challenge_t const *ac = ntlm->ntlm_ac;
+  char const *cnonce = ntlm->ntlm_cnonce;
+  unsigned nc = ++ntlm->ntlm_ncount;
+  char *uri = url_as_string(home, url);
+  void const *data = body ? body->pl_data : "";
+  int dlen = body ? body->pl_len : 0;
+
+  msg_header_t *h;
+  auth_hexmd5_t sessionkey, response;
+  auth_response_t ar[1] = {{ 0 }};
+  char ncount[17];
+
+  ar->ar_size = sizeof(ar);
+  ar->ar_username = user;
+  ar->ar_realm = ac->ac_realm;
+  ar->ar_nonce = ac->ac_nonce;
+  ar->ar_algorithm = NULL;
+  ar->ar_md5 = ac->ac_md5;
+  ar->ar_md5sess = ac->ac_md5sess;
+  ar->ar_opaque = ac->ac_opaque;
+  ar->ar_qop = NULL;
+  ar->ar_auth = ac->ac_auth;
+  ar->ar_auth_int = ac->ac_auth_int;
+  ar->ar_uri = uri;
+
+  /* If there is no qop, we MUST NOT include cnonce or nc */
+  if (!ar->ar_auth && !ar->ar_auth_int)
+    cnonce = NULL;
+
+  if (cnonce) {
+    snprintf(ncount, sizeof(ncount), "%08x", nc);
+    ar->ar_cnonce = cnonce;
+    ar->ar_nc = ncount;
+  }
+
+  auth_ntlm_sessionkey(ar, sessionkey, pass);
+  auth_ntlm_response(ar, response, sessionkey, method, data, dlen);
+
+  h = msg_header_format(home, hc, 
+			"NTLM "
+			"username=\"%s\", "
+			"realm=\"%s\", "
+			"nonce=\"%s"
+			"%s%s"
+			"%s%s"
+			"%s%s, "
+			"uri=\"%s\", "
+			"response=\"%s\""
+			"%s%s"
+			"%s%s",
+			ar->ar_username, 
+			ar->ar_realm,
+			ar->ar_nonce,
+			cnonce ? "\",  cnonce=\"" : "", 
+			cnonce ? cnonce : "",
+			ar->ar_opaque ? "\",  opaque=\"" : "", 
+			ar->ar_opaque ? ar->ar_opaque : "",
+			ar->ar_algorithm ? "\", algorithm=" : "",
+			ar->ar_algorithm ? ar->ar_algorithm : "",
+			ar->ar_uri,
+			response,
+			ar->ar_auth || ar->ar_auth_int ? ", qop=" : "", 
+			ar->ar_auth_int ? "auth-int" : 
+			(ar->ar_auth ? "auth" : ""),
+			cnonce ? ", nc=" : "", 
+			cnonce ? ncount : "");
+
+  su_free(home, uri);
+
+  if (!h)
+    return -1;
+  *return_headers = h;
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_common.c
+ *
+ * Functions common to both client and server authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Original Created: Thu Feb 22 12:10:37 2001 ppessi
+ * @date Created: Wed May 17 13:37:50 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/msg_header.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if !HAVE_STRCASESTR
+char *strcasestr(char const *haystack, char const *needle);
+#endif
+
+static inline int has_token(char const *qstring, char const *token);
+
+/**
+ * Parse authentication parameters.
+ *
+ * The function auth_get_params() searches for the authentication parameters
+ * in @a params. The parameter list @a params is seached for each parameter
+ * given in in vararg section, and if it is found, its value is assigned to
+ * the given address. 
+ *
+ * @note The field name should contain the equal ("=") sign.
+ *
+ * @return
+ * The function auth_get_params() returns number of parameters found in
+ * params, or -1 upon an error.
+ */
+issize_t auth_get_params(su_home_t *home,
+			 char const * const params[], ...
+			 /* char const *fmt, char const **return_value */)
+{
+  int n, j;
+  size_t len, namelen;
+  char const *fmt, *expected;
+  char const *value, *p, **return_value;
+  va_list(ap);
+
+  assert(params);
+
+  if (!params) return -1;
+
+  va_start(ap, params);
+
+  for (n = 0; (fmt = va_arg(ap, char const *));) {
+    return_value = va_arg(ap, char const **);
+    len = strlen(fmt);
+    if (!len)
+      continue;
+    namelen = strcspn(fmt, "=");
+    expected = fmt + namelen + 1;
+    value = NULL;
+
+    if (expected[0]) {
+      /* value match: format is name=expected,
+	 if expected is found in parameter value,
+	 return non-NULL pointer in *return_value */
+      for (j = 0; (p = params[j++]);) {
+	if (strcasecmp(p, fmt) == 0) {
+	  /* Matched the whole parameter with fmt name=expected */
+	  value = p;
+	  break;
+	}
+	else if (strncasecmp(p, fmt, namelen) ||
+		 p[namelen] != '=')
+	  continue;
+
+	p = p + namelen + 1;
+
+	if (p[0] == '"' && has_token(p, expected)) {
+	  /* Quoted parameter value has expected value,
+	   * e.g., qop=auth matches qop="auth,auth-int" */
+	  value = p;
+	  break;
+	}
+	else if (strcasecmp(p, expected) == 0) {
+	  /* Parameter value matches with extected value
+	   * e.g., qop=auth matches qop=auth */
+	  value = p;
+	  break;
+	}
+      }
+    }
+    else {
+      /* format is name= , return unquoted parameter value after = */
+      for (j = 0; (p = params[j++]);) {
+	if (strncasecmp(p, fmt, len))
+	  continue;
+
+	if (p[len] == '"')
+	  value = msg_unquote_dup(home, p + len);
+	else
+	  value = su_strdup(home, p + len);
+
+	if (value == NULL)
+	  return -1;
+
+	break;
+      }
+    }
+
+    if (value) {
+      *return_value = value;
+      n++;
+    }
+  }
+
+  va_end(ap);
+
+  return n;
+}
+
+int auth_struct_copy(void *dst, void const *src, isize_t s_size)
+{
+  int d_size = *(int *)dst;
+
+  if (d_size < 0)
+    return -1;
+
+  if ((size_t)d_size > s_size) {
+    memcpy(dst, src, s_size);
+    memset((char *)dst + s_size, 0, d_size - s_size);
+  }
+  else {
+    memcpy(dst, src, d_size);
+    *(int *)dst = d_size;
+  }
+  return 0;
+}
+
+static inline int has_token(char const *qstring, char const *token)
+{
+  size_t n = strlen(token);
+  char const *q;
+
+  q = strcasestr(qstring, token);
+  return (q &&
+	  (q[n] == 0 || strchr("\", \t", q[n])) &&
+	  (q == qstring || strchr("\", \t", q[-1])));
+}
+
+
+/** Compare two strings, even if they are quoted */
+int auth_strcmp(char const *quoted, char const *unquoted)
+{
+  size_t i, j;
+
+  if (quoted[0] != '"')
+    return strcmp(quoted, unquoted);
+
+  /* Compare quoted with unquoted  */
+
+  for (i = 1, j = 0; ; i++, j++) {
+    char q = quoted[i], u = unquoted[j];
+
+    if (q == '"')
+      q = '\0';
+    else if (q == '\\' && u != '\0')
+      q = quoted[i++];
+
+    if (q - u)
+      return q - u;
+
+    if (q == '\0')
+      return 0;
+  }
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,350 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_digest.c
+ *
+ * Implementation for digest authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_md5.h>
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/auth_digest.h"
+#include "sofia-sip/msg_header.h"
+#include "sofia-sip/auth_common.h"
+
+#include "iptsec_debug.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <assert.h>
+
+/**Get digest-challenge parameters.
+ *
+ * The function digest_challenge_get() searches for the digest authentication
+ * parameters in @a params.  The parameters are assigned to the appropriate
+ * fields in @a ac structure.
+ *
+ * @return
+ *
+ * The function digest_challenge_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_digest_challenge_get(su_home_t *home,
+				   auth_challenge_t *ac0, 
+				   char const * const params[])
+{
+  ssize_t n;
+  auth_challenge_t ac[1] = {{ 0 }};
+  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+    *stale = NULL,
+    *qop_auth = NULL, *qop_auth_int = NULL;
+
+  ac->ac_size = sizeof(ac);
+
+  assert(ac0); 
+  assert(ac0->ac_size >= (int) sizeof(*ac));
+
+  if (ac0 == NULL || params == NULL)
+    return -1;
+
+  n = auth_get_params(home, params,
+		      "realm=", &ac->ac_realm,
+		      "domain=", &ac->ac_domain,
+		      "nonce=", &ac->ac_nonce,
+		      "opaque=", &ac->ac_opaque,
+		      "algorithm=", &ac->ac_algorithm,
+		      "qop=", &ac->ac_qop,
+		      "algorithm=md5", &md5,
+		      "algorithm=md5-sess", &md5sess,
+		      "algorithm=sha1", &sha1,
+		      "stale=true", &stale,
+		      "qop=auth", &qop_auth,
+		      "qop=auth-int", &qop_auth_int,
+		      NULL);
+  if (n < 0)
+    return n;
+
+  ac->ac_stale = stale != NULL;
+  ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;
+  ac->ac_md5sess = md5sess != NULL;
+  ac->ac_sha1 = sha1 != NULL;
+  ac->ac_auth = qop_auth != NULL;
+  ac->ac_auth_int = qop_auth_int != NULL;
+
+  auth_struct_copy(ac0, ac, sizeof(ac));
+
+  SU_DEBUG_5(("%s(): got "MOD_ZD"\n", "auth_digest_challenge_get", n));
+  
+  return n;
+}
+
+/** Free challenge parameters */
+void auth_digest_challenge_free_params(su_home_t *home, auth_challenge_t *ac)
+{
+  if (ac->ac_realm)
+    su_free(home, (void *)ac->ac_realm), ac->ac_realm = NULL;
+  if (ac->ac_domain)
+    su_free(home, (void *)ac->ac_domain), ac->ac_domain = NULL;
+  if (ac->ac_nonce)
+    su_free(home, (void *)ac->ac_nonce), ac->ac_nonce = NULL;
+  if (ac->ac_opaque)
+    su_free(home, (void *)ac->ac_opaque), ac->ac_opaque = NULL;
+  if (ac->ac_algorithm)
+    su_free(home, (void *)ac->ac_algorithm), ac->ac_algorithm = NULL;
+  if (ac->ac_qop)
+    su_free(home, (void *)ac->ac_qop), ac->ac_qop = NULL;
+}
+
+/**Get digest-response parameters.
+ *
+ * The function auth_response_get() searches for the digest authentication
+ * parameters in @a params.  The parameters are assigned to the appropriate
+ * fields in @a ar structure.
+ *
+ * @return
+ *
+ * The function auth_response_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_digest_response_get(su_home_t *home,
+				  auth_response_t *ar0, 
+				  char const *const params[])
+{
+  ssize_t n;
+  auth_response_t ar[1] = {{ 0 }};
+  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+    *qop_auth = NULL, *qop_auth_int = NULL;
+
+  ar->ar_size = sizeof(ar);
+
+  assert(ar0); assert(params); assert(ar0->ar_size >= (int) sizeof(ar));
+
+  if (ar0 == NULL || params == NULL)
+    return -1;
+
+  n = auth_get_params(home, params,
+		      "username=", &ar->ar_username,
+		      "realm=", &ar->ar_realm,
+		      "nonce=", &ar->ar_nonce,
+		      "uri=", &ar->ar_uri,
+		      "response=", &ar->ar_response,
+		      "algorithm=", &ar->ar_algorithm,
+		      "opaque=", &ar->ar_opaque,
+		      "cnonce=", &ar->ar_cnonce,
+		      "qop=", &ar->ar_qop,
+		      "nc=", &ar->ar_nc,
+		      "algorithm=md5", &md5,
+		      "algorithm=md5-sess", &md5sess,
+		      "algorithm=sha1", &sha1,
+		      "qop=auth", &qop_auth,
+		      "qop=auth-int", &qop_auth_int,
+		      NULL);
+  if (n < 0)
+    return n;
+
+  ar->ar_md5      = md5 != NULL || ar->ar_algorithm == NULL;
+  ar->ar_md5sess  = md5sess != NULL;
+  ar->ar_sha1     = sha1 != NULL;
+  ar->ar_auth     = qop_auth != NULL;
+  ar->ar_auth_int = qop_auth_int != NULL;
+
+  auth_struct_copy(ar0, ar, sizeof(ar));
+
+  SU_DEBUG_7(("%s: "MOD_ZD"\n", "auth_digest_response_get", n));
+
+  return n;
+}
+
+static void unquote_update(su_md5_t md5[1], char const *quoted)
+{
+  if (!quoted)
+    /*xyzzy*/;
+  else if (quoted[0] == '"') {
+    char const *q; 
+    size_t n;
+
+    for (q = quoted + 1; *q; q += n + 2) {
+      n = strcspn(q, "\"\\");
+      su_md5_update(md5, q, n);
+      if (q[n] == '"' || q[n] == '\0')
+	break;
+      su_md5_update(md5, q + n + 1, 1);
+    }
+  }
+  else
+    su_md5_strupdate(md5, quoted);
+}
+
+/** Generate A1 hash for digest authentication. 
+ */
+int auth_digest_a1(auth_response_t *ar, 
+		   auth_hexmd5_t ha1,
+		   char const *secret)
+{
+  su_md5_t md5[1];
+
+  /* Calculate A1 */
+  su_md5_init(md5);
+  su_md5_strupdate(md5, ar->ar_username);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_realm);
+  su_md5_update(md5, ":", 1);
+  su_md5_strupdate(md5, secret);
+
+  su_md5_hexdigest(md5, ha1);
+
+  SU_DEBUG_5(("auth_digest_a1() has A1 = MD5(%s:%s:%s) = %s\n", 
+	      ar->ar_username, ar->ar_realm, secret, ha1));
+
+  return 0;
+}
+
+int auth_digest_a1sess(auth_response_t *ar, 
+		       auth_hexmd5_t ha1sess,
+		       char const *ha1)
+{
+  su_md5_t md5[1];
+
+  su_md5_init(md5);
+  su_md5_strupdate(md5, ha1);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_nonce);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_cnonce);
+
+  su_md5_hexdigest(md5, ha1sess);
+
+  SU_DEBUG_5(("auth_sessionkey has A1' = MD5(%s:%s:%s) = %s\n", 
+	      ha1, ar->ar_nonce, ar->ar_cnonce, ha1sess));
+
+  return 0;
+}
+
+/** Generate MD5 session key for digest authentication. 
+ */
+int auth_digest_sessionkey(auth_response_t *ar, 
+			   auth_hexmd5_t ha1,
+			   char const *secret)
+{
+  if (ar->ar_md5sess)
+    ar->ar_algorithm = "MD5-sess";
+  else if (ar->ar_md5)
+    ar->ar_algorithm = "MD5";
+  else
+    return -1;
+
+  if (ar->ar_md5sess) {
+    auth_hexmd5_t base_ha1; 
+    auth_digest_a1(ar, base_ha1, secret);
+    auth_digest_a1sess(ar, ha1, base_ha1);
+  } else {
+    auth_digest_a1(ar, ha1, secret);
+  }
+
+  return 0;
+}
+
+/** Generate response for digest authentication. 
+ *
+ */
+int auth_digest_response(auth_response_t *ar, 
+			 auth_hexmd5_t response,
+			 auth_hexmd5_t const ha1, 
+			 char const *method_name,
+			 void const *data, isize_t dlen)
+{
+  su_md5_t md5[1];
+  auth_hexmd5_t Hentity, HA2;
+
+  if (ar->ar_auth_int)
+    ar->ar_qop = "auth-int";
+  else if (ar->ar_auth)
+    ar->ar_qop = "auth";
+  else
+    ar->ar_qop = NULL;
+
+  /* Calculate Hentity */
+  if (ar->ar_auth_int) {
+    if (data && dlen) {
+      su_md5_init(md5);
+      su_md5_update(md5, data, dlen);
+      su_md5_hexdigest(md5, Hentity);
+    } else {
+      strcpy(Hentity, "d41d8cd98f00b204e9800998ecf8427e");
+    }
+  }
+
+  /* Calculate A2 */
+  su_md5_init(md5);
+  su_md5_strupdate(md5, method_name);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_uri);
+  if (ar->ar_auth_int) {
+    su_md5_update(md5, ":", 1);
+    su_md5_update(md5, Hentity, sizeof(Hentity) - 1);
+  }
+  su_md5_hexdigest(md5, HA2);
+
+  SU_DEBUG_5(("A2 = MD5(%s:%s%s%s)\n", method_name, ar->ar_uri, 
+	      ar->ar_auth_int ? ":" : "", ar->ar_auth_int ? Hentity : ""));
+
+  /* Calculate response */
+  su_md5_init(md5);
+  su_md5_update(md5, ha1, 32);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_nonce);
+
+  if (ar->ar_auth || ar->ar_auth_int) {
+    su_md5_update(md5, ":", 1);
+    su_md5_strupdate(md5, ar->ar_nc);
+    su_md5_update(md5, ":", 1);
+    unquote_update(md5, ar->ar_cnonce);
+    su_md5_update(md5, ":", 1);
+    su_md5_strupdate(md5, ar->ar_qop);
+  }
+
+  su_md5_update(md5, ":", 1);
+  su_md5_update(md5, HA2, 32);      
+  su_md5_hexdigest(md5, response);
+
+  SU_DEBUG_5(("auth_response: %s = MD5(%s:%s%s%s%s%s%s%s:%s) (qop=%s)\n", 
+	      response, ha1, ar->ar_nonce, 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_nc : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_cnonce : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_qop : "", 
+	      HA2,
+	      ar->ar_qop ? ar->ar_qop : "NONE"));
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1529 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_module.c
+ * @brief Authentication verification module
+ *
+ * The authentication module provides server or proxy-side authentication
+ * verification for network elements like registrars, presence servers, and
+ * proxies.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include "iptsec_debug.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_mod";
+#endif
+
+#include <sofia-sip/su_debug.h>
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_md5.h>
+
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_date.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+#define APW_HASH(apw) ((apw)->apw_index)
+
+char const auth_internal_server_error[] = "Internal server error";
+
+static void auth_md5_hmac_key(auth_mod_t *am);
+
+HTABLE_PROTOS_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
+HTABLE_BODIES_WITH(auth_htable, aht, auth_passwd_t, APW_HASH, 
+		   usize_t, unsigned);
+
+/**Allocate an authentication module instance.
+ *
+ * The function auth_mod_alloc() allocates an authentication module object.
+ *
+ */
+auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  auth_mod_t *am = NULL;
+
+  if ((am = su_home_new(scheme->asch_size))) {
+    am->am_scheme = scheme;
+    am->am_refcount = 1;
+  }
+
+  return am;
+}
+
+/**Initialize an authentication module instance.
+ *
+ * The function auth_mod_init_default() initializes an authentication module
+ * object used to authenticate the requests.
+ *
+ * @param am
+ * @param base
+ * @param root
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * AUTHTAG_REALM(), AUTHTAG_OPAQUE(), AUTHTAG_DB(), AUTHTAG_QOP(),
+ * AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(), AUTHTAG_NEXT_EXPIRES(),
+ * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
+ * AUTHTAG_FAKE(), AUTHTAG_ALLOW(), AUTHTAG_REMOTE(), and
+ * AUTHTAG_MASTER_KEY().
+ *
+ * @return 0 if successful
+ * @return -1 upon an error
+ */
+int auth_init_default(auth_mod_t *am,
+		      auth_scheme_t *base,
+		      su_root_t *root,
+		      tag_type_t tag, tag_value_t value, ...)
+{
+  int retval = 0;
+
+  ta_list ta;
+
+  char const *realm = NULL, *opaque = NULL, *db = NULL, *allows = NULL;
+  char const *qop = NULL, *algorithm = NULL;
+  unsigned expires = 60 * 60, next_expires = 5 * 60;
+  unsigned blacklist = 5;
+  int forbidden = 0;
+  int anonymous = 0;
+  int fake = 0;
+  url_string_t const *remote = NULL;
+  char const *master_key = "fish";
+  char *s;
+
+  ta_start(ta, tag, value);
+
+  /* Authentication stuff */
+  tl_gets(ta_args(ta),
+	  AUTHTAG_REALM_REF(realm),
+	  AUTHTAG_OPAQUE_REF(opaque),
+	  AUTHTAG_DB_REF(db),
+	  AUTHTAG_QOP_REF(qop),
+	  AUTHTAG_ALGORITHM_REF(algorithm),
+	  AUTHTAG_EXPIRES_REF(expires),
+	  AUTHTAG_NEXT_EXPIRES_REF(next_expires),
+	  AUTHTAG_BLACKLIST_REF(blacklist),
+	  AUTHTAG_FORBIDDEN_REF(forbidden),
+	  AUTHTAG_ANONYMOUS_REF(anonymous),
+	  AUTHTAG_FAKE_REF(fake),
+	  AUTHTAG_ALLOW_REF(allows),
+	  AUTHTAG_REMOTE_REF(remote),
+	  AUTHTAG_MASTER_KEY_REF(master_key),
+	  TAG_NULL());
+
+  if (!realm) realm = "*";
+  if (!allows) allows = "ACK, BYE, CANCEL";
+
+  am->am_realm = su_strdup(am->am_home, realm);
+  am->am_opaque = su_strdup(am->am_home, opaque);
+  am->am_db = su_strdup(am->am_home, db);
+  s = su_strdup(am->am_home, allows);
+  if (s)
+    msg_commalist_d(am->am_home, &s, &am->am_allow, NULL);
+  am->am_expires = expires;
+  am->am_next_exp = next_expires;
+  am->am_blacklist = blacklist;
+  am->am_forbidden = forbidden;
+  am->am_anonymous = anonymous;
+  am->am_fake = fake;
+  am->am_remote = url_hdup(am->am_home, (url_t *)remote);
+  am->am_algorithm = algorithm ? su_strdup(am->am_home, algorithm) : "MD5";
+  am->am_nextnonce = !algorithm || strcasecmp(algorithm, "MD5") == 0;
+  if (next_expires == 0)
+    am->am_nextnonce = 0;
+  am->am_qop = su_strdup(am->am_home, qop);
+
+  if (master_key) {
+    su_md5_t md5[1];
+
+    su_md5_init(md5);
+    su_md5_strupdate(md5, master_key);
+    su_md5_strupdate(md5, "70P 53KR37");
+    su_md5_digest(md5, am->am_master_key);
+  }
+
+  auth_md5_hmac_key(am);
+
+  /* Make sure that we have something
+     that can be used to identify credentials */
+  if (am->am_opaque && strcmp(am->am_opaque, "*") == 0) {
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+    char hostname[HOST_NAME_MAX + 1];
+    su_md5_t md5[1];
+    uint8_t hmac[6];
+
+    gethostname(hostname, sizeof hostname);
+
+    auth_md5_hmac_init(am, md5);
+
+    su_md5_strupdate(md5, hostname);
+    su_md5_update(md5, ":", 1);
+    if (am->am_remote)
+      url_update(md5, am->am_remote);
+
+    auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);
+
+    base64_e(hostname, sizeof hostname, hmac, sizeof hmac);
+
+    am->am_opaque = su_strdup(am->am_home, hostname);
+
+    if (!am->am_opaque) {
+      retval = -1;
+      SU_DEBUG_1(("%s: cannot create unique identifier\n", __func__));
+    }
+  }
+
+  if (retval < 0)
+    ;
+  else if (db) {
+    retval = auth_readdb(am);
+    if (retval == -1) {
+      int err = errno;
+      SU_DEBUG_1(("auth-module: %s: %s\n", am->am_db, strerror(err)));
+      errno = err;
+    }
+  }
+  else {
+    retval = auth_htable_resize(am->am_home, am->am_users, 0);
+  }
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/** Destroy (a reference to) an authentication module. */
+void auth_mod_destroy(auth_mod_t *am)
+{
+  if (am && am->am_refcount != 0 && --am->am_refcount == 0) {
+    am->am_scheme->asch_destroy(am);
+    su_home_zap(am->am_home);
+  }
+}
+
+/** Do-nothing destroy function.
+ *
+ * The auth_destroy_default() is the default member function called by
+ * auth_mod_destroy().
+ */
+void auth_destroy_default(auth_mod_t *am)
+{
+}
+
+/** Create a new reference to authentication module. */
+auth_mod_t *auth_mod_ref(auth_mod_t *am)
+{
+  if (!am || am->am_refcount == 0)
+    return NULL;
+
+  am->am_refcount++;
+
+  return am;
+}
+
+/** Destroy a reference to an authentication module. */
+void auth_mod_unref(auth_mod_t *am)
+{
+  auth_mod_destroy(am);
+}
+
+/** Get authenticatin module name. @NEW_1_12_4. */
+char const *auth_mod_name(auth_mod_t *am)
+{
+  return am ? am->am_scheme->asch_method : "<nil>";
+}
+
+/** Initialize a auth_status_t stucture.
+ *
+ * @retval NULL upon an error
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_init(void *p, isize_t size)
+{
+  return auth_status_init_with(p, size, 500, auth_internal_server_error);
+}
+
+/** Initialize a auth_status_t stucture.
+ *
+ * @retval NULL upon an error
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_init_with(void *p,
+				     isize_t size,
+				     int status,
+				     char const *phrase)
+{
+  auth_status_t *as;
+
+  if (!p || size < (sizeof *as))
+    return NULL;
+
+  if (size > INT_MAX) size = INT_MAX;
+
+  as = memset(p, 0, size);
+  as->as_home->suh_size = (int)size;
+
+  /* su_home_init(as->as_home); */
+
+  as->as_status = status, as->as_phrase = phrase;
+
+  return as;
+}
+
+/** Allocate a new auth_status_t structure. @relates auth_status_t */
+
+auth_status_t *auth_status_new(su_home_t *home)
+{
+  auth_status_t *as = su_home_clone(home, (sizeof *as));
+  if (as) {
+    as->as_status = 500;
+    as->as_phrase = auth_internal_server_error;
+  }
+  return as;
+}
+
+/** Create a new reference to an auth_status_t structure.
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_ref(auth_status_t *as)
+{
+  return (auth_status_t *)su_home_ref(as->as_home);
+}
+
+/** Destroy (a reference to) an auth_status_t structure. @relates auth_status_t
+ */
+void auth_status_unref(auth_status_t *as)
+{
+  su_home_unref(as->as_home);
+}
+
+/** Authenticate user.
+ *
+ * The function auth_mod_method() invokes scheme-specific authentication
+ * operation where the user's credentials are checked using scheme-specific
+ * method. The authentication result along with an optional challenge header
+ * is stored in the @a as structure.
+ *
+ * @param am           pointer to authentication module object [in]
+ * @param as           pointer to authentication status structure [in/out]
+ * @param credentials  pointer to a header with user's credentials [in]
+ * @param ach          pointer to a structure describing challenge [in]
+ *
+ * The @a ach structure defines what kind of response and challenge header
+ * is returned to the user. For example, a server authentication is
+ * implemented with 401 response code and phrase along with WWW-Authenticate
+ * header template in the @a ach structure.
+ *
+ * The auth_mod_method() returns the authentication result in the
+ * #auth_mod_t @a as structure. The @a as->as_status describes the result
+ * as follows:
+ * - <i>as->as_status == 0</i> authentication is successful
+ * - <i>as->as_status == 100</i> authentication is pending
+ * - <i>as->as_status >= 400</i> authentication fails,
+ *   return as_status as an error code to client
+ *
+ * When the authentication is left pending, the client must set the
+ * as_callback pointer in @a as structure to an appropriate callback
+ * function. The callback is invoked when the authentication is completed,
+ * either successfully or with an error.
+ *
+ * Note that the authentication module may generate a new challenge each
+ * time authentication is used (e.g., Digest using MD5 algorithm). Such a
+ * challenge header is stored in the @a as->as_response return-value field.
+ *
+ * @note The authentication plugin may use the given reference to @a as, @a
+ * credentials and @a ach structures until the asynchronous authentication
+ * completes. Therefore, they should not be allocated from stack unless
+ * application uses strictly synchronous authentication schemes only (Basic
+ * and Digest).
+ *
+ * @note This function should be called auth_mod_check().
+ */
+void auth_mod_verify(auth_mod_t *am,
+		     auth_status_t *as,
+		     msg_auth_t *credentials,
+		     auth_challenger_t const *ach)
+{
+  char const *wildcard, *host;
+
+  if (!am || !as || !ach)
+    return;
+
+  wildcard = strchr(am->am_realm, '*');
+
+  host = as->as_domain;
+
+  /* Initialize per-request realm */
+  if (as->as_realm)
+    ;
+  else if (!wildcard) {
+    as->as_realm = am->am_realm;
+  }
+  else if (!host) {
+    return;			/* Internal error */
+  }
+  else if (strcmp(am->am_realm, "*") == 0) {
+    as->as_realm = host;
+  }
+  else {
+    /* Replace * with hostpart */
+    as->as_realm = su_sprintf(as->as_home, "%.*s%s%s",
+			      (int)(wildcard - am->am_realm), am->am_realm,
+			      host,
+			      wildcard + 1);
+  }
+
+  am->am_scheme->asch_check(am, as, credentials, ach);
+}
+
+/** Make a challenge header.
+ *
+ * This function invokes plugin-specific member function generating a
+ * challenge header. Client uses the challenge header contents when
+ * prompting the user for a username and password then generates its
+ * credential header using the parameters given in the challenge header.
+ *
+ * @param am pointer to authentication module object
+ * @param as pointer to authentication status structure (return-value)
+ * @param ach pointer to a structure describing challenge
+ *
+ * The auth_mod_challenge() returns the challenge header, appropriate
+ * response code and reason phrase in the #auth_status_t structure. The
+ * auth_mod_challenge() is currently always synchronous function.
+ */
+void auth_mod_challenge(auth_mod_t *am,
+			auth_status_t *as,
+			auth_challenger_t const *ach)
+{
+  if (am && as && ach)
+    am->am_scheme->asch_challenge(am, as, ach);
+}
+
+
+/** Cancel asynchronous authentication.
+ *
+ * The auth_mod_cancel() function cancels a pending authentication.
+ * Application can reclaim the authentication status, credential and
+ * challenger objects by using auth_mod_cancel().
+ */
+void auth_mod_cancel(auth_mod_t *am, auth_status_t *as)
+{
+  if (am && as)
+    am->am_scheme->asch_cancel(am, as);
+}
+
+/** Do-nothing cancel function.
+ *
+ * The auth_cancel_default() is the default member function called by
+ * auth_mod_cancel().
+ */
+void auth_cancel_default(auth_mod_t *am, auth_status_t *as)
+{
+}
+
+/* ====================================================================== */
+/* Basic authentication scheme */
+
+static void auth_method_basic_x(auth_mod_t *am,
+				auth_status_t *as,
+				msg_auth_t *au,
+				auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_basic[1] =
+  {{
+      "Basic",			/* asch_method */
+      sizeof (auth_mod_t),	/* asch_size */
+      auth_init_default,	/* asch_init */
+      auth_method_basic_x, 	/* asch_check */
+      auth_challenge_basic,	/* asch_challenge */
+      auth_cancel_default,	/* asch_cancel */
+      auth_destroy_default	/* asch_destroy */
+  }};
+
+/**Authenticate a request with @b Basic authentication.
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_basic_x(auth_mod_t *am,
+			 auth_status_t *as,
+			 msg_auth_t *au,
+			 auth_challenger_t const *ach)
+{
+  if (am) {
+    auth_readdb_if_needed(am);
+    auth_method_basic(am, as, au, ach);
+  }
+}
+
+/** Authenticate a request with @b Basic authentication scheme.
+ *
+ */
+void auth_method_basic(auth_mod_t *am,
+		       auth_status_t *as,
+		       msg_auth_t *au,
+		       auth_challenger_t const *ach)
+{
+  char *userpass, buffer[128];
+  size_t n, upsize;
+  char *pass;
+  auth_passwd_t *apw;
+
+  if (!as->as_realm)
+    return;
+
+  userpass = buffer, upsize = sizeof buffer;
+
+  for (au = auth_mod_credentials(au, "Basic", NULL);
+       au;
+       au = auth_mod_credentials(au->au_next, "Basic", NULL)) {
+    if (!au->au_params)
+      continue;
+    n = base64_d(userpass, upsize - 1, au->au_params[0]);
+    if (n < 0 || n >= INT_MAX)
+      continue;
+    if (n >= upsize) {
+      upsize = n + 1;
+      userpass = realloc(userpass == buffer ? NULL : userpass, upsize);
+      if (userpass == NULL)
+	continue;
+      base64_d(userpass, upsize - 1, au->au_params[0]);
+    }
+    userpass[n] = 0;
+    if (!(pass = strchr(userpass, ':')))
+      continue;
+    *pass++ = '\0';
+    SU_DEBUG_5(("auth_method_basic: %s => %s:%s\n",
+		au->au_params[0], userpass, pass));
+
+    if (!(apw = auth_mod_getpass(am, userpass, as->as_realm)))
+      continue;
+    if (strcmp(apw->apw_pass, pass))
+      continue;
+
+    as->as_user = apw->apw_user;
+    as->as_anonymous = apw == am->am_anon_user;
+    as->as_ident = apw->apw_ident;
+    as->as_match = (msg_header_t *)au;
+    as->as_status = 0;	/* Successful authentication! */
+
+    break;
+  }
+
+  if (userpass != buffer)
+    free(userpass);
+
+  if (au)
+    return;
+
+  if (auth_allow_check(am, as))
+    auth_challenge_basic(am, as, ach);
+}
+
+/** Construct a challenge header for @b Basic authentication scheme. */
+void auth_challenge_basic(auth_mod_t *am,
+			  auth_status_t *as,
+			  auth_challenger_t const *ach)
+{
+  as->as_status = ach->ach_status;
+  as->as_phrase = ach->ach_phrase;
+  as->as_response = msg_header_format(as->as_home, ach->ach_header,
+				      "Basic realm=\"%s\"", as->as_realm);
+}
+
+/* ====================================================================== */
+/* Digest authentication scheme */
+
+static void auth_method_digest_x(auth_mod_t *am,
+				 auth_status_t *as,
+				 msg_auth_t *au,
+				 auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_digest[1] =
+  {{
+      "Digest",			/* asch_method */
+      sizeof (auth_mod_t),	/* asch_size */
+      auth_init_default,	/* asch_init */
+      auth_method_digest_x,	/* asch_check */
+      auth_challenge_digest,	/* asch_challenge */
+      auth_cancel_default,	/* asch_cancel */
+      auth_destroy_default	/* asch_destroy */
+  }};
+
+struct nonce {
+  msg_time_t issued;
+  uint32_t   count;
+  uint16_t   nextnonce;
+  uint8_t    digest[6];
+};
+
+#define AUTH_DIGEST_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
+
+/** Authenticate a request with @b Digest authentication scheme.
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_digest_x(auth_mod_t *am,
+			  auth_status_t *as,
+			  msg_auth_t *au,
+			  auth_challenger_t const *ach)
+{
+  if (am) {
+    auth_readdb_if_needed(am);
+    auth_method_digest(am, as, au, ach);
+  }
+}
+
+/** Authenticate a request with @b Digest authentication scheme.
+ */
+void auth_method_digest(auth_mod_t *am,
+			auth_status_t *as,
+			msg_auth_t *au,
+			auth_challenger_t const *ach)
+{
+  as->as_allow = as->as_allow || auth_allow_check(am, as) == 0;
+
+  if (as->as_realm)
+    au = auth_digest_credentials(au, as->as_realm, am->am_opaque);
+  else
+    au = NULL;
+
+  if (as->as_allow) {
+    SU_DEBUG_5(("%s: allow unauthenticated %s\n", __func__, as->as_method));
+    as->as_status = 0, as->as_phrase = NULL;
+    as->as_match = (msg_header_t *)au;
+    return;
+  }
+
+  if (au) {
+    auth_response_t ar[1] = {{ sizeof(ar) }};
+    auth_digest_response_get(as->as_home, ar, au->au_params);
+    as->as_match = (msg_header_t *)au;
+    auth_check_digest(am, as, ar, ach);
+  }
+  else {
+    /* There was no matching credentials, send challenge */
+    SU_DEBUG_5(("%s: no credentials matched\n", __func__));
+    auth_challenge_digest(am, as, ach);
+  }
+}
+
+/** Verify digest authentication */
+void auth_check_digest(auth_mod_t *am,
+		       auth_status_t *as,
+		       auth_response_t *ar,
+		       auth_challenger_t const *ach)
+{
+  char const *a1;
+  auth_hexmd5_t a1buf, response;
+  auth_passwd_t *apw;
+  char const *phrase;
+  msg_time_t now = msg_now();
+
+  if (am == NULL || as == NULL || ar == NULL || ach == NULL) {
+    if (as) {
+      as->as_status = 500, as->as_phrase = "Internal Server Error";
+      as->as_response = NULL;
+    }
+    return;
+  }
+
+  phrase = "Bad authorization";
+
+#define PA "Authorization missing "
+
+  if ((!ar->ar_username && (phrase = PA "username")) ||
+      (!ar->ar_nonce && (phrase = PA "nonce")) ||
+      (!ar->ar_uri && (phrase = PA "URI")) ||
+      (!ar->ar_response && (phrase = PA "response")) ||
+      /* (!ar->ar_opaque && (phrase = PA "opaque")) || */
+      /* Check for qop */
+      (ar->ar_qop &&
+       ((ar->ar_auth &&
+	 strcasecmp(ar->ar_qop, "auth") &&
+	 strcasecmp(ar->ar_qop, "\"auth\"")) ||
+	(ar->ar_auth_int &&
+	 strcasecmp(ar->ar_qop, "auth-int") &&
+	 strcasecmp(ar->ar_qop, "\"auth-int\"")))
+       && (phrase = PA "has invalid qop"))) {
+    assert(phrase);
+    SU_DEBUG_5(("auth_method_digest: 400 %s\n", phrase));
+    as->as_status = 400, as->as_phrase = phrase;
+    as->as_response = NULL;
+    return;
+  }
+
+  if (as->as_nonce_issued == 0 /* Already validated nonce */ &&
+      auth_validate_digest_nonce(am, as, ar, now) < 0) {
+    as->as_blacklist = am->am_blacklist;
+    auth_challenge_digest(am, as, ach);
+    return;
+  }
+
+  if (as->as_stale) {
+    auth_challenge_digest(am, as, ach);
+    return;
+  }
+
+  apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm);
+
+  if (apw && apw->apw_hash)
+    a1 = apw->apw_hash;
+  else if (apw && apw->apw_pass)
+    auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+  else
+    auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+
+  if (ar->ar_md5sess)
+    auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf;
+
+  auth_digest_response(ar, response, a1,
+		       as->as_method, as->as_body, as->as_bodylen);
+
+  if (!apw || strcmp(response, ar->ar_response)) {
+
+    if (am->am_forbidden) {
+      as->as_status = 403, as->as_phrase = "Forbidden";
+      as->as_response = NULL;
+      as->as_blacklist = am->am_blacklist;
+    }
+    else {
+      auth_challenge_digest(am, as, ach);
+      as->as_blacklist = am->am_blacklist;
+    }
+    SU_DEBUG_5(("auth_method_digest: response did not match\n"));
+
+    return;
+  }
+
+  assert(apw);
+
+  as->as_user = apw->apw_user;
+  as->as_anonymous = apw == am->am_anon_user;
+  as->as_ident = apw->apw_ident;
+
+  if (am->am_nextnonce || am->am_mutual)
+    auth_info_digest(am, as, ach);
+
+  if (am->am_challenge)
+    auth_challenge_digest(am, as, ach);
+
+  SU_DEBUG_7(("auth_method_digest: successful authentication\n"));
+
+  as->as_status = 0;	/* Successful authentication! */
+  as->as_phrase = "";
+}
+
+/** Construct a challenge header for @b Digest authentication scheme. */
+void auth_challenge_digest(auth_mod_t *am,
+			   auth_status_t *as,
+			   auth_challenger_t const *ach)
+{
+  char const *u, *d;
+  char nonce[AUTH_DIGEST_NONCE_LEN];
+
+  auth_generate_digest_nonce(am, nonce, sizeof nonce, 0, msg_now());
+
+  u = as->as_uri;
+  d = as->as_pdomain;
+
+  as->as_response =
+    msg_header_format(as->as_home, ach->ach_header,
+		      "Digest"
+		      " realm=\"%s\","
+		      "%s%s%s"
+		      "%s%s%s"
+		      " nonce=\"%s\","
+		      "%s%s%s"
+		      "%s"	/* stale */
+		      " algorithm=%s"
+		      "%s%s%s",
+		      as->as_realm,
+		      u ? " uri=\"" : "", u ? u : "", u ? "\"," : "",
+		      d ? " domain=\"" : "", d ? d : "", d ? "\"," : "",
+		      nonce,
+		      am->am_opaque ? " opaque=\"" : "",
+		      am->am_opaque ? am->am_opaque : "",
+		      am->am_opaque ? "\"," : "",
+		      as->as_stale ? " stale=true," : "",
+		      am->am_algorithm,
+		      am->am_qop ? ", qop=\"" : "",
+		      am->am_qop ? am->am_qop : "",
+		      am->am_qop ? "\"" : "");
+
+  if (!as->as_response)
+    as->as_status = 500, as->as_phrase = auth_internal_server_error;
+  else
+    as->as_status = ach->ach_status, as->as_phrase = ach->ach_phrase;
+}
+
+/** Construct a info header for @b Digest authentication scheme. */
+void auth_info_digest(auth_mod_t *am,
+		      auth_status_t *as,
+		      auth_challenger_t const *ach)
+{
+  if (!ach->ach_info)
+    return;
+
+  if (am->am_nextnonce) {
+    char nonce[AUTH_DIGEST_NONCE_LEN];
+
+    auth_generate_digest_nonce(am, nonce, sizeof nonce, 1, msg_now());
+
+    as->as_info =
+      msg_header_format(as->as_home, ach->ach_info, "nextnonce=\"%s\"", nonce);
+  }
+}
+
+
+/* ====================================================================== */
+/* Password database */
+
+static inline void
+auth_htable_append_local(auth_htable_t *pr, auth_passwd_t *apw);
+
+/** Get an passwd entry for user. */
+auth_passwd_t *auth_mod_getpass(auth_mod_t *am,
+				char const *user,
+				char const *realm)
+{
+  auth_passwd_t *apw, **slot;
+  unsigned hash;
+
+  if (am == NULL || user == NULL)
+    return NULL;
+
+  hash = msg_hash_string(user);
+
+  for (slot = auth_htable_hash(am->am_users, hash);
+       (apw = *slot);
+       slot = auth_htable_next(am->am_users, slot)) {
+    if (hash != apw->apw_index)
+      continue;
+    if (strcmp(user, apw->apw_user))
+      continue;
+    if (realm && apw->apw_realm[0] && strcmp(realm, apw->apw_realm))
+      continue;
+    break;			/* Found it */
+  }
+
+  return apw;
+}
+
+/** Add a password entry. */
+auth_passwd_t *auth_mod_addpass(auth_mod_t *am,
+				char const *user,
+				char const *realm)
+{
+  auth_passwd_t *apw, **slot;
+  unsigned index;
+
+  if (am == NULL || user == NULL)
+    return NULL;
+
+  index = msg_hash_string(user);
+
+  for (slot = auth_htable_hash(am->am_users, index);
+       (apw = *slot);
+       slot = auth_htable_next(am->am_users, slot)) {
+    if (index != apw->apw_index)
+      continue;
+    if (strcmp(user, apw->apw_user))
+      continue;
+    if (realm && strcmp(realm, apw->apw_realm))
+      continue;
+    break;			/* Found it */
+  }
+
+  if (realm == NULL)
+    realm = "";
+
+  if (!apw) {
+    size_t ulen = strlen(user) + 1, rlen = strlen(realm) + 1;
+    size_t size = sizeof *apw + ulen + rlen;
+
+    apw = su_alloc(am->am_home, size);
+
+    if (apw) {
+      memset(apw, 0, sizeof *apw);
+      apw->apw_index = index;
+      apw->apw_user = memcpy((char *)(apw + 1), user, ulen);
+      apw->apw_realm = memcpy((char *)apw->apw_user + ulen, realm, rlen);
+
+      if (!auth_htable_is_full(am->am_users)) {
+	*slot = apw, am->am_users->aht_used++;
+      } else {
+	if (auth_htable_resize(am->am_home, am->am_users, 0) < 0)
+	  su_free(am->am_home, apw), apw = NULL;
+	else
+	  auth_htable_append(am->am_users, apw);
+      }
+    }
+  }
+
+  return apw;
+}
+
+static ssize_t readfile(su_home_t *, FILE *,
+			void **contents, int add_trailing_lf);
+static int auth_readdb_internal(auth_mod_t *am, int always);
+
+/** Read authentication database */
+int auth_readdb(auth_mod_t *am)
+{
+  return auth_readdb_internal(am, 1);
+}
+
+/** Read authentication database only when needed */
+int auth_readdb_if_needed(auth_mod_t *am)
+{
+  struct stat st[1];
+
+  if (!am->am_stat || !am->am_db)
+    return 0;
+
+  if (stat(am->am_db, st) != -1 &&
+      st->st_dev == am->am_stat->st_dev &&
+      st->st_ino == am->am_stat->st_ino &&
+      st->st_size == am->am_stat->st_size &&
+      memcmp(&st->st_mtime, &am->am_stat->st_mtime,
+	     (sizeof st->st_mtime)) == 0)
+    /* Nothing has changed or passwd file is removed */
+    return 0;
+
+  return auth_readdb_internal(am, 0);
+}
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+#endif
+
+#define auth_apw_local auth_readdb_internal
+
+/** Read authentication database */
+static
+int auth_readdb_internal(auth_mod_t *am, int always)
+{
+  FILE *f;
+  char *data, *s;
+  size_t len, i, n, N;
+  auth_passwd_t *apw;
+
+  if (!am->am_stat)
+    am->am_stat = su_zalloc(am->am_home, sizeof (*am->am_stat));
+
+  f = fopen(am->am_db, "rb");
+
+  if (f) {
+    void *buffer = NULL;
+    auth_passwd_t *fresh = NULL;
+
+#if HAVE_FLOCK
+    int locked;
+
+    /* Obtain shared lock on the database file */
+    if (flock(fileno(f), LOCK_SH | (always ? 0 : LOCK_NB)) == 0) {
+      locked = 1;
+    } else {
+      locked = 0;
+
+      if (errno == ENOLCK) {
+	;
+      }
+      else if (errno == EWOULDBLOCK) {
+	SU_DEBUG_3(("auth(%s): user file \"%s\" is busy, trying again later\n",
+		    am->am_scheme->asch_method, am->am_db));
+	fclose(f);
+	return always ? -1 : 0;
+      }
+      else {
+	SU_DEBUG_3(("auth(%s): flock(\"%s\"): %s (%u)\n",
+		    am->am_scheme->asch_method, am->am_db,
+		    strerror(errno), errno));
+	fclose(f);
+	return always ? -1 : 0;
+      }
+    }
+#endif
+    if (am->am_stat)
+      stat(am->am_db, am->am_stat); /* too bad if this fails */
+
+    len = readfile(am->am_home, f, &buffer, 1);
+
+#if HAVE_FLOCK
+    /* Release shared lock on the database file */
+    if (locked && flock(fileno(f), LOCK_UN) == -1) {
+      SU_DEBUG_0(("auth(%s): un-flock(\"%s\"): %s (%u)\n",
+		  am->am_scheme->asch_method, am->am_db, strerror(errno), errno));
+      fclose(f);
+      return -1;
+    }
+#endif
+
+    fclose(f);
+
+    if (len < 0)
+      return -1;
+
+    /* Count number of entries in new buffer */
+    for (i = am->am_anonymous, s = data = buffer;
+	 s < data + len;
+	 s += n + strspn(s + n, "\r\n")) {
+      n = strcspn(s, "\r\n");
+      if (*s != '#' && *s != '\n' && *s != '\r')
+	i++;
+    }
+
+    N = i, i = 0;
+
+    if (N > 0) {
+      if (auth_htable_resize(am->am_home, am->am_users, N) < 0 ||
+	  !(fresh = su_zalloc(am->am_home, sizeof(*fresh) * N))) {
+	su_free(am->am_home, buffer);
+	return -1;
+      }
+    }
+
+    if (am->am_anonymous) {
+      assert(i < N);
+
+      apw = fresh + i++;
+
+      apw->apw_index = msg_hash_string("anonymous");
+      apw->apw_user = "anonymous";
+      apw->apw_pass = "";
+      apw->apw_realm = "";
+
+      am->am_anon_user = apw;
+
+      if (auth_htable_is_full(am->am_users))
+	auth_htable_resize(am->am_home, am->am_users, 0);
+
+      auth_htable_append_local(am->am_users, apw);
+    }
+
+    apw = NULL;
+
+    for (data = buffer, s = data;
+	 s < data + len && i < N;
+	 s += n + strspn(s + n, "\r\n")) {
+      char *user, *pass, *realm, *ident;
+
+      n = strcspn(s, "\r\n");
+      if (*s == '#')
+	continue;
+
+      user = s;
+      s[n++] = '\0';
+      if (!(pass = strchr(user, ':')))
+	continue;
+
+      *pass++ = '\0';
+      if (!*pass || !*user)
+	continue;
+
+      realm = ""; ident = "";
+
+      if ((realm = strchr(pass, ':'))) {
+	*realm++ = '\0';
+	if ((ident = strchr(realm, ':')))
+	  *ident++ = '\0';
+      }
+
+      apw = fresh + i++;
+
+      apw->apw_index = msg_hash_string(user);
+      apw->apw_user = user;
+      apw->apw_ident = ident;
+
+      /* Check for htdigest format */
+      if (span_hexdigit(realm) == 32 && realm[32] == '\0') {
+	apw->apw_realm = pass;
+	apw->apw_hash = realm;
+      } else {
+	apw->apw_pass = pass;
+	apw->apw_realm = realm;
+      }
+
+      if (auth_htable_is_full(am->am_users))
+	auth_htable_resize(am->am_home, am->am_users, 0);
+
+      auth_htable_append_local(am->am_users, apw);
+    }
+
+    assert(i <= N);
+    N = i;
+
+    /* Remove from hash those entries that were read from old passwd file */
+    for (i = 0; i < am->am_local_count; i++) {
+      if (am->am_locals[i].apw_type == auth_apw_local)
+	auth_htable_remove(am->am_users, &am->am_locals[i]);
+    }
+
+    if (am->am_locals)
+      su_free(am->am_home, am->am_locals); /* Free old entries */
+    if (am->am_buffer)
+      su_free(am->am_home, am->am_buffer); /* Free old passwd file contents */
+
+    SU_DEBUG_5(("auth(%s): read %u entries from \"%s\"\n",
+		am->am_scheme->asch_method, (unsigned)N, am->am_db));
+
+    am->am_locals = fresh;
+    am->am_local_count = N;
+    am->am_buffer = buffer;
+
+    return 0;
+  }
+
+  return -1;
+}
+
+/** Append to hash, remove existing user */
+static inline void
+auth_htable_append_local(auth_htable_t *aht, auth_passwd_t *apw)
+{
+  auth_passwd_t **slot;
+
+  apw->apw_type = auth_apw_local;
+
+  /* Append to hash */
+  for (slot = auth_htable_hash(aht, apw->apw_index);
+       *slot;
+       slot = auth_htable_next(aht, slot)) {
+    if (strcmp((*slot)->apw_user, apw->apw_user) == 0) {
+      if ((*slot)->apw_type == auth_apw_local) {
+	(*slot)->apw_type = NULL;
+	assert(aht->aht_used > 0); aht->aht_used--;
+	apw->apw_extended = (*slot)->apw_extended;
+	*slot = NULL;
+	break;
+      }
+      else {
+	/* We insert local before external entry */
+	auth_passwd_t *swap = apw;
+	apw = *slot;
+	*slot = swap;
+      }
+    }
+  }
+
+  aht->aht_used++; assert(aht->aht_used <= aht->aht_size);
+
+  *slot = apw;
+}
+
+static
+ssize_t readfile(su_home_t *home,
+		 FILE *f,
+		 void **contents,
+		 int add_trailing_lf)
+{
+  /* Read in whole (binary!) file */
+  char *buffer = NULL;
+  long size;
+  size_t len;
+
+  /* Read whole file in */
+  if (fseek(f, 0, SEEK_END) < 0 ||
+      (size = ftell(f)) < 0 ||
+      fseek(f, 0, SEEK_SET) < 0 ||
+      (long)(len = (size_t)size) != size ||
+      size + 2 > SSIZE_MAX) {
+    SU_DEBUG_1(("%s: unable to determine file size (%s)\n",
+		__func__, strerror(errno)));
+    return -1;
+  }
+
+  if (!(buffer = su_alloc(home, len + 2)) ||
+      fread(buffer, 1, len, f) != len) {
+    SU_DEBUG_1(("%s: unable to read file (%s)\n", __func__, strerror(errno)));
+    if (buffer)
+      su_free(home, buffer);
+    return -1;
+  }
+
+  if (add_trailing_lf) {
+    /* Make sure that the buffer has trailing newline */
+    if (len == 0 || buffer[len - 1] != '\n')
+      buffer[len++] = '\n';
+  }
+
+  buffer[len] = '\0';
+  *contents = buffer;
+
+  return len;
+}
+
+/* ====================================================================== */
+/* Helper functions */
+
+/** Check if request method is on always-allowed list.
+ *
+ * @return 0 if allowed
+ * @return 1 otherwise
+ */
+int auth_allow_check(auth_mod_t *am, auth_status_t *as)
+{
+  char const *method = as->as_method;
+  int i;
+
+  if (method && strcmp(method, "ACK") == 0) /* Hack */
+    return as->as_status = 0;
+
+  if (!method || !am->am_allow)
+    return 1;
+
+  if (am->am_allow[0] && strcmp(am->am_allow[0], "*") == 0)
+    return as->as_status = 0;
+
+  for (i = 0; am->am_allow[i]; i++)
+    if (strcmp(am->am_allow[i], method) == 0)
+      return as->as_status = 0;
+
+  return 1;
+}
+
+/** Find a credential header with matching scheme and realm. */
+msg_auth_t *auth_mod_credentials(msg_auth_t *auth,
+				 char const *scheme,
+				 char const *realm)
+{
+  char const *arealm;
+
+  for (;auth; auth = auth->au_next) {
+    if (strcasecmp(auth->au_scheme, scheme))
+      continue;
+
+    if (!realm)
+      return auth;
+
+    arealm = msg_header_find_param(auth->au_common, "realm=");
+
+    if (!arealm)
+      continue;
+
+    if (arealm[0] == '"') {
+      /* Compare quoted arealm with unquoted realm */
+      int i, j;
+      for (i = 1, j = 0; arealm[i] != 0; i++, j++) {
+	if (arealm[i] == '"' && realm[j] == 0)
+	  return auth;
+
+	if (arealm[i] == '\\' && arealm[i + 1] != '\0')
+	  i++;
+
+	if (arealm[i] != realm[j])
+	  break;
+      }
+    } else {
+      if (strcmp(arealm, realm) == 0)
+	return auth;
+    }
+  }
+
+  return NULL;
+}
+
+/** Find a Digest credential header with matching realm and opaque. */
+msg_auth_t *auth_digest_credentials(msg_auth_t *auth,
+				    char const *realm,
+				    char const *opaque)
+{
+  char const *arealm, *aopaque;
+
+  for (;auth; auth = auth->au_next) {
+    if (strcasecmp(auth->au_scheme, "Digest"))
+      continue;
+
+    if (realm) {
+      int cmp = 1;
+
+      arealm = msg_header_find_param(auth->au_common, "realm=");
+      if (!arealm)
+	continue;
+
+      if (arealm[0] == '"') {
+	/* Compare quoted arealm with unquoted realm */
+	int i, j;
+	for (i = 1, j = 0, cmp = 1; arealm[i] != 0; i++, j++) {
+	  if (arealm[i] == '"' && realm[j] == 0) {
+	    cmp = 0;
+	    break;
+	  }
+
+	  if (arealm[i] == '\\' && arealm[i + 1] != '\0')
+	    i++;
+
+	  if (arealm[i] != realm[j])
+	    break;
+	}
+      }
+      else {
+	cmp = strcmp(arealm, realm);
+      }
+
+      if (cmp)
+	continue;
+    }
+
+    if (opaque) {
+      int cmp = 1;
+
+      aopaque = msg_header_find_param(auth->au_common, "opaque=");
+      if (!aopaque)
+	continue;
+
+      if (aopaque[0] == '"') {
+	/* Compare quoted aopaque with unquoted opaque */
+	int i, j;
+	for (i = 1, j = 0, cmp = 1; aopaque[i] != 0; i++, j++) {
+	  if (aopaque[i] == '"' && opaque[j] == 0) {
+	    cmp = 0;
+	    break;
+	  }
+
+	  if (aopaque[i] == '\\' && aopaque[i + 1] != '\0')
+	    i++;
+
+	  if (aopaque[i] != opaque[j])
+	    break;
+	}
+      } else {
+	cmp = strcmp(aopaque, opaque);
+      }
+
+      if (cmp)
+	continue;
+    }
+
+    return auth;
+  }
+
+  return NULL;
+}
+
+/** Generate nonce parameter.
+ *
+ * @param am pointer to authentication module object
+ * @param buffer string buffer for nonce [OUT]
+ * @param bsize size of buffer [IN]
+ * @param nextnonce true if this is a "nextnonce" [IN]
+ * @param now  current time [IN]
+ */
+isize_t auth_generate_digest_nonce(auth_mod_t *am,
+				   char buffer[],
+				   size_t bsize,
+				   int nextnonce,
+				   msg_time_t now)
+{
+  struct nonce nonce[1] = {{ 0 }};
+  su_md5_t md5[1];
+
+  am->am_count += 3730029547U;	/* 3730029547 is a prime */
+
+  nonce->issued = now;
+  nonce->count = am->am_count;
+  nonce->nextnonce = nextnonce != 0;
+
+  /* Calculate HMAC of nonce data */
+  auth_md5_hmac_init(am, md5);
+  su_md5_update(md5, nonce, offsetof(struct nonce, digest));
+  auth_md5_hmac_digest(am, md5, nonce->digest, sizeof nonce->digest);
+
+  return base64_e(buffer, bsize, nonce, sizeof(nonce));
+}
+
+
+/** Validate nonce parameter.
+ *
+ * @param am   pointer to authentication module object
+ * @param as   authentication status structure [OUT]
+ * @param ar   decoded authentication response from client [IN]
+ * @param now  current time [IN]
+ */
+int auth_validate_digest_nonce(auth_mod_t *am,
+			       auth_status_t *as,
+			       auth_response_t *ar,
+			       msg_time_t now)
+{
+  struct nonce nonce[1] = {{ 0 }};
+  su_md5_t md5[1];
+  uint8_t hmac[sizeof nonce->digest];
+  unsigned expires;
+
+  /* Check nonce */
+  if (!ar->ar_nonce) {
+    SU_DEBUG_5(("auth_method_digest: no nonce\n"));
+    return -1;
+  }
+  if (base64_d((void*)nonce, (sizeof nonce), ar->ar_nonce) != (sizeof nonce)) {
+    SU_DEBUG_5(("auth_method_digest: too short nonce\n"));
+    return -1;
+  }
+
+  /* Calculate HMAC over decoded nonce data */
+  auth_md5_hmac_init(am, md5);
+  su_md5_update(md5, nonce, offsetof(struct nonce, digest));
+  auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);
+
+  if (memcmp(nonce->digest, hmac, sizeof nonce->digest)) {
+    SU_DEBUG_5(("auth_method_digest: bad nonce\n"));
+    return -1;
+  }
+
+  as->as_nonce_issued = nonce->issued;
+  as->as_nextnonce = nonce->nextnonce != 0;
+
+  expires = nonce->nextnonce ? am->am_next_exp : am->am_expires;
+
+  if (nonce->issued > now ||
+      (expires && nonce->issued + expires < now)) {
+    SU_DEBUG_5(("auth_method_digest: nonce expired %lu seconds ago "
+		"(lifetime %u)\n",
+		now - (nonce->issued + expires), expires));
+    as->as_stale = 1;
+  }
+
+  /* We should also check cnonce, nc... */
+
+  return 0;
+}
+
+
+/* ====================================================================== */
+/* HMAC routines */
+static
+void auth_md5_hmac_key(auth_mod_t *am)
+{
+  size_t i;
+  uint8_t ipad[SU_MD5_DIGEST_SIZE];
+  uint8_t opad[SU_MD5_DIGEST_SIZE];
+
+  assert(SU_MD5_DIGEST_SIZE == sizeof am->am_master_key);
+
+  /* Derive HMAC ipad and opad from master key */
+  for (i = 0; i < sizeof am->am_master_key; i++) {
+    ipad[i] = am->am_master_key[i] ^ 0x36;
+    opad[i] = am->am_master_key[i] ^ 0x5C;
+  }
+
+  /* Pre-calculate sum of ipad */
+  su_md5_init(&am->am_hmac_ipad);
+  su_md5_update(&am->am_hmac_ipad, ipad, sizeof ipad);
+
+  /* Pre-calculate sum of opad */
+  su_md5_init(&am->am_hmac_opad);
+  su_md5_update(&am->am_hmac_opad, opad, sizeof opad);
+}
+
+void auth_md5_hmac_init(auth_mod_t *am, struct su_md5_t *imd5)
+{
+  *imd5 = am->am_hmac_ipad;
+}
+
+void auth_md5_hmac_digest(auth_mod_t *am, struct su_md5_t *imd5,
+			  void *hmac, size_t size)
+{
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+  su_md5_t omd5[1];
+
+  /* inner sum */
+  su_md5_digest(imd5, digest);
+
+  *omd5 = am->am_hmac_opad;
+  su_md5_update(omd5, digest, sizeof *digest);
+
+  /* outer sum */
+  if (size == sizeof digest) {
+    su_md5_digest(omd5, hmac);
+  }
+  else {
+    su_md5_digest(omd5, digest);
+
+    if (size > sizeof digest) {
+      memset((char *)hmac + (sizeof digest), 0, size - sizeof digest);
+      size = sizeof digest;
+    }
+
+    memcpy(hmac, digest, size);
+  }
+}
+
+/* ====================================================================== */
+/* Compatibility interface */
+
+void auth_mod_method(auth_mod_t *am,
+		     auth_status_t *as,
+		     msg_auth_t *credentials,
+		     auth_challenger_t const *ach)
+{
+  auth_mod_verify(am, as, credentials, ach);
+}
+
+void auth_mod_check_client(auth_mod_t *am,
+			   auth_status_t *as,
+			   msg_auth_t *credentials,
+			   auth_challenger_t const *ach)
+{
+  auth_mod_verify(am, as, credentials, ach);
+}
+
+
+void auth_mod_challenge_client(auth_mod_t *am,
+			       auth_status_t *as,
+			       auth_challenger_t const *ach)
+{
+  auth_mod_challenge(am, as, ach);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_module_http.c
+ * @brief Authenticate HTTP request
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Urpalainen <Jari.Urpalainen at nokia.com>
+ *
+ * @date Created: Thu Jan 15 17:23:21 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/auth_module.h>
+
+static auth_challenger_t http_server_challenger[] = 
+  {{ HTTP_401_UNAUTHORIZED, http_www_authenticate_class }};
+
+static auth_challenger_t http_proxy_challenger[] = 
+  {{ HTTP_407_PROXY_AUTH, http_proxy_authenticate_class }};
+
+const char *auth_mod_check_http(auth_mod_t *am,
+	 	                auth_status_t *as,
+	                        http_t const *http,
+		                auth_kind_t proxy)
+{
+  msg_auth_t *credentials = 
+    proxy ? http->http_proxy_authorization : http->http_authorization;
+  auth_challenger_t const *challenger = 
+    proxy ? http_proxy_challenger : http_server_challenger;
+
+  if (http->http_request) {
+    if (!as->as_method)
+      as->as_method = http->http_request->rq_method_name;
+#if 0
+    if (!as->as_uri) 
+      as->as_uri = http->http_request->rq_url;
+#endif
+  }
+
+  if (http->http_payload && !as->as_body)
+    as->as_body = http->http_payload->pl_data, 
+      as->as_bodylen = http->http_payload->pl_len;
+
+  /* Call real authentication method */
+  auth_mod_check_client(am, as, credentials, challenger);
+
+  if (as->as_status)
+    return NULL;
+  else
+    return as->as_user;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_module_sip.c
+ * @brief Authenticate SIP request
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Urpalainen <Jari.Urpalainen at nokia.com>
+ *
+ * @date Created: Thu Jan 15 17:23:21 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/nta.h>
+
+#include <sofia-sip/auth_module.h>
+
+static auth_challenger_t sip_server_challenger[] = 
+  {{ SIP_401_UNAUTHORIZED, sip_www_authenticate_class,
+     sip_authentication_info_class
+    }};
+
+static auth_challenger_t sip_proxy_challenger[] = 
+  {{ SIP_407_PROXY_AUTH_REQUIRED, sip_proxy_authenticate_class }};
+
+/** Authenticate an incoming SIP request. 
+ *
+ * The function auth_mod_check() completes the @a as structure and calls the
+ * scheme-specific authentication method performing the actual
+ * authentication.  
+ *
+ * A successful authentication is indicated by setting @a as->as_status to
+ * 0.  The authentication module sets @a as->as_match as the matching
+ * credential header.
+ */
+void auth_mod_check(auth_mod_t *am,
+		    auth_status_t *as,
+		    sip_t const *sip,
+		    auth_kind_t proxy)
+{
+  msg_auth_t *credentials;
+  auth_challenger_t const *challenger;
+
+  if (as == NULL || sip == NULL)
+    return;
+
+  if (am == NULL) {
+    as->as_status = 0;
+    return;
+  }
+
+  credentials = proxy ? sip->sip_proxy_authorization : sip->sip_authorization;
+  challenger = proxy ? sip_proxy_challenger : sip_server_challenger;
+
+  if (sip->sip_request)
+    as->as_method = sip->sip_request->rq_method_name;
+
+  if (sip->sip_payload)
+    as->as_body = sip->sip_payload->pl_data, 
+      as->as_bodylen = sip->sip_payload->pl_len;
+
+  auth_mod_method(am, as, credentials, challenger);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,323 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_ntlm.c
+ *
+ * Implementation for digest authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sofia-sip/su_md5.h>
+#include "sofia-sip/auth_digest.h"
+#include "sofia-sip/auth_ntlm.h"
+
+#include "iptsec_debug.h"
+
+static inline int has_token(char const *qstring, char const *token);
+
+
+/**Get ntlm-challenge parameters.
+ *
+ * The function ntlm_challenge_get() searches for the ntlm authentication
+ * parameters in @a params.  The parameters are assigned to the appropriate
+ * fields in @a ac structure.
+ *
+ * @return
+ *
+ * The function ntlm_challenge_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_ntlm_challenge_get(su_home_t *home,
+				auth_challenge_t *ac0, 
+				char const * const params[])
+{
+  ssize_t n;
+  auth_challenge_t ac[1] = {{ 0 }};
+  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+    *qop_auth = NULL, *qop_auth_int = NULL;
+
+  ac->ac_size = sizeof(ac);
+
+  assert(ac0); 
+  assert(ac0->ac_size >= sizeof(*ac));
+
+  if (ac0 == NULL || params == NULL)
+    return -1;
+
+  n = auth_get_params(home, params,
+		      "realm=", &ac->ac_realm,
+		      "domain=", &ac->ac_domain,
+		      "nonce=", &ac->ac_nonce,
+		      "opaque=", &ac->ac_opaque,
+		      "stale=", &ac->ac_stale,
+		      "algorithm=", &ac->ac_algorithm,
+		      "qop=", &ac->ac_qop,
+		      "algorithm=md5", &md5,
+		      "algorithm=md5-sess", &md5sess,
+		      "algorithm=sha1", &sha1,
+		      "qop=auth", &qop_auth,
+		      "qop=auth-int", &qop_auth_int,
+		      NULL);
+  if (n < 0)
+    return n;
+
+  if (ac->ac_stale && strcasecmp(ac->ac_stale, "true") != 0)
+    ac->ac_stale = NULL;
+
+  ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;
+  ac->ac_md5sess = md5sess != NULL;
+  ac->ac_sha1 = sha1 != NULL;
+  ac->ac_auth = qop_auth != NULL;
+  ac->ac_auth_int = qop_auth_int != NULL;
+
+  auth_struct_copy(ac0, ac, sizeof(ac));
+
+  SU_DEBUG_5(("%s(): got %d\n", "auth_ntlm_challenge_get", n));
+  
+  return n;
+}
+
+/**Get ntlm-response parameters.
+ *
+ * The function auth_response_get() searches for the ntlm authentication
+ * parameters in @a params.  The parameters are assigned to the appropriate
+ * fields in @a ar structure.
+ *
+ * @return
+ *
+ * The function auth_response_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_ntlm_response_get(su_home_t *home,
+				auth_response_t *ar0, 
+				char const *const params[])
+{
+  ssize_t n;
+  auth_response_t ar[1] = {{ 0 }};
+  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+    *qop_auth = NULL, *qop_auth_int = NULL;
+
+  ar->ar_size = sizeof(ar);
+
+  assert(ar0); assert(params); assert(ar0->ar_size >= sizeof(ar));
+
+  if (ar0 == NULL || params == NULL)
+    return -1;
+
+  n = auth_get_params(home, params,
+		      "username=", &ar->ar_username,
+		      "realm=", &ar->ar_realm,
+		      "nonce=", &ar->ar_nonce,
+		      "uri=", &ar->ar_uri,
+		      "response=", &ar->ar_response,
+		      "algorithm=", &ar->ar_algorithm,
+		      "opaque=", &ar->ar_opaque,
+		      "cnonce=", &ar->ar_cnonce,
+		      "qop=", &ar->ar_qop,
+		      "nc=", &ar->ar_nc,
+		      "algorithm=md5", &md5,
+		      "algorithm=md5-sess", &md5sess,
+		      "algorithm=sha1", &sha1,
+		      "qop=auth", &qop_auth,
+		      "qop=auth-int", &qop_auth_int,
+		      NULL);
+  if (n < 0)
+    return n;
+
+  ar->ar_md5      = md5 != NULL || ar->ar_algorithm == NULL;
+  ar->ar_md5sess  = md5sess != NULL;
+  ar->ar_sha1     = sha1 != NULL;
+  ar->ar_auth     = qop_auth != NULL;
+  ar->ar_auth_int = qop_auth_int != NULL;
+
+  auth_struct_copy(ar0, ar, sizeof(ar));
+
+  SU_DEBUG_7(("%s: %d\n", "auth_ntlm_response_get", n));
+
+  return n;
+}
+
+#if 0
+
+/** Generate A1 hash for digest authentication. 
+ */
+int auth_digest_a1(auth_response_t *ar, 
+		   auth_hexmd5_t ha1,
+		   char const *secret)
+{
+  su_md5_t md5[1];
+
+  /* Calculate A1 */
+  su_md5_init(md5);
+  su_md5_strupdate(md5, ar->ar_username);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_realm);
+  su_md5_update(md5, ":", 1);
+  su_md5_strupdate(md5, secret);
+
+  su_md5_hexdigest(md5, ha1);
+
+  SU_DEBUG_5(("auth_digest_a1() has A1 = MD5(%s:%s:%s) = %s\n", 
+	      ar->ar_username, ar->ar_realm, secret, ha1));
+
+  return 0;
+}
+
+int auth_digest_a1sess(auth_response_t *ar, 
+		       auth_hexmd5_t ha1sess,
+		       char const *ha1)
+{
+  su_md5_t md5[1];
+
+  su_md5_init(md5);
+  su_md5_strupdate(md5, ha1);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_nonce);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_cnonce);
+
+  su_md5_hexdigest(md5, ha1sess);
+
+  SU_DEBUG_5(("auth_sessionkey has A1' = MD5(%s:%s:%s) = %s\n", 
+	      ha1, ar->ar_nonce, ar->ar_cnonce, ha1sess));
+
+  return 0;
+}
+
+/** Generate MD5 session key for digest authentication. 
+ */
+int auth_digest_sessionkey(auth_response_t *ar, 
+			   auth_hexmd5_t ha1,
+			   char const *secret)
+{
+  if (ar->ar_md5sess)
+    ar->ar_algorithm = "MD5-sess";
+  else if (ar->ar_md5)
+    ar->ar_algorithm = "MD5";
+  else
+    return -1;
+
+  if (ar->ar_md5sess) {
+    auth_hexmd5_t base_ha1; 
+    auth_digest_a1(ar, base_ha1, secret);
+    auth_digest_a1sess(ar, ha1, base_ha1);
+  } else {
+    auth_digest_a1(ar, ha1, secret);
+  }
+
+  return 0;
+}
+
+#endif /* 0 */
+
+
+#if 0
+
+/** Generate response for digest authentication. 
+ *
+ */
+int auth_digest_response(auth_response_t *ar, 
+			 auth_hexmd5_t response,
+			 auth_hexmd5_t const ha1, 
+			 char const *method_name,
+			 void const *data, issize_t dlen)
+{
+  su_md5_t md5[1];
+  auth_hexmd5_t Hentity, HA2;
+
+  if (ar->ar_auth_int)
+    ar->ar_qop = "auth-int";
+  else if (ar->ar_auth)
+    ar->ar_qop = "auth";
+  else
+    ar->ar_qop = NULL;
+
+  /* Calculate Hentity */
+  if (ar->ar_auth_int) {
+    if (data && dlen) {
+      su_md5_init(md5);
+      su_md5_update(md5, data, dlen);
+      su_md5_hexdigest(md5, Hentity);
+    } else {
+      strcpy(Hentity, "d41d8cd98f00b204e9800998ecf8427e");
+    }
+  }
+
+  /* Calculate A2 */
+  su_md5_init(md5);
+  su_md5_strupdate(md5, method_name);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_uri);
+  if (ar->ar_auth_int) {
+    su_md5_update(md5, ":", 1);
+    su_md5_update(md5, Hentity, sizeof(Hentity) - 1);
+  }
+  su_md5_hexdigest(md5, HA2);
+
+  SU_DEBUG_5(("A2 = MD5(%s:%s%s%s)\n", method_name, ar->ar_uri, 
+	      ar->ar_auth_int ? ":" : "", ar->ar_auth_int ? Hentity : ""));
+
+  /* Calculate response */
+  su_md5_init(md5);
+  su_md5_update(md5, ha1, 32);
+  su_md5_update(md5, ":", 1);
+  unquote_update(md5, ar->ar_nonce);
+
+  if (ar->ar_auth || ar->ar_auth_int) {
+    su_md5_update(md5, ":", 1);
+    su_md5_strupdate(md5, ar->ar_nc);
+    su_md5_update(md5, ":", 1);
+    unquote_update(md5, ar->ar_cnonce);
+    su_md5_update(md5, ":", 1);
+    su_md5_strupdate(md5, ar->ar_qop);
+  }
+
+  su_md5_update(md5, ":", 1);
+  su_md5_update(md5, HA2, 32);      
+  su_md5_hexdigest(md5, response);
+
+  SU_DEBUG_5(("auth_response: %s = MD5(%s:%s%s%s%s%s%s%s:%s) (qop=%s)\n", 
+	      response, ha1, ar->ar_nonce, 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_nc : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_cnonce : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 
+	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_qop : "", 
+	      HA2,
+	      ar->ar_qop ? ar->ar_qop : "NONE"));
+
+  return 0;
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_plugin.c
+ * @brief Plugin interface for authentication verification modules.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Apr 27 15:23:31 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin";
+#endif
+
+#include <sofia-sip/su_debug.h>
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+extern auth_scheme_t auth_scheme_basic[];
+extern auth_scheme_t auth_scheme_digest[];
+extern auth_scheme_t auth_scheme_delayed[];
+
+enum { N = 32 };
+
+static auth_scheme_t *schemes[N] = {
+  auth_scheme_basic,
+  auth_scheme_digest,
+  auth_scheme_delayed
+};
+
+/** Register an authentication plugin. 
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auth_mod_register_plugin(auth_scheme_t *asch)
+{
+  int i;
+
+  for (i = 0; schemes[i]; i++) {
+    if (i == N)
+      return -1;
+  }
+  
+  schemes[i] = asch;
+
+  return 0;
+}
+
+/**Create an authentication plugin module. 
+ *
+ * The function auth_mod_create() creates a module used to authenticate the
+ * requests.
+ * 
+ * @param root pointer to a su_root_t object
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * AUTHTAG_METHOD(), AUTHTAG_REALM(), AUTHTAG_DB(), AUTHTAG_ALLOW(),
+ * AUTHTAG_QOP(), AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(),
+ * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
+ * AUTHTAG_REMOTE().
+ */
+auth_mod_t *auth_mod_create(su_root_t *root,
+			    tag_type_t tag, tag_value_t value, ...)
+{
+  auth_mod_t *am = NULL;
+
+  ta_list ta;
+
+  char const *method = NULL;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  AUTHTAG_METHOD_REF(method),
+	  TAG_NULL());
+
+  if (method) {
+    auth_scheme_t *bscheme = NULL;
+    char const *base;
+    size_t len;
+
+    base = strrchr(method, '+');
+    if (base) 
+      len = base++ - method;
+    else
+      len = strlen(method);
+
+    if (base == NULL)
+      ;
+    else if (strcasecmp(base, "Basic") == 0)
+      bscheme = auth_scheme_basic;
+    else if (strcasecmp(base, "Digest") == 0) 
+      bscheme = auth_scheme_digest;
+
+    if (base == NULL || bscheme) {
+      int i;
+
+      for (i = 0; schemes[i] && i < N; i++) {
+	if (strncasecmp(schemes[i]->asch_method, method, len) == 0 &&
+	    schemes[i]->asch_method[len] == 0) {
+	  am = auth_mod_alloc(schemes[i], ta_tags(ta));
+	  if (schemes[i]->asch_init(am, bscheme, root, ta_tags(ta)) == -1) {
+	    auth_mod_destroy(am), am = NULL;
+	  }
+	  break;
+	}
+      }
+    }
+  }
+
+  ta_end(ta);
+  
+  return am;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_plugin_delayed.c
+ *
+ * @brief Plugin for delayed authentication. 
+ *
+ * This authentication plugin provides authentication operation that is
+ * intentionally delayed. It serves as an example of server-side
+ * authentication plugins.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define SU_MSG_ARG_T struct auth_splugin_t
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin_delayed";
+#endif
+
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+struct auth_plugin_t 
+{
+  su_root_t      *ap_root;
+  auth_scheme_t  *ap_base;
+  auth_splugin_t *ap_list;
+  auth_splugin_t**ap_tail;
+};
+
+/* Digest (or Basic) with delay */
+
+static int delayed_auth_init(auth_mod_t *am,
+			     auth_scheme_t *base,
+			     su_root_t *root,
+			     tag_type_t tag, tag_value_t value, ...);
+
+static void delayed_auth_method(auth_mod_t *am,
+				auth_status_t *as,
+				msg_auth_t *auth,
+				auth_challenger_t const *ach);
+
+static void delayed_auth_challenge(auth_mod_t *am, 
+				   auth_status_t *as,
+				   auth_challenger_t const *ach);
+
+static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as);
+
+static void delayed_auth_destroy(auth_mod_t *am);
+
+auth_scheme_t auth_scheme_delayed[1] = 
+  {{
+      "Delayed",
+      sizeof (struct { auth_mod_t mod[1]; auth_plugin_t plug[1]; }),
+      delayed_auth_init,
+      delayed_auth_method, 
+      delayed_auth_challenge,
+      delayed_auth_cancel,
+      delayed_auth_destroy
+  }};
+
+static int delayed_auth_init(auth_mod_t *am,
+			     auth_scheme_t *base,
+			     su_root_t *root,
+			     tag_type_t tag, tag_value_t value, ...)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+  int retval = -1;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  if (root && base && auth_init_default(am, base, root, ta_tags(ta)) != -1) {
+    ap->ap_root = root;
+    ap->ap_base = base;
+    ap->ap_tail = &ap->ap_list;
+
+    retval = 0;
+  }
+    
+  ta_end(ta);
+
+  return retval;
+}
+
+struct auth_splugin_t 
+{
+  void const      *asp_tag;
+  auth_splugin_t  *asp_next;
+  auth_splugin_t **asp_prev;
+  auth_mod_t      *asp_am;
+  auth_status_t   *asp_as;
+  msg_auth_t      *asp_header;
+  auth_challenger_t const *asp_ach;
+  int              asp_canceled;
+};
+
+
+static void delayed_auth_method_recv(su_root_magic_t *rm,
+				     su_msg_r msg,
+				     auth_splugin_t *u);
+
+static void delayed_auth_method(auth_mod_t *am,
+				auth_status_t *as,
+				msg_auth_t *auth,
+				auth_challenger_t const *ach)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+  su_msg_r mamc = SU_MSG_R_INIT;
+  auth_splugin_t *asp;
+
+  if (su_msg_create(mamc, 
+		    su_root_task(ap->ap_root),
+		    su_root_task(ap->ap_root),
+		    delayed_auth_method_recv,
+		    sizeof *asp) == SU_FAILURE) {
+    as->as_status = 500;
+    as->as_phrase = "Asynchronous authentication failure";
+    return;
+  }
+
+  asp = su_msg_data(mamc); assert(asp);
+
+  asp->asp_tag = delayed_auth_cancel;
+  asp->asp_am = am;
+  asp->asp_as = as;
+  asp->asp_header = auth;
+  asp->asp_ach = ach;
+  asp->asp_canceled = 0;
+
+  if (su_msg_send(mamc) == SU_FAILURE) {
+    su_msg_destroy(mamc);
+    as->as_status = 500;
+    as->as_phrase = "Asynchronous authentication failure";
+    return;
+  }
+
+  as->as_plugin = asp;
+
+  as->as_status = 100;
+  as->as_phrase = "Trying";
+
+  return;
+}
+
+static void delayed_auth_method_recv(su_root_magic_t *rm,
+				     su_msg_r msg,
+				     auth_splugin_t *asp)
+{
+  auth_mod_t *am = asp->asp_am;
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+  if (asp->asp_canceled)
+    return;
+
+  ap->ap_base->asch_check(am, asp->asp_as, asp->asp_header, asp->asp_ach);
+
+  if (asp->asp_as->as_callback)
+    asp->asp_as->as_callback(asp->asp_as->as_magic, asp->asp_as);
+}
+
+static void delayed_auth_challenge(auth_mod_t *am, 
+				   auth_status_t *as,
+				   auth_challenger_t const *ach)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+  /* Invoke member function of base scheme */
+  ap->ap_base->asch_challenge(am, as, ach);
+}
+
+static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+  (void)ap;			/* xyzzy */
+  
+  if (as->as_plugin && as->as_plugin->asp_tag == delayed_auth_cancel)
+    as->as_plugin->asp_canceled = 1;
+
+  as->as_status = 500, as->as_phrase = "Authentication canceled";
+}
+
+static void delayed_auth_destroy(auth_mod_t *am)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+  /* Invoke member function of base scheme */
+  ap->ap_base->asch_destroy(am);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,391 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_plugin_ntlm.c
+ *
+ * @brief Plugin for delayed authentication. 
+ *
+ * This authentication plugin provides authentication operation that is
+ * intentionally delayed. It serves as an example of server-side
+ * authentication plugins.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+#include "sofia-sip/auth_ntlm.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin_ntml";
+#endif
+
+/* ====================================================================== */
+/* NTLM authentication scheme */
+
+static int auth_init_ntlm(auth_mod_t *am,
+			  auth_scheme_t *base,
+			  su_root_t *root,
+			  tag_type_t tag, tag_value_t value, ...);
+
+static void auth_method_ntlm_x(auth_mod_t *am,
+			       auth_status_t *as,
+			       msg_auth_t *au,
+			       auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_ntlm[1] =
+  {{
+      "NTLM",			/* asch_method */
+      sizeof (auth_mod_t),	/* asch_size */
+      auth_init_default,	/* asch_init */
+      auth_method_ntlm_x,	/* asch_check */
+      auth_challenge_ntlm,	/* asch_challenge */
+      auth_cancel_default,	/* asch_cancel */
+      auth_destroy_default	/* asch_destroy */
+  }};
+
+#define AUTH_NTLM_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
+
+static int auth_init_ntlm(auth_mod_t *am,
+			     auth_scheme_t *base,
+			     su_root_t *root,
+			     tag_type_t tag, tag_value_t value, ...)
+{
+  auth_plugin_t *ap = AUTH_PLUGIN(am);
+  int retval = -1;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  if (auth_init_default(am, NULL, root, ta_tags(ta)) != -1) {
+    retval = 0;
+  }
+    
+  ta_end(ta);
+
+  return retval;
+}
+
+
+/** Authenticate a request with @b NTLM authentication scheme. 
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_ntlm_x(auth_mod_t *am,
+			auth_status_t *as,
+			msg_auth_t *au,
+			auth_challenger_t const *ach)
+{
+  if (am) {
+    auth_readdb_if_needed(am);
+    auth_method_ntlm(am, as, au, ach);
+  }
+}
+
+/** Authenticate a request with @b Ntlm authentication scheme. 
+ */
+void auth_method_ntlm(auth_mod_t *am,
+		      auth_status_t *as,
+		      msg_auth_t *au,
+		      auth_challenger_t const *ach)
+{
+  as->as_allow = as->as_allow || auth_allow_check(am, as) == 0;
+
+  if (as->as_realm)
+    au = auth_ntlm_credentials(au, as->as_realm, am->am_opaque,
+			       am->am_gssapi_data, am->am_targetname);
+
+  else
+    au = NULL;
+
+  if (as->as_allow) {
+    SU_DEBUG_5(("%s: allow unauthenticated %s\n", __func__, as->as_method));
+    as->as_status = 0, as->as_phrase = NULL;
+    as->as_match = (msg_header_t *)au;
+    return;
+  } 
+
+  if (au) {
+    auth_response_t ar[1] = {{ sizeof(ar) }};
+    auth_ntlm_response_get(as->as_home, ar, au->au_params);
+    as->as_match = (msg_header_t *)au;
+    auth_check_ntlm(am, as, ar, ach);
+  }
+  else {
+    /* There was no matching credentials, send challenge */
+    SU_DEBUG_5(("%s: no credentials matched\n", __func__));
+    auth_challenge_ntlm(am, as, ach);
+  }
+}
+
+
+/** Find a NTLM credential header with matching realm and opaque. */
+msg_auth_t *auth_ntlm_credentials(msg_auth_t *auth, 
+				  char const *realm,
+				  char const *opaque,
+				  char const *gssapidata,
+				  char const *targetname)
+{
+  char const *agssapidata, *atargetname;
+
+  for (;auth; auth = auth_mod_credentials(auth->au_next)) {
+    if (strcasecmp(auth->au_scheme, "NTLM"))
+      continue;
+
+    if (gssapidata) {
+      agssapidata = msg_header_find_param(auth->au_common, "gssapi-data=");
+      if (!agssapidata || auth_strcmp(agssapidata, gssapidata))
+	continue;
+    }
+
+    if (targetname) {
+      atargetname = msg_header_find_param(auth->au_common, "targetname=");
+      if (!atargetname || auth_strcmp(atargetname, targetname))
+	continue;
+    }
+
+    return auth;
+  }
+
+  return NULL;
+}
+
+
+/** Check ntlm authentication */
+void auth_check_ntlm(auth_mod_t *am,
+		       auth_status_t *as,
+		       auth_response_t *ar,
+		       auth_challenger_t const *ach)
+{
+  char const *a1;
+  auth_hexmd5_t a1buf, response;
+  auth_passwd_t *apw;
+  char const *phrase;
+  msg_time_t now = msg_now();
+
+  if (am == NULL || as == NULL || ar == NULL || ach == NULL) {
+    if (as) {
+      as->as_status = 500, as->as_phrase = "Internal Server Error";
+      as->as_response = NULL;
+    }
+    return;
+  }
+
+  phrase = "Bad authorization";
+
+#define PA "Authorization missing "
+
+  if ((!ar->ar_username && (phrase = PA "username")) || 
+      (!ar->ar_nonce && (phrase = PA "nonce")) || 
+      (!ar->ar_uri && (phrase = PA "URI")) || 
+      (!ar->ar_response && (phrase = PA "response")) || 
+      /* (!ar->ar_opaque && (phrase = PA "opaque")) || */
+      /* Check for qop */
+      (ar->ar_qop && 
+       ((ar->ar_auth && 
+	 strcasecmp(ar->ar_qop, "auth") &&
+	 strcasecmp(ar->ar_qop, "\"auth\"")) ||
+	(ar->ar_auth_int && 
+	 strcasecmp(ar->ar_qop, "auth-int") &&
+	 strcasecmp(ar->ar_qop, "\"auth-int\""))) 
+       && (phrase = PA "has invalid qop"))) {
+    assert(phrase);
+    SU_DEBUG_5(("auth_method_ntlm: 400 %s\n", phrase));
+    as->as_status = 400, as->as_phrase = phrase;
+    as->as_response = NULL;
+    return;
+  }
+
+  /* XXX - replace */
+#if 0
+  if (as->as_nonce_issued == 0 /* Already validated nonce */ && 
+      auth_validate_ntlm_nonce(am, as, ar, now) < 0) {
+#else
+  if (as->as_nonce_issued == 0 /* Already validated nonce */ && 
+      auth_validate_digest_nonce(am, as, ar, now) < 0) {
+#endif
+    as->as_blacklist = am->am_blacklist;
+    auth_challenge_ntlm(am, as, ach);
+    return;
+  }
+
+  if (as->as_stale) {
+    auth_challenge_ntlm(am, as, ach);
+    return;
+  }
+
+  apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm);
+
+#if 0
+  if (apw && apw->apw_hash)
+    a1 = apw->apw_hash;
+  else if (apw && apw->apw_pass)
+    auth_ntlm_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+  else 
+    auth_ntlm_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+  
+  if (ar->ar_md5sess)
+    auth_ntlm_a1sess(ar, a1buf, a1), a1 = a1buf;
+#else
+  if (apw && apw->apw_hash)
+    a1 = apw->apw_hash;
+  else if (apw && apw->apw_pass)
+    auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+  else 
+    auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+  
+  if (ar->ar_md5sess)
+    auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf;
+#endif
+
+  /* XXX - replace with auth_ntlm_response */      
+#if 0
+  auth_ntlm_response(ar, response, a1, 
+		     as->as_method, as->as_body, as->as_bodylen);
+#else
+  auth_digest_response(ar, response, a1, 
+		       as->as_method, as->as_body, as->as_bodylen);
+#endif
+
+  if (!apw || strcmp(response, ar->ar_response)) {
+    if (am->am_forbidden) {
+      as->as_status = 403, as->as_phrase = "Forbidden";
+      as->as_blacklist = am->am_blacklist;
+      as->as_response = NULL;
+    }
+    else {
+      auth_challenge_ntlm(am, as, ach);
+      as->as_blacklist = am->am_blacklist;
+    }
+    SU_DEBUG_5(("auth_method_ntlm: response did not match\n"));
+
+    return;
+  }
+
+  assert(apw);
+
+  as->as_user = apw->apw_user;
+  as->as_anonymous = apw == am->am_anon_user;
+
+  if (am->am_nextnonce || am->am_mutual)
+    auth_info_ntlm(am, as, ach);
+
+  if (am->am_challenge)
+    auth_challenge_ntlm(am, as, ach);
+
+  SU_DEBUG_7(("auth_method_ntlm: successful authentication\n"));
+
+  as->as_status = 0;	/* Successful authentication! */
+  as->as_phrase = "";
+}
+
+/** Construct a challenge header for @b Ntlm authentication scheme. */
+void auth_challenge_ntlm(auth_mod_t *am, 
+			   auth_status_t *as,
+			   auth_challenger_t const *ach)
+{
+  char const *u, *d;
+  char nonce[AUTH_NTLM_NONCE_LEN];
+
+#if 0
+  auth_generate_ntlm_nonce(am, nonce, sizeof nonce, 0, msg_now());
+#else
+  auth_generate_digest_nonce(am, nonce, sizeof nonce, 0, msg_now());
+#endif
+
+  u = as->as_uri;
+  d = as->as_pdomain;
+
+  as->as_response = 
+    msg_header_format(as->as_home, ach->ach_header, 
+		      "Ntlm"
+		      " realm=\"%s\","
+		      "%s%s%s"
+		      "%s%s%s"
+		      " nonce=\"%s\","
+		      "%s%s%s"
+		      "%s"	/* stale */
+		      " algorithm=%s" 
+		      "%s%s%s",
+		      as->as_realm, 
+		      u ? " uri=\"" : "", u ? u : "", u ? "\"," : "", 
+		      d ? " domain=\"" : "", d ? d : "", d ? "\"," : "", 
+		      nonce, 
+		      am->am_opaque ? " opaque=\"" : "",
+		      am->am_opaque ? am->am_opaque : "",
+		      am->am_opaque ? "\"," : "",
+		      as->as_stale ? " stale=true," : "",
+		      am->am_algorithm,
+		      am->am_qop ? ", qop=\"" : "",
+		      am->am_qop ? am->am_qop : "",
+		      am->am_qop ? "\"" : "");
+
+  if (!as->as_response)
+    as->as_status = 500, as->as_phrase = auth_internal_server_error;
+  else
+    as->as_status = ach->ach_status, as->as_phrase = ach->ach_phrase;
+}
+
+/** Construct a info header for @b Ntlm authentication scheme. */
+void auth_info_ntlm(auth_mod_t *am, 
+		      auth_status_t *as,
+		      auth_challenger_t const *ach)
+{
+  if (!ach->ach_info)
+    return;
+
+  if (am->am_nextnonce) {
+    char nonce[AUTH_NTLM_NONCE_LEN];
+
+    /* XXX - replace */
+#if 0
+    auth_generate_ntlm_nonce(am, nonce, sizeof nonce, 1, msg_now());
+#else
+    auth_generate_digest_nonce(am, nonce, sizeof nonce, 1, msg_now());
+#endif
+
+    as->as_info = 
+      msg_header_format(as->as_home, ach->ach_info, "nextnonce=\"%s\"", nonce);
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_tag.c
+ * @brief Tags for authentication verification module for NTA servers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "auth"
+
+#include "sofia-sip/auth_module.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+/**@def AUTHTAG_ANY()
+ * 
+ * Filter tag matching any AUTHTAG_*().
+ */
+tag_typedef_t authtag_any = NSTAG_TYPEDEF(*);
+
+/**@def AUTHTAG_MODULE()
+ * 
+ * Pointer to an authentication server module (auth_mod_t). 
+ *
+ * The tag item AUTHTAG_MODULE() contains pointer to an authentication server
+ * module. It is used to pass an already initialized authentication module
+ * to a server object (like web server or registrar object).
+ */
+tag_typedef_t authtag_module = PTRTAG_TYPEDEF(module);
+
+/**@def AUTHTAG_METHOD()
+ *
+ * Name of the authentication scheme.
+ * 
+ * The tag AUTHTAG_METHOD() specifies the authentication module and scheme
+ * to be used by the auth_module. The name can specify a basic
+ * authentication module, like "Digest" or "Basic", or an plugin module,
+ * like "SGMF+Digest". 
+ *
+ * @sa See <auth_plugin.h> for plugin interface.
+ */
+tag_typedef_t authtag_method = STRTAG_TYPEDEF(method);
+
+/**@def AUTHTAG_REALM()
+ *
+ * Authentication realm used by authentication server.
+ *
+ * The tag authtag_method specifies the authentication realm used by the @b
+ * auth_module.  For servers, the domain name in the request URI is inserted
+ * in the realm returned to the client if the realm string contains an
+ * asterisk @c "*".  Only the first asterisk is replaced by request domain
+ * name.
+ *
+ * @p Default Value
+ * "*".
+ */
+tag_typedef_t authtag_realm = STRTAG_TYPEDEF(realm);
+
+/**@def AUTHTAG_OPAQUE()
+ *
+ * Opaque data used by authentication server.
+ *
+ * The tag authtag_opaque is used to pass opaque data to the @b auth_module. 
+ * The opaque data will be included in all the challenges (however, the data
+ * is prefixed with a "." and other opaque data used by the algorithms.
+ *
+ * @p Default Value
+ * "".
+ */
+tag_typedef_t authtag_opaque = STRTAG_TYPEDEF(opaque);
+
+/**@def AUTHTAG_DB()
+ *
+ * Name of authentication database used by authentication server.
+ *
+ * The tag AUTHTAG_DB() specifies the file name used to store the
+ * authentication data. The file contains triplets as follows:
+ *
+ * @code
+ * user:password:realm
+ * @endcode
+ *
+ * @note
+ * Currently, the passwords are stored as plaintext.
+ */
+tag_typedef_t authtag_db = STRTAG_TYPEDEF(db);
+
+/**@def AUTHTAG_QOP()
+ *
+ * Quality-of-protection used by Digest authentication.
+ * 
+ * The tag AUTHTAG_QOP() specifies the qop scheme to be used by the
+ * digest authentication.
+ */
+tag_typedef_t authtag_qop = STRTAG_TYPEDEF(qop);
+
+/**@def AUTHTAG_ALGORITHM()
+ *
+ * Authentication algorithm used by Digest authentication.
+ * 
+ * The tag AUTHTAG_ALGORITHM() specifies the qop scheme to be used by the
+ * digest authentication.
+ */
+tag_typedef_t authtag_algorithm = STRTAG_TYPEDEF(algorithm);
+
+/**@def AUTHTAG_EXPIRES()
+ *
+ * Nonce expiration time for Digest authentication.
+ * 
+ * The tag AUTHTAG_EXPIRES() specifies the time in seconds that a nonce is
+ * considered valid. If 0, the nonce lifetime unbounded. The default time is
+ * 3600 seconds.
+ */
+tag_typedef_t authtag_expires = UINTTAG_TYPEDEF(expires);
+
+/**@def AUTHTAG_NEXT_EXPIRES()
+ *
+ * Next nonce expiration time for Digest authentication.
+ * 
+ * The tag AUTHTAG_NEXT_EXPIRES() specifies the time in seconds that a
+ * nextnonce sent in Authentication-Info header is considered valid. If 0,
+ * the nonce lifetime is unbounded. The default time is 3600 seconds.
+ */
+tag_typedef_t authtag_next_expires = UINTTAG_TYPEDEF(next_expires);
+
+/**@def AUTHTAG_BLACKLIST()
+ *
+ * Blacklist time.
+ * 
+ * The tag AUTHTAG_BLACKLIST() specifies the time the server delays its
+ * response if it is given bad credentials or malformed nonce. The default
+ * time is 5 seconds.
+ *
+ * @todo Implement delayed response.
+ */
+tag_typedef_t authtag_blacklist = UINTTAG_TYPEDEF(blacklist);
+
+/**@def AUTHTAG_FORBIDDEN()
+ *
+ * Respond with 403 Forbidden.
+ * 
+ * When given a true argument, the tag AUTHTAG_FORBIDDEN() specifies that the
+ * server responds with 403 Forbidden (instead of 401/407) when it receives
+ * bad credentials.
+ */
+tag_typedef_t authtag_forbidden = BOOLTAG_TYPEDEF(forbidden);
+
+/**@def AUTHTAG_ANONYMOUS()
+ *
+ * Allow anonymous access.
+ *
+ * When given a true argument, the tag AUTHTAG_ANONYMOUS() allows
+ * authentication module to accept the account "anonymous" with an empty
+ * password. The auth_status_t::as_anonymous flag is set in auth_status_t
+ * structure after anonymous authentication.
+ */
+tag_typedef_t authtag_anonymous = BOOLTAG_TYPEDEF(anonymous);
+
+/**@def AUTHTAG_FAKE()
+ *
+ * Fake authentication process.
+ *
+ * When given a true argument, the tag AUTHTAG_FAKE() causes authentication
+ * module to allow access with any password when the username is valid. The
+ * auth_status_t::as_fake flag is set in auth_status_t structure after a
+ * fake authentication.
+ */
+tag_typedef_t authtag_fake = BOOLTAG_TYPEDEF(fake);
+
+/**@def AUTHTAG_REMOTE()
+ *
+ * Remote authenticator URL.
+ * 
+ * The tag AUTHTAG_REMOTE() is used to specify URL for remote authenticator. 
+ * The meaning of the URL is specific to the authentication module. The
+ * authentication module is selected by AUTHTAG_METHOD().
+ */
+tag_typedef_t authtag_remote = URLTAG_TYPEDEF(remote);
+
+/**@def AUTHTAG_ALLOW()
+ *
+ * Comma-separated list of methods that are not challenged. 
+ * 
+ * The tag AUTHTAG_ALLOW() takes its argument a string containing a
+ * comma-separated list of methods, for example,
+ * @code
+ * AUTHTAG_ALLOW("ACK, BYE, CANCEL").
+ * @endcode
+ *
+ * The specified methods are not challenged by the authentication module. 
+ * For example, this may include SIP ACK method or SIP methods only used
+ * within an already established dialog.
+ */
+tag_typedef_t authtag_allow = STRTAG_TYPEDEF(allow);
+
+/**@def AUTHTAG_MASTER_KEY()
+ *
+ * Private master key for the authentication module.
+ * 
+ * The tag AUTHTAG_MASTER_KEY() specifies a private master key that can be
+ * used by the authentication module for various purposes (for instance,
+ * validating that nonces are really generated by it).
+ */
+tag_typedef_t authtag_master_key = STRTAG_TYPEDEF(master_key);
+
+/**@def AUTHTAG_CACHE_USERS()
+ *
+ * Time to cache user data.
+ * 
+ * The tag AUTHTAG_CACHE_USERS() specifies how many seconds the user data is
+ * cached locally. Default value is typically 30 minutes.
+ */
+tag_typedef_t authtag_cache_users = UINTTAG_TYPEDEF(cache_users);
+
+/**@def AUTHTAG_CACHE_ERRORS()
+ *
+ * Time to cache errors.
+ * 
+ * The tag AUTHTAG_CACHE_ERRORS() specifies the lifetime in seconds for
+ * errors in the local authentication data cache. Note that the errors
+ * generated locally (e.g., because of connectivity problem with
+ * authentication server) have maximum lifetime of 2 minutes.
+ */
+tag_typedef_t authtag_cache_errors = UINTTAG_TYPEDEF(cache_errors);
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "iptsec" - Authentication Module
+ *
+ * @section iptsec_meta Module Meta Information
+ *
+ * The iptsec module currently provides interfaces to HTTP
+ * Basic and Digest authentication, used by HTTP and SIP protocol elements. 
+ * There are both 
+ * @ref auth_client "client-side" and 
+ * @ref auth_module "server-side" 
+ * (authentication verification) functionality available.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section auth_module Server Verifying Authentication
+ *
+ * The file <auth_module.h> defines the interface used by a server verifying
+ * the authentication from client. After the server has created an @ref
+ * auth_mod_t "authentication module", the usual authentication operation is
+ * simple enough:
+
+ * -# server initializes an #auth_status_t structure with information from
+ *    the request
+ * -# server calls auth_mod_method() 
+ * -# server checks the status from auth_status_t structure, sends an error 
+ *    response to the client if authentication fails
+ * -# server proceeds serving the authenticated request.
+ *
+ * If the operation is asynchronous, only a preliminary result is stored in
+ * the auth_status_t structure when the call to auth_mod_method() returns. 
+ * In that case, the application can assign a callback function to the
+ * structure. The callback function is invoked when the authentication
+ * operation is completed. An asynchronous authentication operation can be
+ * terminated before its completion by calling auth_mod_cancel().
+ *
+ * @subsection auth_module_tags Server-Side Authentication Parameters
+ *
+ * When the server creates the authentication module with auth_mod_create(),
+ * it can specify numerous parameters affecting the authentication protocol
+ * and algorithms. The parameter tags are defined in <auth_module.h>. The
+ * most important parameters include:
+ *
+ * - AUTHTAG_METHOD(),
+ * - AUTHTAG_ALGORITHM(),
+ * - AUTHTAG_QOP(), and
+ * - AUTHTAG_REMOTE().
+ *
+ * @section auth_client Client Authenticating User
+ *
+ * The file <auth_client.h> defines the interface used by a client
+ * authenticating a user with a server. Because there may be multiple
+ * servers or proxies requiring authentication, the client-side
+ * authentication information is represented using a list of #auth_client_t
+ * objects. The client-side operation is as follows:
+ *
+ * -# send a request
+ * -# get a response with specific response code (401 or 407) and challenge
+ * -# store the challenge to a list with auc_challenge()
+ * -# prompt user and feed credentials (username and password) to the list
+ *    with auc_credentials() or auc_all_credentials()
+ * -# authorize a request (add credential headers to it) with 
+ *    auc_authorization() and resend the request
+ *
+ * If there are several username/password pairs for multiple authentication
+ * realms required, the application must provide the corresponding realm as
+ * an argument to auc_all_credentials().
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file iptsec_debug.c
+ * @brief Debug log for IPTSEC module.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Dec 19 15:55:30 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#include "iptsec_debug.h"
+
+/**@var IPTSEC_DEBUG
+ *
+ * Environment variable determining the debug log level for @b iptsec
+ * module.
+ *
+ * The IPTSEC_DEBUG environment variable is used to determine the debug
+ * logging level for @b iptsec module. The default level is 3.
+ * 
+ * @sa <su_debug.h>, iptsec_log, SOFIA_DEBUG
+ */
+extern char const IPTSEC_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b iptsec module. 
+ * 
+ * The iptsec_log is the log object used by @b iptsec module. The level of
+ * #iptsec_log is set using #IPTSEC_DEBUG environment variable.
+ */
+su_log_t iptsec_log[] = { SU_LOG_INIT("iptsec", "IPTSEC_DEBUG", SU_DEBUG) };
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef IPTSEC_DEBUG_H
+/** Defined when <iptsec_debug.h> has been included. */
+#define IPTSEC_DEBUG_H
+
+/**@file iptsec_debug.h
+ * @brief Debug log for IPTSEC module.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Dec 19 15:56:35 2002 ppessi
+ */
+
+#include <sofia-sip/su_log.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Common log for application and srvlib components. */
+SOFIAPUBVAR su_log_t iptsec_log[];
+
+SOFIA_END_DECLS
+
+#define SU_LOG (iptsec_log)
+
+#include <sofia-sip/su_debug.h>
+
+#endif /* !defined IPTSEC_DEBUG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_CLIENT_H
+/** Defined when <sofia-sip/auth_client.h> has been included. */
+#define AUTH_CLIENT_H 
+
+/**@file sofia-sip/auth_client.h
+ *
+ * @brief Client-side authenticator library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Authenticator object. */
+typedef struct auth_client_s auth_client_t;
+
+SOFIAPUBFUN
+int auc_challenge(auth_client_t **auc, su_home_t *home, 
+		  msg_auth_t const *auth,
+		  msg_hclass_t *crcl);
+
+SOFIAPUBFUN
+int auc_credentials(auth_client_t **auc, su_home_t *home, char const *data);
+
+SOFIAPUBFUN
+int auc_info(auth_client_t **auc_list,
+	     msg_auth_info_t const *ai,
+	     msg_hclass_t *credential_class);
+
+SOFIAPUBFUN
+int auc_all_credentials(auth_client_t **auc_list, 
+			char const *scheme,
+			char const *realm, 
+			char const *user,
+			char const *pass);
+
+SOFIAPUBFUN
+int auc_clear_credentials(auth_client_t **auc_list, 
+			  char const *scheme,
+			  char const *realm);
+
+SOFIAPUBFUN
+int auc_copy_credentials(auth_client_t **dst, auth_client_t const *src);
+
+SOFIAPUBFUN
+int auc_has_authorization(auth_client_t **auc_list);
+
+SOFIAPUBFUN
+int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
+		      char const *method, 
+		      url_t const *url, 
+		      msg_payload_t const *body);
+
+SOFIAPUBFUN
+int auc_authorization_headers(auth_client_t **auc_list, 
+			      su_home_t *home,
+			      char const *method, 
+			      url_t const *url, 
+			      msg_payload_t const *body,
+			      msg_header_t **return_headers);
+
+struct sip_s;
+
+SOFIAPUBFUN
+int auc_authorize(auth_client_t **auc, msg_t *msg, struct sip_s *sip);
+
+typedef struct auth_client_plugin auth_client_plugin_t;
+
+SOFIAPUBFUN
+int auc_register_plugin(auth_client_plugin_t const *plugin);
+
+SOFIA_END_DECLS
+
+#endif 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_CLIENT_PLUGIN_H
+/** Defined when <sofia-sip/auth_client_plugin.h> has been included. */
+#define AUTH_CLIENT_PLUGIN_H 
+
+/**@file sofia-sip/auth_client_plugin.h
+ * @brief Client-side plugin interface for authentication
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri May 19 16:18:21 EEST 2006
+ */
+
+#ifndef AUTH_CLIENT_H
+#include "sofia-sip/auth_client.h"
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+
+struct auth_client_s {
+  su_home_t     ca_home[1];
+  auth_client_plugin_t const *ca_auc;
+
+  auth_client_t *ca_next;
+
+  char const   *ca_scheme;
+  char const   *ca_realm;
+  char         *ca_user;
+  char         *ca_pass;
+
+  msg_hclass_t *ca_credential_class;
+};
+
+struct auth_client_plugin
+{
+  int auc_plugin_size;		/* Size of this structure */
+  int auc_size;			/* Size of the client structure */
+
+  char const *auc_name;		/* Name of the autentication scheme */
+  
+  /** Store challenge */
+  int (*auc_challenge)(auth_client_t *ca, 
+		       msg_auth_t const *ch);
+
+  /** Authorize request. */
+  int (*auc_authorize)(auth_client_t *ca, 
+		       su_home_t *h,
+		       char const *method, 
+		       url_t const *url, 
+		       msg_payload_t const *body,
+		       msg_header_t **return_headers);
+
+  /** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */
+  int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai);
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined AUTH_CLIENT_PLUGIN_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_COMMON_H
+/** Defined when <sofia-sip/auth_common.h> has been included. */
+#define AUTH_COMMON_H
+
+/**@file sofia-sip/auth_common.h 
+ *
+ * Functions common for client/server.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 19 15:54:08 EEST 2006 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN issize_t auth_get_params(su_home_t *home,
+				     char const * const params[], ...
+ 			          /* char const * name, 
+				     char const **return_value */);
+
+SOFIAPUBFUN int auth_struct_copy(void *dst, void const *src, isize_t s_size);
+
+SOFIAPUBFUN int auth_strcmp(char const *quoted, char const *unquoted);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_DIGEST_H
+/** Defined when <sofia-sip/auth_digest.h> has been included. */
+#define AUTH_DIGEST_H
+
+/**@file sofia-sip/auth_digest.h 
+ * Datatypes and functions for Digest authentication.
+ *
+ * The structures and functions here follow the RFC 2617.
+ *
+ * @sa @RFC2617,
+ * <i>"HTTP Authentication: Basic and Digest Access Authentication"</i>,
+ * J. Franks et al, 
+ * June 1999.
+ *
+ * @sa @RFC3261 section 22
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:25:55 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Parameters for digest-challenge.
+ *
+ * The digest-challenge is sent by server or proxy to client. It can be
+ * included in, e.g, WWW-Authenticate or Proxy-Authenticate headers.
+ *
+ * @code
+ *   challenge        =  "Digest" digest-challenge
+ *   digest-challenge  = 1#( realm | [domain] | nonce |
+ *                           [opaque] | [stale] | [algorithm] |
+ *                           [qop-options] | [auth-param] )
+ *   domain            = "domain" "=" <"> URI ( 1*SP URI ) <">
+ *   URI               = absoluteURI | abs_path
+ *   nonce             = "nonce" "=" nonce-value
+ *   nonce-value       = quoted-string
+ *   opaque            = "opaque" "=" quoted-string
+ *   stale             = "stale" "=" ( "true" | "false" )
+ *   algorithm         = "algorithm" "=" ( "MD5" | "MD5-sess" | token )
+ *   qop-options       = "qop" "=" <"> 1#qop-value <">
+ *   qop-value         = "auth" | "auth-int" | token
+ * @endcode
+ *
+ * @sa @RFC2617
+ */
+typedef struct {
+  int         ac_size;
+  char const *ac_realm;		/**< realm */
+  char const *ac_domain;	/**< domain */
+  char const *ac_nonce;		/**< nonce */
+  char const *ac_opaque;	/**< opaque */
+  char const *ac_algorithm;	/**< algorithm */
+  char const *ac_qop;		/**< qop */
+  unsigned    ac_stale : 1;	/**< stale=true */
+  unsigned    ac_md5 : 1;	/**< algorithm=MS5 (or missing) */
+  unsigned    ac_md5sess : 1;	/**< algorithm=MD5-sess */
+  unsigned    ac_sha1 : 1;	/**< algorithm=sha1 (SSA Hash) */
+  unsigned    ac_auth : 1;	/**< qop=auth */
+  unsigned    ac_auth_int : 1;	/**< qop=auth-int */
+  unsigned : 0;
+} auth_challenge_t;
+
+/** Digest parameters for digest-response in Authorize.
+ *
+ * The digest-response is sent by the client to a server or a proxy. It can
+ * be included in, e.g., Authorization or Proxy-Authorization headers.
+ *
+ * @code
+ *   credentials      = "Digest" digest-response
+ *   digest-response  = 1#( username | realm | nonce | digest-uri | 
+ *                          response | [ algorithm ] | [cnonce] | [opaque] |
+ *                          [message-qop] | [nonce-count] | [auth-param] )
+ *   username         = "username" "=" username-value
+ *   username-value   = quoted-string
+ *   digest-uri       = "uri" "=" digest-uri-value
+ *   digest-uri-value = request-uri   ; As specified by HTTP/1.1
+ *   message-qop      = "qop" "=" qop-value
+ *   cnonce           = "cnonce" "=" cnonce-value
+ *   cnonce-value     = nonce-value
+ *   nonce-count      = "nc" "=" nc-value
+ *   nc-value         = 8LHEX
+ *   response         = "response" "=" request-digest
+ *   request-digest   = <"> 32LHEX <">
+ *   LHEX             =  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ *                       "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
+ * @endcode
+ */
+typedef struct {
+  int         ar_size;
+  char const *ar_username;
+  char const *ar_realm;		/**< realm */
+  char const *ar_nonce;		/**< nonce */
+  char const *ar_uri;		/**< uri */
+  char const *ar_response;	/**< response */
+  char const *ar_algorithm;	/**< algorithm */
+  char const *ar_cnonce;	/**< cnonce */
+  char const *ar_opaque;	/**< opaque */
+  char const *ar_qop;		/**< qop */
+  char const *ar_nc;		/**< nonce count */
+  unsigned    ar_md5 : 1;	/**< MS5 algorithm */
+  unsigned    ar_md5sess : 1;	/**< MD5-sess algorithm */
+  unsigned    ar_sha1 : 1;	/**< SHA1 algorithm */
+  unsigned    ar_auth : 1;	/**< qop=auth */
+  unsigned    ar_auth_int : 1;	/**< qop=auth-int */
+  unsigned : 0;
+} auth_response_t;
+
+typedef char auth_hexmd5_t[33];
+
+SOFIAPUBFUN issize_t auth_digest_challenge_get(su_home_t *, auth_challenge_t *,
+					       char const * const params[]);
+SOFIAPUBFUN void auth_digest_challenge_free_params(su_home_t *home,
+						   auth_challenge_t *ac);
+SOFIAPUBFUN issize_t auth_digest_response_get(su_home_t *, auth_response_t *,
+					      char const * const params[]);
+
+SOFIAPUBFUN int auth_digest_a1(auth_response_t *ar,
+			       auth_hexmd5_t ha1,
+			       char const *secret);
+
+SOFIAPUBFUN int auth_digest_a1sess(auth_response_t *ar,
+				   auth_hexmd5_t ha1sess,
+				   char const *ha1);
+
+SOFIAPUBFUN int auth_digest_sessionkey(auth_response_t *, auth_hexmd5_t ha1,
+				       char const *secret);
+SOFIAPUBFUN int auth_digest_response(auth_response_t *, auth_hexmd5_t response,
+				     auth_hexmd5_t const ha1,
+				     char const *method_name,
+				     void const *data, isize_t dlen);
+
+SOFIAPUBFUN int auth_struct_copy(void *dst, void const *src, isize_t s_size);
+
+SOFIAPUBFUN int auth_strcmp(char const *quoted, char const *unquoted);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_MODULE_H
+/** Defined when <sofia-sip/auth_module.h> has been included. */
+#define AUTH_MODULE_H 
+
+/**@file sofia-sip/auth_module.h  
+ * @brief Authentication verification interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Mon Jul 23 19:21:24 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct auth_mod_t auth_mod_t;
+/** Authentication operation. */
+typedef struct auth_status_t auth_status_t;
+
+#ifdef  AUTH_MAGIC_T 
+typedef AUTH_MAGIC_T auth_magic_t;
+#else
+typedef void auth_magic_t;
+#endif
+
+/** Virtual table for authentication plugin. */
+typedef struct auth_scheme const auth_scheme_t;
+
+/** Opaque data used by authentication plugin module. */
+typedef struct auth_plugin_t  auth_plugin_t;
+/** Opaque user data used by plugin module. */
+typedef struct auth_splugin_t auth_splugin_t;
+/** Opaque authentication operation data used by plugin module. */
+typedef struct auth_uplugin_t auth_uplugin_t;
+
+/** Callback from completeted asynchronous authentication operation. */
+typedef void auth_callback_t(auth_magic_t *, auth_status_t *);
+
+/**Authentication operation result.
+ *
+ * The auth_status_t structure is used to store the status of the
+ * authentication operation and all the related data. The application
+ * verifying the authentication fills the auth_status_t structure, then
+ * calls auth_mod_method() (or auth_mod_challenge()). The operation result
+ * is stored in the structure. 
+ *
+ * If the operation is asynchronous, only a preliminary result is stored in
+ * the auth_status_t structure when the call to auth_mod_method() returns. 
+ * In that case, the application @b must assign a callback function to the
+ * structure. The callback function is invoked when the authentication
+ * operation is completed.
+ *
+ * It is recommended that the auth_status_t structure is allocated with
+ * auth_status_new() or initialized with auth_status_init() or
+ * auth_status_init_with() functions.
+ */
+struct auth_status_t
+{
+  su_home_t       as_home[1];	/**< Memory home for authentication */
+
+  int          	  as_status;	/**< Return authorization status [out] */
+  char const   	 *as_phrase;	/**< Return response phrase [out] */
+  char const   	 *as_user;	/**< Authenticated username [in/out] */
+  char const   	 *as_display;	/**< Return user's real name [in/out] */
+
+  url_t const    *as_user_uri;	/* Return user's identity [in/out] */
+  char const     *as_ident;	/**< Identities [out] */
+  unsigned        as_profile;	/**< User profile (group) [out] */
+  
+  su_addrinfo_t  *as_source;	/**< Source address [in] */
+
+  char const   	 *as_realm;	/**< Authentication realm [in] */
+  char const  	 *as_domain;	/**< Hostname [in] */
+  char const  	 *as_uri;	/**< Request-URI [in] */
+  char const     *as_pdomain;	/**< Domain parameter [in] (ignored). */
+  char const   	 *as_method;	/**< Method name to authenticate [in] */
+
+  void const   	 *as_body;	/**< Message body to protect [in] */
+  isize_t      	  as_bodylen;	/**< Length of message body [in] */
+
+  msg_time_t      as_nonce_issued; /**< Nonce issue time [out] */
+  unsigned   	  as_blacklist; /**< Blacklist time [out] */
+  unsigned        as_anonymous:1;/**< Return true if user is anonymous [out] */
+  unsigned        as_stale:1;	/**< Credentials were stale [out] */
+  unsigned        as_allow:1;	/**< Method cannot be challenged [out] */
+  unsigned        as_nextnonce:1; /**< Client used nextnonce [out] */
+  unsigned :0;
+
+  msg_header_t 	 *as_response;	/**< Authentication challenge [out] */
+  msg_header_t   *as_info;	/**< Authentication-Info [out] */
+  msg_header_t 	 *as_match;	/**< Used authentication header [out] */
+
+  /** @defgroup Callback information for asynchronous operation.  */
+  /** @{ */
+  auth_magic_t   *as_magic;	/**< Application data [in] */
+  auth_callback_t*as_callback;	/**< Completion callback [in] */
+  /** @} */
+
+  /** Pointer to extended state, used exclusively by plugin modules. */
+  auth_splugin_t *as_plugin;	
+};
+
+/** Authentication challenge.
+ *
+ * This structure defines what kind of response and challenge header is
+ * returned to the user. For example, a server authentication is implemented
+ * with 401 response code and phrase along with header class for
+ * @b WWW-Authenticate header in the @a ach structure.
+ */
+typedef struct auth_challenger 
+{
+  int           ach_status;	/**< Response status for challenge response */
+  char const   *ach_phrase;	/**< Response phrase for challenge response */
+  msg_hclass_t *ach_header;	/**< Header class for challenge header */
+  msg_hclass_t *ach_info;
+} auth_challenger_t;
+
+SOFIAPUBVAR char const auth_internal_server_error[];
+
+#define AUTH_STATUS_INIT \
+  {{ SU_HOME_INIT(auth_status_t) }, 500, auth_internal_server_error, NULL }
+
+#define AUTH_STATUS_DEINIT(as) \
+  su_home_deinit(as->as_home)
+
+#define AUTH_RESPONSE_INIT(as) AUTH_STATUS_INIT
+#define AUTH_RESPONSE_DEINIT(as) AUTH_STATUS_DEINIT(as)
+
+SOFIAPUBFUN int auth_mod_register_plugin(auth_scheme_t *asch);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_create(su_root_t *root,
+					tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN void auth_mod_destroy(auth_mod_t *);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_ref(auth_mod_t *am);
+SOFIAPUBFUN void auth_mod_unref(auth_mod_t *am);
+
+SOFIAPUBFUN char const *auth_mod_name(auth_mod_t *am);
+
+SOFIAPUBFUN auth_status_t *auth_status_init(void *, isize_t size);
+SOFIAPUBFUN auth_status_t *auth_status_init_with(void *, isize_t size,
+						 int status,
+						 char const *phrase);
+
+SOFIAPUBFUN auth_status_t *auth_status_new(su_home_t *);
+
+SOFIAPUBFUN auth_status_t *auth_status_ref(auth_status_t *as);
+
+SOFIAPUBFUN void auth_status_unref(auth_status_t *as);
+
+SOFIAPUBFUN void auth_mod_verify(auth_mod_t *am,
+				 auth_status_t *as,
+				 msg_auth_t *credentials,
+				 auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_challenge(auth_mod_t *am,
+				    auth_status_t *as,
+				    auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_authorize(auth_mod_t *am,
+				    auth_status_t *as,
+				    auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_cancel(auth_mod_t *am, auth_status_t *as);
+
+/* ====================================================================== */
+/* Deprecated functions */
+
+typedef enum {
+  auth_server,
+  auth_proxy,
+  auth_proxy_consume,
+  auth_consume
+} auth_kind_t;
+
+SOFIAPUBFUN void auth_mod_method(auth_mod_t *am,
+				 auth_status_t *as,
+				 msg_auth_t *credentials,
+				 auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_check_client(auth_mod_t *am,
+				       auth_status_t *as,
+				       msg_auth_t *credentials,
+				       auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_challenge_client(auth_mod_t *am,
+					   auth_status_t *as,
+					   auth_challenger_t const *ach);
+
+#ifdef SIP_H
+SOFIAPUBFUN void auth_mod_check(auth_mod_t *am,
+				auth_status_t *as,
+				sip_t const *sip,
+				auth_kind_t proxy);
+#endif
+
+#ifdef HTTP_H
+SOFIAPUBFUN const char *auth_mod_check_http(auth_mod_t *am,
+					    auth_status_t *as,
+					    http_t const *http,
+					    auth_kind_t proxy);
+#endif
+
+/* ====================================================================== */
+/* Tags */
+
+#define AUTHTAG_ANY()         authtag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t authtag_any;
+
+/** Pointer to an authentication server (auth_mod_t). */
+#define AUTHTAG_MODULE(x)	authtag_module, authtag_module_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_module;
+
+#define AUTHTAG_MODULE_REF(x)	authtag_module_ref, authtag_module_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_module_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t authtag_module_v(auth_mod_t *v) {
+  return (tag_value_t)v;
+}
+static inline tag_value_t authtag_module_vr(auth_mod_t **vp) {
+  return (tag_value_t)vp;
+}
+#else
+#define authtag_module_v(v)   ((tag_value_t)(v))
+#define authtag_module_vr(v)  ((tag_value_t)(v))
+#endif
+
+/** Authentication scheme used by authentication module. */
+#define AUTHTAG_METHOD(x)	authtag_method, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_method;
+
+#define AUTHTAG_METHOD_REF(x)	authtag_method_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_method_ref;
+
+/** Authentication realm used by authentication server. */
+#define AUTHTAG_REALM(x)	authtag_realm, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_realm;
+
+#define AUTHTAG_REALM_REF(x)	authtag_realm_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_realm_ref;
+
+/** Opaque authentication data always included in challenge. */
+#define AUTHTAG_OPAQUE(x)	authtag_opaque, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_opaque;
+
+#define AUTHTAG_OPAQUE_REF(x)	authtag_opaque_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_opaque_ref;
+
+/** Name of authentication database used by authentication server. */
+#define AUTHTAG_DB(x)		authtag_db, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_db;
+
+#define AUTHTAG_DB_REF(x)		authtag_db_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_db_ref;
+
+/** Quality-of-protection used by digest authentication. */
+#define AUTHTAG_QOP(x)	        authtag_qop, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_qop;
+
+#define AUTHTAG_QOP_REF(x)	        authtag_qop_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_qop_ref;
+
+/** Algorithm used by digest authentication. */
+#define AUTHTAG_ALGORITHM(x)    authtag_algorithm, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_algorithm;
+
+#define AUTHTAG_ALGORITHM_REF(x)    authtag_algorithm_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_algorithm_ref;
+
+/** Nonce lifetime. */
+#define AUTHTAG_EXPIRES(x)    authtag_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_expires;
+
+#define AUTHTAG_EXPIRES_REF(x)    authtag_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_expires_ref;
+
+/** Lifetime for nextnonce, 0 disables nextnonce. */
+#define AUTHTAG_NEXT_EXPIRES(x)    authtag_next_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_next_expires;
+
+#define AUTHTAG_NEXT_EXPIRES_REF(x)  \
+  authtag_next_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_next_expires_ref;
+
+/** Extra delay when responding if provided invalid credentials or nonce. */
+#define AUTHTAG_BLACKLIST(x)    authtag_blacklist, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_blacklist;
+
+#define AUTHTAG_BLACKLIST_REF(x)    authtag_blacklist_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_blacklist_ref;
+
+/** Respond with 403 Forbidden if given invalid credentials. */
+#define AUTHTAG_FORBIDDEN(x)    authtag_forbidden, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_forbidden;
+
+#define AUTHTAG_FORBIDDEN_REF(x)    authtag_forbidden_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_forbidden_ref;
+
+/** Allow anonymous access. */
+#define AUTHTAG_ANONYMOUS(x)    authtag_anonymous, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_anonymous;
+
+#define AUTHTAG_ANONYMOUS_REF(x)    authtag_anonymous_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_anonymous_ref;
+
+/** Fake authentication procedure - do not check result. */
+#define AUTHTAG_FAKE(x)    authtag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_fake;
+
+#define AUTHTAG_FAKE_REF(x)    authtag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_fake_ref;
+
+/** HSS client structure. */
+#define AUTHTAG_HSS(x)        authtag_hss, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_hss;
+
+#define AUTHTAG_HSS_REF(x)    authtag_hss_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t authtag_hss_ref;
+
+/** Remote authenticator URL. */
+#define AUTHTAG_REMOTE(x)     authtag_remote, urltag_url_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_remote;
+
+#define AUTHTAG_REMOTE_REF(x) authtag_remote_ref, urltag_url_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_remote_ref;
+
+/** Comma-separated list of methods never challenged. */
+#define AUTHTAG_ALLOW(x)      authtag_allow, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_allow;
+
+#define AUTHTAG_ALLOW_REF(x)  authtag_allow_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_allow_ref;
+
+/** Check that user exists, don't do authentication. */
+#define AUTHTAG_FAKE(x)	authtag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_fake;
+
+#define AUTHTAG_FAKE_REF(x) authtag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_fake_ref;
+
+/** Master key in base64 for the authentication module. */
+#define AUTHTAG_MASTER_KEY(x)	authtag_master_key, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_master_key;
+
+#define AUTHTAG_MASTER_KEY_REF(x) authtag_master_key_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_master_key_ref;
+
+/** Cache time for authentication data. */
+#define AUTHTAG_CACHE_USERS(x)	authtag_cache_users, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_users;
+
+#define AUTHTAG_CACHE_USERS_REF(x) authtag_cache_users_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_users_ref;
+
+/** Cache time for errors. */
+#define AUTHTAG_CACHE_ERRORS(x)	authtag_cache_errors, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_errors;
+
+#define AUTHTAG_CACHE_ERRORS_REF(x) authtag_cache_errors_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_errors_ref;
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_NTLM_H
+/** Defined when <sofia-sip/auth_ntlm.h> has been included. */
+#define AUTH_NTLM_H 
+
+/**@file sofia-sip/auth_ntlm.h 
+ * Datatypes and functions for Ntlm authentication.
+ *
+ * The structures and functions here follow the RFC 2617.
+ *
+ * @sa 
+ * <a href="ftp://ftp.ietf.org/rfc/rfc2617.txt">RFC 2617</a>, 
+ * <i>"HTTP Authentication: Basic and Ntlm Access Authentication"</i>,
+ * J. Franks et al, 
+ * June 1999.
+ *
+ * @sa Section 19 from 
+ * <a href="ftp://ftp.ietf.org/internet-drafts/draft-ietf-sip-rfc2543bis-04.txt>draft-ietf-sip-rfc2543bis-04</a>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:25:55 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef AUTH_PLUGIN_H
+#include <sofia-sip/auth_plugin.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+issize_t auth_ntlm_challenge_get(su_home_t *, auth_challenge_t *, 
+				 char const * const params[]);
+issize_t auth_ntlm_response_get(su_home_t *, auth_response_t *, 
+				char const * const params[]);
+
+int auth_ntlm_a1(auth_response_t *ar, 
+		   auth_hexmd5_t ha1,
+		   char const *secret);
+
+int auth_ntlm_a1sess(auth_response_t *ar, 
+		       auth_hexmd5_t ha1sess,
+		       char const *ha1);
+
+int auth_ntlm_sessionkey(auth_response_t *, auth_hexmd5_t ha1,
+			   char const *secret);
+int auth_ntlm_response(auth_response_t *, auth_hexmd5_t response,
+		       auth_hexmd5_t const ha1, 
+		       char const *method_name, void const *data, issize_t dlen);
+
+/** NTLM scheme */
+msg_auth_t *auth_ntlm_credentials(msg_auth_t *auth, 
+				  char const *realm,
+				  char const *opaque,
+				  char const *gssapidata,
+				  char const *targetname);
+
+void auth_challenge_ntlm(auth_mod_t *am, 
+			 auth_status_t *as,
+			 auth_challenger_t const *ach);
+
+
+void auth_method_ntlm(auth_mod_t *am,
+		      auth_status_t *as,
+		      msg_auth_t *au,
+		      auth_challenger_t const *ach);
+
+
+void auth_check_ntlm(auth_mod_t *am,
+		     auth_status_t *as,
+		     auth_response_t *ar,
+		     auth_challenger_t const *ach);
+
+int auth_generate_ntlm_nonce(auth_mod_t *am, 
+			     char buffer[],
+			     size_t buffer_len,
+			     int nextnonce,
+			     msg_time_t now);
+
+int auth_validate_ntlm_nonce(auth_mod_t *am, 
+			     auth_status_t *as,
+			     auth_response_t *ar,
+			     msg_time_t now);
+
+void auth_info_ntlm(auth_mod_t *am, 
+		    auth_status_t *as,
+		    auth_challenger_t const *ach);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,266 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_PLUGIN_H
+/** Defined when <sofia-sip/auth_plugin.h> has been included. */
+#define AUTH_PLUGIN_H 
+
+/**@file sofia-sip/auth_plugin.h
+ * @brief Plugin interface for authentication verification modules.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Apr 27 15:22:07 2004 ppessi
+ */
+
+#ifndef AUTH_MODULE_H
+#include "sofia-sip/auth_module.h"
+#endif
+
+#ifndef AUTH_DIGEST_H
+#include "sofia-sip/auth_digest.h"
+#endif
+
+#ifndef AUTH_COMMON_H
+#include "sofia-sip/auth_common.h"
+#endif
+
+#ifndef MSG_DATE_H
+#include <sofia-sip/msg_date.h>
+#endif
+
+#ifndef SU_MD5_H
+#include <sofia-sip/su_md5.h>
+#endif
+
+#include <sofia-sip/htable.h>
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+/* Plugin interface for authentication */
+
+/** Authentication scheme */
+struct auth_scheme
+{
+  /** Name */
+  char const *asch_method;
+
+  /** Size of module object */
+  usize_t asch_size;
+
+  /** Initialize module. Invoked by auth_mod_create(). */
+  int (*asch_init)(auth_mod_t *am,
+		   auth_scheme_t *base,
+		   su_root_t *root,
+		   tag_type_t tag, tag_value_t value, ...);
+
+  /** Check authentication. Invoked by auth_mod_method(). */
+  void (*asch_check)(auth_mod_t *am, 
+		     auth_status_t *as,
+		     msg_auth_t *auth,
+		     auth_challenger_t const *ch);
+
+  /** Create a challenge. Invoked by auth_mod_challenge(). */
+  void (*asch_challenge)(auth_mod_t *am, 
+			 auth_status_t *as,
+			 auth_challenger_t const *ch);
+
+  /** Cancel an asynchronous authentication request. 
+   * Invoked by auth_mod_cancel().
+   */
+  void (*asch_cancel)(auth_mod_t *am, 
+		      auth_status_t *as);
+
+  /** Reclaim resources an authentication module.
+   *
+   * Invoked by auth_mod_destroy()/auth_mod_unref().
+   */
+  void (*asch_destroy)(auth_mod_t *am);
+
+};
+
+/** User data structure */
+typedef struct
+{
+  unsigned        apw_index;	/**< Key to hash table */
+  void const     *apw_type;	/**< Magic pointer */
+
+  char const   	 *apw_user;	/**< Username */
+  char const     *apw_realm;	/**< Realm */
+  char const   	 *apw_pass;	/**< Password */
+  char const     *apw_hash;	/**< MD5 of the username, realm and pass */
+  char const     *apw_ident;	/**< Identity information */
+  auth_uplugin_t *apw_extended;	/**< Method-specific extension */
+} auth_passwd_t;
+
+
+HTABLE_DECLARE_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
+
+struct stat;
+
+/** Common data for authentication module */
+struct auth_mod_t
+{
+  su_home_t      am_home[1];
+  unsigned       am_refcount;	/**< Number of references to this module */
+
+  /* User database / cache */
+  char const    *am_db;		/**< User database file name */
+  struct stat   *am_stat;	/**< State of user file when read */
+  auth_htable_t  am_users[1];	/**< Table of users */
+
+  void          *am_buffer;	/**< Buffer for database */
+  auth_passwd_t *am_locals;	/**< Entries from local user file */
+  size_t         am_local_count; /**< Number of entries from local user file */
+
+  auth_passwd_t *am_anon_user;	/**< Special entry for anonymous user */
+
+  /* Attributes */
+  url_t         *am_remote;	/**< Remote authenticator */
+  char const    *am_realm;	/**< Our realm */
+  char const    *am_opaque;	/**< Opaque identification data */
+  char const    *am_gssapi_data; /**< NTLM data */
+  char const    *am_targetname; /**< NTLM target name */
+  auth_scheme_t *am_scheme;	/**< Authentication scheme (Digest, Basic). */
+  char const   **am_allow;	/**< Methods to allow without authentication */
+  msg_param_t    am_algorithm;	/**< Defauilt algorithm */
+  msg_param_t    am_qop;	/**< Default qop (quality-of-protection) */
+  unsigned       am_expires;	/**< Nonce lifetime */
+  unsigned       am_next_exp;	/**< Next nonce lifetime */
+  unsigned       am_blacklist;	/**< Extra delay if bad credentials. */
+  unsigned       am_forbidden:1;/**< Respond with 403 if bad credentials */
+  unsigned       am_anonymous:1;/**< Allow anonymous access */
+  unsigned       am_challenge:1;/**< Challenge even if successful */
+  unsigned       am_nextnonce:1;/**< Send next nonce in responses */
+  unsigned       am_mutual:1;   /**< Mutual authentication */
+  unsigned       am_fake:1;	/**< Fake authentication */
+
+  unsigned :0;			/**< Pad */
+  unsigned       am_count;	/**< Nonce counter */
+
+  uint8_t        am_master_key[16]; /**< Private master key */
+  
+  su_md5_t       am_hmac_ipad;	/**< MD5 with inner pad */
+  su_md5_t       am_hmac_opad;	/**< MD5 with outer pad */
+};
+
+SOFIAPUBFUN
+auth_passwd_t *auth_mod_getpass(auth_mod_t *am,
+				char const *user,
+				char const *realm);
+
+SOFIAPUBFUN
+auth_passwd_t *auth_mod_addpass(auth_mod_t *am,
+				char const *user,
+				char const *realm);
+
+SOFIAPUBFUN int auth_readdb_if_needed(auth_mod_t *am);
+
+SOFIAPUBFUN int auth_readdb(auth_mod_t *am);
+
+SOFIAPUBFUN msg_auth_t *auth_mod_credentials(msg_auth_t *auth, 
+					     char const *scheme,
+					     char const *realm);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme, 
+				       tag_type_t, tag_value_t, ...);
+
+#define AUTH_PLUGIN(am) (auth_plugin_t *)((am) + 1)
+
+SOFIAPUBFUN
+int auth_init_default(auth_mod_t *am,
+		      auth_scheme_t *base,
+		      su_root_t *root,
+		      tag_type_t tag, tag_value_t value, ...);
+
+/** Default cancel method */
+SOFIAPUBFUN void auth_cancel_default(auth_mod_t *am, auth_status_t *as);
+
+/** Default destroy method */
+SOFIAPUBFUN void auth_destroy_default(auth_mod_t *am);
+
+/** Basic scheme */
+SOFIAPUBFUN
+void auth_method_basic(auth_mod_t *am,
+		       auth_status_t *as,
+		       msg_auth_t *auth,
+		       auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_challenge_basic(auth_mod_t *am, 
+			  auth_status_t *as,
+			  auth_challenger_t const *ach);
+
+/** Digest scheme */
+SOFIAPUBFUN
+msg_auth_t *auth_digest_credentials(msg_auth_t *auth, 
+				    char const *realm,
+				    char const *opaque);
+
+SOFIAPUBFUN
+void auth_method_digest(auth_mod_t *am,
+			auth_status_t *as,
+			msg_auth_t *au,
+			auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_info_digest(auth_mod_t *am, 
+		      auth_status_t *as,
+		      auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_check_digest(auth_mod_t *am,
+		       auth_status_t *as,
+		       auth_response_t *ar,
+		       auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_challenge_digest(auth_mod_t *am, 
+			   auth_status_t *as,
+			   auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+isize_t auth_generate_digest_nonce(auth_mod_t *am, 
+				   char buffer[],
+				   size_t buffer_len,
+				   int nextnonce,
+				   msg_time_t now);
+
+SOFIAPUBFUN
+int auth_validate_digest_nonce(auth_mod_t *am, 
+			       auth_status_t *as,
+			       auth_response_t *ar,
+			       msg_time_t now);
+
+SOFIAPUBFUN int auth_allow_check(auth_mod_t *am, auth_status_t *as);
+
+/** Init md5 for MD5-based HMAC */
+SOFIAPUBFUN void auth_md5_hmac_init(auth_mod_t *am, su_md5_t *md5);
+SOFIAPUBFUN void auth_md5_hmac_digest(auth_mod_t *am, su_md5_t *md5, 
+				      void *hmac, size_t size);
+
+SOFIA_END_DECLS
+
+#endif /* !defined AUTH_PLUGIN_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1217 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_auth_digest.c
+ *
+ * @brief Test authentication functions for "Digest" scheme.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_SOFIA_SIP
+#define PROTOCOL "SIP/2.0"
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_hclasses.h>
+#else
+#define PROTOCOL "HTTP/1.1"
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+#define sip_authentication_info_class   http_authentication_info_class
+#define sip_authorization               http_authorization
+#define sip_authorization_class	        http_authorization_class
+#define sip_authorization_make	        http_authorization_make
+#define sip_authorization_t	        http_authorization_t
+#define sip_default_mclass	        http_default_mclass
+#define sip_object		        http_object
+#define sip_payload		        http_payload
+#define sip_proxy_authenticate_make     http_proxy_authenticate_make
+#define sip_proxy_authenticate_t        http_proxy_authenticate_t
+#define sip_proxy_authorization_make    http_proxy_authorization_make
+#define sip_proxy_authorization_t       http_proxy_authorization_t
+#define sip_request		        http_request
+#define sip_request_t		        http_request_t
+#define sip_t			        http_t
+#define sip_www_authenticate	        http_www_authenticate
+#define sip_www_authenticate_class      http_www_authenticate_class
+#define sip_www_authenticate            http_www_authenticate
+#define sip_www_authenticate_make       http_www_authenticate_make
+#define sip_www_authenticate_t	        http_www_authenticate_t
+#endif
+
+#include <sofia-sip/auth_digest.h>
+#include <sofia-sip/auth_client.h>
+#include <sofia-sip/msg_header.h>
+#include <sofia-sip/su_wait.h>
+
+int tstflags;
+char *argv0;
+
+#define TSTFLAGS tstflags 
+
+#include <sofia-sip/tstdef.h>
+
+#if defined(_WIN32)
+#include <fcntl.h>
+#endif
+
+char const name[] = "test_auth_digest";
+
+/* Fake su_time() implementation */
+#include <time.h>
+
+unsigned offset;
+
+void su_time(su_time_t *tv)
+{
+  tv->tv_sec = time(NULL) + offset + 
+    /* Seconds from 1.1.1900 to 1.1.1970 */ 2208988800UL ;
+  tv->tv_usec = 555555;
+}
+
+int test_digest()
+{
+  char challenge[] = "Digest "
+    "realm=\"garage.sr.ntc.nokia.com\", "
+    "nonce=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", "
+    "algorithm=MD5, "
+    "qop=\"auth\"";
+
+  char response[] = 
+    "DIGEST USERNAME=\"digest\", "
+    "REALM=\"garage.sr.ntc.nokia.com\", "
+    "NONCE=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", "
+    "RESPONSE=\"d9d7f1ae99a013cb05f319f0f678251d\", "
+    "URI=\"sip:garage.sr.ntc.nokia.com\"";
+
+  char rfc2617[] = 
+    "Digest username=\"Mufasa\", "
+    "realm=\"testrealm at host.com\", "
+    "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+    "cnonce=\"0a4f113b\", "
+    "nc=\"00000001\", "
+    "qop=\"auth\", "
+    "algorithm=\"md5\", "
+    "uri=\"/dir/index.html\"";
+
+  char indigo[] = 
+    "Digest username=\"user1\", "
+    "realm=\"nokia-proxy\", "
+    "nonce=\"0YXwH29PCT4lEz8+YJipQg==\", "
+    "uri=\"sip:nokia at 62.254.248.33\", "
+    "response=\"dd22a698b1a9510c4237c52e0e2cbfac\", "
+    "algorithm=MD5, "
+    "cnonce=\"V2VkIEF1ZyAxNSAxNzozNDowNyBHTVQrMDE6MDAgMjAwMVtCQDI0YmZhYQ==\", "
+    "opaque=\"WiMlvw==\", "
+    "qop=auth, "
+    "nc=000000002";
+
+  char proxy_authenticate[] = 
+    "Digest realm=\"IndigoSw\", "
+    "domain=\"indigosw.com aol.com\", "
+    "nonce=\"V2VkIEF1ZyAxNSAxNzoxNzozNyBCU1QgMjAwMVtCQDE3OWU4Yg==\", "
+    "opaque=\"Nzg5MWU3YjZiNDQ0YzI2Zg==\", "
+    "stale=false, "
+    "algorithm=md5, "
+    "qop=\"auth, auth-int\"";
+
+  sip_www_authenticate_t *wa;
+  sip_authorization_t *au;
+  sip_proxy_authenticate_t *pa;
+  sip_proxy_authorization_t *pz;
+
+  auth_challenge_t ac[1] = {{ sizeof(ac) }};
+  auth_response_t  ar[1] = {{ sizeof(ar) }};
+  su_home_t home[1] = {{ sizeof(home) }};
+
+  auth_hexmd5_t sessionkey, hresponse;
+
+  BEGIN();
+
+  TEST0(wa = sip_www_authenticate_make(home, challenge));
+  TEST_SIZE(auth_digest_challenge_get(home, ac, wa->au_params), 6);
+  TEST_S(ac->ac_realm, "garage.sr.ntc.nokia.com");
+  TEST_S(ac->ac_nonce, "MjAwMS0wMS0yMSAxNTowODo1OA==");
+  TEST_S(ac->ac_algorithm, "MD5");
+  TEST_1(ac->ac_md5); TEST_1(!ac->ac_md5sess); TEST_1(!ac->ac_sha1);
+  TEST_S(ac->ac_qop, "auth");
+  TEST_1(ac->ac_auth); TEST_1(!ac->ac_auth_int);
+
+  TEST0(au = sip_authorization_make(home, response));
+  TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 5);
+
+  TEST0(au = sip_authorization_make(home, rfc2617));
+  TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 10);
+
+  TEST0(auth_digest_sessionkey(ar, sessionkey, "Circle Of Life") == 0);
+  if (tstflags & tst_verbatim) 
+    printf("%s: sessionkey=\"%s\"\n", name, sessionkey);
+  TEST0(strcmp(sessionkey, "939e7578ed9e3c518a452acee763bce9") == 0);
+
+  TEST0(auth_digest_response(ar, hresponse, sessionkey, "GET", NULL, 0) == 0);
+  if (tstflags & tst_verbatim) 
+    printf("%s: hresponse=\"%s\"\n", name, hresponse);
+  TEST0(strcmp(hresponse, "6629fae49393a05397450978507c4ef1") == 0);
+
+  TEST0(au = sip_authorization_make(home, indigo));
+  TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 12);
+  TEST0(auth_digest_sessionkey(ar, sessionkey, "secret") == 0);
+  TEST0(auth_digest_response(ar, hresponse, sessionkey, "BYE", NULL, 0) == 0);
+  TEST0(strcmp(hresponse, "dd22a698b1a9510c4237c52e0e2cbfac") == 0);
+
+  TEST0(pa = sip_proxy_authenticate_make(home, proxy_authenticate));
+  TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 9);
+
+  TEST_S(ac->ac_realm, "IndigoSw");
+  TEST_1(ac->ac_auth);
+  TEST_1(ac->ac_auth_int);
+
+  {
+    char challenge[] = 
+      "Digest realm=\"opera.ntc.nokia.com\", "
+      "nonce=\"InyiWI+qIdvDKkO2jFK7mg==\"";
+
+    char credentials[] = 
+      "Digest username=\"samuel.privat.saturday at opera.ntc.nokia.com\", "
+      "realm=\"opera.ntc.nokia.com\", nonce=\"InyiWI+qIdvDKkO2jFK7mg==\", "
+      "algorithm=MD5, uri=\"sip:opera.ntc.nokia.com\", "
+      "response=\"4b4edab897dafce8d9af4b37abcdc086\"";
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+    TEST0(pa = sip_www_authenticate_make(home, challenge));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 2);
+
+    TEST0(pz = sip_proxy_authorization_make(home, credentials));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 7);
+
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST0(!auth_digest_sessionkey(ar, sessionkey, "1123456789ABCDEF"));
+    TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0));
+    TEST_S(hresponse, "4b4edab897dafce8d9af4b37abcdc086");
+  }
+
+  if (0) {
+    /*
+      RFC 2069:
+      that the username for this document is "Mufasa", and the password is
+      "CircleOfLife".
+
+      The first time the client requests the document, no Authorization
+      header is sent, so the server responds with:
+
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Digest    realm="testrealm at host.com",
+                            nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+                            opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+  The client may prompt the user for the username and password, after
+  which it will respond with a new request, including the following
+  Authorization header:
+
+Authorization: Digest       username="Mufasa",
+                            realm="testrealm at host.com",
+                            nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+                            uri="/dir/index.html",
+                            response="e966c932a9242554e42c8ee200cec7f6",
+                            opaque="5ccc069c403ebaf9f0171e9517f40e41"
+    */
+
+    char challenge[] = 
+      "Digest realm=\"testrealm at host.com\", "
+      "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+      "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+
+    char rfc2069_cred[] = 
+      "Digest username=\"Mufasa\", "
+      "realm=\"testrealm at host.com\", "
+      "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+      "uri=\"/dir/index.html\", "
+      "response=\"e966c932a9242554e42c8ee200cec7f6\", "
+      "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+    TEST0(pa = sip_www_authenticate_make(home, challenge));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 3);
+
+    TEST0(pz = sip_proxy_authorization_make(home, rfc2069_cred));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 6);
+
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST_S(ar->ar_username, "Mufasa");
+    TEST0(!auth_digest_sessionkey(ar, sessionkey, "CircleOfLife"));
+    TEST0(!auth_digest_response(ar, hresponse, sessionkey, "GET", NULL, 0));
+    TEST_S(hresponse, "e966c932a9242554e42c8ee200cec7f6");
+  }
+
+  {
+    char worldcom_chal[] = 
+      "Digest realm=\"WCOM\", nonce=\"ce2292f3f748fbe239bda9e852e8b986\"";
+
+    char worldcom_cred[] = 
+      "Digest realm=\"WCOM\", username=\"jari\", "
+      "nonce=\"ce2292f3f748fbe239bda9e852e8b986\", "
+      "response=\"ea692d202019d41a75c70df4b2401e2f\", "
+      "uri=\"sip:1234 at 209.132.126.82\"";
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+    TEST0(pa = sip_proxy_authenticate_make(home, worldcom_chal));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 2);
+
+    TEST0(pz = sip_proxy_authorization_make(home, worldcom_cred));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 5);
+
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST0(!auth_digest_sessionkey(ar, sessionkey, "pass"));
+    TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0));
+    TEST_S(hresponse, "ea692d202019d41a75c70df4b2401e2f");
+  }
+
+  {
+    char etri_chal[] = 
+      "Digest realm=\"nokia-proxy\", domain=\"sip:194.2.188.133\", "
+      "nonce=\"wB7JBwIb/XhtgfGp1VuPoQ==\", opaque=\"wkJxwA==\", "
+      ", algorithm=MD5, qop=\"auth\"";
+
+    char etri_cred[] = 
+      "Digest username=\"myhuh\", realm=\"nokia-proxy\", "
+      "nonce=\"wB7JBwIb/XhtgfGp1VuPoQ==\", uri=\"sip:194.2.188.133\", "
+      "response=\"32960a62bdc202171ca5a294dc229a6d\", "
+      "opaque=\"wkJxwA==\"" /* , qop=\"auth\"" */;
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+    
+    TEST0(pa = sip_proxy_authenticate_make(home, etri_chal));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 8);
+
+    TEST0(pz = sip_proxy_authorization_make(home, etri_cred));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 6 /* 8 */);
+    
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST(auth_digest_sessionkey(ar, sessionkey, "myhuh"), 0);
+    TEST(auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0), 0);
+    TEST_S(hresponse, "32960a62bdc202171ca5a294dc229a6d");
+  }
+
+  {
+    char chal[] = 
+      "Digest realm=\"nokia-proxy\", domain=\"sip:10.21.32.63\", "
+      "nonce=\"GjbLsrozHC6Lx95C57vGlw==\", opaque=\"HN22wQ==\", algorithm=MD5";
+
+    char cred[] =
+      "digest username=\"test1\",realm=\"nokia-proxy\","
+      "nonce=\"GjbLsrozHC6Lx95C57vGlw==\",opaque=\"HN22wQ==\","
+      "uri=\"sip:10.21.32.63\",response=\"e86db25d96713482e35378504caaba6b\","
+      "algorithm=\"MD5\"";
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+    
+    TEST0(pa = sip_proxy_authenticate_make(home, chal));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 6);
+
+    TEST0(pz = sip_proxy_authorization_make(home, cred));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 8);
+    
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST(auth_digest_sessionkey(ar, sessionkey, "test1"), 0);
+    TEST(auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0), 0);
+    TEST_S(hresponse, "db41913e8964dde69a1519739f35a302");
+  }
+
+  {
+    char challenge[] = 
+      "Digest realm=\"nokia-proxy\", domain=\"sip:194.2.188.133\", "
+      "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", opaque=\"+GNywA==\", "
+      "algorithm=MD5, qop=\"auth-int\"";
+    char credentials[] = 
+      "Digest username=\"test\", realm=\"nokia-proxy\", "
+      "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", "
+      "cnonce=\"11RkhFg9EdaIRD36w0EMVA==\", opaque=\"+GNywA==\", "
+      "uri=\"sip:3000 at 194.2.188.133\", algorithm=MD5, "
+      "response=\"26e8b9aaacfca2d68770fab1ec04e2c7\", "
+      "qop=auth-int, nc=00000001";
+    char data[] = 
+      "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+      "<presence>\n"
+      "<presentity uri=\"sip:3000 at 194.2.188.133\"/>\n"
+      "<atom atomid=\"BQpTalFpkMyF9hOlR8olWQ==\">\n"
+      "<address uri=\"sip:3000 at 194.2.188.133\" priority=\" 0\">\n"
+      "<status status=\"open\"/>\n"
+      "<class class=\"business\"/>\n"
+      "<duplex duplex=\"full\"/>\n"
+      "<feature feature=\"voicemail\"/>\n"
+      "<mobility mobility=\"fixed\"/>\n"
+      "<note>\n"
+      "</note>\n"
+      "</address>\n"
+      "</atom>\n"
+      "</presence>\n";
+
+    memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+    memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+    
+    TEST0(pa = sip_proxy_authenticate_make(home, challenge));
+    TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 8);
+
+    TEST0(pz = sip_proxy_authorization_make(home, credentials));
+    TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 12);
+    
+    ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+    TEST0(!auth_digest_sessionkey(ar, sessionkey, "test"));
+    TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER", 
+				data, strlen(data)));
+    TEST_S(hresponse, "26e8b9aaacfca2d68770fab1ec04e2c7");
+  }
+
+  su_home_deinit(home);
+  
+  END();
+}
+
+#include <sofia-sip/msg_addr.h>
+
+msg_t *read_message(int flags, char const buffer[])
+{
+  int n, m;
+  msg_t *msg;
+  msg_iovec_t iovec[2];
+
+  n = strlen(buffer);
+  if (n == 0) 
+    return NULL;
+
+  msg = msg_create(sip_default_mclass(), flags);
+  if (msg_recv_iovec(msg, iovec, 2, n, 1) < 0) {
+    perror("msg_recv_iovec");
+  }
+  memcpy(iovec->mv_base, buffer, n);
+  msg_recv_commit(msg, n, 1);
+
+  m = msg_extract(msg);
+  if (m < 0) {
+    fprintf(stderr, "test_auth_digest: parsing error\n");
+    return NULL;
+  }
+
+  return msg;
+}
+
+#define AUTH_MAGIC_T su_root_t
+
+#include <sofia-sip/auth_module.h>
+
+static
+void test_callback(su_root_t *root, auth_status_t *as)
+{
+  su_root_break(root);
+}
+
+static 
+void init_as(auth_status_t *as)
+{
+  memset(as, 0, sizeof *as); 
+  as->as_home->suh_size = (sizeof *as);
+  su_home_init(as->as_home);
+  as->as_method = "REGISTER";
+  as->as_status = 500;
+  as->as_phrase = "Infernal Error";
+}
+
+static 
+void deinit_as(auth_status_t *as)
+{
+  su_home_deinit(as->as_home);
+  memset(as, 0, sizeof *as);
+}
+
+static 
+void reinit_as(auth_status_t *as)
+{
+  deinit_as(as); init_as(as);
+}
+
+/* Test digest authentication client and server */
+int test_digest_client()
+{
+  BEGIN();
+  
+  {
+    char challenge[] = 
+      PROTOCOL " 401 Unauthorized\r\n"
+      "Call-ID:0e3dc2b2-dcc6-1226-26ac-258b5ce429ab\r\n"
+      "CSeq:32439043 REGISTER\r\n"
+      "From:surf3.ims3.so.noklab.net <sip:surf3 at ims3.so.noklab.net>;tag=I8hFdg0H3OK\r\n"
+      "To:<sip:surf3 at ims3.so.noklab.net>\r\n"
+      "Via:SIP/2.0/UDP 10.21.36.70:23800;branch=z9hG4bKJjKGu9vIHqf;received=10.21.36.70;rport\r\n"
+      "WWW-Authenticate:Digest algorithm=MD5,nonce=\"h7wIpP+atU+/+Zau5UwLMA==\",realm=\"ims3.so.noklab.net\"\r\n"
+      "Content-Length:0\r\n"
+      "Security-Server:digest\r\n"
+      "r\n";
+      
+    char request[] = 
+      "REGISTER sip:ims3.so.noklab.net " PROTOCOL "\r\n"
+      "Via: SIP/2.0/UDP 10.21.36.70:23800;rport;branch=z9hG4bKRE18GFwa3AS\r\n"
+      "Max-Forwards: 80\r\n"
+      "From: surf3.ims3.so.noklab.net <sip:surf3 at ims3.so.noklab.net>;tag=I8hFdg0H3OK\r\n"
+      "To: <sip:surf3 at ims3.so.noklab.net>\r\n"
+      "Call-ID: 0e3dc2b2-dcc6-1226-26ac-258b5ce429ab\r\n"
+      "CSeq: 32439044 REGISTER\r\n"
+      "Contact: <sip:10.21.36.70:23800>\r\n"
+      "Expires: 3600\r\n"
+      "Supported: timer, 100rel\r\n"
+      "Security-Client: digest\r\n"
+      "Security-Verify: digest;d-ver=\"1234\"\r\n"
+      "Content-Length: 0\r\n"
+      "r\n";
+
+    msg_t *m1, *m2;
+    sip_t *sip;
+    auth_client_t *aucs = NULL;
+    sip_request_t *rq;
+    su_home_t *home;
+    su_root_t *root;
+    char *srcdir, *s, *testpasswd;
+    auth_mod_t *am;
+    auth_status_t as[1];
+    sip_www_authenticate_t *au;
+    auth_challenger_t ach[1] = 
+      {{ 401, "Authorization required", 
+	 sip_www_authenticate_class,
+	 sip_authentication_info_class
+	}};
+
+    TEST_1(home = su_home_new(sizeof(*home)));
+
+    TEST_1(m1 = read_message(MSG_DO_EXTRACT_COPY, challenge));
+    TEST_1(sip = sip_object(m1));
+    
+    TEST(auc_challenge(&aucs, home, sip->sip_www_authenticate, 
+		       sip_authorization_class), 1);
+    msg_destroy(m1);
+    
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "surf3.private at ims3.so.noklab.net", "1234"), 1);
+
+    TEST_1(m2 = read_message(MSG_DO_EXTRACT_COPY, request));
+    TEST_1(sip = sip_object(m2));
+    TEST_P(sip->sip_authorization, NULL);
+    TEST_1(rq = sip->sip_request);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   rq->rq_url, sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+    TEST_S(msg_params_find(sip->sip_authorization->au_params,
+			   "response="),
+	   "\"860f5ecc9990772e16937750ced9594d\"");
+
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+    TEST_S(msg_params_find(sip->sip_authorization->au_params,
+			   "response="),
+	   "\"9ce0d6a5869b4e09832d5b705453cbfc\"");
+
+    srcdir = getenv("srcdir");
+    if (srcdir == NULL) {
+      srcdir = su_strdup(home, argv0);
+      if ((s = strrchr(srcdir, '/')))
+	*s = '\0';
+      else
+	srcdir = ".";
+    }
+    TEST_1(testpasswd = su_sprintf(home, "%s/testpasswd", srcdir));
+
+    TEST_1(root = su_root_create(NULL));
+
+    TEST_1(am = auth_mod_create(NULL, 
+				AUTHTAG_METHOD("Digest"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				AUTHTAG_OPAQUE("+GNywA=="),
+				TAG_END()));
+
+    init_as(as);
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 401);
+
+    TEST_1(au = sip_authorization_make(home, 
+				       "Digest username=\"user1\", "
+				       "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", "
+				       "opaque=\"+GNywA==\", "
+				       "uri=\"sip:3000 at 194.2.188.133\", "
+				       "response=\"26e8b9aaacfca2d6"
+				       "8770fab1ec04e2c7\", "
+				       "realm=\"ims3.so.noklab.net\""));
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, au, ach);
+    TEST(as->as_status, 401);
+
+    {
+      char const *username = au->au_params[0];
+      char const *nonce = au->au_params[1];
+      char const *opaque = au->au_params[2];
+      char const *uri = au->au_params[3];
+      char const *response = au->au_params[4];
+      char const *realm = au->au_params[5];
+      
+      TEST_S(username, "username=\"user1\"");
+      TEST_S(nonce, "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\"");
+      TEST_S(opaque, "opaque=\"+GNywA==\"");
+      TEST_S(uri, "uri=\"sip:3000 at 194.2.188.133\"");
+      TEST_S(response, "response=\"26e8b9aaacfca2d68770fab1ec04e2c7\"");
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "username"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 400);
+      msg_params_add(home, (msg_param_t **)&au->au_params, username);
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "nonce"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 400);
+      msg_params_add(home, (msg_param_t **) &au->au_params, nonce);
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "opaque"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 401);	/* We use opaque to match authorization */
+      msg_params_add(home, (msg_param_t **) &au->au_params, opaque);
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "uri"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 400);
+      msg_params_add(home, (msg_param_t **) &au->au_params, uri);
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "response"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 400);
+      msg_params_add(home, (msg_param_t **)&au->au_params, response);
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "realm"), 1);
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 401);	/* au is ignored by auth_module */
+      msg_params_add(home, (msg_param_t **)&au->au_params, realm);
+
+      reinit_as(as);
+      auth_mod_check_client(am, as, au, ach);
+      TEST(as->as_status, 401);
+    }
+
+    as->as_response = (msg_header_t *)
+      sip_www_authenticate_make(as->as_home, "Unknown realm=\"huu haa\"");
+    TEST_1(as->as_response);
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    aucs = NULL;
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, NULL, ach);
+    TEST(as->as_status, 401);
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    reinit_as(as);
+    
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    TEST_1(msg_params_find(sip->sip_authorization->au_params, "cnonce=") == 0);
+    TEST_1(msg_params_find(sip->sip_authorization->au_params, "nc=") == 0);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+    TEST_1(as->as_info);	/* challenge for next round */
+    auth_mod_destroy(am);
+    aucs = NULL;
+
+    TEST_1(am = auth_mod_create(NULL, 
+				AUTHTAG_METHOD("Digest"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				AUTHTAG_ALGORITHM("MD5-sess"),
+				AUTHTAG_QOP("auth"),
+				AUTHTAG_OPAQUE("opaque=="),
+				TAG_END()));
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+    {
+      msg_auth_t *au = (msg_auth_t *)as->as_response;
+      int i;
+      char *equal;
+
+      if (au->au_params)
+	for (i = 0; au->au_params[i]; i++) {
+	  if (strncasecmp(au->au_params[i], "realm=", 6) == 0)
+	    continue;
+	  equal = strchr(au->au_params[i], '=');
+	  if (equal)
+	    msg_unquote(equal + 1, equal + 1);
+	}
+
+      TEST(auc_challenge(&aucs, home, au, sip_authorization_class), 1);
+      reinit_as(as);
+    }
+
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+    TEST_1(as->as_info == NULL);	/* No challenge for next round */
+
+    /* Test with changed payload */
+
+    reinit_as(as);
+    as->as_body = "foo"; as->as_bodylen = 3;
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+
+    reinit_as(as); aucs = NULL;
+
+    /* Test without opaque */
+    {
+      msg_auth_t *au;
+      char const *opaque;
+
+      auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+      au = (void *)msg_header_dup(home, as->as_response); TEST_1(au);
+
+      TEST_1(msg_params_find_slot((msg_param_t *)au->au_params, "opaque"));
+
+      opaque = *msg_params_find_slot((msg_param_t *)au->au_params, "opaque");
+
+      TEST(msg_params_remove((msg_param_t *)au->au_params, "opaque"), 1);
+
+      TEST(auc_challenge(&aucs, home, au, sip_authorization_class), 1);
+      TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			       "user1", "secret"), 1);
+      msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+
+      TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			     (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			     sip->sip_payload), 1);
+
+      TEST_1(sip->sip_authorization);
+      msg_params_add(home,
+		     (msg_param_t **)&sip->sip_authorization->au_params,
+		     opaque);
+
+      reinit_as(as);
+      auth_mod_check_client(am, as, sip->sip_authorization, ach);
+      TEST(as->as_status, 0);
+    }
+
+    reinit_as(as); auth_mod_destroy(am); aucs = NULL;
+
+    /* Test nextnonce */
+    {
+      char const *nonce1, *nextnonce, *nonce2;
+
+      reinit_as(as); auth_mod_destroy(am); aucs = NULL;
+
+      TEST_1(am = auth_mod_create(NULL, 
+				  AUTHTAG_METHOD("Digest"),
+				  AUTHTAG_REALM("ims3.so.noklab.net"),
+				  AUTHTAG_DB(testpasswd),
+				  AUTHTAG_ALGORITHM("MD5"),
+				  AUTHTAG_QOP("auth-int"),
+				  AUTHTAG_EXPIRES(90),
+				  /* Generate nextnonce
+				     if NEXT_EXPIRES in nonzero */
+				  AUTHTAG_NEXT_EXPIRES(900),
+				  TAG_END()));
+      
+      reinit_as(as);
+      auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+      
+      TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+			 sip_authorization_class), 1);
+      TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			       "user1", "secret"), 1);
+      msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+      TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			     (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			     sip->sip_payload), 1);
+      TEST_1(sip->sip_authorization);
+      TEST_1(nonce1 = msg_header_find_param(sip->sip_authorization->au_common, "nonce"));
+      
+      reinit_as(as);
+      auth_mod_check_client(am, as, sip->sip_authorization, ach);
+      TEST(as->as_status, 0);
+      /* We got authentication-info */
+      TEST_1(as->as_info);
+      /* It contains nextnonce */
+      TEST_1(nextnonce = msg_header_find_param(as->as_info->sh_common, "nextnonce"));
+
+      /* Store it in authenticator */
+      TEST(auc_info(&aucs, (msg_auth_info_t const *)as->as_info, sip_authorization_class), 1);
+
+      msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+      TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			     (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			     sip->sip_payload), 1);
+      TEST_1(sip->sip_authorization);
+      TEST_1(nonce2 = msg_header_find_param(sip->sip_authorization->au_common, "nonce"));
+
+      /*
+       * Make sure that server-side sends nextnonce in Authentication-info
+       * header, nextnonce differs from nonce sent in Challenge
+       */
+      TEST_1(strcmp(nonce1, nextnonce));
+      /* And client-side uses it */
+      TEST_S(nonce2, nextnonce);
+
+      auth_mod_destroy(am); aucs = NULL;
+    }
+
+    TEST_1(am = auth_mod_create(NULL, 
+				AUTHTAG_METHOD("Digest"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				AUTHTAG_ALGORITHM("MD5-sess"),
+				AUTHTAG_QOP("auth-int"),
+				TAG_END()));
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+    auth_mod_destroy(am); aucs = NULL;
+
+    TEST_1(am = auth_mod_create(NULL, 
+				AUTHTAG_METHOD("Digest"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				AUTHTAG_ALGORITHM("MD5-sess"),
+				AUTHTAG_QOP("auth,auth-int"),
+				AUTHTAG_FORBIDDEN(1),
+				AUTHTAG_ANONYMOUS(1),
+				TAG_END()));
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    reinit_as(as);
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+
+    au = (void*)msg_header_copy(msg_home(m2), (void*)sip->sip_authorization);
+
+    /* Test with invalid qop (bug #2329) */
+    msg_params_replace(msg_home(m2), (void *)&au->au_params, 
+		       "qop=\"auth,auth-int\"");
+    reinit_as(as);
+    auth_mod_check_client(am, as, au, ach);
+    TEST(as->as_status, 400);
+
+    reinit_as(as);
+    as->as_body = "foo"; as->as_bodylen = 3;
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 403);
+
+    reinit_as(as);
+    as->as_body = ""; as->as_bodylen = 0;
+    as->as_method = "OPTIONS";
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 403);
+
+    /* Test staleness check */
+    offset = 2 * 3600;
+    reinit_as(as);
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 401);
+    TEST_1(au = (void *)as->as_response); TEST_1(au->au_params);
+    TEST_S(msg_params_find(au->au_params, "stale="), "true");
+    aucs = NULL;
+
+    /* Test anonymous operation */
+    reinit_as(as);
+    auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    reinit_as(as);
+
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "anonymous", ""), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+    auth_mod_destroy(am); aucs = NULL;
+
+    /* Test Basic authentication scheme */
+    TEST_1(am = auth_mod_create(root, 
+				AUTHTAG_METHOD("Basic"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				TAG_END()));
+
+    reinit_as(as);    
+    auth_mod_check_client(am, as, NULL, ach); 
+    TEST(as->as_status, 401);
+    
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    reinit_as(as);    
+
+    TEST(auc_all_credentials(&aucs, "Basic", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+
+    aucs = NULL;
+
+    reinit_as(as);    
+    auth_mod_check_client(am, as, NULL, ach); 
+    TEST(as->as_status, 401);
+    
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+    reinit_as(as);    
+
+    TEST(auc_all_credentials(&aucs, "Basic", "\"ims3.so.noklab.net\"", 
+         "very-long-user-name-that-surely-exceeds-the-static-buffer", 
+         "at-least-when-used-with-the-even-longer-password"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 0);
+
+    auth_mod_destroy(am); deinit_as(as); aucs = NULL;
+
+    /* Test asynchronous operation */
+    aucs = NULL;
+    TEST_1(am = auth_mod_create(root, 
+				AUTHTAG_METHOD("Delayed+Digest"),
+				AUTHTAG_REALM("ims3.so.noklab.net"),
+				AUTHTAG_DB(testpasswd),
+				AUTHTAG_ALGORITHM("MD5-sess"),
+				AUTHTAG_QOP("auth-int"),
+				AUTHTAG_REMOTE((void *)"http://localhost:9"),
+				TAG_END()));
+
+    reinit_as(as);
+    as->as_callback = test_callback;
+    as->as_magic = root;
+    auth_mod_check_client(am, as, NULL, ach);
+    TEST(as->as_status, 100);
+    su_root_run(root);
+    TEST(as->as_status, 401);
+    
+    TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, 
+		       sip_authorization_class), 1);
+
+    reinit_as(as);
+    as->as_callback = test_callback;
+    as->as_magic = root;
+
+    TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"", 
+			     "user1", "secret"), 1);
+    msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+    TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, 
+			   (url_t *)"sip:surf3 at ims3.so.noklab.net", 
+			   sip->sip_payload), 1);
+    TEST_1(sip->sip_authorization);
+
+    auth_mod_check_client(am, as, sip->sip_authorization, ach);
+    TEST(as->as_status, 100);
+    su_root_run(root);
+    TEST(as->as_status, 0);
+
+    auth_mod_destroy(am); aucs = NULL;
+
+    deinit_as(as);
+    msg_destroy(m2);
+
+    su_root_destroy(root);
+
+    su_home_unref(home);
+  }
+
+  END();
+}
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+#endif
+
+#include <sofia-sip/auth_plugin.h>
+
+char tmppasswd[] = "/tmp/test_auth_digest.XXXXXX";
+
+#include <unistd.h>
+
+static void rmtmp(void)
+{
+  if (tmppasswd[0])
+    unlink(tmppasswd);
+}
+
+char const passwd[] =
+  "# Comment\n"
+  "malformed line\n"
+  "user1:secret:\n"
+  /* user2 has password "secret", too */
+  "user2:realm:4cbc2aff0b5b2b33675c0731c0db1c14\n"
+  /* duplicate user. fun */
+  "user1:secret:realm\n"
+  /* empty line */
+  "\n";
+
+/* Test digest authentication client and server */
+int test_module_io()
+{
+  auth_mod_t *am, am0[1];
+  auth_passwd_t *apw, *apw2;
+  int tmpfd;
+
+  BEGIN();
+
+#ifndef _WIN32
+  tmpfd = mkstemp(tmppasswd); TEST_1(tmpfd != -1);
+#else
+  tmpfd = open(tmppasswd, O_WRONLY); TEST_1(tmpfd != -1);
+#endif
+  atexit(rmtmp);		/* Make sure temp file is unlinked */
+
+  TEST_SIZE(write(tmpfd, passwd, strlen(passwd)), strlen(passwd));
+  TEST(close(tmpfd), 0);
+
+  /* Test file reading operation */
+  am = auth_mod_create(NULL, 
+		       AUTHTAG_METHOD("Digest"),
+		       AUTHTAG_REALM("realm"),
+		       AUTHTAG_DB(tmppasswd),
+		       AUTHTAG_ALGORITHM("MD5-sess"),
+		       AUTHTAG_QOP("auth-int"),
+		       TAG_END()); TEST_1(am);
+
+  apw = auth_mod_getpass(am, "user1", NULL); TEST_1(apw);
+  TEST_S(apw->apw_realm, "realm");
+
+  apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+  TEST_S(apw->apw_hash, "4cbc2aff0b5b2b33675c0731c0db1c14");
+  
+  apw2 = apw;
+
+  *am0 = *am;
+
+  TEST_1(auth_readdb_if_needed(am) == 0);
+
+  apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+  TEST_P(apw, apw2);
+
+  apw = auth_mod_addpass(am, "user3", "realm"); TEST_1(apw);
+  /* user3 with password fisu */
+  apw->apw_hash = "056595147630692bb29d1855089bc95b";
+
+  {
+    char const user3[] = "user3:realm:7df96b4718bd933af4883c8b73c96318\n";
+    tmpfd = open(tmppasswd, O_WRONLY|O_APPEND, 0); TEST_1(tmpfd != -1);
+    /* user3 with password fish */
+    TEST_SIZE(write(tmpfd, user3, strlen(user3)), strlen(user3));
+    TEST_1(close(tmpfd) == 0);
+  }
+
+#if HAVE_FLOCK
+  /* Test flock(). */
+  tmpfd = open(tmppasswd, O_RDONLY);
+
+  TEST_1(flock(tmpfd, LOCK_EX) != -1);
+
+  TEST_1(auth_readdb_if_needed(am) == 0);
+
+  /* there should be no changes in user table */
+  apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+  TEST_P(apw, apw2);
+
+  TEST_1(flock(tmpfd, LOCK_UN) != -1);
+#endif
+
+  TEST_1(auth_readdb_if_needed(am) == 0);
+
+  apw = auth_mod_getpass(am, "user2", "realm"); TEST_1(apw);
+  TEST_1(apw != apw2);
+
+  /* Local user3 overrides non-local */
+  apw = auth_mod_getpass(am, "user3", "realm"); TEST_1(apw);
+  TEST_S(apw->apw_hash, "7df96b4718bd933af4883c8b73c96318");
+
+  /* Test truncating */
+  {
+    char const user1[] = "user1:secret:\n";
+    tmpfd = open(tmppasswd, O_WRONLY|O_TRUNC, 0); TEST_1(tmpfd != -1);
+    TEST_SIZE(write(tmpfd, user1, strlen(user1)), strlen(user1));
+    TEST_1(close(tmpfd) == 0);
+  }
+
+  TEST_1(auth_readdb_if_needed(am) == 0);
+
+  apw = auth_mod_getpass(am, "user2", "realm"); TEST_1(apw == NULL);
+
+  /* Non-local user3 is kept in database */
+  apw = auth_mod_getpass(am, "user3", "realm"); TEST_1(apw);
+  TEST_S(apw->apw_hash, "056595147630692bb29d1855089bc95b");
+
+  auth_mod_destroy(am);
+
+  if (unlink(tmppasswd) == 0)
+    tmppasswd[0] = '\0';
+
+  END();
+}
+
+#include <sofia-sip/su_log.h>
+
+extern su_log_t iptsec_log[];
+
+static
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v] [-l n]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  argv0 = argv[0];
+
+  su_init();
+
+  for (i = 1; argv[i]; i++) {
+    if (argv[i] && strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      int level = 3;
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage();
+      
+      su_log_set_level(iptsec_log, level);
+    } else {
+      usage();
+    }
+  }
+
+  if ((TSTFLAGS & tst_verbatim))
+    su_log_soft_set_level(iptsec_log, 9);
+  else
+    su_log_soft_set_level(iptsec_log, 0);
+
+  retval |= test_digest();
+  retval |= test_digest_client();
+
+  retval |= test_module_io();
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+user1:secret:
+user2:fish:
+very-long-user-name-that-surely-exceeds-the-static-buffer:at-least-when-used-with-the-even-longer-password:
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+2006-01-17  Martti Mela  <martti.mela at nokia.com>
+
+	* msg_mime.c: defines for Mac OS X (which are lacking EBADMSG).
+
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Renamed msg_test.c as test_msg.c.
+
+	* Renamed msg_test_class.[hc] as test_class.[hc], 
+	  msg_test_protos.h(.in) as test_protos.h(.in),
+	  msg_test_table.c(.in) as test_table.c(.in).
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed msg_home() macro.
+
+    M ./libsofia-sip-ua/msg/msg.h -1 +1
+
+2005-10-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Dox fix to msg_header_replace().
+
+    M ./libsofia-sip-ua/msg/msg_parser.c -2 +3
+
+2005-08-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am: Do not include msg_test_class.o in libmsg.
+
+2005-08-01  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* msg_mime.c: Returning -2 from msg_accept_any_d() if the list is
+	empty.
+
+	* msg_internal.h, msg_mclass.h, msg_mclass.c, msg_parser.awk:
+
+	Added header-specific flags in parser table for
+	msg_extract_errors().
+
+	* msg.h, msg.c: Added msg_extract_errors().
+
+	* msg_parser.c: Using header-specific flags to classify parsing
+	errors with msg_extract_errors().
+	
+	Added support for apndlist headers.
+
+	* msg_header.h: Added support for apndlist headers.
+
+	* msg_mime.c: Various Accept* headers are now apndlist meaning
+	that they are printed on single line by default.
+	
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+PROJECT_NAME         = "msg"
+OUTPUT_DIRECTORY     = ../docs/html/msg
+
+INPUT 		     = msg.docs . sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+ at INCLUDE = ../sip/sip.doxyaliases
+
+TAGFILES             += ../docs/ipt.doxytags=../ipt  \
+			../docs/su.doxytags=../su    \
+			../docs/sip.doxytags=../sip  \
+			../docs/nta.doxytags=../nta  \
+			../docs/http.doxytags=../http
+
+GENERATE_TAGFILE     = ../docs/msg.doxytags
+
+IMAGE_PATH           += ../sip/images

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,117 @@
+#
+# Makefile.am for msg module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libmsg.la
+noinst_LIBRARIES = 	libtest_msg.a
+check_PROGRAMS = 	msg_name_hash test_msg
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+GENERATED_H = 		sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h
+PUBLIC_H = 		sofia-sip/msg.h sofia-sip/msg_header.h \
+			sofia-sip/msg_types.h sofia-sip/msg_mclass.h \
+			sofia-sip/msg_mclass_hash.h sofia-sip/msg_parser.h \
+			sofia-sip/msg_addr.h sofia-sip/msg_date.h \
+			sofia-sip/msg_buffer.h sofia-sip/msg_tag_class.h \
+			sofia-sip/msg_mime.h
+
+INTERNAL_H = msg_internal.h test_class.h
+
+nobase_include_sofia_HEADERS = \
+			$(GENERATED_H) $(PUBLIC_H) 
+
+BUILT_SOURCES = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
+
+libmsg_la_SOURCES = $(INTERNAL_H) \
+	msg.c msg_tag.c \
+	msg_mime.c msg_mime_table.c \
+	msg_header_copy.c msg_header_make.c \
+	msg_parser.c msg_mclass.c msg_parser_util.c \
+	msg_basic.c msg_generic.c msg_date.c msg_auth.c
+
+COVERAGE_INPUT = 	$(libmsg_la_SOURCES) $(include_sofia_HEADERS)
+
+libtest_msg_a_SOURCES = test_class.c test_table.c test_protos.h
+
+LDADD = 		libtest_msg.a libmsg.la \
+			../bnf/libbnf.la \
+			../url/liburl.la \
+			../su/libsu.la 
+
+test_msg_LDFLAGS = 	-static
+
+msg_name_hash_LDFLAGS =	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+dist_pkgdata_SCRIPTS = 	msg_parser.awk
+
+EXTRA_DIST =		Doxyfile msg.docs \
+			sofia-sip/msg_mime_protos.h.in \
+			sofia-sip/msg_protos.h.in \
+			msg_mime_table.c.in \
+			test_protos.h.in \
+			test_table.c.in
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = 		test_msg
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+MSG_PARSER_AWK = $(srcdir)/msg_parser.awk
+
+AWK_MSG_AWK = $(AWK) -f $(MSG_PARSER_AWK)
+
+test_protos.h: test_protos.h.in $(MSG_PARSER_AWK)
+test_table.c: test_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime_protos.h.in
+sofia-sip/msg_protos.h: sofia-sip/msg_protos.h.in
+msg_mime_table.c: msg_mime_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/msg_mime_protos.h sofia-sip/msg_protos.h: $(MSG_PARSER_AWK)
+
+test_protos.h: test_class.h
+	$(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \
+		PR=$@ TEMPLATE=$(srcdir)/test_protos.h.in $<
+
+test_table.c: test_class.h 
+	$(AWK_MSG_AWK) module=msg_test prefix=msg \
+		MC_HASH_SIZE=127 multipart=msg_multipart \
+		PT=$@ TEMPLATE=$(srcdir)/test_table.c.in $<
+
+sofia-sip/msg_protos.h: sofia-sip/msg_mime.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_MIDDLE=1 \
+		PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_protos.h.in $<
+
+sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_LAST=1 \
+		PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_mime_protos.h.in $<
+
+msg_mime_table.c: sofia-sip/msg_mime.h
+	$(AWK_MSG_AWK) module=msg_multipart \
+		tprefix=msg prefix=mp MC_HASH_SIZE=127 \
+		PT=$@ TEMPLATE=$(srcdir)/msg_mime_table.c.in $<

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,830 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for msg module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+
+SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) msg_name_hash.c test_msg.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = msg_name_hash$(EXEEXT) test_msg$(EXEEXT)
+DIST_COMMON = $(dist_pkgdata_SCRIPTS) $(nobase_include_sofia_HEADERS) \
+	$(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/msg
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libtest_msg_a_AR = $(AR) $(ARFLAGS)
+libtest_msg_a_LIBADD =
+am_libtest_msg_a_OBJECTS = test_class.$(OBJEXT) test_table.$(OBJEXT)
+libtest_msg_a_OBJECTS = $(am_libtest_msg_a_OBJECTS)
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmsg_la_LIBADD =
+am__objects_1 =
+am_libmsg_la_OBJECTS = $(am__objects_1) msg.lo msg_tag.lo msg_mime.lo \
+	msg_mime_table.lo msg_header_copy.lo msg_header_make.lo \
+	msg_parser.lo msg_mclass.lo msg_parser_util.lo msg_basic.lo \
+	msg_generic.lo msg_date.lo msg_auth.lo
+libmsg_la_OBJECTS = $(am_libmsg_la_OBJECTS)
+msg_name_hash_SOURCES = msg_name_hash.c
+msg_name_hash_OBJECTS = msg_name_hash.$(OBJEXT)
+msg_name_hash_LDADD = $(LDADD)
+msg_name_hash_DEPENDENCIES = libtest_msg.a libmsg.la ../bnf/libbnf.la \
+	../url/liburl.la ../su/libsu.la
+test_msg_SOURCES = test_msg.c
+test_msg_OBJECTS = test_msg.$(OBJEXT)
+test_msg_LDADD = $(LDADD)
+test_msg_DEPENDENCIES = libtest_msg.a libmsg.la ../bnf/libbnf.la \
+	../url/liburl.la ../su/libsu.la
+am__installdirs = "$(DESTDIR)$(pkgdatadir)" \
+	"$(DESTDIR)$(include_sofiadir)"
+dist_pkgdataSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(dist_pkgdata_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) \
+	msg_name_hash.c test_msg.c
+DIST_SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) \
+	msg_name_hash.c test_msg.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libmsg.la
+noinst_LIBRARIES = libtest_msg.a
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+GENERATED_H = sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h
+PUBLIC_H = sofia-sip/msg.h sofia-sip/msg_header.h \
+			sofia-sip/msg_types.h sofia-sip/msg_mclass.h \
+			sofia-sip/msg_mclass_hash.h sofia-sip/msg_parser.h \
+			sofia-sip/msg_addr.h sofia-sip/msg_date.h \
+			sofia-sip/msg_buffer.h sofia-sip/msg_tag_class.h \
+			sofia-sip/msg_mime.h
+
+INTERNAL_H = msg_internal.h test_class.h
+nobase_include_sofia_HEADERS = \
+			$(GENERATED_H) $(PUBLIC_H) 
+
+BUILT_SOURCES = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
+libmsg_la_SOURCES = $(INTERNAL_H) \
+	msg.c msg_tag.c \
+	msg_mime.c msg_mime_table.c \
+	msg_header_copy.c msg_header_make.c \
+	msg_parser.c msg_mclass.c msg_parser_util.c \
+	msg_basic.c msg_generic.c msg_date.c msg_auth.c
+
+COVERAGE_INPUT = $(libmsg_la_SOURCES) $(include_sofia_HEADERS)
+libtest_msg_a_SOURCES = test_class.c test_table.c test_protos.h
+LDADD = libtest_msg.a libmsg.la \
+			../bnf/libbnf.la \
+			../url/liburl.la \
+			../su/libsu.la 
+
+test_msg_LDFLAGS = -static
+msg_name_hash_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+dist_pkgdata_SCRIPTS = msg_parser.awk
+EXTRA_DIST = Doxyfile msg.docs \
+			sofia-sip/msg_mime_protos.h.in \
+			sofia-sip/msg_protos.h.in \
+			msg_mime_table.c.in \
+			test_protos.h.in \
+			test_table.c.in
+
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = test_msg
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+MSG_PARSER_AWK = $(srcdir)/msg_parser.awk
+AWK_MSG_AWK = $(AWK) -f $(MSG_PARSER_AWK)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/msg/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/msg/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libtest_msg.a: $(libtest_msg_a_OBJECTS) $(libtest_msg_a_DEPENDENCIES) 
+	-rm -f libtest_msg.a
+	$(libtest_msg_a_AR) libtest_msg.a $(libtest_msg_a_OBJECTS) $(libtest_msg_a_LIBADD)
+	$(RANLIB) libtest_msg.a
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libmsg.la: $(libmsg_la_OBJECTS) $(libmsg_la_DEPENDENCIES) 
+	$(LINK)  $(libmsg_la_LDFLAGS) $(libmsg_la_OBJECTS) $(libmsg_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+msg_name_hash$(EXEEXT): $(msg_name_hash_OBJECTS) $(msg_name_hash_DEPENDENCIES) 
+	@rm -f msg_name_hash$(EXEEXT)
+	$(LINK) $(msg_name_hash_LDFLAGS) $(msg_name_hash_OBJECTS) $(msg_name_hash_LDADD) $(LIBS)
+test_msg$(EXEEXT): $(test_msg_OBJECTS) $(test_msg_DEPENDENCIES) 
+	@rm -f test_msg$(EXEEXT)
+	$(LINK) $(test_msg_LDFLAGS) $(test_msg_OBJECTS) $(test_msg_LDADD) $(LIBS)
+install-dist_pkgdataSCRIPTS: $(dist_pkgdata_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)"
+	@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  if test -f $$d$$p; then \
+	    f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	    echo " $(dist_pkgdataSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \
+	    $(dist_pkgdataSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-dist_pkgdataSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	  echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \
+	done
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_auth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_date.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_generic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_header_copy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_header_make.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mclass.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mime.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mime_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_name_hash.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_parser_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_class.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_msg.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_table.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLIBRARIES clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdataSCRIPTS \
+	install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgdataSCRIPTS uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLIBRARIES clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am \
+	install-dist_pkgdataSCRIPTS install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-dist_pkgdataSCRIPTS \
+	uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+test_protos.h: test_protos.h.in $(MSG_PARSER_AWK)
+test_table.c: test_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime_protos.h.in
+sofia-sip/msg_protos.h: sofia-sip/msg_protos.h.in
+msg_mime_table.c: msg_mime_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/msg_mime_protos.h sofia-sip/msg_protos.h: $(MSG_PARSER_AWK)
+
+test_protos.h: test_class.h
+	$(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \
+		PR=$@ TEMPLATE=$(srcdir)/test_protos.h.in $<
+
+test_table.c: test_class.h 
+	$(AWK_MSG_AWK) module=msg_test prefix=msg \
+		MC_HASH_SIZE=127 multipart=msg_multipart \
+		PT=$@ TEMPLATE=$(srcdir)/test_table.c.in $<
+
+sofia-sip/msg_protos.h: sofia-sip/msg_mime.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_MIDDLE=1 \
+		PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_protos.h.in $<
+
+sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_LAST=1 \
+		PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_mime_protos.h.in $<
+
+msg_mime_table.c: sofia-sip/msg_mime.h
+	$(AWK_MSG_AWK) module=msg_multipart \
+		tprefix=msg prefix=mp MC_HASH_SIZE=127 \
+		PT=$@ TEMPLATE=$(srcdir)/msg_mime_table.c.in $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file msg.c Message object implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>		/* XXX */
+#include <sofia-sip/su.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_mclass.h"
+
+/**
+ * Create a message.
+ *
+ * @relatesalso msg_s
+ *
+ * @param mc    message class
+ * @param flags message control flags
+ */
+msg_t *msg_create(msg_mclass_t const *mc, int flags)
+{
+  msg_t *msg = su_home_new(sizeof(*msg) + mc->mc_msize);
+
+  if (msg) {
+    if ((flags & MSG_FLG_THRDSAFE) &&
+	su_home_threadsafe(msg->m_home) < 0) {
+      su_home_unref(msg->m_home);
+      return NULL;
+    }
+
+    msg->m_refs++;
+    msg->m_tail = &msg->m_chain;
+    msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
+    msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
+    msg->m_maxsize = 0;
+
+    flags &= MSG_FLG_USERMASK;
+
+    msg->m_class = mc;
+    msg->m_oflags = flags;
+    msg->m_object = (void *)(msg + 1);
+    msg->m_object->msg_size = mc->mc_msize;
+    msg->m_object->msg_flags = mc->mc_flags | flags;
+    msg->m_object->msg_common->h_class = (void *)mc;
+  }
+
+  return msg;
+}
+
+/**Increment a message reference count.
+ *
+ * @relatesalso msg_s
+ *
+ * Creates a reference to a message.  The
+ * referenced message is not freed until all the references have been
+ * destroyed.
+ *
+ * @param msg   message of which a reference is created
+ * 
+ * @return
+ * A pointer to a message.
+ */
+msg_t *msg_ref_create(msg_t *msg)
+{
+  if (msg) {
+    su_home_mutex_lock(msg->m_home);
+    msg->m_refs++;
+    su_home_mutex_unlock(msg->m_home);
+  }
+  return msg;
+}
+
+/**Set a message parent.
+ *
+ * @relatesalso msg_s
+ *
+ * Set a parent for a message. The parent message is not destroyed until all
+ * its kids have been destroyed - each kid keeps a reference to its parent
+ * message.
+ *
+ * @param kid  child message
+ * @param dad  parent message
+ */
+void msg_set_parent(msg_t *kid, msg_t *dad)
+{
+  if (kid) {
+    msg_t *step_dad = kid->m_parent;
+
+    if (dad && step_dad && step_dad != dad)
+      msg_ref_destroy(step_dad);
+
+    kid->m_parent = msg_ref_create(dad);
+  }
+}
+
+/** Destroy a reference to a message.
+ *
+ * @relatesalso msg_s
+ *
+ * @param ref pointer to msg object
+ * 
+ * @deprecated Use msg_destroy() instead.
+ */
+void msg_ref_destroy(msg_t *ref)
+{
+  msg_destroy(ref);
+}
+
+/**Deinitialize and free a message.
+ *
+ * @relatesalso msg_s
+ *
+ * @param msg  message to be destroyed
+ */
+void msg_destroy(msg_t *msg)
+{
+  msg_t *parent;
+  
+  for (; msg; msg = parent) {
+    int refs;
+    su_home_mutex_lock(msg->m_home);
+    parent = msg->m_parent;
+    if (msg->m_refs)
+      msg->m_refs--;
+    refs = msg->m_refs;
+    su_home_mutex_unlock(msg->m_home);
+    if (refs)
+      break;
+    su_home_zap(msg->m_home);
+  }
+}
+
+/* Message object routines */
+
+/**Retrieve public message structure.
+ *
+ * Get a pointer to the public message structure.
+ * 
+ * @param msg pointer to msg object
+ * 
+ * @returns
+ * A pointer to the public message structure, or NULL if none.
+ */
+msg_pub_t *msg_object(msg_t const *msg)
+{
+  if (msg)
+    return msg->m_object;
+  else
+    return NULL;
+}
+
+/**Retrieve public message structure of given type.
+ *
+ * @relatesalso msg_s
+ *
+ * Get a pointer to the public message structure of the
+ * given protocol.
+ * 
+ * @param msg pointer to msg object
+ * @param tag tag of public message structure
+ * 
+ * @returns
+ * A pointer to the public message structure, or NULL if there is none or
+ * the message is not for desired protocol.
+ */
+msg_pub_t *msg_public(msg_t const *msg, void *tag)
+{
+  if (msg && msg->m_class->mc_tag == tag)
+    return msg->m_object;
+  else
+    return NULL;
+}
+
+/**Retrieve message class.
+ *
+ * @relatesalso msg_s
+ *
+ * Get a pointer to the message class object
+ * (factory object for the message).
+ * 
+ * @param msg pointer to msg object
+ * 
+ * @returns
+ * A pointer to the message class, or NULL if none.
+ */
+msg_mclass_t const *msg_mclass(msg_t const *msg)
+{
+  if (msg)
+    return msg->m_class;
+  else
+    return NULL;
+}
+
+/* Address management */
+
+/** Zero the message address.
+ *
+ * @relatesalso msg_s
+ *
+ * Zero the address and addressinfo structures associated with the message.
+ *
+ * @sa msg_addrinfo(), msg_set_address(), msg_get_address(), msg_addr_copy().
+ */ 
+void msg_addr_zero(msg_t *msg)
+{
+  memset(&msg->m_addr, 0, sizeof(&msg->m_addr));
+  memset(&msg->m_addrinfo, 0, sizeof(&msg->m_addrinfo));
+
+  msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
+  msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
+}
+
+/** Get pointer to socket address structure. 
+ *
+ * @relatesalso msg_s
+ *
+ * @deprecated Use msg_get_address() or msg_set_address() instead.
+ */
+su_sockaddr_t *msg_addr(msg_t *msg)
+{
+  return msg ? msg->m_addr : 0;
+}
+
+/** Get message address.
+ *
+ * @relatesalso msg_s
+ *
+ * Copy the socket address associated with the message to the supplied
+ * socket address struture.
+ *
+ * @param msg pointer to msg object
+ * @param su pointer to socket address structure
+ * @param return_len return parameter value for length 
+ *                    of socket address structure
+ *
+ * @sa msg_addrinfo(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
+ */
+int msg_get_address(msg_t *msg, su_sockaddr_t *su, socklen_t *return_len)
+{
+  if (msg && return_len && *return_len >= msg->m_addrinfo.ai_addrlen) {
+    *return_len = (socklen_t)msg->m_addrinfo.ai_addrlen;
+    if (su)
+      memcpy(su, msg->m_addr, msg->m_addrinfo.ai_addrlen);
+    return 0;
+  }
+  if (msg)
+    msg->m_errno = EFAULT;
+  return -1;
+}
+
+/** Set message address. 
+ *
+ * @relatesalso msg_s
+ *
+ * Copy the supplied socket address to the socket address structure
+ * associated with the message.
+ * 
+ * @param msg pointer to msg object
+ * @param su pointer to socket address structure
+ * @param sulen length of socket address structure
+ *
+ * @sa msg_addrinfo(), msg_get_address(), msg_addr_zero(), msg_addr_copy().
+ */
+int msg_set_address(msg_t *msg, su_sockaddr_t const *su, socklen_t sulen)
+{
+  if (sulen < (sizeof msg->m_addr) && msg && su) {
+    memcpy(msg->m_addr, su, msg->m_addrinfo.ai_addrlen = sulen);
+    msg->m_addrinfo.ai_family = su->su_family;
+    return 0;
+  }
+  if (msg)
+    msg->m_errno = EFAULT;
+  return -1;
+}
+
+/** Get addrinfo structure.
+ *
+ * @relatesalso msg_s
+ *
+ * Get pointer to the addrinfo structure associated with the message.
+ *
+ * @param msg pointer to msg object
+ *
+ * @retval pointer to addrinfo structure
+ * @retval NULL if msg is NULL
+ *
+ * @sa msg_get_address(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
+ */
+su_addrinfo_t *msg_addrinfo(msg_t *msg)
+{
+  return msg ? &msg->m_addrinfo : 0;
+}
+
+/**Copy message address.
+ *
+ * @relatesalso msg_s
+ *
+ * Copy the addrinfo and socket address structures from @a src to the @a dst
+ * message object.
+ *
+ * @param dst pointer to destination message object 
+ * @param src pointer to source message object
+ *
+ * @sa msg_addrinfo(), msg_get_address(), msg_set_address(), msg_addr_zero().
+ */
+void msg_addr_copy(msg_t *dst, msg_t const *src)
+{
+  dst->m_addrinfo = src->m_addrinfo;
+  dst->m_addrinfo.ai_next = NULL;
+  dst->m_addrinfo.ai_canonname = NULL;
+  memcpy(dst->m_addrinfo.ai_addr = &dst->m_addr->su_sa, 
+	 src->m_addr, src->m_addrinfo.ai_addrlen);
+  if (dst->m_addrinfo.ai_addrlen < sizeof(dst->m_addr))
+    memset((char *)dst->m_addr + dst->m_addrinfo.ai_addrlen, 0, 
+	   sizeof(dst->m_addr) - dst->m_addrinfo.ai_addrlen);
+}
+
+
+/** Get error classification flags.
+ *
+ * @relatesalso msg_s
+ *
+ * If the message parser fails to parse certain headers in the message, it
+ * sets the corresponding extract error flags. The flags corresponding to
+ * each header are stored in the message parser (msg_mclass_t) structure. 
+ * They are set when the header is added to the parser table. 
+ * 
+ * The SIP flags are defined in <sofia-sip/sip_headers.h>. For well-known
+ * SIP headers, the flags for each header are listed in a separate text file
+ * (sip_bad_mask) read by msg_parser.awk.
+ *
+ * The flags can be used directly by NTA (the mask triggering 400 response
+ * is set with NTATAG_BAD_REQ_MASK(), the mask triggering response messages
+ * to be dropped is set with NTATAG_BAD_RESP_MASK()). Alternatively the
+ * application can check them based on the method or required SIP features.
+ *
+ * @sa msg_mclass_insert_with_mask(), NTATAG_BAD_REQ_MASK(),
+ * NTATAG_BAD_RESP_MASK().
+ */
+unsigned msg_extract_errors(msg_t const *msg)
+{
+  return msg ? msg->m_extract_err : (unsigned)-1;
+}
+
+
+/** Get error number associated with message.
+ *
+ * @relatesalso msg_s
+ *
+ * @param msg pointer to msg object
+ *
+ */
+int msg_errno(msg_t const *msg)
+{
+  return msg ? msg->m_errno : EINVAL;
+}
+
+/** Set error number associated with message.
+ *
+ * @relatesalso msg_s
+ *
+ * @param msg pointer to msg object
+ * @param err error value (as defined in <sofia-sip/su_errno.h>).
+ *
+ */
+void msg_set_errno(msg_t *msg, int err)
+{
+  if (msg)
+    msg->m_errno = err;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,506 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "msg" - Message Parser Module
+
+ at section msg_meta Module Meta Information
+
+This module contains parser and functions for manipulating messages and
+headers for text-based protocols like SIP, HTTP or RTSP. It also
+provides parsing of MIME headers and MIME multipart messages common to
+these protocols.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at section msg_contents Contents of msg Module
+
+The msg module contains the public header files as follows:
+- <sofia-sip/msg.h>         base message interfaces
+- <sofia-sip/msg_types.h>   message and header struct definitions and typedefs
+- <sofia-sip/msg_protos.h>  prototypes of header-specific functions for generic headers
+- <sofia-sip/msg_header.h>  function prototypes and macros for manipulating message
+                            headers
+- <sofia-sip/msg_addr.h>    functions for accessing network addresses and I/O vectors
+                            associated with the message
+- <sofia-sip/msg_date.h>    types and functions for handling dates and times
+- <sofia-sip/msg_mime.h>    types, function prototypes and macros for MIME headers
+                            and @ref msg_multipart "multipart messages"
+- <sofia-sip/msg_mime_protos.h> prototypes of MIME-header-specific functions
+
+In addition to this interface, the @ref msg_parser "parser documentation"
+contains description of the functionality required when an existing parser
+is extended by a new header or a parser is created for a completely new
+protocol. It is possible to add new headers to the parser or extend the
+definition of existing ones. The header files used for constructing these
+parsers are as follows: 
+- <sofia-sip/msg_parser.h> parsing functions, macros 
+- <sofia-sip/msg_mclass.h> message factory object definition 
+- <sofia-sip/msg_mclass_hash.h> hashing of header names
+
+ at section msg_overview Parsers, Messages and Headers
+
+The Sofia @b msg module contains interface to the text-based parsers for
+RFC822-like message, the header and message objects. Currently, there
+are three parsers defined: SIP, HTTP, and MIME.
+
+The C structure corresponding to each header is defined either in a
+<sofia-sip/msg_types.h> or in a protocol-specific header file. These
+protocol-specific header files include <sofia-sip/sip.h>, <sofia-sip/http.h>, and
+<sofia-sip/msg_mime.h>. For each header, there is defined a @em header @em class
+structure, some standard functions, and tags for including them in tag
+lists. 
+
+As a convention, all the identifiers for SIP headers start with prefix @c
+sip and all the macros with @c SIP. Same thing holds for HTTP, too: it
+uses prefix @c http. However, the MIME headers
+and the functions related to them are defined within the @b msg module and
+they use prefix @c msg. If a SIP or HTTP header uses a structure
+defined in <sofia-sip/msg_types.h>, there is a typedef suitable for the particular
+protocol, for example @b Accept header is defined multiple times:
+
+ at code
+typedef struct msg_accept_s sip_accept_t;
+typedef struct msg_accept_s http_accept_t;
+ at endcode
+
+For header @e X of protocol @e NS, there are types, functions, macros and
+header class as follows:
+
+ - @c ns_X_t is the structure used to store parsed header,
+ - @c ns_hclass_t @c ns_X_class[] contains the @em header @em class 
+   for header X,
+ - @c NS_X_INIT() initializes a static instance of @c ns_X_t,
+ - @c ns_X_init() initializes a dynamic instance of @c ns_X_t,
+ - @c ns_is_X() tests if header object is instance of header X,
+ - @c ns_X_make() creates a header X object by decoding given string,
+ - @c ns_X_format() creates a header X object by decoding given 
+   @c printf() list,
+ - @c ns_X_dup() duplicates (deeply copies) the header X, 
+ - @c ns_X_copy() copies the header X, 
+ - @c NSTAG_X() is used include instance of @c ns_X_t in a tag list, and
+ - @c NSTAG_X_STR() is used to include string containing value header 
+      in a tag list.
+
+The declarations of header tags and the prototypes for these functions can
+be imported separately from the type definitions, for instance, the tags
+related to SIP headers are declared in the include file
+<sofia-sip/sip_tag.h>, and the header-specific functions in
+<sofia-sip/sip_header.h>.
+
+ at section parser_intro Parsing Text Messages
+
+Sofia text parser follows @em recursive-descent principle.  In other words,
+it is a program that descends the syntax tree top-down recursively.
+(All syntax trees have root at top and they grow downwards.)
+
+In the case of SIP, HTTP and other similar protocols, such a parser is very
+efficient. The parser can choose between different forms based on each
+token, as the protocol syntax is carefully designed so that it requires only
+minimal scan-ahead. It is also easy to extend a recursive-descent parser via
+a standard API, unlike, for instance, a LALR parser generated by @em Bison.
+
+The abstract message module @b msg contains a high-level parser engine that
+drives the parsing process and invokes the protocol-specific parser for each
+header. As there is no low-layer framing between the RFC822-style messages,
+the parser considers any received data, be it a UDP datagram or a TCP
+stream, as a @em byte @em stream. The protocol-specific parsers controls how
+a byte stream is split into separate messages or if it consists of a single
+message only. 
+
+The parser engine works by separating stream into fragments, then passing
+the fragment to a suitable parser. A fragment is a piece of message that is
+parsed during a single step: the first line, each header, the empty line
+between headers and message body, the message body. (In case of HTTP, the
+message body can consists of multiple fragments known as chunks.)
+
+The parser starts by separating the first line (e.g., request or status
+line) from the byte stream, then passing the line to the suitable parser. 
+After first line comes the message headers. The parser continues parsing
+process by extracting headers, each on their own line, from the stream and
+passing contents of each header to its parser. The message structure is
+populated based on the parsing results. When an empty line - indicating end
+of headers - is encountered, the control is passed to the protocol-specific
+parser. Protocol-specific functions take care of extracting the possible
+message body from the byte stream.
+
+After parsing process is completed, it can be given to the upper layers
+(typically a protocol state machine). The parser continues processing the
+stream and feeding the messages to protocol engine until the end of the
+stream is reached.
+
+ at image html sip-parser.gif Separating byte stream to messages
+ at image latex sip-parser.eps Separating byte stream to messages
+
+When the parsing process has completed, the first line, each header,
+separator and the message body are all in their own fragment structure. The
+fragments form a dual-linked list known as @e fragment @e chain as shown in
+the above figure. The memory buffers for the message, the fragment chain,
+and a whole lot of other stuff is held by the generic message type, #msg_t,
+defined in <msg.h>. The internal structure of #msg_t is known only within @b
+msg module and it is opaque to other modules.
+
+The @b msg parser engine also drives the reverse process, invoking the
+encoding method of each fragment so that the whole outgoing message can be
+encoded properly.
+
+ at section msg_header_struct Message Header as a C struct
+
+Just separating headers from each other and from the message body is not
+usually enough. When a header contains structured data, the header contents
+should be converted to a form that is convenient to use from C programs. For
+that purpose, the message parser needs a parsing function specific to each
+individual header. This parsing function divides the contents of the header
+into semantically meaningful segments and stores the result in the structure
+specific to each header.
+
+The parser engine passes the fragment contents to the parsing function after
+it has separated the fragment from the rest of the message. The parser
+engine selects correct @e header @e class either by implication (in case of
+first line), or it searches for the header class from the hash table using
+the header name as the hash key. The @e header @e class contains a pointer
+to the parsing function. The parser has also special header classes for
+headers with errors and @e unknown headers, header with a name that is not
+regocnized by the parser.
+
+For instance, the Accept header has following syntax:
+ at code
+   Accept         = "Accept" ":" #( media-range [ accept-params ] )
+
+   media-range    = ( "*" "/" "*"
+                    | ( type "/" "*" )
+                    | ( type "/" subtype ) ) *( ";" parameter )
+
+   accept-params  = ";" "q" "=" qvalue *( accept-extension )
+
+   accept-extension = ";" token [ "=" ( token | quoted-string ) ]
+ at endcode
+
+When an Accept header is parsed, the header parser function (msg_accept_d())
+separates the @e type, @e subtype, and each parameter in the list to
+strings. The parsing result is assigned to a #msg_accept_t structure, which is
+defined as follows:
+
+ at code
+typedef struct msg_accept_s
+{
+  msg_common_t        ac_common[1]; //< Common fragment info
+  msg_accept_t       *ac_next;	    //< Pointer to next Accept header
+  char const         *ac_type;	    //< Pointer to type/subtype
+  char const         *ac_subtype;   //< Points after first slash in type
+  msg_param_t const  *ac_params;    //< List of parameters
+  msg_param_t         ac_q;	    //< Value of q parameter
+} 
+msg_accept_t;
+ at endcode
+
+The string containing the @e type is put into the @c ac_type field, the @e
+subtype after slash in the can be found in the @c ac_subtype field, and the
+list of @e accept-params (together with media-specific-parameters) is put in
+the @c ac_params array. If there is a @e q parameter present, a pointer to
+the @c qvalue is assigned to @c ac_q field.
+
+In the beginning of the header structure there are two boilerplate members. 
+The @c ac_common[1] contains information common to all message fragments. 
+The @c ac_next is a pointer to next header field with the same name, in case
+a message contains multiple @b Accept headers or multiple comma-separated
+header fields are located in a single line.
+
+ at section msg_object_example Representing a Message as a C struct
+
+It is not enough to represent a message as a list of headers following each
+other. The programmer also needs a convenient way to access certain headers
+at the message level, for example, accessing directly the @b Accept header
+instead of going through all headers and examining their name. The
+structured view to the message is provided via a message-specific C struct. 
+In general, its type is msg_pub_t (it provides public view to message). The
+protocol-specific type is #sip_t, #http_t or #msg_multipart_t for
+SIP, HTTP and MIME, respectively.
+
+So, a single message is represented by two objects, first object (#msg_t) is
+private to the @b msg module and opaque by an application programmer, second
+(#sip_t, #http_t or #msg_multipart_t) is a public protocol-specific
+structure accessible by all.
+
+ at note The application programmer can obtain a pointer to the
+protocol-specific structure from an #msg_t object using msg_public()
+function. The msg_public() takes a protocol tag, a well-known identifier, as
+its argument. The SIP, HTTP and MIME already define a wrapper around
+msg_public(), for example, a #sip_t structure can be obtained with
+sip_object() function (or macro).
+
+As an example, the #sip_t structure is defined as follows:
+ at code
+typedef struct sip_s {
+  msg_common_t        sip_common[1];    // Used with recursive inclusion
+  msg_pub_t          *sip_next;         // Ditto
+  void               *sip_user;	        // Application data
+  unsigned            sip_size;         // Size of the structure with
+                                        // extension headers
+  int                 sip_flags;        // Parser flags
+
+  sip_error_t        *sip_error;	// Erroneous headers
+
+  sip_request_t      *sip_request;      // Request line
+  sip_status_t       *sip_status;       // Status line
+
+  sip_via_t          *sip_via;          // Via (v)
+  sip_route_t        *sip_route;        // Route
+  sip_record_route_t *sip_record_route; // Record-Route
+  sip_max_forwards_t *sip_max_forwards; // Max-Forwards
+  ...
+} sip_t;
+ at endcode
+
+As you can see above, the public #sip_t structure contains the common
+header members that are also found in the beginning of a header
+structure. The @e sip_size indicates the size of the structure - the
+application can extend the parser and #sip_t structure beyond the
+original size. The @e sip_flags contains various flags used during the
+parsing and printing process. They are documented in the <msg.h>. These
+boilerplate members are followed by the pointers to various message
+elements and headers.
+
+ at section msg_parsing_example Result of Parsing Process
+
+Let us now show how a simple message is parsed and presented to the
+applications. As an exampe, we choose a SIP request message with method BYE,
+including only the mandatory fields:
+ at code
+BYE sip:joe at example.com SIP/2.0
+Via: SIP/2.0/UDP sip.example.edu;branch=d7f2e89c.74a72681
+Via: SIP/2.0/UDP pc104.example.edu:1030;maddr=110.213.33.19
+From: Bobby Brown <sip:bb at example.edu>;tag=77241a86
+To: Joe User <sip:joe at example.com>;tag=7c6276c1
+Call-ID: 4c4e911b at pc104.example.edu
+CSeq: 2
+ at endcode
+
+The figure below shows the layout of the BYE message above after parsing:
+
+ at image html sip-parser2.gif BYE message and its representation in C 
+ at image latex sip-parser2.eps BYE message and its representation in C
+
+The leftmost box represents the message of type #msg_t.  Next box from
+the left reprents the #sip_t structure, which contains pointers to a
+header objects.  The next column contains the header objects.  There is
+one header object for each message fragment. The rightmost box represents
+the I/O buffer used when the message was received.  Note that the I/O
+buffer may be non-continous and composed of many separate memory areas.
+
+The message object has link to the public message structure (@a
+m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O
+buffer (@a m_buffer).  The public message structure contains pointers to
+the headers according to their type.  If there are multiple headers of
+the same type (like there are two Via headers in the above message), the
+headers are put into a single-linked list.
+
+Each fragment has pointers to successing and preceding fragment. It also
+contains pointer to the corresponding data within the I/O buffer and its
+length.
+
+The main purpose of the fragment chain is to preserve the original order
+of the headers.  If there were an third Via header after CSeq in the
+message, the fragment representing it would be after the CSeq header in
+the fragment chain but after second Via in the header list.
+
+ at section msg_parsing_memory Example: Parsing a Complete Message
+
+The following code fragment is an example of parsing a complete message. The
+parsing process is more hairy when there is stream to be parsed.
+
+ at code
+msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len)
+{
+  msg_t *msg;
+  int m;
+  msg_iovec_t iovec[2] = {{ 0 }};
+
+  msg  = msg_create(mclass, 0);
+  if (!msg)
+    return NULL;
+
+  m = msg_recv_iovec(msg, iovec, 2, n, 1);
+  if (m < 0) {
+    msg_destroy(msg);
+    return NULL;
+  }
+  assert(m <= 2);
+  assert(iovec[0].mv_len + iovec[1].mv_len == n);
+
+  memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len);
+  if (m == 2)
+    memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len);
+
+  msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1);
+
+  m = msg_extract(msg);
+  assert(m != 0);
+  if (m < 0) {
+     msg_destroy(msg);
+     return NULL;
+  }
+  return msg;
+}
+ at endcode
+
+Let's go through this simple function, step by step. First, we get the @a
+data pointer and its size in bytes, @a len. We first initialize an I/O
+vector used to represent message with the parser.
+
+ at code
+msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len)
+{
+  msg_t *msg;
+  int m;
+  msg_iovec_t iovec[2] = {{ 0 }};
+ at endcode
+
+The message class @a mclass (a parser driver object, #msg_mclass_t) is used
+to represent a particular protocol-specific parser instance. When a message
+object is created, it is given as an argument to msg_create() function:
+
+ at code
+  msg  = msg_create(mclass, 0);
+  if (!msg)
+    return NULL;
+ at endcode
+
+Next we obtain a memory buffer for data with msg_recv_iovec(). The memory
+buffer is usually a single continous memory area, but in some cases it may
+consist of two distinct areas. Therefore the @a iovec is used here to pass
+the buffers around. The @a iovec is also very handly as it can be directly
+passed to various system I/O calls.
+
+ at code
+  m = msg_recv_iovec(msg, iovec, 2, n, 1);
+  if (m < 0) {
+    msg_destroy(msg);
+    return NULL;
+  }
+ at endcode
+
+These assumptions hold always true when you call msg_recv_iovec() first
+time with a complete message:
+
+ at code
+  assert(m >= 1 && m <= 2);
+  assert(iovec[0].mv_len + iovec[1].mv_len == n);
+ at endcode
+
+Next, we copy the data to the I/O vector and commit the copied data to the
+message. Earlier with msg_recv_iovec() we allocated buffer space for data,
+now calling msg_recv_commit() indicates that valid data has been copied to
+the buffer. The last parameter to msg_recv_commit() indicates that the end
+of stream is encountered and no more data is to be expected.
+
+ at code
+  memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len);
+  if (m == 2)
+    memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len);
+
+  msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1);
+ at endcode
+
+We call msg_extract() next; it takes care of parsing the message. A fatal
+parsing error is indicated by returning -1. If the message is incomplete,
+msg_extract() returns 0. When a complete message has been parsed, a positive
+value is returned. We know that a message cannot be incomplete, as a call to
+msg_recv_commit() indicated to the parser that the end-of-stream has been
+encountered.
+
+ at code
+  m = msg_extract(msg);
+  assert(m != 0);
+  if (m < 0) {
+     msg_destroy(msg);
+     return NULL;
+  }
+  return msg;
+}
+ at endcode
+
+ */
+
+/**@class msg_s msg.h
+ *
+ * @brief Message object.
+ *
+ * The message object is used by Sofia parsers for SIP and HTTP
+ * protocols. The message object has an abstract, protocol-independent
+ * inteface type #msg_t, and a separate public protocol-specific interface
+ * #msg_pub_t (which is typedef'ed to #sip_t or #http_t depending
+ * on the protocol).
+ *
+ * The main interface to abstract messages is defined in <sofia-sip/msg.h>. The
+ * network I/O interface used by transport protocols is defined in
+ * <sofia-sip/msg_addr.h>. The protocol-specific parser table, also known as message
+ * class, is defined in <sofia-sip/msg_mclass.h>. (The message class is used as a
+ * factory object when a message object is created with msg_create()).
+ */
+
+/**@typedef typedef struct msg_s msg_t;
+ *
+ * Message object. 
+ *
+ * The @a msg_t is the type of a message object used by Sofia signaling
+ * protocols and parsers. Its contents are not directly accessible.
+ */
+
+/**@typedef typedef struct msg_common_s msg_common_t;
+ *
+ * Common part of header. 
+ *
+ * The @a msg_common_t is the base type of a message headers used by
+ * protocol parsers. Instead of #msg_common_t, most interfaces use
+ * #msg_header_t, which is supposed to be a union of all possible headers.
+ */
+
+
+/**
+ * @defgroup msg_parser Parser Building Blocks
+ *
+ * This submodule contains the functions and types for building a
+ * protocol-specific parser.
+ */
+
+/**
+ * @defgroup msg_headers Headers
+ *
+ * This submodule contains the functions and types for handling message
+ * headers and other elements.
+ */
+
+
+/**
+ * @defgroup msg_mime MIME Headers
+ *
+ * This submodule contains the header classes, functions and types for
+ * handling MIME headers (@RFC2045) and MIME multipart (@RFC2046) processing.
+ *
+ * The MIME headers implemented are as follows:
+ * - @ref msg_accept "@b Accept header"
+ * - @ref msg_accept_charset "@b Accept-Charser header"
+ * - @ref msg_accept_encoding "@b Accept-Encoding header"
+ * - @ref msg_accept_language "@b Accept-Language header"
+ * - @ref msg_content_disposition "@b Content-Disposition header"
+ * - @ref msg_content_encoding "@b Content-Encoding header"
+ * - @ref msg_content_id "@b Content-ID header"
+ * - @ref msg_content_location "@b Content-Location header"
+ * - @ref msg_content_language "@b Content-Language header"
+ * - @ref msg_content_md5 "@b Content-MD5 header"
+ * - @ref msg_content_transfer_encoding "@b Content-Transfer-Encoding header"
+ * - @ref msg_mime_version "@b MIME-Version header"
+ */
+
+/**
+ * @defgroup test_msg Testing Parser
+ *
+ * This submodule contains the functions and types for building a
+ * parser objects for testing purposes.
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_auth.c
+ *
+ * Functions for handling authentication-related headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <sofia-sip/msg.h>
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_header.h>
+#include <sofia-sip/bnf.h>
+
+#if 0
+/**
+ * Scan and compact an authentication parameter.
+ *
+ * Scan an authentication parameter, which has syntax as follows:
+ * @code
+ * auth-item = auth-param | base64-string
+ * auth-param = token [ "=" (token | quoted-string)]
+ * @endcode
+ *
+ * Parameters:
+ * @param s      pointer to string to scan
+ *
+ * @return Number of characters scanned, or zero upon an error.
+ */
+static size_t msg_auth_item_scan(char *start)
+{
+  char *p, *s;
+
+  p = s = start;
+
+  /* XXX */
+
+  return start - s;
+}
+#endif
+
+/* ====================================================================== */
+/*
+ * auth           = ("Authorization" | "Encryption" | 
+ *                   "Proxy-Authenticate" | "Proxy-Authorization" |
+ *                   "Response-Key" | "WWW-Authenticate") ":" 
+ *                    scheme 1*SP #auth-param
+ * scheme         = token
+ * auth-param     = token | token "=" token | token "=" quoted-string
+ */
+
+/** Parse security headers. */
+issize_t msg_auth_d(su_home_t *home,
+		    msg_header_t *h,
+		    char *s,
+		    isize_t slen)
+{
+  msg_auth_t *au = (msg_auth_t *)h;
+
+  au->au_scheme = s;
+  
+  skip_token(&s);
+  if (!IS_LWS(*s)) return -1;
+  *s++ = '\0';			/* NUL-terminate scheme */
+
+  return msg_commalist_d(home, &s, (msg_param_t **)&au->au_params, 
+			 NULL /* msg_auth_item_scan */);
+}
+
+issize_t msg_auth_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  msg_auth_t const *au = (msg_auth_t *)h;
+  int compact = MSG_IS_COMPACT(f);
+  char *b0 = b, *end = b + bsiz;
+
+  MSG_STRING_E(b, end, au->au_scheme);
+  if (au->au_params) {
+    MSG_CHAR_E(b, end, ' ');
+    MSG_COMMALIST_E(b, end, au->au_params, compact);
+  }
+  MSG_TERM_E(b, end);
+  
+  return b - b0;
+}
+
+/**@internal 
+ * Extra size of a msg_auth_t object.
+ *
+ * This function calculates extra size required by a msg_auth_t object.
+ *
+ * @param a pointer to a msg_auth_t object
+ *
+ * @return
+ *   Size of strings related to msg_auth_t object.
+ */
+isize_t msg_auth_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_auth_t const *au = h->sh_auth;
+
+  MSG_PARAMS_SIZE(offset, au->au_params);
+  offset += MSG_STRING_SIZE(au->au_scheme);
+    
+  return offset;
+}
+
+/**Duplicate one msg_auth_t object. */
+char *msg_auth_dup_one(msg_header_t *dst,
+		       msg_header_t const *src,
+		       char *b,
+		       isize_t xtra)
+{
+  msg_auth_t *au = dst->sh_auth;
+  msg_auth_t const *o = src->sh_auth;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&au->au_params, o->au_params, b, xtra);
+  MSG_STRING_DUP(b, au->au_scheme, o->au_scheme);
+    
+  assert(b <= end); (void)end;
+
+  return b;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,357 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_headers
+ * @CFILE msg_basic.c
+ * @brief Basic header handling.
+ *
+ * This file contains implementation of basic headers, that is, generic
+ * headers like Subject or Organization containing non-structured text only,
+ * numeric headers like Content-Length or Max-Forwards containing only an
+ * 32-bit unsigned integer, or token list headers like Supported or Allow.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 19:51:55 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include <sofia-sip/msg.h>
+#include <sofia-sip/bnf.h>
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_header.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#define msg_generic_update NULL
+
+/* ====================================================================== */
+
+/**@ingroup msg_headers
+ * @defgroup msg_error Erroneous Headers
+ *
+ * The erroneous headers are stored in #msg_error_t structure.
+ * 
+ * @note Parser may put other headers (like duplicate Content-Length
+ * headers) into the list of erroneous headers. If the list of erroneous
+ * headers is processed, the header type must be validated first by calling
+ * msg_is_error() (or by other relevant tests).
+ */
+
+/**@ingroup msg_error
+ * @typedef typedef struct msg_error_s msg_error_t;
+ * Type for erroneous headers.
+ */
+
+isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset);
+char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
+			  char *b, isize_t xtra);
+
+msg_hclass_t msg_error_class[] =
+MSG_HEADER_CLASS(msg_, error, "", "", er_common, append,
+                 msg_error, msg_generic);
+
+issize_t msg_error_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return 0;
+}
+
+issize_t msg_error_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  /* There is no way to encode an erroneous header */
+  return 0;
+}
+
+isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  return msg_default_dup_xtra(h, offset);
+}
+
+char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  return msg_default_dup_one(dst, src, b, xtra);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_headers
+ * @defgroup msg_unknown Unknown Headers
+ *
+ * The unknown headers are handled with #msg_unknown_t structure. The whole
+ * unknown header including its name is included in the header value string
+ * @a g_value.
+ * 
+ * @note It is possible to speed up parsing process by creating a parser
+ * which does understand only a minimum number of headers. If such a parser
+ * is used, some well-known headers are not regocnized or parser, but they
+ * are treated as unknown and put unparsed into the list of unknown headers.
+ */
+
+/**@ingroup msg_unknown
+ * @typedef typedef struct msg_unknown_s msg_unknown_t;
+ *
+ * Type for unknown headers.
+ */
+
+msg_hclass_t msg_unknown_class[] =
+MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append,
+                 msg_unknown, msg_generic);
+
+issize_t msg_unknown_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_unknown_t *un = (msg_unknown_t *)h;
+
+  if (msg_token_d(&s, &un->un_name) < 0 ||
+      *s != ':')
+    return -1;
+
+  *s++ = '\0';
+  skip_lws(&s);
+  un->un_value = s;
+					   
+  return 0;
+}
+
+issize_t msg_unknown_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  msg_unknown_t *un = (msg_unknown_t *)h;
+  int const compact = MSG_IS_COMPACT(flags);
+
+  MSG_STRING_E(b, end, un->un_name);
+  MSG_CHAR_E(b, end, ':');
+  if (!compact) MSG_CHAR_E(b, end, ' ');
+  MSG_STRING_E(b, end, un->un_value);
+  
+  return b - b0;
+}
+
+isize_t msg_unknown_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_unknown_t const *un = (msg_unknown_t *)h;
+  return offset + MSG_STRING_SIZE(un->un_name) + MSG_STRING_SIZE(un->un_value);
+}
+
+char *msg_unknown_dup_one(msg_header_t *dst, msg_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  msg_unknown_t *un = (msg_unknown_t *)dst;
+  msg_unknown_t const *o = (msg_unknown_t *)src;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, un->un_name, o->un_name);
+  MSG_STRING_DUP(b, un->un_value, o->un_value);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_headers
+ * @defgroup msg_payload Message Body
+ *
+ * The payload object contains the message body. The message body has no
+ * structure, but it is stored in the @a pl_data buffer as a byte array. 
+ * Multiple payload objects may be linked to a list.
+ */
+
+/**@ingroup msg_payload
+ * @typedef typedef struct msg_payload_s msg_payload_t;
+ *
+ * The structure msg_payload_t contains representation of MIME message payload.
+ *
+ * The msg_payload_t is defined as follows:
+ * @code
+ * typedef struct msg_payload_s {
+ *   msg_common_t    pl_common[1];      // Common fragment info
+ *   msg_header_t   *pl_next;           // Next payload object 
+ *   char           *pl_data;           // Data - may contain zero bytes
+ *   usize_t         pl_len;            // Length of message payload
+ * } msg_payload_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_payload_class[1] =
+MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append,
+		 msg_payload, msg_generic);
+
+/** Create a MIME payload */
+msg_payload_t *msg_payload_create(su_home_t *home, void const *data, usize_t len)
+{
+  msg_header_t *h = msg_header_alloc(home, msg_payload_class, len + 1);
+  msg_payload_t *pl = h->sh_payload;
+
+  if (pl) {
+    char *b = msg_header_data(h->sh_common);
+    if (data)
+      memcpy(b, data, len);
+    else
+      memset(b, 0, len);
+    b[len] = 0;
+
+    h->sh_data = pl->pl_data = b;
+    h->sh_len = pl->pl_len = len;
+
+    return pl;
+  }
+  return NULL;
+}
+
+/** Parse payload. */
+issize_t msg_payload_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  h->sh_payload->pl_len = slen;
+  h->sh_payload->pl_data = s;
+
+  h->sh_len = slen;
+  h->sh_data = s;
+
+  return 0;
+}
+
+issize_t msg_payload_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  size_t len = h->sh_payload->pl_len;
+
+  if (bsiz > 0) {
+    memcpy(b, h->sh_payload->pl_data, bsiz > len ? len : bsiz);
+    b[bsiz > len ? len : bsiz - 1] = '\0';
+  }
+
+  return len;
+}
+
+isize_t msg_payload_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  return offset + h->sh_payload->pl_len + 1;
+}
+
+char *msg_payload_dup_one(msg_header_t *dst,
+			  msg_header_t const *src,
+			  char *b, 
+			  isize_t xtra)
+{
+  msg_payload_t *pl = dst->sh_payload;
+  msg_payload_t const *o = src->sh_payload;
+
+  memcpy(pl->pl_data = b, o->pl_data, pl->pl_len = o->pl_len);
+
+  pl->pl_common->h_data = pl->pl_data;
+  pl->pl_common->h_len = pl->pl_len;
+
+  pl->pl_data[pl->pl_len] = 0;	/* NUL terminate just in case */
+
+  return b + pl->pl_len + 1;
+}
+
+usize_t msg_payload_length(msg_payload_t const *pl)
+{
+  /* XXX */
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_headers
+ * @defgroup msg_separator Message Separator 
+ *
+ * An empty line separates headers from the message body. In order to avoid
+ * modifying messages with integrity protection, the separator line has its
+ * own header structure which is included in the msg_t structure.
+ */
+
+/**@ingroup msg_separator
+ * @typedef typedef struct msg_separator_s msg_separator_t;
+ *
+ * The structure msg_separator_t contains representation of separator line
+ * between message headers and body.
+ *
+ * The msg_separator_t is defined as follows:
+ * @code
+ * typedef struct msg_separator_s {
+ *   msg_common_t    sep_common[1];     // Common fragment info
+ *   msg_header_t   *sep_next;          // Pointer to next header
+ *   char            sep_data[4];       // NUL-terminated separator
+ * } msg_separator_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_separator_class[] =
+MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single,
+		 msg_default, msg_generic);
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(s) ((s[0]) == '\r' ? ((s[1]) == '\n') + 1 : (s[0])=='\n')
+
+/** Parse a separator line. */
+issize_t msg_separator_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  int len = CRLF_TEST(s);
+
+  if (len == 0 && slen > 0)
+    return -1;
+  
+  memcpy(h->sh_separator->sep_data, s, len);
+  h->sh_separator->sep_data[len] = '\0';
+
+  return 0;
+}
+
+/** Encode a separator line. */
+issize_t msg_separator_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  size_t n = strlen(h->sh_separator->sep_data);
+
+  if (bsiz > n)
+    strcpy(b, h->sh_separator->sep_data);
+
+  return (issize_t)n;
+}
+
+msg_separator_t *msg_separator_create(su_home_t *home)
+{
+  msg_separator_t *sep = 
+    msg_header_alloc(home, msg_separator_class, 0)->sh_separator;
+
+  if (sep)
+    strcpy(sep->sep_data, CRLF);
+
+  return sep;
+}
+
+/* ====================================================================== */
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_date.c
+ * @brief Parser for HTTP-Date and HTTP-Delta.
+ *
+ * Parsing functions for @RFC1123 (GMT) date.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Apr 11 18:57:06 2001 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sofia-sip/msg_date.h>
+#include <sofia-sip/bnf.h>
+
+#include <sofia-sip/su_time.h>
+
+/** Return current time as seconds since Mon, 01 Jan 1900 00:00:00 GMT. */
+msg_time_t msg_now(void)
+{
+  return su_now().tv_sec;
+}
+
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+
+/**Epoch year. @internal
+ *
+ * First day of the epoch year should be Monday.
+ */
+#define EPOCH 1900		
+/** Is this year a leap year? @internal */
+#define LEAP_YEAR(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
+/** Day number of New Year Day of given year. @internal */
+#define YEAR_DAYS(y) \
+  (((y)-1) * 365 + ((y)-1) / 4 - ((y)-1) / 100 + ((y)-1) / 400)
+
+
+/* ====================================================================== */
+
+static unsigned char const days_per_months[12] = 
+  {
+    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+  };
+
+/** Offset of first day of the month with formula day = 30 * month + offset. */
+static signed char const first_day_offset[12] = 
+  {
+    0, 1, -1, 0, 0, 1, 1, 2, 3, 3, 4, 4
+  };
+
+static char const wkdays[7 * 4] = 
+  "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" "Sun";
+
+static char const months[12 * 4] = 
+  "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" 
+  "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec";
+
+/** Parse a month name. 
+ *
+ * @return The function month_d() returns 0..11 if given first three letters
+ * of month name, or -1 if no month name matches.
+ */
+static inline
+int month_d(char const *s)
+{
+  unsigned const uc = ('a' - 'A') << 16 | ('a' - 'A') << 8 | ('a' - 'A');
+  unsigned m;
+
+  if (!s[0] || !s[1] || !s[2])
+    return -1;
+
+  #define MONTH_V(s) (uc | (((s[0]) << 16) + ((s[1]) << 8) + ((s[2]))))
+  m = MONTH_V(s);
+
+  #define MONTH_D(n) \
+  if (m == (uc | (months[4*(n)]<<16)|(months[4*(n)+1]<<8)|(months[4*(n)+2])))\
+    return (n)
+
+  MONTH_D(0);
+  MONTH_D(1);
+  MONTH_D(2);
+  MONTH_D(3);
+  MONTH_D(4);
+  MONTH_D(5);
+  MONTH_D(6);
+  MONTH_D(7);
+  MONTH_D(8);
+  MONTH_D(9);
+  MONTH_D(10);
+  MONTH_D(11);
+
+  return -1;
+}
+
+/* Parse SP 2DIGIT ":" 2DIGIT ":" 2DIGIT SP */
+static inline
+int time_d(char const **ss, 
+	   unsigned long *hour, unsigned long *min, unsigned long *sec)
+{
+  char const *s = *ss;
+  if (!IS_LWS(*s)) 
+    return -1; 
+  skip_lws(&s);
+  if (!is_digit(*s)) return -1;
+  *hour = *s++ - '0'; if (is_digit(*s)) *hour = 10 * (*hour) + *s++ - '0';
+  if (*s++ != ':' || !is_digit(s[0]) || !is_digit(s[1])) 
+    return -1;
+  *min = 10 * s[0] + s[1] - 11 * '0'; s += 2;
+  if (*s++ != ':' || !is_digit(s[0]) || !is_digit(s[1])) 
+    return -1;
+  *sec = 10 * s[0] + s[1] - 11 * '0'; s += 2;
+  if (*s) {
+    if (!IS_LWS(*s)) return -1; skip_lws(&s);
+  }
+  *ss = s;
+  return 0;
+}
+
+/**Decode RFC1123-date, RFC822-date or asctime-date.
+ * 
+ * The function msg_date_d() decodes <HTTP-date>, which may have 
+ * different formats.
+ * 
+ * @code
+ * HTTP-date    = rfc1123-date / rfc850-date / asctime-date
+ *
+ * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ * date1        = 2DIGIT SP month SP 4DIGIT
+ *                ; day month year (e.g., 02 Jun 1982)
+ *
+ * rfc850-date  = weekday "," SP date2 SP time SP "GMT"
+ * date2        = 2DIGIT "-" month "-" 2DIGIT
+ *                ; day-month-year (e.g., 02-Jun-82)
+ *
+ * asctime-date = wkday SP date3 SP time SP 4DIGIT
+ * date3        = month SP ( 2DIGIT / ( SP 1DIGIT ))
+ *                ; month day (e.g., Jun  2)
+ *
+ * time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                ; 00:00:00 - 23:59:59
+ *
+ * wkday        = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
+ * weekday      = "Monday" / "Tuesday" / "Wednesday"
+ *              / "Thursday" / "Friday" / "Saturday" / "Sunday"
+ * month        = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" 
+ *              / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+ * @endcode
+ */
+issize_t msg_date_d(char const **ss, msg_time_t *date)
+{
+  char const *s = *ss;
+  char const *wkday;
+  char const *tz;
+  unsigned long day, year, hour, min, sec;
+  int mon;
+
+  if (!IS_TOKEN(*s) || !date)
+    return -1;
+
+  wkday = s; skip_token(&s); if (*s == ',') s++; 
+  while (IS_LWS(*s)) s++;
+
+  if (is_digit(*s)) {
+    day = *s++ - '0'; if (is_digit(*s)) day = 10 * day + *s++ - '0';
+    
+    if (*s == ' ') {
+      /* rfc1123-date = 
+	 wkday "," SP 2DIGIT SP month SP 4DIGIT SP time SP "GMT"
+       */
+      mon = month_d(++s); skip_token(&s);
+      if (mon < 0 || !IS_LWS(*s)) return -1;
+      s++;
+      if (!is_digit(s[0]) || !is_digit(s[1]) || 
+	  !is_digit(s[2]) || !is_digit(s[3]))
+	return -1;
+      year = 1000 * s[0] + 100 * s[1] + 10 * s[2] + s[3] - 1111 * '0'; s += 4;
+    }
+    else if (*s == '-') {
+      /* rfc822-date = 
+	 weekday "," SP 2DIGIT "-" month "-" 2DIGIT SP time SP "GMT"
+       */
+
+      mon = month_d(++s);
+      if (mon < 0 || s[3] != '-' ||
+	  !is_digit(s[4]) || !is_digit(s[5]))
+	return -1;
+      year = 10 * s[4] + s[5] - 11 * '0'; 
+      if (is_digit(s[6]) && is_digit(s[7])) {
+	/* rfc2822-date = 
+	   weekday "," SP 2DIGIT "-" month "-" 4DIGIT SP time SP "GMT"
+	*/
+	year = year * 100 + 10 * s[6] + s[7] - 11 * '0';
+	s += 8;
+      }
+      else {
+	if (year >= 70)
+	  year = 1900 + year;
+	else
+	  year = 2000 + year;
+	s += 6;
+      }
+    }
+    else
+      return -1;
+
+    if (time_d(&s, &hour, &min, &sec) < 0) return -1;
+    if (*s) {
+      tz = s; skip_token(&s); skip_lws(&s);
+      if (strncasecmp(tz, "GMT", 3) && strncasecmp(tz, "UCT", 3))
+	return -1;
+    }
+  }
+  else {
+    /* actime-date = 
+       wkday SP month SP ( 2DIGIT | ( SP 1DIGIT )) SP time SP 4DIGIT */
+    mon = month_d(s); skip_token(&s);
+    if (mon < 0 || !IS_LWS(*s)) return -1; s++;
+    while (IS_LWS(*s)) s++; 
+    if (!is_digit(*s)) return -1;
+    day = *s++ - '0'; if (is_digit(*s)) day = 10 * day + *s++ - '0';
+    if (time_d(&s, &hour, &min, &sec) < 0) return -1;
+    /* Accept also unix date (if it is GMT) */ 
+    if ((s[0] == 'G' && s[1] == 'M' && s[2] == 'T' && s[3] == ' ') ||
+	(s[0] == 'U' && s[1] == 'T' && s[2] == 'C' && s[3] == ' '))
+      s += 4;
+    else if (s[0] == 'U' && s[1] == 'T' && s[2] == ' ')
+      s += 3;
+    if (!is_digit(s[0]) || !is_digit(s[1]) || 
+	!is_digit(s[2]) || !is_digit(s[3]))
+      return -1;
+    year = 1000 * s[0] + 100 * s[1] + 10 * s[2] + s[3] - 1111 * '0'; s += 4;
+  }
+  
+  if (hour > 24 || min >= 60 || sec >= 60 ||
+      (hour == 24 && min > 0 && sec > 0))
+    return -1;
+
+  if (day == 0 || day > days_per_months[mon]) {
+    if (day != 29 || mon != 1 || !LEAP_YEAR(year))
+      return -1;
+  }
+  
+  if (year < EPOCH) {
+    *date = 0;
+  }
+  else if (year > EPOCH + 135) {
+    *date = 0xfdeefb80;	/* XXX: EPOCH + 135 years */
+  }
+  else {
+    int leap_year = LEAP_YEAR(year);
+    msg_time_t ydays = YEAR_DAYS(year) - YEAR_DAYS(EPOCH);
+    
+#if 0
+    printf("Year %d%s starts %ld = %d - %d days since epoch (%d)\n", 
+	       year, leap_year ? " (leap year)" : "", 
+	   ydays, YEAR_DAYS(year), YEAR_DAYS(EPOCH), EPOCH);
+#endif
+    
+    *date = sec + 60 * 
+      (min + 60 * 
+	   (hour + 24 * 
+	    (day - 1 + mon * 30 + first_day_offset[mon] + 
+	     (leap_year && mon > 2) + ydays)));
+  }
+  *ss = s;
+
+  return 0;
+}
+
+
+/**Encode RFC1123-date.
+ * 
+ * The function msg_date_e() prints @e http-date in the <rfc1123-date>
+ * format. The format is as follows:
+ * 
+ * @code
+ * rfc1123-date = wkday "," SP date SP time SP "GMT"
+ * wkday        = "Mon" | "Tue" | "Wed"
+ *              | "Thu" | "Fri" | "Sat" | "Sun"
+ * date         = 2DIGIT SP month SP 4DIGIT
+ *                ; day month year (e.g., 02 Jun 1982)
+ * month        = "Jan" | "Feb" | "Mar" | "Apr"
+ *              | "May" | "Jun" | "Jul" | "Aug"
+ *              | "Sep" | "Oct" | "Nov" | "Dec"
+ * time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                ; 00:00:00 - 23:59:59
+ * @endcode
+ * 
+ * @param b         buffer to print the date
+ * @param bsiz      size of the buffer
+ * @param http_date seconds since 01 Jan 1900.
+ * 
+ * @return The function msg_date_e() returns the size of the formatted date.
+ */
+issize_t msg_date_e(char b[], isize_t bsiz, msg_time_t http_date)
+{
+  msg_time_t sec, min, hour, wkday, day, month, year;
+  msg_time_t days_per_month, leap_year;
+
+  sec  = http_date % 60; http_date /= 60;
+  min  = http_date % 60; http_date /= 60;
+  hour = http_date % 24; http_date /= 24;
+
+  wkday = http_date % 7;
+  day = http_date + YEAR_DAYS(EPOCH);
+  year = EPOCH + http_date / 365;
+
+  for (;;) {
+    if (day >= YEAR_DAYS(year + 1))
+      year++;
+    else if (day < YEAR_DAYS(year))
+      year--;
+    else
+      break;
+  }
+
+  day -= YEAR_DAYS(year);
+  leap_year = LEAP_YEAR(year);
+
+  month = 0, days_per_month = 31; 
+  while (day >= days_per_month) {
+    day -= days_per_month;
+    month++;
+    days_per_month = days_per_months[month] + (leap_year && month == 2);
+  }
+
+  return snprintf(b, bsiz, "%s, %02ld %s %04ld %02ld:%02ld:%02ld GMT",
+		  wkdays + wkday * 4, day + 1, months + month * 4, 
+		  year, hour, min, sec);
+}
+
+
+/**Decode a delta-seconds.
+ * 
+ * The function msg_delta_d() decodes a <delta-seconds> field.
+ *
+ * The <delta-seconds> is defined as follows:
+ * @code
+ * delta-seconds  = 1*DIGIT
+ * @endcode
+ *
+ * Note, however, that <delta-seconds> may not be larger than #MSG_TIME_MAX.
+ */
+issize_t msg_delta_d(char const **ss, msg_time_t *delta)
+{
+  char const *s = *ss;
+
+  if (!is_digit(*s))
+    return -1;
+
+  *delta = strtoul(*ss, (char **)ss, 10);
+  skip_lws(ss);
+
+  return *ss - s;
+}
+
+/**Encode @ref msg_delta_d() "<delta-seconds>" field.
+ */
+issize_t msg_delta_e(char b[], isize_t bsiz, msg_time_t delta)
+{
+  return snprintf(b, bsiz, "%lu", (unsigned long)delta);
+}
+
+/** Decode a HTTP date or delta 
+ * 
+ * Decode a @ref msg_date_d() "<http-date>" or 
+ * @ref msg_delta_d() "<delta-seconds>" field.
+ */
+issize_t msg_date_delta_d(char const **ss,
+			  msg_time_t *date,
+			  msg_time_t *delta)
+{
+  if (delta && is_digit(**ss)) {
+    return msg_delta_d(ss, delta);
+  }
+  else if (date && IS_TOKEN(**ss)) {
+    return msg_date_d(ss, date);
+  }
+  return -1;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @file msg_generic.c
+ * @brief Functions for generic headers
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jan 23 20:08:00 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/msg.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_header.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+
+/**
+ * Parse a generic header.
+ *
+ * The function msg_generic_d() parses a generic header structure.
+ *
+ * @param[in]     home memory home 
+ * @param[in,out] h    header structure 
+ * @param[in]     s    string to be parsed 
+ * @param[in]     slen length of the string 
+ *
+ * @retval 0 when successful, 
+ * @retval -1 upon an error.
+ */
+issize_t msg_generic_d(su_home_t *home,
+		       msg_header_t *h,
+		       char *s, 
+		       isize_t slen)
+{
+  h->sh_generic->g_string = s;
+  return 0;
+}
+
+/**
+ * Encode a generic header.
+ *
+ * The function @c msg_generic_e encodes a generic header.
+ *
+ */
+issize_t msg_generic_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  msg_generic_t const *g = h->sh_generic;  
+  size_t n = strlen(g->g_string);
+  
+  if (bsiz > n)
+    strcpy(b, g->g_string);
+
+  return (issize_t)n;
+}
+
+/** Calculate the size of strings associated with a @c msg_generic_t object. */
+isize_t msg_generic_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_generic_t const *g = h->sh_generic;
+  return offset + MSG_STRING_SIZE(g->g_string);
+}
+
+/** Duplicate one @c msg_generic_t object. */
+char *msg_generic_dup_one(msg_header_t *dst,
+			  msg_header_t const *src,
+			  char *b,
+			  isize_t xtra)
+{
+  char *end = b + xtra;
+  MSG_STRING_DUP(b, dst->sh_generic->g_string, src->sh_generic->g_string);
+  assert(b <= end); (void)end;
+  return b;
+}
+
+issize_t msg_numeric_d(su_home_t *home,
+		      msg_header_t *h,
+		      char *s,
+		      isize_t slen)
+{
+  uint32_t value = 0;
+  issize_t retval = msg_uint32_d(&s, &value);
+
+  h->sh_numeric->x_value = value;
+
+  if (*s)
+    return -1;
+
+  return retval;
+}
+
+issize_t msg_numeric_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  uint32_t value = h->sh_numeric->x_value;
+
+  if (h->sh_numeric->x_value > 0xffffffff)
+    return -1;
+
+  return snprintf(b, bsiz, "%lu", (unsigned long)value);
+}
+
+/* ====================================================================== */
+/* Comma-separated list */
+
+/** @typedef struct msg_list_s msg_list_t; 
+ *
+ * Type for token list headers.
+ *
+ */
+
+issize_t msg_list_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return msg_commalist_d(home, &s, &h->sh_list->k_items, NULL);
+}
+
+issize_t msg_list_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  int compact = MSG_IS_COMPACT(flags);
+  char *b0 = b, *end = b + bsiz;
+  
+  MSG_COMMALIST_E(b, end, h->sh_list->k_items, compact);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/**@internal 
+ * Extra size of a msg_auth_t object.
+ *
+ * This function calculates extra size required by a msg_auth_t object.
+ *
+ * @param a pointer to a msg_auth_t object
+ *
+ * @return
+ *   Size of strings related to msg_auth_t object.
+ */
+isize_t msg_list_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  MSG_PARAMS_SIZE(offset, h->sh_list->k_items);
+  return offset;
+}
+
+char *msg_list_dup_one(msg_header_t *dst,
+		       msg_header_t const *src,
+		       char *b, 
+		       isize_t xtra)
+{
+  char *end = b + xtra;
+  msg_param_t const ** items = (msg_param_t const **)&dst->sh_list->k_items;
+
+  b = msg_params_dup(items, src->sh_list->k_items, b, xtra);
+    
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Append a list of constant items to a list.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int msg_list_append_items(su_home_t *home, 
+			  msg_list_t *k, 
+			  msg_param_t const items[])
+{
+  size_t i;
+
+  if (k == NULL) return -1;
+  if (items == NULL) return 0;
+
+  for (i = 0; items[i]; i++) {
+    if (msg_header_add_param(home, (msg_common_t *)k, items[i]) < 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Replace a list of constant items.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int msg_list_replace_items(su_home_t *home,
+			   msg_list_t *k,
+			   msg_param_t const items[])
+{
+  size_t i;
+
+  if (k == NULL) return -1;
+  if (items == NULL) return 0;
+
+  for (i = 0; items[i]; i++) {
+    if (msg_header_replace_item(home, (msg_common_t *)k, items[i]) < 0)
+      return -1;
+  }
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,534 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_headers
+ * @CFILE msg_header_copy.c 
+ * 
+ * Copying and duplicating headers structures.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <sofia-sip/su_alloc.h>
+
+#include <sofia-sip/su.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_header.h"
+
+/** Calculate size of a parameter vector */
+static inline
+size_t msg_params_copy_xtra(msg_param_t const pp[], size_t offset)
+{
+  size_t n = msg_params_count(pp);
+  if (n) {
+    MSG_STRUCT_SIZE_ALIGN(offset);
+    offset += MSG_PARAMS_NUM(n + 1) * sizeof(pp[0]);
+  }
+  return offset;
+}
+
+/** Copy a vector of parameters */
+static inline
+char *msg_params_copy(char *b, size_t size,
+		      msg_param_t **dst, 
+		      msg_param_t const src[])
+{
+  size_t n = msg_params_count(src);
+
+  if (n) {
+    MSG_STRUCT_ALIGN(b);
+    *dst = memcpy(b, src, (n + 1) * sizeof(src[0]));
+    b += MSG_PARAMS_NUM(n + 1) * sizeof(src[0]);
+  }
+  else {
+    *dst = NULL;
+  }
+
+  return b;
+}
+
+/**Copy a header object.
+ *
+ * The function @c msg_header_copy_as() shallowly copies a header object.
+ *
+ * @param home pointer to the memory home
+ * @param hc   header class for the copied header
+ * @param src  pointer to a header object
+ *
+ * @return 
+ * The function @c msg_header_copy_as() returns a pointer to the the shallow copy
+ * of the header object, or @c NULL upon an error.
+ */
+static msg_header_t *msg_header_copy_one_as(su_home_t *home, 
+					    msg_hclass_t *hc,
+					    msg_header_t const *src)
+{
+  msg_header_t *h;
+  size_t size = hc->hc_size, xtra;
+  msg_param_t const *params;
+  char *end;
+
+  if (hc->hc_params) {
+    params = *(msg_param_t const **)((char const *)src + hc->hc_params);
+    xtra = msg_params_copy_xtra(params, size) - size;
+  }
+  else {
+    params = NULL;
+    xtra = 0;
+  }
+
+  if (!(h = msg_header_alloc(home, hc, (isize_t)xtra)))
+    return NULL;			/* error */
+
+  memcpy(&h->sh_data, &src->sh_data, size - offsetof(msg_common_t, h_data));
+  h->sh_next = NULL;
+  if (params) {
+    msg_param_t **pparams = (msg_param_t **)((char *)h + hc->hc_params);
+    end = msg_params_copy((char *)h + size, xtra, pparams, params);
+    if (!end) {
+      su_free(home, h);
+      return NULL;
+    }
+  }
+  else
+    end = (char *)h + size;
+
+  assert(end == (char *)h + xtra + size);
+
+  return h;
+}
+
+/**Copy a list of header objects.
+ *
+ * The function @c msg_header_copy_as() shallowly copies a list of header
+ * objects, and casts them to the given header class.
+ *
+ * @param home pointer to the memory home
+ * @param hc   header class
+ * @param src  pointer to a list of header objects to be copied
+ *
+ * @return The function @c msg_header_copy_as() returns a pointer to the
+ * first of the copied msg header object(s), or @c NULL upon an error.
+ */
+msg_header_t *msg_header_copy_as(su_home_t *home, 
+				 msg_hclass_t *hc,
+				 msg_header_t const *src)
+{
+  msg_header_t *h, *rv = NULL, *prev = NULL;
+
+  if (src == NULL || src == MSG_HEADER_NONE)
+    return NULL;
+
+  if (hc == NULL)
+    hc = src->sh_class;
+
+  for (; src; src = src->sh_next, prev = h) {
+    if (!(h = msg_header_copy_one_as(home, hc, src)))
+      break;
+
+    if (!rv) 
+      rv = h;
+    else
+      prev->sh_next = h;
+  }
+
+  if (src) {
+    /* Copy was not successful, free all copied headers in list */
+    for (;rv; rv = h) {
+      h = rv->sh_next;
+      su_free(home, rv);
+    }
+  }
+
+  return rv;
+}
+
+/** Copy a single header. */
+msg_header_t *msg_header_copy_one(su_home_t *home, msg_header_t const *src)
+{
+  assert(MSG_HEADER_TEST(src));
+
+  if (!src || !src->sh_class)
+    return NULL;
+
+  return msg_header_copy_one_as(home, src->sh_class, src);
+}
+
+/** Copy a header list. */
+msg_header_t *msg_header_copy(su_home_t *home, msg_header_t const *src)
+{
+  assert(MSG_HEADER_TEST(src));
+
+  if (!src || !src->sh_class)
+    return NULL;
+
+  return msg_header_copy_as(home, src->sh_class, src);
+}
+
+/** Duplicate a sigle header.
+ *
+ * Deeply copy a single header.
+ *
+ * @param home pointer to the memory home
+ * @param src  pointer to asingle header object to be copied
+ *
+ * @return Return a pointer to the
+ * the duplicated msg header object(s), or @c NULL upon an error.
+ */
+msg_header_t *msg_header_dup_one(su_home_t *home, 
+				 msg_header_t const *src)
+{
+  msg_hclass_t *hc;
+  size_t size, xtra;
+  msg_header_t *h;
+  char *end;
+
+  if (src == NULL || src == MSG_HEADER_NONE)
+    return NULL;
+
+  hc = src->sh_class;
+
+  assert(hc);
+
+  size = hc->hc_size;
+  xtra = hc->hc_dxtra(src, size) - size;
+
+  if (!(h = msg_header_alloc(home, hc, xtra)))
+    return NULL;
+
+  if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra))) {
+    su_free(home, h);
+    return NULL;
+  }
+
+  if (hc->hc_update)
+    msg_header_update_params(h->sh_common, 1);
+
+  assert(end == (char *)h + size + xtra);
+
+  return h;
+}
+
+/** Duplicate a header as class @a hc.
+ *
+ * The function @c msg_header_dup_as() casts a list of header headers to
+ * given type, and then deeply copies the list.
+ *
+ * @param home pointer to the memory home
+ * @param hc   header class
+ * @param src  pointer to a list of header objects to be copied
+ *
+ * @return The function @c msg_header_copy_as() returns a pointer to the
+ * first of the copied msg header object(s), or @c NULL upon an error.
+ */
+msg_header_t *msg_header_dup_as(su_home_t *home, msg_hclass_t *hc,
+				msg_header_t const *src)
+{
+  msg_header_t *h, *rv = NULL, **prev;
+
+  if (src == NULL || src == MSG_HEADER_NONE)
+    return NULL;
+
+  if (hc == NULL)
+    hc = src->sh_class;
+
+  assert(hc);
+
+  for (prev = &rv; src; src = src->sh_next, prev = &h->sh_next) {
+    size_t size = hc->hc_size;
+    size_t xtra = hc->hc_dxtra(src, size) - size;
+    char *end;
+
+    if (!(h = msg_header_alloc(home, hc, (isize_t)xtra)))
+      break;			/* error */
+
+    if (!rv) 
+      rv = h;
+
+    if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
+      break;			/* error */
+
+    if (hc->hc_update)
+      msg_header_update_params(h->sh_common, 1);
+
+    assert(end == (char *)h + size + xtra);
+
+    *prev = h;
+  }
+
+  if (src) {
+    /* Copy was not successful, free all duplicated headers in list */
+    for (;rv; rv = h) {
+      h = rv->sh_next;
+      su_free(home, rv);
+    }
+  }
+
+  return rv;
+}
+
+/** Duplicate a header list.
+ *
+ * The function @c msg_header_dup() deeply copies a list of message headers
+ * objects.
+ *
+ * @param home pointer to the memory home
+ * @param h    pointer to a list of header objects to be copied
+ *
+ * @return The function @c msg_header_dup() returns a pointer to the first
+ * of the copied message header object(s), or @c NULL upon an error.
+ */
+msg_header_t *msg_header_dup(su_home_t *home, msg_header_t const *h)
+{
+  if (h == NULL || h == MSG_HEADER_NONE)
+    return NULL;
+  assert(MSG_HEADER_TEST(h));
+  return msg_header_dup_as(home, h->sh_class, h);
+}
+
+/** Calculate extra size of a plain header. */
+isize_t msg_default_dup_xtra(msg_header_t const *header, isize_t offset)
+{
+  return offset;
+}
+
+/**Duplicate a header object without external references.
+ *
+ * The function @c msg_default_dup_one() copies the contents of header
+ * object @a src to @a h. The header object should not contain external
+ * references (pointers).
+ *
+ * @param h     pointer to newly allocated header object
+ * @param src   pointer to a header object to be duplicated
+ * @param b     memory buffer used to copy (not used)
+ * @param xtra  number bytes in buffer @a b (not used)
+ *
+ * @return The function @c msg_default_dup_one() returns a pointer to the
+ * memory buffer @a b.
+ */
+char *msg_default_dup_one(msg_header_t *h,
+			  msg_header_t const *src,
+			  char *b, 
+			  isize_t xtra)
+{
+  memcpy(&h->sh_header_next[1],
+	 &src->sh_header_next[1],
+	 h->sh_class->hc_size - offsetof(msg_header_t, sh_header_next[1]));
+
+  return b;
+}
+
+/* ====================================================================== */
+/* Copying or duplicating all headers in a message */
+
+static int msg_copy_chain(msg_t *msg, msg_t const *copied);
+static int msg_dup_or_copy_all(msg_t *msg, 
+			       msg_t const *original,
+			       msg_header_t *(*copy_one)(su_home_t *h, 
+							 msg_header_t const *));
+
+
+/**Copy a message shallowly.
+ *
+ * @relatesalso msg_s
+ *
+ * Copy a message and the header structures. The copied message will share
+ * all the strings with the original message. It will keep a reference to
+ * the original message, and the original message is not destroyed until all
+ * the copies have been destroyed.
+ *
+ * @param original message to be copied
+ *
+ * @retval pointer to newly copied message object when successful
+ * @retval NULL upon an error
+ */
+msg_t *msg_copy(msg_t *original)
+{
+  if (original) {
+    msg_t *copy = msg_create(original->m_class, original->m_object->msg_flags);
+
+    if (copy) {
+      if (original->m_chain 
+	  ? msg_copy_chain(copy, original) < 0 
+	  : msg_dup_or_copy_all(copy, original, msg_header_copy_one) < 0) {
+	msg_destroy(copy), copy = NULL;
+      }
+      else
+	msg_set_parent(copy, original);
+
+      return copy;
+    }
+  }
+
+  return NULL;
+}
+
+/** Copy header chain.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+static
+int msg_copy_chain(msg_t *msg, msg_t const *original)
+{
+  su_home_t *home = msg_home(msg);
+  msg_pub_t *dst = msg->m_object;
+  msg_header_t **tail;
+  msg_header_t *dh;
+  msg_header_t const *sh;
+  msg_header_t **hh;
+  
+  tail = msg->m_tail;
+  
+  for (sh = original->m_chain; sh; sh = (msg_header_t const *)sh->sh_succ) {
+    hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
+    if (!hh)
+      break;
+    while (*hh)
+      hh = &(*hh)->sh_next;
+      
+    dh = msg_header_copy_one(home, sh);
+    if (!dh) 
+      break;
+
+    dh->sh_prev = tail, *tail = dh, tail = &dh->sh_succ;
+
+    *hh = dh;
+  }
+
+  msg->m_tail = tail;
+
+  if (sh)
+    return -1;
+
+  return 0;
+
+}
+
+/**Deep copy a message.
+ *
+ * @relatesalso msg_s
+ *
+ * Copy a message, the header structures and all the related strings. The
+ * duplicated message does not share any (non-const) data with original.
+ * Note that the cached representation (in h_data) is not copied.
+ *
+ * @param original message to be duplicated
+ *
+ * @retval pointer to newly duplicated message object when successful
+ * @retval NULL upon an error
+ */
+msg_t *msg_dup(msg_t const *original)
+{
+  if (original) {
+    msg_t *dup = msg_create(original->m_class, original->m_object->msg_flags);
+
+    if (dup && msg_dup_or_copy_all(dup, original, msg_header_dup_one) < 0) {
+      msg_destroy(dup), dup = NULL;
+    }
+
+    return dup;
+  }
+
+  return NULL;
+}
+
+/** Copy a complete message, not keeping the header chain structure. 
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+static
+int msg_dup_or_copy_all(msg_t *msg, 
+			msg_t const *original,
+			msg_header_t *(*copy_one)(su_home_t *h, 
+						  msg_header_t const *))
+{
+  su_home_t *home = msg_home(msg);
+  msg_pub_t *dst = msg->m_object;
+
+  msg_pub_t const *src = original->m_object;
+  msg_header_t * const *ssh;
+  msg_header_t * const *end;
+  msg_header_t const *sh;
+  msg_header_t **hh;
+
+  msg_header_t *h;
+
+  assert(copy_one);
+
+  end = (msg_header_t**)((char *)src + src->msg_size);
+  
+  for (ssh = &src->msg_request; ssh < end; ssh++) {
+    sh = *ssh;
+    if (!sh)
+      continue;
+
+    hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
+    if (hh == NULL)
+	return -1;
+
+    for (; sh; sh = sh->sh_next) {
+      h = copy_one(home, sh);
+      if (h == NULL)
+	return -1;
+
+      if (*hh) {
+	/* If there is multiple instances of single headers,
+	   put the extra headers into the list of erroneous headers */
+	if (msg_is_single(h)) {
+	  msg_error_t **e;
+	  for (e = &dst->msg_error; *e; e = &(*e)->er_next)
+	    ;
+	  *e = (msg_error_t *)h;
+	  continue;
+	}
+
+	while (*hh)
+	  hh = &(*hh)->sh_next;
+      }
+      *hh = h;
+
+      if (msg_is_list(sh))
+	/* Copy only first list entry */
+	break;
+    }
+  }
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_headers
+ * @CFILE msg_header_make.c
+ *
+ * Creating message headers from strings.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 14:06:34 2001 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/msg.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_header.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+
+#if defined(va_copy)
+/* Xyzzy */
+#elif defined(__va_copy)
+#define va_copy(dst, src) __va_copy((dst), (src))
+#else
+#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
+#endif
+
+#include <assert.h>
+
+/** Make a header from a value string. */
+msg_header_t *msg_header_make(su_home_t *home, 
+			      msg_hclass_t *hc,
+			      char const *s)
+{
+  size_t xtra;
+  msg_header_t *h;
+  int normal = hc->hc_name ||
+    (hc->hc_hash != msg_payload_hash && 
+     hc->hc_hash != msg_separator_hash &&
+     hc->hc_hash != msg_error_hash);
+
+  if (s == NULL)
+    return NULL;
+
+  /* For normal headers, strip LWS from both ends */
+  if (normal) 
+    skip_lws(&s);
+  xtra = strlen(s);
+  if (normal)
+    while (xtra > 0 && IS_LWS(s[xtra - 1]))
+      xtra--;
+
+  h = msg_header_alloc(home, hc, xtra + 1);
+
+  if (h) {
+    char *b = MSG_HEADER_DATA(h);
+
+    strncpy(b, s, xtra)[xtra] = 0;
+
+    if (hc->hc_parse(home, h, b, xtra) == -1) {
+      /* Note: parsing function is responsible to free 
+	 everything it has allocated (like parameter lists) */
+      /* XXX - except header structures */
+      su_free(home, h), h = NULL;
+    }
+  }
+
+  return h;
+}
+
+/** Make a MSG header with formatting provided. */
+msg_header_t *msg_header_vformat(su_home_t *home, 
+				msg_hclass_t *hc,
+				char const *fmt,
+				va_list ap)
+{
+  msg_header_t *h;
+  
+  int n;
+  size_t xtra = 64;		/* reasonable default */
+
+  /* Quick path */
+  if (!fmt || !strchr(fmt, '%'))
+    return msg_header_make(home, hc, fmt);
+
+  /* Another quickie */
+  if (strcmp(fmt, "%s") == 0) {
+    fmt = va_arg(ap, char const *);
+    return msg_header_make(home, hc, fmt);
+  }
+  
+  if (!(h = msg_header_alloc(home, hc, xtra)))
+    return NULL;
+
+  for (;;) {
+    va_list aq;
+
+    va_copy(aq, ap);
+    n = vsnprintf(MSG_HEADER_DATA(h), xtra, fmt, aq);
+    va_end(aq);
+    
+    if (n >= 0 && (size_t)n < xtra)
+      break;
+
+    /* Try again with more space */
+    su_free(home, h);
+
+    if (xtra >= INT_MAX)
+      return NULL;
+
+    if (n >= 0)
+      xtra = n + 1; /* precisely what is needed */
+    else
+      xtra *= 2;    /* glibc 2.0 - twice the old size */
+
+    if (xtra > INT_MAX)
+      xtra = INT_MAX;
+    
+    if (!(h = msg_header_alloc(home, hc, xtra)))
+      return NULL;
+  }
+  
+  if (hc->hc_parse(home, h, MSG_HEADER_DATA(h), (size_t)n) == -1) {
+    /* Note: parsing function is responsible to free 
+       everything it has allocated (like parameter lists) */
+    su_free(home, h), h = NULL;
+  }
+
+  return h;
+}
+
+msg_header_t *msg_header_format(su_home_t *home, 
+				msg_hclass_t *hc,
+				char const *fmt,
+				...)
+{
+  msg_header_t *h;
+  va_list ap;
+
+  va_start(ap, fmt);
+
+  h = msg_header_vformat(home, hc, fmt, ap);
+
+  va_end(ap);
+
+  return h;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_INTERNAL_H
+/** Defined when <msg_internal.h> has been included. */
+#define MSG_INTERNAL_H 
+
+/**@IFILE msg_internal.h 
+ * @brief Abstract messages - internal interface 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ *
+ */
+
+#ifdef MSG_H
+#error "msg_internal.h" should be included before "msg.h"
+#endif
+
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_addr.h"
+#include "sofia-sip/msg_buffer.h"
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* Types used when handling streaming */
+
+typedef struct msg_buffer_s msg_buffer_t;
+
+/* ---------------------------------------------------------------------- */
+
+struct msg_s {
+  su_home_t           m_home[1]; /**< Memory home */
+
+  msg_mclass_t const *m_class;	/**< Message class */
+  int                 m_oflags;	/**< Original flags */
+
+  msg_pub_t          *m_object;	/**< Public view to parsed message */
+
+  size_t              m_maxsize;/**< Maximum size */
+  size_t              m_size;	/**< Total size of fragments */
+
+  msg_header_t       *m_chain;	/**< Fragment chain */
+  msg_header_t      **m_tail;	/**< Tail of fragment chain */
+
+  msg_payload_t      *m_chunk;	/**< Incomplete payload fragment */
+
+  /* Parsing/printing buffer */
+  struct msg_mbuffer_s {
+    char     *mb_data;		/**< Pointer to data */
+    usize_t   mb_size;		/**< Size of buffer */
+    usize_t   mb_used;		/**< Used data */
+    usize_t   mb_commit;	/**< Data committed to msg */
+    unsigned  mb_eos:1;		/**< End-of-stream flag */
+    unsigned :0;
+  } m_buffer[1];
+
+  msg_buffer_t  *m_stream;	/**< User-provided buffers */
+  size_t         m_ssize;	/**< Stream size */
+
+  unsigned short m_extract_err; /**< Bitmask of erroneous headers */
+  /* Internal flags */
+  unsigned     	 m_set_buffer:1;/**< Buffer has been set */
+  unsigned     	 m_streaming:1; /**< Use streaming with message */
+  unsigned       m_prepared:1;	/**< Prepared/not */
+  unsigned  :0;
+
+  msg_t        	*m_next;	/**< Next message */
+
+  msg_t        	*m_parent;	/**< Reference to a parent message */
+  int          	 m_refs;	/**< Number of references to this message */
+
+  su_addrinfo_t	 m_addrinfo;	/**< Message addressing info (protocol) */
+  su_sockaddr_t	 m_addr[1];	/**< Message address */
+
+  int          	 m_errno;	/**< Errno */
+};
+
+/** Buffer for message body. */
+struct msg_buffer_s {
+  char           *b_data;	    /**< Data - may contain NUL */
+  size_t          b_size;	    /**< Length of message payload */
+  size_t          b_used;	    /**< Used data */
+  size_t          b_avail;	    /**< Available data */
+  int             b_complete;	    /**< This buffer completes the message */
+  msg_buffer_t   *b_next;	    /**< Next buffer */
+  msg_payload_t  *b_chunks;	    /**< List of body chunks */
+};
+
+/** Maximum size when streaming. */
+#define MSG_SSIZE_MAX (USIZE_MAX)
+
+/* ---------------------------------------------------------------------- */
+/* Header-kind predicate functions. */
+static inline int msg_is_single(msg_header_t const *h)
+{
+  return h->sh_class->hc_kind == msg_kind_single;
+}
+
+static inline int msg_is_prepend(msg_header_t const *h)
+{
+  return h->sh_class->hc_kind == msg_kind_prepend;
+}
+
+static inline int msg_is_append(msg_header_t const *h)
+{
+  return 
+    h->sh_class->hc_kind == msg_kind_append ||
+    h->sh_class->hc_kind == msg_kind_apndlist;
+}
+
+static inline int msg_is_list(msg_header_t const *h)
+{
+  return h->sh_class->hc_kind == msg_kind_list;
+}
+
+static inline int msg_is_special(msg_header_t const *h)
+{
+  return h->sh_class->hc_hash < 0;
+}
+
+SOFIA_END_DECLS
+
+#endif /* MSG_INTERNAL_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,387 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser 
+ * @CFILE msg_mclass.c
+ *
+ * Message factory object.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jun  5 14:34:24 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <stdarg.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_mclass_hash.h"
+
+/** Clone a message class.
+ *
+ * @relatesalso msg_mclass_s
+ *
+ * The function msg_mclass_clone() makes a copy of message class object @a
+ * old. It is possible to resize the hash table by giving a non-zero @a
+ * newsize. If @a newsize is 0, the size of hash table is not changed. If @a
+ * empty is true, the copied message class object will not recognize any
+ * headers. This is useful if more fine-grained control of parsing process
+ * is required, for instance.
+ * 
+ * @param[in] old      pointer to the message class object to be copied 
+ * @param[in] newsize  size of hash table in the copied object 
+ * @param[in] empty    if true, resulting copy does not contain any headers 
+ * 
+ * @return 
+ * The function msg_mclass_clone() returns a pointer to a newly
+ * copied message class object, or NULL upon an error.
+ * The returned message class object can be freed with free().
+ *
+ * @ERRORS
+ * @ERROR ENOMEM
+ * A memory allocation failed.
+ * @ERROR EINVAL
+ * The function was given invalid arguments.
+ * 
+ * @note The empty parser can handle request/status line. All headers are
+ * put into list of unknown headers (unless they are malformed, and they are
+ * put into list of erronous headers). However, SIP, RTSP, and HTTP
+ * protocols all require that the parser recognizes @b Content-Length header
+ * before they can extract the message body from the data received from
+ * network.
+ *
+ */
+msg_mclass_t *msg_mclass_clone(msg_mclass_t const *old, int newsize, int empty)
+{
+  size_t size, shortsize;
+  msg_mclass_t *mc; 
+  int identical;
+  unsigned short i;
+
+  if (newsize == 0)
+    newsize = old->mc_hash_size;
+
+  if (newsize < old->mc_hash_used ||
+      (unsigned)newsize > USHRT_MAX / sizeof(msg_header_t *)) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  size = offsetof(msg_mclass_t, mc_hash[newsize]);
+  if (old->mc_short)
+    shortsize = MC_SHORT_SIZE * (sizeof old->mc_short[0]);
+  else
+    shortsize = 0;
+  mc = malloc(size + shortsize);
+  identical = newsize == old->mc_hash_size && !empty;
+
+  if (mc) {
+    if (!identical) {
+      memcpy(mc, old, offsetof(msg_mclass_t, mc_hash));
+      memset(mc->mc_hash, 0, size - offsetof(msg_mclass_t, mc_hash));
+      mc->mc_short = NULL;
+      mc->mc_hash_size = newsize;
+      mc->mc_hash_used = 0;
+      for (i = 0; !empty && i < old->mc_hash_size; i++) {
+	msg_mclass_insert(mc, &old->mc_hash[i]);
+      }
+    }
+    else {
+      memcpy(mc, old, size);
+      mc->mc_short = NULL;
+    }
+    
+    if (shortsize) {
+      if (empty)
+	mc->mc_short = memset((char *)mc + size, 0, shortsize);
+      else
+	mc->mc_short = memcpy((char *)mc + size, old->mc_short, shortsize);
+    }
+  }
+
+  return mc;
+}
+
+/**Add a new header to the message class.
+ *
+ * @relatesalso msg_mclass_s
+ *
+ * Insert a header class @a hc to the message class object @a mc. If the
+ * given @a offset of the header in @ref msg_pub_t "public message
+ * structure" is zero, the function extends the public message structure in
+ * order to store newly inserted header there.
+ *
+ * @param[in,out] mc       pointer to a message class object 
+ * @param[in]     hc       pointer to a header class object 
+ * @param[in]     offset   offset of the header in
+ *                         @ref msg_pub_t "public message structure"
+ *
+ * If the @a offset is 0, the msg_mclass_insert_header() increases size of
+ * the public message structure and places the header at the end of message.
+ *
+ * @return Number of collisions in hash table, or -1 upon an error.
+ * 
+ * @deprecated Use msg_mclass_insert_with_mask() instead.
+ */
+int msg_mclass_insert_header(msg_mclass_t *mc, 
+			     msg_hclass_t *hc,
+			     unsigned short offset)
+{
+  msg_href_t hr[1];
+
+  if (mc == NULL || hc == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (msg_hclass_offset(mc, NULL, hc))
+    return (void)(errno = EEXIST), -1;
+
+  if (offset == 0)
+    offset = mc->mc_msize, mc->mc_msize += sizeof(msg_header_t *);
+
+  assert(offset < mc->mc_msize);
+
+  hr->hr_class = hc;
+  hr->hr_offset = offset;
+
+  return msg_mclass_insert(mc, hr);
+}
+
+/**Add a new header to the message class.
+ *
+ * @relatesalso msg_mclass_s
+ *
+ * Insert a header class @a hc to the message class @a mc. If the given @a
+ * offset of the header in @ref msg_pub_t "public message structure" is
+ * zero, extend the size of the public message structure in order to store
+ * headers at the end of structure.
+ *
+ * @param[in,out] mc       pointer to a message class
+ * @param[in]     hc       pointer to a header class
+ * @param[in]     offset   offset of the header in 
+ *                         @ref msg_pub_t "public message structure" 
+ * @param[in]     flags    classification flags for the header 
+ *
+ * @return Number of collisions in hash table, or -1 upon an error.
+ */
+int msg_mclass_insert_with_mask(msg_mclass_t *mc, 
+				msg_hclass_t *hc,
+				unsigned short offset,
+				unsigned short flags)
+{
+  msg_href_t hr[1];
+
+  if (mc == NULL || hc == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (msg_hclass_offset(mc, NULL, hc))
+    return (void)(errno = EEXIST), -1;
+
+  if (offset == 0)
+    offset = mc->mc_msize, mc->mc_msize += sizeof(msg_header_t *);
+
+  assert(offset < mc->mc_msize);
+
+  hr->hr_class = hc;
+  hr->hr_offset = offset;
+  hr->hr_flags = flags;
+
+  return msg_mclass_insert(mc, hr);
+}
+
+/** Add a header reference to the message class.
+ *
+ * @relatesalso msg_mclass_s
+ *
+ * @param[in,out] mc       pointer to a message class object 
+ * @param[in]     hr       header reference object 
+ *
+ * @return Number of collisions in hash table, or -1 upon an error.
+ */
+int msg_mclass_insert(msg_mclass_t *mc, msg_href_t const *hr)
+{
+  int j, j0;
+  int N;
+  int collisions = 0;
+  msg_hclass_t *hc;
+
+  if (mc == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (hr == NULL || (hc = hr->hr_class) == NULL) 
+    return 0;
+
+  /* Add short form */
+  if (mc->mc_short && hc->hc_short[0]) {
+    char compact = hc->hc_short[0];
+    msg_href_t *shorts = (msg_href_t *)mc->mc_short;
+
+    if (compact < 'a' || compact > 'z')
+      return -1;
+
+    if (shorts[compact - 'a'].hr_class && 
+	shorts[compact - 'a'].hr_class != hc)
+      return -1;
+      
+    shorts[compact - 'a'] = *hr;
+  }
+
+  N = mc->mc_hash_size;
+  j0 = msg_header_name_hash(hc->hc_name, NULL) % N;
+
+  for (j = j0; mc->mc_hash[j].hr_class; ) {
+    collisions++;
+    if (mc->mc_hash[j].hr_class == hc)
+      return -1;
+    j = (j + 1) % N;
+    if (j == j0)
+      return -1;
+  }
+
+  mc->mc_hash[j] = hr[0];
+  mc->mc_hash_used++;
+  
+  return collisions;
+}
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(cr, lf) ((cr) == '\r' ? ((lf) == '\n') + 1 : (cr)=='\n')
+
+/**Search for a header class.
+ *
+ * @relatesalso msg_mclass_s
+ *
+ * The function msg_find_hclass() searches for a header class from a message
+ * class based on the contents of the header to be parsed. The buffer @a s
+ * should point to the first character in the header name.
+ *
+ * @param[in]  mc   message class object 
+ * @param[in]  s    header contents 
+ * @param[out] return_start_of_content start of header content (may be NULL)
+ *
+ * @return The function msg_find_hclass() returns a pointer to a header
+ * reference structure. A pointer to a header reference for unknown headers
+ * is returned, if the header is not included in the message class.
+ *
+ * @par
+ * The return-value parameter @a return_start_of_content will contain the
+ * start of the header contents within @a s, or 0 upon an error parsing the
+ * header name and following colon.
+ *
+ * @par 
+ * Upon a fatal error, a NULL pointer is returned.
+ */
+msg_href_t const *msg_find_hclass(msg_mclass_t const *mc, 
+				  char const *s, 
+				  isize_t *return_start_of_content)
+{
+  msg_href_t const *hr;
+  short i, N, m;
+  isize_t len;
+
+  assert(mc);
+
+  N = mc->mc_hash_size;
+
+  i = msg_header_name_hash(s, &len) % N;
+
+  if (len == 0 || len > HC_LEN_MAX) {
+    if (return_start_of_content)
+      *return_start_of_content = 0;
+    return mc->mc_error;
+  }
+
+  m = (short)len;
+
+  if (m == 1 && mc->mc_short) {
+    short c = s[0];
+    if (c >= 'a' && c <= 'z')
+      hr = &mc->mc_short[c - 'a'];
+    else if (c >= 'A' && c <= 'Z')
+      hr = &mc->mc_short[c - 'A'];
+    else
+      hr = mc->mc_unknown;
+
+    if (hr->hr_class == NULL)
+      hr = mc->mc_unknown;
+  }
+  else {
+    msg_hclass_t *hc;
+
+    /* long form */
+    for (hr = NULL; (hc = mc->mc_hash[i].hr_class); i = (i + 1) % N) {
+      if (m == hc->hc_len && strncasecmp(s, hc->hc_name, m) == 0) {
+	hr = &mc->mc_hash[i];
+	break;
+      }
+    }
+
+    if (hr == NULL)
+      hr = mc->mc_unknown;
+  }
+
+  if (!return_start_of_content)	/* Just header name */
+    return hr;
+
+  if (s[len] == ':') {		/* Fast path */
+    *return_start_of_content = ++len;
+    return hr;
+  }
+
+  if (IS_LWS(s[len])) {
+    int crlf = 0;
+    do {
+      len += span_ws(s + len + crlf) + crlf; /* Skip lws before colon */
+      crlf = CRLF_TEST(s[len], s[len + 1]);
+    }
+    while (IS_WS(s[len + crlf]));
+  }
+
+  if (s[len++] != ':')		/* Colon is required in header */
+    len = 0;
+
+  *return_start_of_content = len;
+
+  return hr;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2176 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_mime
+ * @CFILE msg_mime.c
+ *
+ * MIME-related headers and MIME multipart bodies for SIP/HTTP/RTSP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ *
+ *
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE 1
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_mime.h"
+
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su_errno.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+	     const void *needle, size_t needlelen);
+#endif
+
+size_t memspn(const void *mem, size_t memlen,
+	      const void *accept, size_t acceptlen);
+size_t memcspn(const void *mem, size_t memlen,
+	       const void *reject, size_t rejectlen);
+
+/** Protocol version of MIME */
+char const msg_mime_version_1_0[] = "MIME/1.0";
+
+/* Internally used version of msg_header_t */
+union msg_mime_u
+{
+  msg_common_t    sh_common[1];
+  struct {
+    msg_common_t  shn_common;
+    msg_header_t *shn_next;
+  }               sh_header_next[1];
+
+  msg_multipart_t           sh_multipart[1];
+
+  msg_accept_t              sh_accept[1];
+  msg_accept_any_t          sh_accept_any[1];
+  msg_accept_charset_t      sh_accept_charset[1];
+  msg_accept_encoding_t     sh_accept_encoding[1];
+  msg_accept_language_t     sh_accept_language[1];
+  msg_content_disposition_t sh_content_disposition[1];
+  msg_content_encoding_t    sh_content_encoding[1];
+  msg_content_id_t          sh_content_id[1];
+  msg_content_language_t    sh_content_language[1];
+  msg_content_length_t      sh_content_length[1];
+  msg_content_location_t    sh_content_location[1];
+  msg_content_type_t        sh_content_type[1];
+  msg_mime_version_t        sh_mime_version[1];
+  msg_warning_t             sh_warning[1];
+  msg_unknown_t             sh_unknown[1];
+  msg_separator_t           sh_separator[1];
+  msg_payload_t             sh_payload[1];
+};
+
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_mime_protos.h>
+
+/** Define a header class for headers without any extra data to copy */
+#define MSG_HEADER_CLASS_G(c, l, s, kind) \
+  MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic, msg_generic)
+
+#define msg_generic_update NULL
+
+/** Define a header class for a msg_list_t kind of header */
+#define MSG_HEADER_CLASS_LIST(c, l, s, kind) \
+  MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list, msg_list)
+
+#define msg_list_update NULL
+
+/* ====================================================================== */
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
+
+/**@ingroup msg_mime
+ * @defgroup msg_multipart MIME Multipart Body
+ *
+ * Representing MIME multipart bodies and their manipulation.
+ *
+ * The #msg_multipart_t is an object for storing MIME multipart message
+ * bodies. It includes message components used for framing and identifying
+ * message parts. Its syntax is defined in  @RFC2046 as follows:
+ *
+ * @code
+ *
+ *   multipart-body := [preamble CRLF]
+ *                     dash-boundary transport-padding CRLF
+ *                     body-part *encapsulation
+ *                     close-delimiter transport-padding
+ *                     [CRLF epilogue]
+ *
+ *   preamble := discard-text
+ *
+ *   discard-text := *(*text CRLF)
+ *                   ; May be ignored or discarded.
+ *
+ *   dash-boundary := "--" boundary
+ *                    ; boundary taken from the value of boundary parameter
+ *                    ; of the Content-Type field.
+ *
+ *   boundary := 0*69<bchars> bcharsnospace
+ *
+ *   bchars := bcharsnospace / " "
+ *
+ *   bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ *                    "+" / "_" / "," / "-" / "." /
+ *                    "/" / ":" / "=" / "?"
+ *
+ *   transport-padding := *LWSP-char
+ *                        ; Composers MUST NOT generate non-zero length
+ *                        ; transport padding, but receivers MUST be able to
+ *                        ; handle padding added by message transports.
+ *
+ *   body-part := <"message" as defined in @RFC822, with all header fields
+ *                 optional, not starting with the specified dash-boundary,
+ *                 and with the delimiter not occurring anywhere in the body
+ *                 part. Note that the semantics of a part differ from the
+ *                 semantics of a message, as described in the text.>
+ *
+ *   encapsulation := delimiter transport-padding CRLF 
+ *                    body-part
+ *
+ *   close-delimiter := delimiter "--"
+ *
+ *   delimiter := CRLF dash-boundary
+ *
+ *   epilogue := discard-text
+ *
+ * @endcode
+ *
+ * @par Parsing a Multipart Message
+ * 
+ * When a message body contains a multipart entity (in other words, it has a
+ * MIME media type of "multipart"), the application can split the multipart
+ * entity into body parts
+ *
+ * The parsing is relatively simple, the application just gives a memory
+ * home object, a Content-Type header object and message body object as an 
+ * argument to msg_multipart_parse() function:
+ * @code
+ *    if (sip->sip_content_type && 
+ *        strncasecmp(sip->sip_content_type, "multipart/", 10) == 0) {
+ *      msg_multipart_t *mp;
+ *
+ *      if (sip->sip_multipart)
+ *        mp = sip->sip_multipart;
+ *      else
+ *        mp = msg_multipart_parse(msg_home(msg), 
+ *                                 sip->sip_content_type,
+ *                                 (sip_payload_t *)sip->sip_payload);
+ * 
+ *      if (mp)
+ *        ... processing multipart ...
+ *      else
+ *        ... error handling ...
+ *    }
+ * @endcode
+ *
+ * The resulting list of msg_multipart_t structures contain the parts of the
+ * multipart entity, each part represented by a separate #msg_multipart_t
+ * structure. Please note that in order to make error recovery possible, the
+ * parsing is not recursive - if multipart contains another multipart, the
+ * application is responsible for scanning for it and parsing it.
+ *
+ * @par Constructing a Multipart Message
+ *
+ * Constructing a multipart body is a bit more hairy. The application needs
+ * a message object (#msg_t), which is used to buffer the encoding of
+ * multipart components.
+ *
+ * As an example, let us create a "multipart/mixed" multipart entity with a
+ * HTML and GIF contents, and convert it into a #sip_payload_t structure:
+ * @code
+ *   msg_t *msg = msg_create(sip_default_mclass, 0);
+ *   su_home_t *home = msg_home(msg);
+ *   sip_t *sip = sip_object(msg);
+ *   sip_content_type_t *c;
+ *   msg_multipart_t *mp = NULL;
+ *   msg_header_t *h = NULL;
+ *   char *b;
+ *   size_t len, offset;
+ * 
+ *   mp = msg_multipart_create(home, "text/html;level=3", html, strlen(html));
+ *   mp->mp_next = msg_multipart_create(home, "image/gif", gif, giflen);
+ *
+ *   c = sip_content_type_make(home, "multipart/mixed");
+ * 
+ *   // Add delimiters to multipart, and boundary parameter to content-type
+ *   if (msg_multipart_complete(home, c, mp) < 0)
+ *     return -1;		// Error
+ *
+ *   // Combine multipart components into the chain
+ *   h = NULL;
+ *   if (msg_multipart_serialize(&h, mp) < 0)
+ *     return -1;		// Error
+ *
+ *   // Encode all multipart components 
+ *   len = msg_multipart_prepare(msg, mp, 0);
+ *   if (len < 0)
+ *     return -1;		// Error
+ *
+ *   pl = sip_payload_create(home, NULL, len);
+ *
+ *   // Copy each element from multipart to pl_data 
+ *   b = pl->pl_data;
+ *   for (offset = 0, h = mp; offset < len; h = h->sh_succ) {
+ *     memcpy(b + offset, h->sh_data, h->sh_len);
+ *     offset += h->sh_len;
+ *   }
+ * @endcode
+ *
+ */
+
+/**Create a part for MIME multipart entity.
+ *
+ * The function msg_multipart_create() allocates a new #msg_multipart_t
+ * object from memory home @a home. If @a content_type is non-NULL, it makes
+ * a #msg_content_type_t header object and adds the header to the
+ * #msg_multipart_t object. If @a dlen is nonzero, it allocates a
+ * msg_payload_t structure of @a dlen bytes for the payload of the newly
+ * created #msg_multipart_t object. If @a data is non-NULL, it copies the @a
+ * dlen bytes of of data to the payload of the newly created
+ * #msg_multipart_t object.
+ *
+ * @return A pointer to the newly created #msg_multipart_t object, or NULL
+ * upon an error.
+ */
+msg_multipart_t *msg_multipart_create(su_home_t *home,
+				      char const *content_type,
+				      void const *data,
+				      isize_t dlen)
+{
+  msg_multipart_t *mp;
+
+  mp = (msg_multipart_t *)msg_header_alloc(home, msg_multipart_class, 0);
+
+  if (mp) {
+    if (content_type)
+      mp->mp_content_type = msg_content_type_make(home, content_type);
+    if (dlen)
+      mp->mp_payload = msg_payload_create(home, data, dlen);
+
+    if ((!mp->mp_content_type && content_type) ||
+	(!mp->mp_payload && dlen)) {
+      su_free(home, mp->mp_content_type);
+      su_free(home, mp->mp_payload);
+      su_free(home, mp);
+      mp = NULL;
+    }
+  }
+
+  return mp;
+}
+
+/** Convert boundary parameter to a search string. */
+static char *
+msg_multipart_boundary(su_home_t *home, char const *b)
+{
+  char *boundary;
+
+  if (!b || !(boundary = su_alloc(home, 2 + 2 + strlen(b) + 2 + 1)))
+    return NULL;
+
+  strcpy(boundary, CR LF "--");
+
+  if (b[0] == '"') /* " See http://bugzilla.gnome.org/show_bug.cgi?id=134216 */
+
+    msg_unquote(boundary + 4, b);
+  else
+    strcpy(boundary + 4, b);
+
+
+  strcat(boundary + 4, CR LF);
+
+  return boundary;
+}
+
+
+/** Boundary chars. */
+static char const bchars[] = 
+"'()+_,-./:=?"
+"0123456789"
+"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+"abcdefghijklmnopqrstuvwxyz"
+" ";
+
+#define bchars_len (sizeof(bchars) - 1)
+
+/** Search for a suitable boundary from MIME. */
+static char *
+msg_multipart_search_boundary(su_home_t *home, char const *p, size_t len)
+{
+  size_t m;
+  unsigned crlf;
+  char const *end = p + len;
+  char *boundary;
+
+  if (len < 2)
+    return NULL;
+
+  /* Boundary looks like LF -- string SP* [CR] LF */
+  if (memcmp("--", p, 2) == 0) {
+    /* We can be at boundary beginning, there is no CR LF */
+    m = 2 + memspn(p + 2, len - 2, bchars, bchars_len);
+    if (m + 2 >= len)
+      return NULL;
+    crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
+    while (p[m - 1] == ' ' || p[m - 1] == '\t')
+      m--;
+    if (m > 2 && crlf) {
+      boundary = su_alloc(home, 2 + m + 2 + 1);
+      if (boundary) {
+	memcpy(boundary, CR LF, 2);
+	memcpy(boundary + 2, p, m);
+	strcpy(boundary + m + 2, CR LF);
+      }
+      return boundary;
+    }
+  } 
+
+  /* Look for LF -- */
+  for (;(p = memmem(p, end - p, LF "--", 3)); p += 3) {
+    len = end - p;
+    m = 3 + memspn(p + 3, len - 3, bchars, bchars_len);
+    if (m + 2 >= len)
+      return NULL;
+    crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
+    while (p[m - 1] == ' ' || p[m - 1] == '\t')
+      m--;
+    m--;
+    if (m > 2 && crlf) {
+      boundary = su_alloc(home, 2 + m + 2 + 1);
+      if (boundary) {
+	memcpy(boundary, CR LF, 2);
+	memcpy(boundary + 2, p + 1, m);
+	strcpy(boundary + 2 + m, CR LF);
+      }
+      return boundary;
+    }
+  }
+
+  return NULL;
+}
+
+/** Parse a MIME multipart.
+ *
+ * The function msg_multipart_parse() parses a MIME multipart message. The
+ * common syntax of multiparts is described in @RFC2046 (section 7).
+ *
+ * @param[in,out] home home for allocating structures 
+ * @param[in]     c    content-type header for multipart 
+ * @param[in]     pl   payload structure for multipart 
+ *
+ * After parsing, the @a pl will contain the plain-text preamble (if any).
+ *
+ * @note If no @b Content-Type header is given, the msg_multipart_parse()
+ * tries to look for a suitable boundary. Currently, it takes first
+ * boundary-looking string and uses that, so it can be fooled with, for
+ * instance, signature @c "--Pekka".
+ */
+msg_multipart_t *msg_multipart_parse(su_home_t *home,
+				     msg_content_type_t const *c,
+				     msg_payload_t *pl)
+{
+  msg_multipart_t *mp = NULL, *all = NULL, **mmp = &all;
+  /* Dummy msg object */
+  msg_t msg[1] = {{{ SU_HOME_INIT(msg) }}};
+  size_t len, m, blen;
+  char *boundary, *p, *next, save;
+  char const *b, *end;
+  msg_param_t param;
+
+  p = pl->pl_data; len = pl->pl_len; end = p + len;
+
+  su_home_init(msg_home(msg));
+  msg->m_class = msg_multipart_mclass;
+  msg->m_tail = &msg->m_chain;
+
+  /* Get boundary from Content-Type */
+  if (c && (param = msg_header_find_param(c->c_common, "boundary=")))
+    boundary = msg_multipart_boundary(msg_home(msg), param);
+  else
+    boundary = msg_multipart_search_boundary(msg_home(msg), p, len);
+
+  if (!boundary)
+    return NULL;
+
+  m = strlen(boundary) - 2, blen = m - 1;
+
+  /* Find first delimiter */
+  if (memcmp(boundary + 2, p, m - 2) == 0)
+    b = p, p = p + m - 2, len -= m - 2;
+  else if ((p = memmem(p, len, boundary + 1, m - 1))) {
+    if (p != pl->pl_data && p[-1] == '\r')
+      b = --p, p = p + m, len -= m;
+    else
+      b = p, p = p + m - 1, len -= m - 1;
+  }
+  else {
+    su_home_deinit(msg_home(msg));
+    return NULL;
+  }
+
+  /* Split multipart into parts */
+  for (;;) {
+    while (p[0] == ' ') 
+      p++;
+
+    p += p[0] == '\r' ? 1 + (p[1] == '\n') : (p[0] == '\n');
+
+    len = end - p;
+
+    if (len < blen)
+      break;
+
+    next = memmem(p, len, boundary + 1, m = blen);
+
+    if (!next)
+      break;			/* error */
+
+    if (next != p && next[-1] == '\r')
+      next--, m++;
+
+    mp = (msg_multipart_t *)msg_header_alloc(msg_home(msg), msg_multipart_class, 0);
+    if (mp == NULL)
+      break;			/* error */
+    *mmp = mp; mmp = &mp->mp_next;
+
+    /* Put delimiter transport-padding CRLF here */
+    mp->mp_common->h_data = b;
+    mp->mp_common->h_len = p - b;
+
+    /* .. and body-part here */
+    mp->mp_data = p;
+    mp->mp_len = next - p;
+
+    if (next[m] == '-' && next[m + 1] == '-') {
+      /* We found close-delimiter */
+      assert(mp);
+      if (!mp)
+	break;			/* error */
+      mp->mp_close_delim = (msg_payload_t *)
+	msg_header_alloc(msg_home(msg), msg_payload_class, 0);
+      if (!mp->mp_close_delim)
+	break;			/* error */
+      /* Include also transport-padding and epilogue in the close-delimiter */
+      mp->mp_close_delim->pl_data = next;
+      mp->mp_close_delim->pl_len = p + len - next;
+      break;
+    }
+
+    b = next; p = next + m; 
+  }
+
+  if (!mp || !mp->mp_close_delim) {
+    su_home_deinit(msg_home(msg));
+    /* Delimiter error */
+    return NULL;
+  }
+
+  /* Parse each part */
+  for (mp = all; mp; mp = mp->mp_next) {
+    msg->m_object = (msg_pub_t *)mp; p = mp->mp_data; next = p + mp->mp_len;
+
+    if (msg->m_tail)
+      mp->mp_common->h_prev = msg->m_tail,
+	*msg->m_tail = (msg_header_t *)mp;
+
+    msg->m_chain = (msg_header_t *)mp;
+    msg->m_tail = &mp->mp_common->h_succ;
+
+    save = *next; *next = '\0';	/* NUL-terminate this part */
+
+    for (len = next - p; len > 0; len -= m, p += m) {
+      if (IS_CRLF(p[0])) {
+	m = msg_extract_separator(msg, (msg_pub_t*)mp, p, len, 1);
+	assert(m > 0);
+
+	p += m; len -= m;
+
+	if (len > 0) {
+	  m = msg_extract_payload(msg, (msg_pub_t*)mp, NULL, len, p, len, 1);
+	  assert(m > 0);
+	  assert(len == m);
+	}
+	break;
+      }
+
+      m = msg_extract_header(msg, (msg_pub_t*)mp, p, len, 1);
+
+      if (m <= 0) {
+	assert(m > 0);
+	/* Xyzzy */
+      }
+    }
+
+    *next = save; /* XXX - Should we leave the payload NUL-terminated? */
+  }
+
+  /* Postprocess */
+  blen = strlen(boundary);
+
+  for (mp = all; mp; mp = mp->mp_next) {
+    mp->mp_data = boundary; 
+    mp->mp_len = blen;
+
+    assert(mp->mp_payload || mp->mp_separator);
+
+    if (mp->mp_close_delim) {
+      msg_header_t **tail;
+
+      if (mp->mp_payload)
+	tail = &mp->mp_payload->pl_common->h_succ;
+      else
+	tail = &mp->mp_separator->sep_common->h_succ;
+
+      assert(msg->m_chain == (msg_header_t *)mp);
+      assert(*tail == NULL);
+
+      mp->mp_close_delim->pl_common->h_prev = tail;
+      *tail = (msg_header_t *)mp->mp_close_delim;
+    }
+  }
+
+  msg_fragment_clear(pl->pl_common);
+  pl->pl_len = all->mp_data - (char *)pl->pl_data;
+
+  su_home_move(home, msg_home(msg)); su_home_deinit(msg_home(msg));
+
+  return all;
+}
+
+/**Add all missing parts to the multipart.
+ * 
+ * Add missing components such as boundaries between body parts, separators
+ * between body-part headers and data, and close-delimiter after last
+ * body-part to the multipart message.
+ * 
+ * @param[in,out] home home for allocating structures 
+ * @param[in,out] c    content-type header for multipart 
+ * @param[in,out] mp   pointer to first multipart structure 
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS 
+ * @ERROR EBADMSG
+ * The @b Content-Type header @a c is malformed, or multipart message
+ * contains a malformed @b Content-Type header.
+ * @ERROR ENOMEM
+ * A memory allocation failed.
+ * @ERROR EINVAL
+ * The function msg_multipart_complete() was given invalid arguments.
+ */
+int msg_multipart_complete(su_home_t *home,
+			   msg_content_type_t *c,
+			   msg_multipart_t *mp)
+{
+  char *boundary;
+  char const *b;
+  size_t blen, m;
+
+  if (c == NULL || mp == NULL)
+    return (errno = EINVAL), -1;
+
+  if (!(b = msg_header_find_param(c->c_common, "boundary="))) {
+    /* Generate boundary */
+    enum { tlen = 16 * 4 / 3 };
+    char token[sizeof("boundary=") + tlen + 1];
+
+    if (mp->mp_data) {
+      b = mp->mp_data;
+      m = mp->mp_len;
+
+      if (strncmp(b, CR LF "--", 4) == 0)
+	b += 4, m -= 4;
+      else if (strncmp(b, "--", 2) == 0)
+	b += 2, m -= 2;
+      else
+	return (errno = EBADMSG), -1;
+      /* XXX - quoting? */
+      b = su_sprintf(home, "boundary=\"%.*s\"", (int)m, b);
+    }
+    else {
+      strcpy(token, "boundary=");
+      msg_random_token(token + strlen("boundary="), (size_t)tlen, NULL, 0);
+      b = su_strdup(home, token);
+    }
+
+    if (!b)
+      return -1;
+
+    msg_params_replace(home, (msg_param_t **)&c->c_params, b);
+
+    b += strlen("boundary=");
+  }
+
+  if (!(boundary = msg_multipart_boundary(home, b)))
+    return -1;
+
+  blen = strlen(boundary); m = blen - 2;
+
+  for (; mp; mp = mp->mp_next) {
+    if (mp->mp_data == NULL) {
+      mp->mp_data = boundary, mp->mp_len = blen;
+    } else {
+      if (mp->mp_len < 3)
+	return -1;
+      if (mp->mp_data[0] == '\r' && mp->mp_data[1] == '\n') {
+	if (mp->mp_len < m || memcmp(mp->mp_data + 2, boundary + 2, m - 2))
+	  return -1;
+      } else if (mp->mp_data[0] == '\n') {
+	if (mp->mp_len < m - 1 || memcmp(mp->mp_data + 1, boundary + 2, m - 2))
+	  return -1;
+      } else {
+	if (mp->mp_len < m - 2 || memcmp(mp->mp_data, boundary + 2, m - 2))
+	  return -1;
+      }
+    }
+
+    if (mp->mp_next == NULL) {
+      if (!mp->mp_close_delim)
+	mp->mp_close_delim = msg_payload_format(home, "%.*s--" CR LF, 
+						(int)m, boundary);
+      if (!mp->mp_close_delim)
+	return -1;
+    }
+    else if (mp->mp_close_delim) {
+      msg_payload_t *e = mp->mp_close_delim;
+
+      mp->mp_close_delim = NULL;
+
+      if (e->pl_common->h_prev)
+	*e->pl_common->h_prev = e->pl_common->h_succ;
+      if (e->pl_common->h_succ)
+	e->pl_common->h_succ->sh_prev = e->pl_common->h_prev;
+    }
+
+    mp->mp_common->h_data = mp->mp_data;
+    mp->mp_common->h_len = mp->mp_len;
+
+    if (!mp->mp_separator)
+      if (!(mp->mp_separator = msg_separator_make(home, CR LF)))
+	return -1;
+
+    if (mp->mp_multipart) {
+      c = mp->mp_content_type;
+      if (c == NULL)
+	return (errno = EBADMSG), -1;
+
+      if (msg_multipart_complete(home, c, mp->mp_multipart) < 0)
+	return -1;
+    }
+
+    if (!mp->mp_payload)
+      if (!(mp->mp_payload = msg_payload_create(home, NULL, 0)))
+	return -1;
+  }
+
+  return 0;
+}
+
+/** Serialize a multipart message.
+ *
+ */
+msg_header_t *msg_multipart_serialize(msg_header_t **head0,
+				      msg_multipart_t *mp)
+{
+  msg_header_t *h_succ_all = NULL;
+  msg_header_t *h, **head, **hh, *h0, *h_succ;
+  void *hend;
+
+#define is_in_chain(h) ((h) && ((msg_frg_t*)(h))->h_prev != NULL)
+#define insert(head, h) \
+  ((h)->sh_succ = *(head), *(head) = (h), \
+   (h)->sh_prev = (head), (head) = &(h)->sh_succ)
+
+  if (mp == NULL || head0 == NULL)
+    return NULL;
+
+  h_succ_all = *head0; head = head0;
+
+  for (; mp; mp = mp->mp_next) {
+    h0 = (msg_header_t *)mp;
+
+    assert(mp->mp_separator); assert(mp->mp_payload);
+    assert(mp->mp_next || mp->mp_close_delim);
+
+    if (!mp->mp_separator || !mp->mp_payload ||
+	(!mp->mp_next && !mp->mp_close_delim))
+      return NULL;
+
+    if ((void *)mp == h_succ_all)
+      h_succ_all = NULL;
+
+    *head0 = h0; h0->sh_prev = head;
+
+    if (is_in_chain(mp->mp_separator))
+      hend = mp->mp_separator;
+    else if (is_in_chain(mp->mp_payload))
+      hend = mp->mp_payload;
+    else if (is_in_chain(mp->mp_multipart))
+      hend = mp->mp_multipart;
+    else if (is_in_chain(mp->mp_close_delim))
+      hend = mp->mp_close_delim;
+    else if (is_in_chain(mp->mp_next))
+      hend = mp->mp_next;
+    else
+      hend = NULL;
+
+    /* Search latest header in chain */
+    for (head = &mp->mp_common->h_succ;
+	 *head && *head != hend;
+	 head = &(*head)->sh_succ)
+      ;
+
+    h_succ = *head;
+
+    /* Serialize headers */
+    for (hh = &((msg_pub_t*)mp)->msg_request;
+	 (char *)hh < (char *)&mp->mp_separator;
+	 hh++) {
+      h = *hh; if (!h) continue;
+      for (h = *hh; h; h = h->sh_next) {
+	if (h == h_succ || !is_in_chain(h)) {
+	  *head = h; h->sh_prev = head; head = &h->sh_succ;
+	  while (*head && *head != hend)
+	    head = &(*head)->sh_succ;
+	  if (h == h_succ)
+	    h_succ = *head;
+	}
+	else {
+	  /* XXX Check that h is between head and hend */
+	}
+      }
+    }
+
+    if (!is_in_chain(mp->mp_separator)) {
+      insert(head, (msg_header_t *)mp->mp_separator);
+    } else {
+      assert(h_succ == (msg_header_t *)mp->mp_separator);
+      mp->mp_separator->sep_common->h_prev = head;
+      *head = (msg_header_t *)mp->mp_separator;
+      head = &mp->mp_separator->sep_common->h_succ;
+      h_succ = *head;
+    }
+
+    if (!is_in_chain(mp->mp_payload)) {
+      insert(head, (msg_header_t *)mp->mp_payload);
+    } else {
+      assert(h_succ == (msg_header_t *)mp->mp_payload);
+      mp->mp_payload->pl_common->h_prev = head;
+      *head = (msg_header_t *)mp->mp_payload;
+      head = &mp->mp_payload->pl_common->h_succ;
+      h_succ = *head;
+    }
+
+    if (mp->mp_multipart) {
+      if ((*head = h_succ))
+	h_succ->sh_prev = head;
+      if (!(h = msg_multipart_serialize(head, mp->mp_multipart)))
+	return NULL;
+      head = &h->sh_succ; h_succ = *head;
+    }
+
+    if (mp->mp_close_delim) {
+      if (!is_in_chain(mp->mp_close_delim)) {
+	insert(head, (msg_header_t*)mp->mp_close_delim);
+      } else {
+	assert(h_succ == (msg_header_t *)mp->mp_close_delim);
+	mp->mp_close_delim->pl_common->h_prev = head;
+	*head = (msg_header_t *)mp->mp_close_delim;
+	head = &mp->mp_close_delim->pl_common->h_succ;
+      }
+
+      if (h_succ_all)
+	*head = h_succ_all, h_succ_all->sh_prev = head;
+
+      return (msg_header_t *)mp->mp_close_delim;
+    }
+
+    *head = h_succ;
+
+    head0 = head;
+  }
+
+  assert(!mp);
+
+  return NULL;
+}
+
+/** Encode a multipart.
+ *
+ * @return The size of multipart in bytes, or -1 upon an error.
+ */
+issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags)
+{
+  if (!mp || !mp->mp_data)
+    return -1;
+
+  if (!mp->mp_common->h_data || 
+      mp->mp_common->h_len != mp->mp_len - 2 ||
+      memcmp(mp->mp_common->h_data, mp->mp_data + 2, mp->mp_len - 2)) {
+    mp->mp_common->h_data = mp->mp_data + 2;
+    mp->mp_common->h_len = mp->mp_len - 2;
+  }
+
+  return msg_headers_prepare(msg, (msg_header_t *)mp, flags);
+}
+
+/** Decode a multipart. */
+issize_t msg_multipart_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
+  msg_payload_t pl[1];
+  msg_multipart_t *mp, *result;
+
+  assert(h && msg_is_multipart(h));
+
+  msg_payload_init(pl);
+  
+  result = (msg_multipart_t *)h;
+
+  pl->pl_data = s; 
+  pl->pl_len = slen;
+
+  mp = msg_multipart_parse(tmphome, NULL, pl);
+
+  if (mp) {
+    *result = *mp;
+
+    if (result->mp_common->h_succ->sh_prev)
+      result->mp_common->h_succ->sh_prev = 
+	&result->mp_common->h_succ;
+
+    su_free(tmphome, mp);
+    
+    su_home_move(home, tmphome);
+  }
+   
+  su_home_deinit(tmphome);
+
+  return mp ? 0 : -1;
+}
+
+/** Encode a multipart.
+ *
+ * Please note that here we just encode a element, the msg_multipart_t
+ * itself.
+ */
+issize_t msg_multipart_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  return msg_payload_e(b, bsiz, h, flags);
+}
+
+/** Calculate extra size of a multipart */
+isize_t msg_multipart_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_multipart_t const *mp = (msg_multipart_t *)h;
+  msg_header_t const * const *hh;
+
+  offset = msg_payload_dup_xtra(h, offset);
+
+  for (hh = (msg_header_t const **)&((msg_pub_t *)mp)->msg_request;
+       (char *)hh <= (char *)&mp->mp_close_delim; 
+       hh++) {
+    for (h = *hh; h; h = h->sh_next) {
+      MSG_STRUCT_SIZE_ALIGN(offset);
+      offset = h->sh_class->hc_dxtra(h, offset + h->sh_class->hc_size);
+    }
+  }
+
+  return offset;
+}
+
+/** Duplicate one msg_multipart_t object */
+char *msg_multipart_dup_one(msg_header_t *dst, msg_header_t const *src,
+			    char *b, isize_t xtra)
+{
+  msg_multipart_t const *mp = (msg_multipart_t *)src;
+  msg_header_t *h, **hh;
+  char *end = b + xtra;
+
+  b = msg_payload_dup_one(dst, src, b, xtra);
+
+  for (hh = &((msg_pub_t*)mp)->msg_request;
+       (char *)hh <= (char *)&mp->mp_close_delim; 
+       hh++) {
+    for (h = *hh; h; h = h->sh_next) {
+      MSG_STRUCT_ALIGN(b);
+      dst = (msg_header_t *)b;
+      memset(dst, 0, sizeof dst->sh_common);
+      dst->sh_class = h->sh_class;
+      b = h->sh_class->hc_dup_one(dst, h, b + h->sh_class->hc_size, end - b);
+      if (h->sh_class->hc_update)
+	msg_header_update_params(h->sh_common, 0);
+      assert(b <= end);
+    }
+  }
+
+  return b;
+}
+
+#if 0
+msg_hclass_t msg_multipart_class[] =
+MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart);
+#endif
+
+/**Calculate Q value.
+ *
+ * The function msg_q_value() converts q-value string @a q to numeric value
+ * in range (0..1000).  Q values are used, for instance, to describe
+ * relative priorities of registered contacts.
+ *
+ * @param q q-value string ("1" | "." 1,3DIGIT)
+ *
+ * @return
+ * The function msg_q_value() returns an integer in range 0 .. 1000.
+ */
+unsigned msg_q_value(char const *q)
+{
+  unsigned value = 0;
+
+  if (!q)
+    return 500;
+  if (q[0] != '0' && q[0] != '.' && q[0] != '1')
+    return 500;
+  while (q[0] == '0')
+    q++;
+  if (q[0] >= '1' && q[0] <= '9')
+    return 1000;
+  if (q[0] == '\0')
+    return 0;
+  if (q[0] != '.')
+    /* Garbage... */
+    return 500;
+
+  if (q[1] >= '0' && q[1] <= '9') {
+    value = (q[1] - '0') * 100;
+    if (q[2] >= '0' && q[2] <= '9') {
+      value += (q[2] - '0') * 10;
+      if (q[3] >= '0' && q[3] <= '9') {
+	value += (q[3] - '0');
+	if (q[4] > '5' && q[4] <= '9')
+	  /* Round upwards */
+	  value += 1;
+	else if (q[4] == '5')
+	  value += value & 1; /* Round to even */
+      }
+    }
+  }
+
+  return value;
+}
+
+/** Parse media type (type/subtype).
+ *
+ * The function msg_mediatype_d() parses a mediatype string.
+ *
+ * @param[in,out] ss    string to be parsed 
+ * @param[out]    type  value result for media type 
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+issize_t msg_mediatype_d(char **ss, char const **type)
+{
+  char *s = *ss;
+  char const *result = s;
+  size_t l1 = 0, l2 = 0, n;
+
+  /* Media type consists of two tokens, separated by / */
+
+  l1 = span_token(s);
+  for (n = l1; IS_LWS(s[n]); n++);
+  if (s[n] == '/') {
+    for (n++; IS_LWS(s[n]); n++);
+    l2 = span_token(s + n);
+    n += l2;
+  }
+
+  if (l1 == 0 || l2 == 0)
+    return -1;
+
+  /* If there is extra ws between tokens, compact version */
+  if (n > l1 + 1 + l2) {
+    s[l1] = '/';
+    memmove(s + l1 + 1, s + n - l2, l2);
+    s[l1 + 1 + l2] = 0;
+  }
+
+  s += n;
+
+  while (IS_WS(*s)) *s++ = '\0';
+
+  *ss = s;
+
+  if (type)
+    *type = result;
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept Accept Header
+ *
+ * The @b Accept request-header field can be used to specify certain media
+ * types which are acceptable for the response. Its syntax is defined in
+ * [H14.1, S20.1] as follows:
+ *
+ * @code
+ *    Accept         = "Accept" ":" #( media-range [ accept-params ] )
+ *
+ *    media-range    = ( "*" "/" "*"
+ *                     | ( type "/" "*" )
+ *                     | ( type "/" subtype ) ) *( ";" parameter )
+ *
+ *    accept-params  = ";" "q" "=" qvalue *( accept-extension )
+ *
+ *    accept-extension = ";" token [ "=" ( token | quoted-string ) ]
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept
+ * @typedef typedef struct msg_accept_s msg_accept_t;
+ *
+ * The structure msg_accept_t contains representation of an @b Accept
+ * header.
+ *
+ * The msg_accept_t is defined as follows:
+ * @code
+ * typedef struct msg_accept_s {
+ *   msg_common_t        ac_common[1]; // Common fragment info
+ *   msg_accept_t       *ac_next;      // Pointer to next Accept header
+ *   char const         *ac_type;      // Pointer to type/subtype
+ *   char const         *ac_subtype;   // Points after first slash in type
+ *   msg_param_t const  *ac_params;    // List of parameters
+ *   msg_param_t         ac_q;         // Value of q parameter
+ * } msg_accept_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_class[] =
+MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist, 
+		 msg_accept, msg_accept);
+
+issize_t msg_accept_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_accept_t *ac = (msg_accept_t *)h;
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if (*s == '\0') {
+    /* Empty Accept list is not an error */
+    ac->ac_type = ac->ac_subtype = "";
+    return 0;
+  }
+
+  /* "Accept:" #(type/subtyp ; *(parameters))) */
+  if (msg_mediatype_d(&s, &ac->ac_type) == -1)
+    return -1;
+  if (!(ac->ac_subtype = strchr(ac->ac_type, '/')))
+    return -1;
+  ac->ac_subtype++;
+
+  if (*s == ';' && msg_params_d(home, &s, &ac->ac_params) == -1)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t msg_accept_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  msg_accept_t const *ac = (msg_accept_t *)h;
+
+  assert(msg_is_accept(h));
+
+  if (ac->ac_type) {
+    MSG_STRING_E(b, end, ac->ac_type);
+    MSG_PARAMS_E(b, end, ac->ac_params, flags);
+  }
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+isize_t msg_accept_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_accept_t const *ac = (msg_accept_t *)h;
+
+  if (ac->ac_type) {
+    MSG_PARAMS_SIZE(offset, ac->ac_params);
+    offset += MSG_STRING_SIZE(ac->ac_type);
+  }
+
+  return offset;
+}
+
+/** Duplicate one msg_accept_t object */
+char *msg_accept_dup_one(msg_header_t *dst, msg_header_t const *src,
+		      char *b, isize_t xtra)
+{
+  msg_accept_t *ac = (msg_accept_t *)dst;
+  msg_accept_t const *o = (msg_accept_t *)src;
+  char *end = b + xtra;
+
+  if (o->ac_type) {
+    b = msg_params_dup(&ac->ac_params, o->ac_params, b, xtra);
+    MSG_STRING_DUP(b, ac->ac_type, o->ac_type);
+    if ((ac->ac_subtype = strchr(ac->ac_type, '/')))
+      ac->ac_subtype++;
+  }
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameter(s) for Accept header. */ 
+int msg_accept_update(msg_common_t *h, 
+		      char const *name, isize_t namelen,
+		      char const *value)
+{
+  msg_accept_t *ac = (msg_accept_t *)h;
+
+  if (name == NULL) {
+    ac->ac_q = NULL;
+  }
+  else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+    /* XXX - check for invalid value? */
+    ac->ac_q = value;
+  }
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/** Decode an Accept-* header. */
+issize_t msg_accept_any_d(su_home_t *home,
+			  msg_header_t *h,
+			  char *s, isize_t slen)
+{
+  /** @relatesalso msg_accept_any_s */
+  msg_accept_any_t *aa = (msg_accept_any_t *)h;
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if (*s == '\0')
+    return -2;			/* Empty list */
+
+  /* "Accept-*:" 1#(token *(SEMI accept-param)) */
+  if (msg_token_d(&s, &aa->aa_value) == -1)
+    return -1;
+
+  if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+/** Encode an Accept-* header field. */
+issize_t msg_accept_any_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  /** @relatesalso msg_accept_any_s */
+  char *b0 = b, *end = b + bsiz;
+  msg_accept_any_t const *aa = (msg_accept_any_t *)h;
+
+  MSG_STRING_E(b, end, aa->aa_value);
+  MSG_PARAMS_E(b, end, aa->aa_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra memory used by accept-* headers. */
+isize_t msg_accept_any_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  /** @relatesalso msg_accept_any_s */
+  msg_accept_any_t const *aa = (msg_accept_any_t *)h;
+
+  MSG_PARAMS_SIZE(offset, aa->aa_params);
+  offset += MSG_STRING_SIZE(aa->aa_value);
+
+  return offset;
+}
+
+/** Duplicate one msg_accept_any_t object. */
+char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
+			     char *b, isize_t xtra)
+{
+  /** @relatesalso msg_accept_any_s */
+  msg_accept_any_t *aa = (msg_accept_any_t *)dst;
+  msg_accept_any_t const *o = (msg_accept_any_t *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&aa->aa_params, o->aa_params, b, xtra);
+  MSG_STRING_DUP(b, aa->aa_value, o->aa_value);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameter(s) for Accept-* header. */ 
+int msg_accept_any_update(msg_common_t *h, 
+			  char const *name, isize_t namelen,
+			  char const *value)
+{
+  msg_accept_any_t *aa = (msg_accept_any_t *)h;
+
+  if (name == NULL) {
+    aa->aa_q = NULL;
+  }
+  else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+    aa->aa_q = value;
+  }
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_charset Accept-Charset Header
+ *
+ * The Accept-Charset header is similar to Accept, but restricts the
+ * character set that are acceptable in the response.  Its syntax is
+ * defined in [H14.2] as follows:
+ *
+ * @code
+ *    Accept-Charset = "Accept-Charset" ":"
+ *            1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_charset
+ * @typedef typedef struct msg_accept_charset_s msg_accept_charset_t;
+ *
+ * The structure msg_accept_encoding_t contains representation of @b
+ * Accept-Charset header.
+ *
+ * The msg_accept_charset_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t        aa_common[1]; // Common fragment info
+ *   msg_accept_any_t   *aa_next;      // Pointer to next Accept-Charset
+ *   char const         *aa_value;     // Charset
+ *   msg_param_t const  *aa_params;    // Parameter list
+ *   char const         *aa_q;	       // Q-value
+ * } msg_accept_charset_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_charset_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_charset, "Accept-Charset", "",
+		  aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_charset_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_charset_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  assert(msg_is_accept_charset(h));
+  return msg_accept_any_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_encoding Accept-Encoding Header
+ *
+ * The Accept-Encoding header is similar to Accept, but restricts the
+ * content-codings that are acceptable in the response.  Its syntax is
+ * defined in [H14.3, S20.2] as follows:
+ *
+ * @code
+ *    Accept-Encoding  = "Accept-Encoding" ":"
+ *                       1#( codings [ ";" "q" "=" qvalue ] )
+ *    codings          = ( content-coding | "*" )
+ *    content-coding   = token
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_encoding
+ * @typedef typedef struct msg_accept_encoding_s msg_accept_encoding_t;
+ *
+ * The structure msg_accept_encoding_t contains representation of @b
+ * Accept-Encoding header.
+ *
+ * The msg_accept_encoding_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t        aa_common[1]; // Common fragment info
+ *   msg_accept_any_t   *aa_next;      // Pointer to next Accept-Encoding
+ *   char const         *aa_value;     // Content-coding
+ *   msg_param_t const  *aa_params;    // Parameter list
+ *   char const         *aa_q;	       // Q-value
+ * } msg_accept_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_encoding_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_encoding, "Accept-Encoding", "",
+		  aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  return msg_accept_any_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_language Accept-Language Header
+ *
+ * The Accept-Language header allows the client to indicate to the server in
+ * which language it would prefer to receive reason phrases, session
+ * descriptions or status responses carried as message bodies. Its syntax is
+ * defined in [H14.4, S20.3] as follows:
+ *
+ * @code
+ *    Accept-Language = "Accept-Language" ":"
+ *                      1#( language-range [ ";" "q" "=" qvalue ] )
+ *
+ *    language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_language
+ * @typedef typedef struct msg_accept_language_s msg_accept_language_t;
+ *
+ * The structure msg_accept_language_t contains representation of @b
+ * Accept-Language header.
+ *
+ * The msg_accept_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t        aa_common[1]; // Common fragment info
+ *   msg_accept_any_t   *aa_next;      // Pointer to next Accept-Encoding
+ *   char const         *aa_value;     // Language-range
+ *   msg_param_t const  *aa_params;    // Parameter list
+ *   char const         *aa_q;	       // Q-value
+ * } msg_accept_language_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_language_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_language, "Accept-Language", "",
+		  aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  assert(msg_is_accept_language(h));
+  return msg_accept_any_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_disposition Content-Disposition Header
+ *
+ * The Content-Disposition header field describes how the message body or,
+ * in the case of multipart messages, a message body part is to be
+ * interpreted by the UAC or UAS.  Its syntax is defined in [S20.11]
+ * as follows:
+ *
+ * @code
+ *    Content-Disposition   =  "Content-Disposition" ":"
+ *                             disposition-type *( ";" disposition-param )
+ *    disposition-type      =  "render" | "session" | "icon" | "alert"
+ *                         |   disp-extension-token
+ *    disposition-param     =  "handling" "="
+ *                             ( "optional" | "required" | other-handling )
+ *                         |   generic-param
+ *    other-handling        =  token
+ *    disp-extension-token  =  token
+ * @endcode
+ *
+ * The Content-Disposition header was extended by
+ * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
+ *
+ * @code
+ *    Content-Disposition      =  "Content-Disposition" ":"
+ *                                disposition-type *( ";" disposition-param )
+ *    disposition-type        /=  "script" | "sip-cgi" | token
+ *    disposition-param       /=  action-param
+ *                             /  modification-date-param
+ *    action-param             =  "action" "=" action-value
+ *    action-value             =  "store" | "remove" | token
+ *    modification-date-param  =  "modification-date" "=" quoted-date-time
+ *    quoted-date-time         =  <"> SIP-date <">
+ * @endcode
+ */
+
+/**@ingroup msg_content_disposition
+ * @typedef struct msg_content_disposition_s msg_content_disposition_t; 
+ *
+ * The structure msg_content_disposition_t contains representation of an @b
+ * Content-Disposition header.
+ *
+ * The msg_content_disposition_t is defined as follows:
+ * @code
+ * typedef struct msg_content_disposition_s
+ * {
+ *   msg_common_t       cd_common[1];  // Common fragment info
+ *   msg_error_t       *cd_next;       // Link to next (dummy)
+ *   char const        *cd_type;       // Disposition type
+ *   msg_param_t const *cd_params;     // List of parameters
+ *   msg_param_t        cd_handling;   // Value of @b handling parameter
+ *   unsigned           cd_required:1; // True if handling=required
+ *   unsigned           cd_optional:1; // True if handling=optional
+ * } msg_content_disposition_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_disposition_class[] =
+MSG_HEADER_CLASS(msg_, content_disposition, "Content-Disposition", "",
+		 cd_params, single, msg_content_disposition,
+		 msg_content_disposition);
+
+issize_t msg_content_disposition_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
+
+  if (msg_token_d(&s, &cd->cd_type) < 0 ||
+      (*s == ';' && msg_params_d(home, &s, &cd->cd_params) < 0))
+      return -1;
+
+  if (cd->cd_params)
+    msg_header_update_params(cd->cd_common, 0);
+
+  return 0;
+}
+
+issize_t msg_content_disposition_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  char *b0 = b, *end = b + bsiz;
+  msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
+
+  assert(msg_is_content_disposition(h));
+
+  MSG_STRING_E(b, end, cd->cd_type);
+  MSG_PARAMS_E(b, end, cd->cd_params, f);
+
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+isize_t msg_content_disposition_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
+
+  MSG_PARAMS_SIZE(offset, cd->cd_params);
+  offset += MSG_STRING_SIZE(cd->cd_type);
+
+  return offset;
+}
+
+/** Duplicate one msg_content_disposition_t object */
+char *msg_content_disposition_dup_one(msg_header_t *dst,
+				     msg_header_t const *src,
+				     char *b, isize_t xtra)
+{
+  msg_content_disposition_t *cd = (msg_content_disposition_t *)dst;
+  msg_content_disposition_t const *o = (msg_content_disposition_t *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&cd->cd_params, o->cd_params, b, xtra);
+  MSG_STRING_DUP(b, cd->cd_type, o->cd_type);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update Content-Disposition parameters */
+int msg_content_disposition_update(msg_common_t *h,
+				   char const *name, isize_t namelen,
+				   char const *value)
+{
+  msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
+
+  if (name == NULL) {
+    cd->cd_handling = NULL, cd->cd_required = 0, cd->cd_optional = 0;
+  }
+  else if (namelen == strlen("handling") &&
+	   strncasecmp(name, "handling", namelen) == 0) {
+    cd->cd_handling = value;
+    cd->cd_required = strcasecmp(value, "required") == 0;
+    cd->cd_optional = strcasecmp(value, "optional") == 0;
+  }
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_encoding Content-Encoding Header
+ *
+ * The Content-Encoding header indicates what additional content codings
+ * have been applied to the entity-body. Its syntax is defined in [H14.11]
+ * and [S20.12] as follows:
+ *
+ * @code
+ *    Content-Encoding = ( "Content-Encoding" / "e" ) ":" 1#content-coding
+ *    content-coding   = token
+ * @endcode
+ */
+
+/**@ingroup msg_content_encoding
+ * @typedef struct msg_list_s msg_content_encoding_t; 
+ *
+ * The structure msg_content_encoding_t contains representation of an @b
+ * Content-Encoding header.
+ *
+ * The msg_content_encoding_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } msg_content_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_encoding_class[] =
+  MSG_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
+
+issize_t msg_content_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_content_encoding_t *e = (msg_content_encoding_t *)h;
+  return msg_commalist_d(home, &s, &e->k_items, msg_token_scan);
+}
+
+issize_t msg_content_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  assert(msg_is_content_encoding(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_language Content-Language Header
+ *
+ * The Content-Language header describes the natural language(s) of the
+ * intended audience for the enclosed message body. Note that this might not
+ * be equivalent to all the languages used within the message-body. Its
+ * syntax is defined in [H14.12, S20.13] as follows:
+ *
+ * @code
+ *    Content-Language  = "Content-Language" ":" 1#language-tag
+ * @endcode
+ * or
+ * @code
+ *    Content-Language  =  "Content-Language" HCOLON
+ *                         language-tag *(COMMA language-tag)
+ *    language-tag      =  primary-tag *( "-" subtag )
+ *    primary-tag       =  1*8ALPHA
+ *    subtag            =  1*8ALPHA
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_content_language
+ * @typedef typedef struct msg_content_language_s msg_content_language_t;
+ *
+ * The structure msg_content_language_t contains representation of @b
+ * Content-Language header.
+ *
+ * The msg_content_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t            k_common[1]; // Common fragment info
+ *   msg_content_language_t *k_next;      // (Content-Encoding header)
+ *   msg_param_t            *k_items;     // List of languages
+ * } msg_content_language_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_language_class[] =
+MSG_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);
+
+issize_t msg_content_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_content_language_t *k = (msg_content_language_t *)h;
+  return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t msg_content_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  assert(msg_is_content_language(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_length Content-Length Header
+ *
+ * The Content-Length header indicates the size of the message-body in
+ * decimal number of octets.  Its syntax is defined in [S10.18] as
+ * follows:
+ *
+ * @code
+ *    Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_content_length
+ * @typedef typedef struct msg_content_length_s msg_content_length_t;
+ *
+ * The structure msg_content_length_t contains representation of a
+ * Content-Length header.
+ *
+ * The msg_content_length_t is defined as follows:
+ * @code
+ * typedef struct msg_content_length_s {
+ *   msg_common_t   l_common[1];        // Common fragment info
+ *   msg_error_t   *l_next;             // Link to next (dummy)
+ *   unsigned long  l_length;           // Numeric value
+ * } msg_content_length_t;
+ * @endcode
+ */
+
+#define msg_content_length_d msg_numeric_d
+#define msg_content_length_e msg_numeric_e
+
+msg_hclass_t msg_content_length_class[] =
+MSG_HEADER_CLASS(msg_, content_length, "Content-Length", "l",
+		 l_common, single_critical, msg_default, msg_generic);
+
+/**@ingroup msg_content_length
+ * Create a @b Content-Length header object.
+ *
+ * The function msg_content_length_create() creates a Content-Length
+ * header object with the value @a n.  The memory for the header is
+ * allocated from the memory home @a home.
+ *
+ * @param home  memory home
+ * @param n     payload size in bytes
+ *
+ * @return
+ * The function msg_content_length_create() returns a pointer to newly
+ * created @b Content-Length header object when successful or NULL upon
+ * an error.
+ */
+msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n)
+{
+  msg_content_length_t *l = (msg_content_length_t *)
+    msg_header_alloc(home, msg_content_length_class, 0);
+
+  if (l)
+    l->l_length = n;
+
+  return l;
+}
+
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_md5 Content-MD5 Header
+ *
+ * The Content-MD5 header is an MD5 digest of the entity-body for the
+ * purpose of providing an end-to-end message integrity check (MIC) of the
+ * message-body. Its syntax is defined in [@RFC1864, H14.15] as follows:
+ *
+ * @code
+ *      Content-MD5   = "Content-MD5" ":" md5-digest
+ *      md5-digest   = <base64 of 128 bit MD5 digest as per @RFC1864>
+ * @endcode
+ */
+
+/**@ingroup msg_content_md5
+ * @typedef struct msg_generic_s msg_content_md5_t; 
+ *
+ * The structure msg_content_md5_t contains representation of an @b
+ * Content-MD5 header.
+ *
+ * The msg_content_md5_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Header value
+ * } msg_content_md5_t;
+ * @endcode
+ */
+
+#define msg_content_md5_d msg_generic_d
+#define msg_content_md5_e msg_generic_e
+msg_hclass_t msg_content_md5_class[] =
+MSG_HEADER_CLASS_G(content_md5, "Content-MD5", "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_id Content-ID Header
+ *
+ * The Content-ID header is an unique identifier of an entity-body. The
+ * Content-ID value may be used for uniquely identifying MIME entities in
+ * several contexts, particularly for caching data referenced by the
+ * message/external-body mechanism. Its syntax is defined in [RFC2045] as
+ * follows:
+ *
+ * @code
+ *      Content-ID   = "Content-ID" ":" msg-id
+ *      msg-id       = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+ *      id-left      = dot-atom-text / no-fold-quote / obs-id-left
+ *      id-right     = dot-atom-text / no-fold-literal / obs-id-right
+ * @endcode
+ */
+
+/**@ingroup msg_content_id
+ * @typedef msg_generic_t msg_content_id_t;
+ * Content-ID Header Structure.
+ * @code
+ * typedef struct
+ * {
+ *   msg_common_t      g_common[1];    // Common fragment info
+ *   msg_content_id_t *g_next;	       // Link to next header
+ *   char const       *g_string;       // Header value
+ * }
+ * @endcode
+ */
+
+#define msg_content_id_d msg_generic_d
+#define msg_content_id_e msg_generic_e
+msg_hclass_t msg_content_id_class[] =
+MSG_HEADER_CLASS_G(content_id, "Content-ID", "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_type Content-Type Header
+ *
+ * The @b Content-Type header indicates the media type of the message-body
+ * sent to the recipient. Its syntax is defined in [H3.7, S20.15]
+ * as follows:
+ *
+ * @code
+ *    Content-Type  = ( "Content-Type" | "c" ) ":" media-type
+ *    media-type    = type "/" subtype *( ";" parameter )
+ *    type          = token
+ *    subtype       = token
+ * @endcode
+ */
+
+/**@ingroup msg_content_type
+ * @typedef typedef struct msg_content_type_s msg_content_type_t;
+ *
+ * The structure msg_content_type_t contains representation of @b
+ * Content-Type header.
+ *
+ * The msg_content_type_t is defined as follows:
+ * @code
+ * typedef struct msg_content_type_s {
+ *   msg_common_t        c_common[1];  // Common fragment info
+ *   msg_unknown_t      *c_next;       // Dummy link to next
+ *   char const         *c_type;       // Pointer to type/subtype
+ *   char const         *c_subtype;    // Points after first slash in type
+ *   msg_param_t const  *c_params;     // List of parameters
+ * } msg_content_type_t;
+ * @endcode
+ *
+ * The @a c_type is always void of whitespace, that is, there is no
+ * whitespace around the slash.
+ */
+
+#define msg_content_type_update NULL
+
+msg_hclass_t msg_content_type_class[] =
+MSG_HEADER_CLASS(msg_, content_type, "Content-Type", "c", c_params,
+		 single, msg_content_type, msg_content_type);
+
+issize_t msg_content_type_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_content_type_t *c;
+
+  assert(h);
+
+  c = (msg_content_type_t *)h;
+
+  /* "Content-type:" type/subtyp *(; parameter))) */
+  if (msg_mediatype_d(&s, &c->c_type) == -1 || /* compacts token / token */
+      (c->c_subtype = strchr(c->c_type, '/')) == NULL ||
+      (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
+      (*s != '\0'))
+    return -1;
+
+  c->c_subtype++;
+
+  return 0;
+}
+
+issize_t msg_content_type_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  msg_content_type_t const *c = (msg_content_type_t *)h;
+
+  assert(msg_is_content_type(h));
+
+  MSG_STRING_E(b, end, c->c_type);
+  MSG_PARAMS_E(b, end, c->c_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+isize_t msg_content_type_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_content_type_t const *c = (msg_content_type_t *)h;
+
+  MSG_PARAMS_SIZE(offset, c->c_params);
+  offset += MSG_STRING_SIZE(c->c_type);
+
+  return offset;
+}
+
+/** Duplicate one msg_content_type_t object */
+char *msg_content_type_dup_one(msg_header_t *dst, msg_header_t const *src,
+			       char *b, isize_t xtra)
+{
+  msg_content_type_t *c = (msg_content_type_t *)dst;
+  msg_content_type_t const *o = (msg_content_type_t *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+  MSG_STRING_DUP(b, c->c_type, o->c_type);
+  c->c_subtype = strchr(c->c_type, '/');
+  c->c_subtype++;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_mime_version MIME-Version Header
+ *
+ * MIME-Version header indicates what version of the protocol was used
+ * to construct the message.  Its syntax is defined in [H19.4.1, S20.24]
+ * as follows:
+ *
+ * @code
+ *    MIME-Version   = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+ * @endcode
+ */
+
+/**@ingroup msg_mime_version
+ * @typedef struct msg_generic_s msg_mime_version_t; 
+ *
+ * The structure msg_mime_version_t contains representation of an @b
+ * MIME-Version header.
+ *
+ * The msg_mime_version_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Header value
+ * } msg_mime_version_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_mime_version_class[] =
+MSG_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);
+
+issize_t msg_mime_version_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return msg_generic_d(home, h, s, slen);
+}
+
+issize_t msg_mime_version_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  assert(msg_is_mime_version(h));
+  return msg_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_location Content-Location Header
+ *
+ *
+ */
+
+/**@ingroup msg_content_location
+ * @typedef struct msg_generic_s msg_content_location_t; 
+ *
+ * The structure msg_content_location_t contains representation of an @b
+ * Content-Location header.
+ *
+ * The msg_content_location_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Header value
+ * } msg_content_location_t;
+ * @endcode
+ */
+
+#define msg_content_location_d msg_generic_d
+#define msg_content_location_e msg_generic_e
+msg_hclass_t msg_content_location_class[] =
+MSG_HEADER_CLASS_G(content_location, "Content-Location", "", single);
+
+
+/* ====================================================================== */
+#if 0
+/**@ingroup msg_mime
+ * @defgroup msg_content_base Content-Base Header
+ *
+ * @RFC2617:
+ * Content-Base was deleted from the specification: it was not
+ * implemented widely, and there is no simple, safe way to introduce it
+ * without a robust extension mechanism. In addition, it is used in a
+ * similar, but not identical fashion in MHTML [45].
+ *
+ */
+
+
+/**@ingroup msg_content_base
+ * @typedef msg_generic_t msg_content_base_t;
+ * Content-Base Header Structure.
+ * @code
+ * typedef struct
+ * {
+ *   msg_common_t        g_common[1];    // Common fragment info
+ *   msg_content_base_t *g_next;	 // Link to next header
+ *   char const         *g_string;       // Header value
+ * }
+ * @endcode
+ */
+
+#define msg_content_base_d msg_generic_d
+#define msg_content_base_e msg_generic_e
+msg_hclass_t msg_content_base_class[] =
+MSG_HEADER_CLASS_G(content_base, "Content-Base", "", single);
+
+#endif
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_transfer_encoding Content-Transfer-Encoding Header
+ *
+ *
+ */
+
+/**@ingroup msg_content_transfer_encoding
+ * @typedef struct msg_generic_s msg_content_transfer_encoding_t; 
+ *
+ * The structure msg_content_transfer_encoding_t contains representation of
+ * an @b Content-Transfer-Encoding header.
+ *
+ * The msg_content_transfer_encoding_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Header value
+ * } msg_content_transfer_encoding_t;
+ * @endcode
+ */
+
+
+#define msg_content_transfer_encoding_d msg_generic_d
+#define msg_content_transfer_encoding_e msg_generic_e
+msg_hclass_t msg_content_transfer_encoding_class[] =
+MSG_HEADER_CLASS_G(content_transfer_encoding, "Content-Transfer-Encoding",
+		   "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_warning Warning Header
+ * 
+ * The Warning response-header field is used to carry additional information
+ * about the status of a response. Its syntax is defined in [S20.43]
+ * as follows:
+ * 
+ * @code
+ *    Warning        =  "Warning" HCOLON warning-value *(COMMA warning-value)
+ *    warning-value  =  warn-code SP warn-agent SP warn-text
+ *    warn-code      =  3DIGIT
+ *    warn-agent     =  hostport / pseudonym
+ *                      ;  the name or pseudonym of the server adding
+ *                      ;  the Warning header, for use in debugging
+ *    warn-text      =  quoted-string
+ *    pseudonym      =  token
+ * @endcode
+ */
+
+/**@ingroup msg_warning
+ * @typedef struct msg_warning_s msg_warning_t; 
+ *
+ * The structure msg_warning_t contains representation of an @b
+ * Warning header.
+ *
+ * The msg_warning_t is defined as follows:
+ * @code
+ * typedef struct msg_warning_s
+ * {
+ *   msg_common_t        w_common[1];  // Common fragment info
+ *   msg_warning_t      *w_next;       // Link to next Warning header
+ *   unsigned            w_code;       // Warning code
+ *   char const         *w_host;       // Hostname or pseudonym
+ *   char const         *w_port;       // Port number
+ *   char const         *w_text;       // Warning text
+ * } msg_warning_t;
+ * @endcode
+ */
+
+issize_t msg_warning_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_warning_t *w = (msg_warning_t *)h;
+  char *text;
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  /* Parse protocol */
+  if (!IS_DIGIT(*s))	
+    return -1;
+  w->w_code = strtoul(s, &s, 10);
+  skip_lws(&s);
+
+  /* Host (and port) */
+  if (msg_hostport_d(&s, &w->w_host, &w->w_port) == -1)
+    return -1;
+  if (msg_quoted_d(&s, &text) == -1)
+    return -1;
+  if (msg_unquote(text, text) == NULL)
+    return -1;
+
+  w->w_text = text;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t msg_warning_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+  msg_warning_t const *w = (msg_warning_t *)h;
+  char const *port = w->w_port;
+  int n;
+  size_t m;
+
+  n = snprintf(b, bsiz, "%03u %s%s%s ", 
+	       w->w_code, w->w_host, port ? ":" : "", port ? port : "");
+  if (n < 0)
+    return n;
+
+  m = msg_unquoted_e((size_t)n < bsiz ? b + n : NULL, bsiz - n, w->w_text);
+
+  if (b && n + m < bsiz)
+    b[n + m] = '\0';
+
+  return n + m;
+}
+
+isize_t msg_warning_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  msg_warning_t const *w = (msg_warning_t *)h;
+
+  offset += MSG_STRING_SIZE(w->w_host);
+  offset += MSG_STRING_SIZE(w->w_port);
+  offset += MSG_STRING_SIZE(w->w_text);
+
+  return offset;
+}
+
+char *msg_warning_dup_one(msg_header_t *dst, 
+			  msg_header_t const *src, 
+			  char *b, 
+			  isize_t xtra)
+{
+  msg_warning_t *w = (msg_warning_t *)dst;
+  msg_warning_t const *o = (msg_warning_t *)src;
+  char *end = b + xtra;
+
+  w->w_code = o->w_code;
+  MSG_STRING_DUP(b, w->w_host, o->w_host);
+  MSG_STRING_DUP(b, w->w_port, o->w_port);
+  MSG_STRING_DUP(b, w->w_text, o->w_text);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+#define msg_warning_update NULL
+
+msg_hclass_t msg_warning_class[] = 
+  MSG_HEADER_CLASS(msg_, warning, "Warning", "", w_common, append, 
+		   msg_warning, msg_warning);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+/**@ingroup msg_mime
+ * @IFILE msg_mime_table.c.in
+ *
+ * Template for <msg_mime_table.c>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_mime
+ * 
+ * @CFILE msg_mime_table.c 
+ * @brief Parser table used for testing.
+ *
+ * #AUTO#
+ *
+ * This file is generated from template <msg_mime_table.c.in>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/msg_mime.h>
+#include <sofia-sip/msg_mime_protos.h>
+
+#include <sofia-sip/msg_mclass.h>
+
+#define msg_multipart_extract_body NULL
+
+#define msg_request_class NULL
+#define mp_request mp_common
+
+#define msg_status_class NULL
+#define mp_status  mp_common
+
+#define msg_multipart_update NULL
+
+#define MSG_MULTIPART_HCLASS                                   \
+MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, \
+	         msg_multipart, msg_multipart)
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ * @CFILE msg_name_hash.c
+ * 
+ * Calculate hash for given header name. 
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Tue Aug 20 16:27:01 EEST 2002 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include <sofia-sip/su_alloc.h>
+
+#include <sofia-sip/msg_mclass_hash.h>
+
+int main(int argc, char *argv[])
+{
+  if (!argv[1] || argv[2]) {
+    fprintf(stderr, "usage: msg_name_hash Header-Name\n");
+    exit(1);
+  }
+  printf("%d\n", msg_header_name_hash(argv[1], NULL));
+  exit(0);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,512 @@
+#! /usr/bin/env awk
+#
+# This script recreates C files containing header-specific boilerplate stuff
+# using the given list of headers (usually obtained from the master structure).
+#
+# It can also create a parser table.
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Contributor(s): Pekka.Pessi at nokia.com.
+#
+# Created: Fri Apr  6 12:59:59 2001 ppessi
+#
+
+BEGIN {
+  "date '+%a %b %e %H:%M:%S %Y'" | getline date;
+
+  ascii =			       \
+     "                               " \
+    " !\"#$%&'()*+,-./0123456789:;<=>?" \
+    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \
+    "`abcdefghijklmnopqrstuvwxyz{|}~";
+  lower_case = "abcdefghijklmnopqrstuvwxyz";
+
+  N=0;
+  # Initialize these as arrays
+  split("", symbols);
+  split("", names);
+  split("", comments); 
+  split("", hashes);
+  split("", NAMES);
+  split("", Comments);
+  split("", COMMENTS);
+
+  # indexed by the C name of the header
+  split("", Since);		# Non-NUL if extra
+  split("", Extra);		# Offset in extra headers
+
+  template="";
+  template1="";
+  template2="";
+  template3="";
+  prefix="";
+  tprefix="";
+  extra=0;
+  failed=0;
+  success=0;
+
+  extra_struct = "msg_pub_extra";
+
+  ERRNO="error";
+}
+
+function name_hash (name)
+{
+  hash = 0;
+
+  len = split(name, chars, "");
+
+  for (i = 1; i <= len; i++) {
+    c = tolower(chars[i]);
+    hash = (38501 * (hash + index(ascii, c))) % 65536;
+  }
+
+  if (0) {
+    # Test that hash algorithm above agrees with the C version
+    pipe = ("../msg/msg_name_hash " name);
+    pipe | getline;
+    close(pipe);
+    if (hash != $0) {
+      print name ": " hash " != " $0 > "/dev/stderr";
+    }
+  }
+
+  return hash "";
+}
+
+#
+# Replace magic patterns in template p with header-specific values
+#
+function protos (name, comment, hash, since)
+{
+  NAME=toupper(name);
+  sub(/.*[\/][*][*][<][ 	]*/, "", comment); 
+  sub(/[ 	]*[*][\/].*/, "", comment);
+  sub(/[ 	]+/, " ", comment);
+
+  short = match(comment, /[(][a-z][)]/);
+  if (short) {
+    short = substr(comment, short + 1, 1);
+    sub(/ *[(][a-z][)]/, "", comment);
+    shorts[index(lower_case, short)] = name;
+  }
+
+  do_hash = hash == 0;
+
+  if (do_hash) {
+    split(comment, parts, " ");
+    name2 = tolower(parts[1]);
+    gsub(/-/, "_", name2);
+    if (name2 != name && name2 != tprefix "_" name) {
+      print name " mismatch with " comment " (" real ")" > "/dev/stderr";
+    }
+    
+    hash = name_hash(parts[1]);
+
+    hashed[name] = hash;
+
+    if (comment !~ /header/) { 
+      comment = comment " header";
+    }
+  }
+
+  Comment = comment;
+  if (!do_hash) {
+    comment = tolower(comment);
+  }
+  COMMENT = toupper(comment);
+
+  # Store the various forms into an array for the footer processing
+  N++; 
+  hashes[N] = hash; 
+  names[N] = name;
+  NAMES[N] = NAME; 
+  comments[N] = comment; 
+  Comments[N] = comment; 
+  COMMENTS[N] = COMMENT; 
+
+  symbols[name] = comment;
+  if (since) {
+    Since[name] = since;
+    Extra[name] = extra++;
+  }
+
+  if (PR) {
+    replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
+    replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
+    replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
+    replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
+  }
+}
+
+function replace (p, hash, name, NAME, comment, Comment, COMMENT, since)
+{
+  #
+  # Replace various forms of header name in template, print it out
+  #
+  if (p) {
+    gsub(/#hash#/, hash, p);
+    gsub(/#xxxxxx#/, name, p); 
+    gsub(/#XXXXXX#/, NAME, p);
+    gsub(/#xxxxxxx_xxxxxxx#/, comment, p);
+    gsub(/#Xxxxxxx_Xxxxxxx#/, Comment, p);
+    gsub(/#XXXXXXX_XXXXXXX#/, COMMENT, p);
+
+    if (since) {
+      gsub(/#version#/, since, p);
+    }
+    else {
+      # Remove line with #version#
+      gsub(/\n[^\n]*#version#[^\n]*\n/, "\n", p);
+    }
+    	    
+    print p > PR;
+  }
+}
+
+# 
+# Repeat each line in the footer containing the magic replacement
+# pattern with a instance of all headers
+#
+function process_footer (text)
+{ 
+  if (!match(tolower(text), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
+    n = length(text);
+    while (substr(text, n) == "\n") {
+      n = n - 1;
+      text = substr(text, 1, n);
+    }
+    if (n > 0)
+      print text > PR;
+    return;
+  }
+  
+  n = split(text, lines, RS);
+
+  for (i = 1; i <= n; i++) {
+    l = lines[i];
+    if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
+      for (j = 1; j <= N; j++) {
+	l = lines[i];
+	gsub(/#hash#/, hashes[j], l);
+	gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
+	gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
+	gsub(/#XXXXXXX_XXXXXXX#/, COMMENTS[j], l);
+	gsub(/#xxxxxx#/, names[j], l); 
+	gsub(/#XXXXXX#/, NAMES[j], l);
+	print l > PR;
+      }
+    } else {
+      print l > PR;
+    }
+  }
+}
+
+#
+# Read flags used with headers
+#
+function read_header_flags (flagfile,    line, tokens, name, value)
+{
+  while ((getline line < flagfile) > 0) {
+    sub(/^[ \t]+/, "", line);
+    sub(/[ \t]+$/, "", line);
+    if (line ~ /^#/ || line ~ /^$/)
+      continue;
+
+    split(line, tokens,  /[ \t]*=[ \t]*/); 
+    name = tolower(tokens[1]);
+    gsub(/-/, "_", name);
+    gsub(/,/, " ", name);
+    # print "FLAG: " name " = " tokens[2]
+
+    if (header_flags[name]) {
+      print flagfile ": already defined " tokens[1];
+    }
+    else if (!symbols[name]) {
+      print flagfile ": unknown header \"" tokens[1] "\"";
+    }
+    else {
+      header_flags[name] = tokens[2];
+    }
+  }
+  close(flagfile);
+}
+
+#
+# Read in templates
+#
+function templates ()
+{
+  if (!auto) {
+    auto = FILENAME; 
+
+    if (!prefix) { prefix = module; }
+    if (!tprefix) { tprefix = prefix; }
+
+    sub(/.*\//, "", auto);
+    auto = "This file is automatically generated from <" auto "> by msg_parser.awk.";
+
+    if (PR) {
+      if (TEMPLATE == "") { TEMPLATE = PR ".in"; }
+      RS0=RS; RS="\f\n";
+      if ((getline theader < TEMPLATE) < 0) {
+	print ( TEMPLATE ": " ERRNO );
+	failed=1;
+        exit(1);
+      }
+      getline header < TEMPLATE;
+      getline template < TEMPLATE;
+      getline footer < TEMPLATE;
+
+      if (TEMPLATE1) {
+	if ((getline dummy < TEMPLATE1) < 0) {
+	  print(TEMPLATE1 ": " ERRNO);
+	  failed=1;
+          exit(1);
+        }
+	getline dummy < TEMPLATE1;
+	getline template1 < TEMPLATE1;
+	getline dummy < TEMPLATE1;
+      }
+
+      if (TEMPLATE2) {
+	if ((getline dummy < TEMPLATE2) < 0) {
+	  print( TEMPLATE2 ": " ERRNO );
+	  failed=1;
+	  exit(1);
+	}
+	getline dummy < TEMPLATE2;
+	getline template2 < TEMPLATE2;
+	getline dummy < TEMPLATE2;
+      }
+
+      if (TEMPLATE3) {
+	if ((getline dummy < TEMPLATE3) < 0) {
+	  print( TEMPLATE3 ": " ERRNO );
+	  failed=1;
+	  exit(1);
+	}
+	getline dummy < TEMPLATE3;
+	getline template3 < TEMPLATE3;
+	getline dummy < TEMPLATE3;
+      }
+
+      sub(/.*[\/]/, "", TEMPLATE);
+      gsub(/#AUTO#/, auto, header);
+      gsub(/#DATE#/, "@date Generated: " date, header);
+      if (PACKAGE_NAME) gsub(/#PACKAGE_NAME#/, PACKAGE_NAME, header);
+      if (PACKAGE_VERSION) gsub(/#PACKAGE_VERSION#/, PACKAGE_VERSION, header);
+      print header > PR;
+
+      RS=RS0;
+    }
+
+    if (!NO_FIRST) {
+      protos("request", "/**< Request line */", -1);
+      protos("status", "/**< Status line */", -2);
+    }
+  }
+}
+
+/^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
+HLIST && /^[a-z]/ { protos($1, $0, 0, $2); headers[total++] = $1; }
+/^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0;  }
+
+
+/^ *\/\* === Headers start here \*\// { in_header_list=1;  templates(); }
+/^ *\/\* === Headers end here \*\// { in_header_list=0; }
+
+PT && /^ *\/\* === Hash headers end here \*\// { in_header_list=0;}
+
+in_header_list && /^  (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ { 
+  n=$0
+  sub(/;.*$/, "", n);   
+  sub(/^ *(sip|rtsp|http|msg|mp)_[a-z0-9_]*_t[ 	]*/, "", n);
+  sub(/^[*](sip|rtsp|http|msg|mp)_/, "", n);
+
+  if ($0 !~ /[\/][*][*][<]/) {
+    getline; 
+  }
+  if ($0 !~ /[\/][*][*][<]/) {
+    printf "msg_protos.awk: header %s is malformed\n", n;
+    failed=1;
+    exit 1;
+  }
+
+  if (!NO_MIDDLE)
+    protos(n, $0, 0);
+
+  headers[total++] = n;
+}
+
+END {
+  if (failed) { exit };
+
+  if (!NO_LAST) {
+    protos("unknown", "/**< Unknown headers */", -3);
+    protos("error", "/**< Erroneous headers */", -4);
+    protos("separator", "/**< Separator line between headers and payload */", -5);
+    protos("payload", "/**< Message payload */", -6);
+    if (multipart)
+      protos("multipart", "/**< Multipart payload */", -7);
+  }
+    
+  if (PR) {
+    process_footer(footer);
+  }
+  else if (PT) {
+    if (FLAGFILE)
+      read_header_flags(FLAGFILE);
+
+    if (TEMPLATE == "") { TEMPLATE = PT ".in"; }
+    RS0=RS; RS="\n";
+    getline theader < TEMPLATE;
+    getline header < TEMPLATE;
+    getline template < TEMPLATE;
+    getline footer < TEMPLATE;
+    RS=RS0;
+
+    module_struct = module "_t";
+
+    sub(/.*[\/]/, "", TEMPLATE);
+    gsub(/#AUTO#/, auto, header);
+    gsub(/#DATE#/, "@date Generated: " date, header);
+    print header > PT;
+
+    if (MC_SHORT_SIZE) {
+      printf("static msg_href_t const " \
+	     "%s_short_forms[MC_SHORT_SIZE] = \n{\n", 
+	     module) > PT;      
+
+      for (i = 1; i <= MC_SHORT_SIZE; i = i + 1) {
+	c = (i == MC_SHORT_SIZE) ? "" : ",";
+	if (i in shorts) {
+	  n = shorts[i];
+        flags = header_flags[n]; if (flags) flags = ",\n      " flags;
+	  
+	  printf("  { /* %s */ %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n", 
+		 substr(lower_case, i, 1), 
+		 tprefix, n, module, prefix, n, flags, c)	\
+	    > PT;
+	}
+	else {
+	  printf("  { NULL }%s\n", c) \
+	    > PT;
+	}
+      }
+      printf("};\n\n") > PT;      
+    }
+
+    # printf("extern msg_hclass_t msg_multipart_class[];\n\n") > PT;
+
+    if (extra > 0) {
+      printf("struct %s {\n", extra_struct) > PT;
+      printf("  %s base;\n", module_struct) > PT;
+      printf("  msg_header_t *extra[%u];\n", extra) > PT;
+      printf("};\n\n") > PT;
+      module_struct = "struct " extra_struct;
+    }
+
+    printf("msg_mclass_t const %s_mclass[1] = \n{{\n", module) > PT;
+    printf("# if defined (%s_HCLASS)\n", toupper(module)) > PT;
+    printf("  %s_HCLASS,\n", toupper(module)) > PT;
+    printf("#else\n") > PT;
+    printf("  {{ 0 }},\n") > PT;
+    printf("#endif\n") > PT;
+    printf("  %s_VERSION_CURRENT,\n", toupper(module)) > PT;
+    printf("  %s_PROTOCOL_TAG,\n", toupper(module)) > PT;
+    printf("#if defined (%s_PARSER_FLAGS)\n", toupper(module)) > PT;
+    printf("  %s_PARSER_FLAGS,\n", toupper(module)) > PT;
+    printf("#else\n") > PT;
+    printf("  0,\n") > PT;
+    printf("#endif\n") > PT;
+    printf("  sizeof (%s),\n", module_struct) > PT;
+    printf("  %s_extract_body,\n", module) > PT;
+
+    len = split("request status separator payload unknown error", unnamed, " ");
+
+    for (i = 1; i <= len; i++) {
+      printf("  {{ %s_%s_class, offsetof(%s_t, %s_%s) }},\n", 
+	     tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
+    }
+    if (multipart) {
+      printf("  {{ %s_class, offsetof(%s_t, %s_multipart) }},\n",
+	     multipart, module, prefix) > PT;
+    } else {
+      printf("  {{ NULL, 0 }},\n") > PT;
+    }
+    if (MC_SHORT_SIZE) {
+      printf("  %s_short_forms, \n", module) > PT;      
+    }
+    else {
+      printf("  NULL, \n") > PT;
+    }
+    printf("  %d, %d, \n", MC_HASH_SIZE, total) > PT;
+    printf("  {\n") > PT;
+
+    for (i = 0; i < total; i++) {
+      n = headers[i];
+      h = hashed[n];
+
+      if (h < 0)
+	continue;
+
+      j = h % MC_HASH_SIZE; if (j == -0) j = 0;
+
+      for (; j in header_hash;) {
+	if (++j == MC_HASH_SIZE) {
+	  j = 0;
+	}
+      }
+
+      header_hash[j] = n;
+    }
+
+    for (i = 0; i < MC_HASH_SIZE; i++) {
+      c = (i + 1 == MC_HASH_SIZE) ? "" : ",";
+      if (i in header_hash) {
+	n = header_hash[i];
+        flags = header_flags[n]; if (flags) flags = ",\n      " flags;
+
+	if (Since[n]) {
+	  printf("    { %s_%s_class, offsetof(struct %s, extra[%u])%s }%s\n", 
+		 tprefix, n, extra_struct, Extra[n], flags, c) > PT;
+	}
+	else {
+	  printf("    { %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n", 
+		 tprefix, n, module, prefix, n, flags, c) > PT;
+	}
+      }
+      else {
+	printf("    { NULL, 0 }%s\n", c) > PT;
+      }
+    }
+    printf("  }\n}};\n\n") > PT;
+  }
+
+  exit success;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3042 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_parser.c
+ *
+ * HTTP-like message parser engine.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct  5 14:01:24 2000 ppessi
+ *
+ */
+
+/*#define NDEBUG*/
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <stdarg.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg_header.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_mclass_hash.h"
+#include "sofia-sip/msg_mime.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "msg_parser";
+#endif
+
+static int _msg_header_add_dup_as(msg_t *msg,
+				  msg_pub_t *pub,
+				  msg_hclass_t *hc,
+				  msg_header_t const *src);
+
+static void msg_insert_chain(msg_t *msg, msg_pub_t *pub, int prepend,
+			     msg_header_t **head, msg_header_t *h);
+static void msg_insert_here_in_chain(msg_t *msg,
+				     msg_header_t **prev,
+				     msg_header_t *h);
+static inline msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h);
+
+#ifndef NDEBUG
+static int msg_chain_loop(msg_header_t const *h);
+static int msg_chain_errors(msg_header_t const *h);
+#endif
+
+/* ====================================================================== */
+/* Message properties */
+
+/** Get message flags. */
+unsigned msg_get_flags(msg_t const *msg, unsigned mask)
+{
+  return msg ? msg->m_object->msg_flags & mask : 0;
+}
+
+/** Set message flags. */
+unsigned msg_set_flags(msg_t *msg, unsigned mask)
+{
+  return msg ? msg->m_object->msg_flags |= mask : 0;
+}
+
+/** Clear message flags. */
+unsigned msg_zap_flags(msg_t *msg, unsigned mask)
+{
+  return msg ? msg->m_object->msg_flags &= ~mask : 0;
+}
+
+/** Test if streaming is in progress. */
+int msg_is_streaming(msg_t const *msg)
+{
+  return msg && msg->m_streaming != 0;
+}
+
+/** Enable/disable streaming */
+void msg_set_streaming(msg_t *msg, enum msg_streaming_status what)
+{
+  if (msg)
+    msg->m_streaming = what != 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Test if header is not in the chain */
+#define msg_header_is_removed(h) ((h)->sh_prev == NULL)
+
+static inline int msg_is_request(msg_header_t const *h)
+{
+  return h->sh_class->hc_hash == msg_request_hash;
+}
+
+static inline int msg_is_status(msg_header_t const *h)
+{
+  return h->sh_class->hc_hash == msg_status_hash;
+}
+
+/* ====================================================================== */
+/* Message buffer management */
+
+/** Allocate a buffer of @a size octets, with slack of #msg_min_size. */
+void *msg_buf_alloc(msg_t *msg, usize_t size)
+{
+  struct msg_mbuffer_s *mb = msg->m_buffer;
+  size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
+  size_t target_size;
+
+  if (mb->mb_data && room >= (unsigned)size)
+    return mb->mb_data + mb->mb_used + mb->mb_commit;
+
+  target_size =
+    msg_min_size * ((size + mb->mb_commit) / msg_min_size + 1) - mb->mb_commit;
+
+  return msg_buf_exact(msg, target_size);
+}
+
+/** Allocate a buffer exactly of @a size octets, without any slack. */
+void *msg_buf_exact(msg_t *msg, usize_t size)
+{
+  struct msg_mbuffer_s *mb = msg->m_buffer;
+  size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
+  char *buffer;
+  int realloc;
+
+  if (mb->mb_data && room >= (unsigned)size)
+    return mb->mb_data + mb->mb_used + mb->mb_commit;
+
+  size += mb->mb_commit;
+
+  if (msg->m_maxsize && msg->m_size + size > msg->m_maxsize + 1) {
+    msg->m_object->msg_flags |= MSG_FLG_TOOLARGE;
+    errno = msg->m_errno = ENOBUFS;
+    return NULL;
+  }
+
+  realloc = !mb->mb_used && !msg->m_set_buffer;
+
+  if (realloc)
+    buffer = su_realloc(msg->m_home, mb->mb_data, size);
+  else
+    buffer = su_alloc(msg->m_home, size);
+
+  if (!buffer)
+    return NULL;
+
+  if (!realloc && mb->mb_commit && mb->mb_data)
+    memcpy(buffer, mb->mb_data + mb->mb_used, mb->mb_commit);
+
+  msg->m_set_buffer = 0;
+
+  mb->mb_data = buffer;
+  mb->mb_size = size;
+  mb->mb_used = 0;
+
+  return buffer + mb->mb_commit;
+}
+
+/** Commit data into buffer. */
+usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos)
+{
+  if (msg) {
+    struct msg_mbuffer_s *mb = msg->m_buffer;
+    assert(mb->mb_used + mb->mb_commit + size <= mb->mb_size);
+
+    mb->mb_commit += size;
+    mb->mb_eos = eos;
+
+    if (mb->mb_used == 0 && !msg->m_chunk && !msg->m_set_buffer) {
+      size_t slack = mb->mb_size - mb->mb_commit;
+
+      if (eos || slack >= msg_min_size) {
+	/* realloc and cut down buffer */
+	size_t new_size;
+	void *new_data;
+	
+	if (eos)
+	  new_size = mb->mb_commit + 1;
+	else
+	  new_size = mb->mb_commit + msg_min_size;
+
+	new_data = su_realloc(msg->m_home, mb->mb_data, new_size);
+	if (new_data) {
+	  mb->mb_data = new_data, mb->mb_size = new_size;
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+/** Get length of committed data */
+usize_t msg_buf_committed(msg_t const *msg)
+{
+  if (msg)
+    return msg->m_buffer->mb_commit;
+  else
+    return 0;
+}
+
+/** Get committed data */
+void *msg_buf_committed_data(msg_t const *msg)
+{
+  return msg && msg->m_buffer->mb_data ?
+    msg->m_buffer->mb_data + msg->m_buffer->mb_used
+    : NULL;
+}
+
+usize_t msg_buf_size(msg_t const *msg)
+{
+  assert(msg);
+  if (msg) {
+    struct msg_mbuffer_s const *mb = msg->m_buffer;
+    return mb->mb_size - mb->mb_commit - mb->mb_used;
+  }
+  else
+    return 0;
+}
+
+static inline
+void msg_buf_used(msg_t *msg, usize_t used)
+{
+  msg->m_size += used;
+  msg->m_buffer->mb_used += used;
+  if (msg->m_buffer->mb_commit > used)
+    msg->m_buffer->mb_commit -= used;
+  else
+    msg->m_buffer->mb_commit = 0;
+}
+
+/** Set buffer. */
+void msg_buf_set(msg_t *msg, void *b, usize_t size)
+{
+  if (msg) {
+    struct msg_mbuffer_s *mb = msg->m_buffer;
+
+    assert(!msg->m_set_buffer);	/* This can be set only once */
+
+    mb->mb_data = b;
+    mb->mb_size = size;
+    mb->mb_used = 0;
+    mb->mb_commit = 0;
+    mb->mb_eos  = 0;
+
+    msg->m_set_buffer = 1;
+  }
+}
+
+/** Move unparsed data from src to dst */
+void *msg_buf_move(msg_t *dst, msg_t const *src)
+{
+  void *retval;
+  struct msg_mbuffer_s *db = dst->m_buffer;
+  struct msg_mbuffer_s const *sb = src->m_buffer;
+
+  if (!dst || !src)
+    return NULL;
+
+  if (sb->mb_eos)
+    retval = msg_buf_exact(dst, sb->mb_commit + 1);
+  else
+    retval = msg_buf_alloc(dst, sb->mb_commit + 1);
+
+  if (retval == NULL)
+    return NULL;
+
+  memcpy(retval, sb->mb_data + sb->mb_used, sb->mb_commit);
+
+  db->mb_commit += sb->mb_commit;
+  db->mb_eos = sb->mb_eos;
+
+  return retval;
+}
+
+/**Obtain I/O vector for receiving the data.
+ *
+ * @relatesalso msg_s
+ *
+ * Allocate buffers for receiving @a n bytes
+ * of data available from network. Function returns the buffers in the I/O vector
+ * @a vec. The @a vec is allocated by the caller, the available length is
+ * given as @a veclen. If the protocol is message-oriented like UDP or SCTP
+ * and the available data ends at message boundary, the caller should set
+ * the @a exact as 1. Otherwise some extra buffer (known as @em slack) is
+ * allocated).
+ *
+ * Currently, the msg_recv_iovec() allocates receive buffers in at most two
+ * blocks, so the caller should allocate at least two elements for the I/O
+ * vector @a vec.
+ *
+ * @param[in]  msg     message object 
+ * @param[out] vec     I/O vector 
+ * @param[in]  veclen  available length of @a vec 
+ * @param[in]  n       number of possibly available bytes 
+ * @param[in]  exact   true if data ends at message boundary 
+ *
+ * @return
+ * The length of I/O vector to
+ * receive data, 0 if there are not enough buffers, or -1 upon an error.
+ *
+ * @sa msg_iovec(), su_vrecv()
+ */
+issize_t msg_recv_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen,
+			usize_t n, int exact)
+{
+  size_t i = 0;
+  size_t len = 0;
+  msg_payload_t *chunk;
+  char *buf;
+
+  if (n == 0)
+    return 0;
+
+  if (veclen == 0)
+    vec = NULL;
+
+  for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) {
+    buf = MSG_CHUNK_BUFFER(chunk);
+    len = MSG_CHUNK_AVAIL(chunk);
+
+    if (len == 0)
+      continue;
+    if (!buf)
+      break;
+
+#if SU_HAVE_WINSOCK
+    /* WSABUF has u_long */
+    if (len > SU_IOVECLEN_MAX)
+      len = SU_IOVECLEN_MAX;
+#endif
+    if (len > n)
+      len = n;
+    if (vec)
+      vec[i].mv_base = buf, vec[i].mv_len = (su_ioveclen_t)len;
+    i++;
+    if (len == n)
+      return i;
+    if (i == veclen)
+      vec = NULL;
+    n -= len;
+  }
+
+  if (!chunk && msg->m_chunk && msg_get_flags(msg, MSG_FLG_FRAGS)) {
+    /*
+     * If the m_chunk is the last fragment for this message,
+     * receive rest of the data to the next message
+     */
+    if (msg->m_next == NULL)
+      msg->m_next = msg_create(msg->m_class, msg->m_oflags);
+    if (msg->m_next) {
+      msg->m_next->m_maxsize = msg->m_maxsize;
+      msg_addr_copy(msg->m_next, msg);
+    }
+    msg = msg->m_next;
+    if (msg == NULL)
+      return 0;
+  }
+
+  if (exact)
+    buf = msg_buf_exact(msg, n + 1), len = n;
+  else if (chunk && len > n && !msg_get_flags(msg, MSG_FLG_CHUNKING))
+    buf = msg_buf_exact(msg, len + 1);
+  else
+    buf = msg_buf_alloc(msg, n + 1), len = msg_buf_size(msg);
+
+  if (buf == NULL)
+    return -1;
+
+  if (vec)
+    vec[i].mv_base = buf, vec[i].mv_len = (su_ioveclen_t)n;
+
+  if (chunk) {
+    assert(chunk->pl_data == NULL); assert(chunk->pl_common->h_len == 0);
+
+    chunk->pl_common->h_data = chunk->pl_data = buf;
+
+    if (len < MSG_CHUNK_AVAIL(chunk)) {
+      msg_header_t *h = (void*)chunk;
+      h->sh_succ = msg_header_alloc(msg_home(msg), h->sh_class, 0);
+      if (!h->sh_succ)
+	return -1;
+      h->sh_succ->sh_prev = &h->sh_succ;
+      chunk->pl_next = (msg_payload_t *)h->sh_succ;
+      chunk->pl_next->pl_len = chunk->pl_len - len;
+      chunk->pl_len = len;
+    }
+    else if (len > MSG_CHUNK_AVAIL(chunk)) {
+      len = MSG_CHUNK_AVAIL(chunk);
+    }
+
+    msg_buf_used(msg, len);
+  }
+
+  return i + 1;
+
+#if 0
+  if ((msg->m_ssize || msg->m_stream)
+      /* && msg_get_flags(msg, MSG_FLG_BODY) */) {
+    /* Streaming */
+    msg_buffer_t *b, *b0;
+
+    /* Calculate available size of current buffers */
+    for (b = msg->m_stream, len = 0; b && n > len; b = b->b_next)
+      len += b->b_avail - b->b_size;
+
+    /* Allocate new buffers */
+    if (n > len && msg_buf_external(msg, n, 0) < 0)
+      return -1;
+
+    for (b0 = msg->m_stream; b0; b0 = b0->b_next)
+      if (b0->b_avail != b0->b_size)
+	break;
+
+    for (b = b0; b && n > 0; i++, b = b->b_next) {
+      len = b->b_size - b->b_avail;
+      len = n < len ? n : len;
+      if (vec && i < veclen)
+	vec[i].mv_base = b->b_data + b->b_avail, vec[i].mv_len = len;
+      else
+	vec = NULL;
+      n -= len;
+    }
+
+    return i + 1;
+  }
+#endif
+}
+
+
+/** Obtain a buffer for receiving data.
+ *
+ * @relatesalso msg_s
+ */
+issize_t msg_recv_buffer(msg_t *msg, void **return_buffer)
+{
+  void *buffer;
+
+  if (!msg)
+    return -1;
+
+  if (return_buffer == NULL)
+    return_buffer = &buffer;
+
+  if (msg->m_chunk) {
+    msg_payload_t *pl;
+
+    for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
+      size_t n = MSG_CHUNK_AVAIL(pl);
+      if (n) {
+	*return_buffer = MSG_CHUNK_BUFFER(pl);
+	return n;
+      }
+    }
+
+    return 0;
+  }
+
+  if (msg_get_flags(msg, MSG_FLG_FRAGS)) {
+    /* Message is complete */
+    return 0;
+  }
+  else if ((*return_buffer = msg_buf_alloc(msg, 2))) {
+    return msg_buf_size(msg) - 1;
+  }
+  else {
+    return -1;
+  }
+}
+
+
+
+/**Commit @a n bytes of buffers.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_recv_commit() is called after @a n bytes of data has
+ * been received to the message buffers and the parser can extract the
+ * received data.
+ *
+ * @param msg pointer to message object
+ * @param n   number of bytes received
+ * @param eos true if stream is complete
+ *
+ * @note The @a eos should be always true for message-based transports. It
+ * should also be true when a stram oin stream-based transport ends, for
+ * instance, when TCP FIN is received.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+isize_t msg_recv_commit(msg_t *msg, usize_t n, int eos)
+{
+  msg_payload_t *pl;
+
+  if (eos)
+    msg->m_buffer->mb_eos = 1;
+
+  for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
+    size_t len = MSG_CHUNK_AVAIL(pl);
+
+    if (n <= len)
+      len = n;
+
+    pl->pl_common->h_len += len;
+
+    n -= len;
+
+    if (n == 0)
+      return 0;
+  }
+
+  if (msg->m_chunk && msg->m_next)
+    msg = msg->m_next;
+
+  return msg_buf_commit(msg, n, eos);
+}
+
+/**Get a next message of the stream.
+ *
+ * @relatesalso msg_s
+ *
+ * When parsing a transport stream, only the first message in the stream is
+ * created with msg_create(). The rest of the messages should be created
+ * with msg_next() after previous message has been completely received and
+ * parsed.
+ *
+ */
+msg_t *msg_next(msg_t *msg)
+{
+  msg_t *next;
+  usize_t n;
+
+  if (msg && msg->m_next) {
+    next = msg->m_next;
+    msg->m_next = NULL;
+    return next;
+  }
+
+  if ((n = msg_buf_committed(msg))) {
+    if (msg_buf_move(next = msg_create(msg->m_class, msg->m_oflags), msg)) {
+      msg_addr_copy(next, msg);
+      return next;
+    }
+    /* How to indicate error? */
+    msg_destroy(next);
+  }
+
+  return NULL;
+}
+
+/** Set next message of the stream.
+ *
+ * @relatesalso msg_s
+ */
+int msg_set_next(msg_t *msg, msg_t *next)
+{
+  if (!msg || (next && next->m_next))
+    return -1;
+
+  if (msg->m_next && next)
+    next->m_next = msg->m_next;
+
+  msg->m_next = next;
+
+  return 0;
+}
+
+/** Clear committed data.
+ *
+ * @relatesalso msg_s
+ */
+void msg_clear_committed(msg_t *msg)
+{
+  if (msg) {
+    usize_t n = msg_buf_committed(msg);
+
+    if (n)
+      msg_buf_used(msg, n);
+  }
+}
+
+#if 0
+struct sigcomp_udvm;
+
+struct sigcomp_udvm *msg_get_udvm(msg_t *msg);
+struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *);
+
+/** Save UDVM. */
+struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *udvm)
+{
+  struct sigcomp_udvm *prev = NULL;
+
+  if (msg) {
+    prev = msg->m_udvm;
+    msg->m_udvm = udvm;
+  }
+
+  return prev;
+}
+
+/** Get saved UDVM */
+struct sigcomp_udvm *msg_get_udvm(msg_t *msg)
+{
+  return msg ? msg->m_udvm : NULL;
+}
+
+#endif
+
+/** Mark message as complete.
+ *
+ * @relatesalso msg_s
+ */
+unsigned msg_mark_as_complete(msg_t *msg, unsigned mask)
+{
+  if (msg) {
+    msg->m_streaming = 0;
+    return msg->m_object->msg_flags |= mask | MSG_FLG_COMPLETE;
+  }
+  else {
+    return 0;
+  }
+}
+
+/** Return true if message is complete.
+ *
+ * @relatesalso msg_s
+ */
+int msg_is_complete(msg_t const *msg)
+{
+  return msg && MSG_IS_COMPLETE(msg->m_object);
+}
+
+/** Return true if message has parsing errors.
+ *
+ * @relatesalso msg_s
+*/
+int msg_has_error(msg_t const *msg)
+{
+  return msg->m_object->msg_flags & MSG_FLG_ERROR;
+}
+
+/**Total size of message.
+ *
+ * @relatesalso msg_s
+ */
+usize_t msg_size(msg_t const *msg)
+{
+  return msg ? msg->m_size : 0;
+}
+
+/** Set the maximum size of a message.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_maxsize() sets the maximum buffer size of a message. It
+ * returns the previous maximum size. If the @a maxsize is 0, maximum size
+ * is not set, but the current maximum size is returned.
+ *
+ * If the message size exceeds maxsize, msg_errno() returns ENOBUFS,
+ * MSG_FLG_TOOLARGE and MSG_FLG_ERROR flags are set.
+ */
+usize_t msg_maxsize(msg_t *msg, usize_t maxsize)
+{
+  usize_t retval = 0;
+
+  if (msg) {
+    retval = msg->m_maxsize;
+    if (maxsize)
+      msg->m_maxsize = maxsize;
+  }
+
+  return retval;
+}
+
+/**Set the size of next fragment.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_streaming_size() sets the size of the message body for
+ * streaming.
+ */
+int msg_streaming_size(msg_t *msg, usize_t ssize)
+{
+  if (!msg)
+    return -1;
+
+  msg->m_ssize = ssize;
+
+  return 0;
+}
+
+/**Allocate a list of external buffers.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_buf_external() allocates at most msg_n_fragments
+ * external buffers for the message body.
+ *
+ * @return The function msg_buf_external() returns number of allocated
+ * buffers, or -1 upon an error.
+ */
+issize_t msg_buf_external(msg_t *msg,
+			  usize_t N,
+			  usize_t blocksize)
+{
+  msg_buffer_t *ext, *b, **bb;
+  size_t i, I;
+
+  assert(N <= 128 * 1024);
+
+  if (msg == NULL)
+    return -1;
+  if (blocksize == 0)
+    blocksize = msg_min_block;
+  if (N == 0)
+    N = blocksize;
+  if (N > blocksize * msg_n_fragments)
+    N = blocksize * msg_n_fragments;
+  if (N > msg->m_ssize)
+    N = msg->m_ssize;
+
+  I = (N + blocksize - 1) / blocksize; assert(I <= msg_n_fragments);
+
+  for (i = 0, bb = &ext; i < I; i++) {
+    *bb = su_zalloc(msg_home(msg), sizeof **bb);
+    if (!*bb)
+      break;
+    bb = &(*bb)->b_next;
+  }
+
+  if (i == I)
+    for (b = ext, i = 0; b; b = b->b_next, i++) {
+      b->b_data = su_alloc(msg_home(msg), b->b_size = blocksize);
+      if (!b->b_data)
+	break;
+    }
+
+  if (i == I) {
+    /* Successful return */
+    for (bb = &msg->m_stream; *bb; bb = &(*bb)->b_next)
+      ;
+
+    *bb = ext;
+
+    if (msg->m_ssize != MSG_SSIZE_MAX)
+      for (b = ext; b; b = b->b_next) {
+	if (msg->m_ssize < b->b_size) {
+	  b->b_size = msg->m_ssize;
+	}
+	msg->m_ssize -= b->b_size;
+      }
+
+    return i;
+  }
+
+  for (b = ext; b; b = ext) {
+    ext = b->b_next;
+    su_free(msg_home(msg), b->b_data);
+    su_free(msg_home(msg), b);
+  }
+
+  return -1;
+}
+
+int msg_unref_external(msg_t *msg, msg_buffer_t *b)
+{
+  if (msg && b) {
+    su_free(msg_home(msg), b->b_data);
+    su_free(msg_home(msg), b);
+    return 0;
+  }
+  errno = EINVAL;
+  return -1;
+}
+
+/* ====================================================================== */
+/* Parsing messages */
+
+static inline int extract_incomplete_chunks(msg_t *, int eos);
+static issize_t extract_first(msg_t *, msg_pub_t *,
+			    char b[], isize_t bsiz, int eos);
+static inline issize_t extract_next(msg_t *, msg_pub_t *, char *, isize_t bsiz, 
+				  int eos, int copy);
+static issize_t extract_header(msg_t *, msg_pub_t*,
+			     char b[], isize_t bsiz, int eos, int copy);
+static msg_header_t *header_parse(msg_t *, msg_pub_t *, msg_href_t const *,
+				  char s[], isize_t slen, int copy_buffer);
+static msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
+					msg_href_t const *hr);
+static inline issize_t
+extract_trailers(msg_t *msg, msg_pub_t *mo,
+		 char *b, isize_t bsiz, int eos, int copy);
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
+
+static inline void
+append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
+	      int always_into_chain);
+
+/**Extract and parse a message from internal buffer.
+ *
+ * @relatesalso msg_s
+ *
+ * This function parses the internal buffer and adds the parsed fragments to
+ * the message object. It marks the successfully parsed data as extracted.
+ *
+ * @param msg message to be parsed
+ *
+ * @retval positive if a complete message was parsed
+ * @retval 0 if message was incomplete
+ * @retval negative if an error occurred
+ */
+int msg_extract(msg_t *msg)
+{
+  msg_pub_t *mo = msg_object(msg);
+  msg_mclass_t const *mc;
+  char *b;
+  ssize_t m;
+  size_t bsiz;
+  int eos;
+
+  if (!msg || !msg->m_buffer->mb_data)
+    return -1;
+
+  assert(mo);
+
+  mc = msg->m_class;
+  mo = msg->m_object;
+  eos = msg->m_buffer->mb_eos;
+
+  if (msg->m_chunk) {
+    int incomplete = extract_incomplete_chunks(msg, eos);
+    if (incomplete < 1 || MSG_IS_COMPLETE(mo))
+      return incomplete;
+  }
+
+  if (mo->msg_flags & MSG_FLG_TRAILERS)
+    msg_set_streaming(msg, 0);
+
+  if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit ==
+      msg->m_buffer->mb_size)
+    /* Why? When? */
+    return 0;
+
+  assert(msg->m_buffer->mb_used + msg->m_buffer->mb_commit <
+	 msg->m_buffer->mb_size);
+
+  m = 0;
+
+  b = msg->m_buffer->mb_data + msg->m_buffer->mb_used;
+  bsiz = msg->m_buffer->mb_commit;
+  b[bsiz] = '\0';
+
+  while (msg->m_buffer->mb_commit > 0) {
+    int flags = mo->msg_flags;
+    int copy = MSG_IS_EXTRACT_COPY(flags);
+
+    if (flags & MSG_FLG_COMPLETE)
+      break;
+
+    if (flags & MSG_FLG_TRAILERS)
+      m = extract_trailers(msg, mo, b, bsiz, eos, copy);
+    else if (flags & MSG_FLG_BODY)
+      m = mc->mc_extract_body(msg, mo, b, bsiz, eos);
+    else if (flags & MSG_FLG_HEADERS)
+      m = extract_next(msg, mo, b, bsiz, eos, copy);
+    else
+      m = extract_first(msg, mo, b, bsiz, eos);
+
+    if (m <= 0 || msg->m_chunk)
+      break;
+
+    b += m;
+    bsiz -= m;
+
+    msg_buf_used(msg, (size_t)m);
+  }
+
+  if (eos && bsiz == 0)
+    msg_mark_as_complete(msg, 0);
+
+  if (m < 0 || (mo->msg_flags & MSG_FLG_ERROR)) {
+    msg_mark_as_complete(msg, MSG_FLG_ERROR);
+    return -1;
+  }
+  else if (!MSG_IS_COMPLETE(mo))
+    return 0;
+  else if (!(mo->msg_flags & MSG_FLG_HEADERS)) {
+    msg_mark_as_complete(msg, MSG_FLG_ERROR);
+    return -1;
+  }
+  else
+    return 1;
+}
+
+static
+issize_t extract_first(msg_t *msg, msg_pub_t *mo, char b[], isize_t bsiz, int eos)
+{
+  /* First line */
+  size_t k, l, m, n, xtra;
+  int crlf;
+  msg_header_t *h;
+  msg_href_t const *hr;
+  msg_mclass_t const *mc = msg->m_class;
+
+  for (k = 0; IS_LWS(b[k]); k++) /* Skip whitespace */
+    ;
+  if (!b[k]) return k;
+
+  /* If first token contains no /, this is request, otherwise status line */
+  l = span_token(b + k) + k;
+  if (b[l] != '/')
+    hr = mc->mc_request;
+  else
+    hr = mc->mc_status;
+
+  n = span_non_crlf(b + l) + l;
+  if (!b[n])
+    return eos ? -1 : 0;
+  crlf = CRLF_TEST(b + n);
+
+  for (m = n + crlf; IS_WS(b[m]); m++)
+    ;
+  /* In order to skip possible whitespace after first line, we don't parse
+     first line until first non-ws char from next one has been received */
+  if (!b[m] && !eos)
+    return 0;
+
+  xtra = MSG_IS_EXTRACT_COPY(mo->msg_flags) ? n + 1 - k : 0;
+  if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, xtra)))
+    return -1;
+
+  if (xtra) {
+    char *bb = memcpy(MSG_HEADER_DATA(h), b, xtra - 1);
+    h->sh_data = b, h->sh_len = n + crlf;
+    b = bb; n = xtra - 1;
+  }
+  else {
+    b = b + k; n = n - k;
+  }
+
+  b[n] = 0;
+
+  if (hr->hr_class->hc_parse(msg_home(msg), h, b, n) < 0)
+    return -1;
+
+  assert(hr->hr_offset);
+
+  append_parsed(msg, mo, hr, h, 1);
+
+  mo->msg_flags |= MSG_FLG_HEADERS;
+
+  return m;
+}
+
+/* Extract header or message body */
+static inline issize_t
+extract_next(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz, 
+	     int eos, int copy)
+{
+  if (IS_CRLF(b[0]))
+    return msg->m_class->mc_extract_body(msg, mo, b, bsiz, eos);
+  else
+    return extract_header(msg, mo, b, bsiz, eos, copy);
+}
+
+/** Extract a header. */
+issize_t msg_extract_header(msg_t *msg, msg_pub_t *mo, 
+			   char b[], isize_t bsiz, int eos)
+{
+  return extract_header(msg, mo, b, bsiz, eos, 0);
+}
+
+/** Extract a header from buffer @a b.
+ */
+static
+issize_t
+extract_header(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz, int eos,
+	       int copy_buffer)
+{
+  size_t len, m;
+  size_t name_len = 0, xtra;
+  isize_t n = 0;
+  int crlf = 0, name_len_set = 0;
+  int error = 0;
+  msg_header_t *h;
+  msg_href_t const *hr;
+  msg_mclass_t const *mc = msg->m_class;
+
+  hr = msg_find_hclass(mc, b, &n); /* Get header name */
+  error = n == 0;
+  if (hr == NULL)		/* Panic */
+    return -1;
+
+  xtra = span_ws(b + n);
+
+  /* Find next crlf which is not followed by whitespace */
+  do {
+    n += xtra + crlf;
+    if (!eos && bsiz == n)
+      return 0;
+    m = span_non_crlf(b + n);
+    if (!name_len_set && m)
+      name_len = n, name_len_set = 1; /* First non-ws after COLON */
+    n += m;
+    crlf = CRLF_TEST(b + n);
+    xtra = span_ws(b + n + crlf);
+  }
+  while (xtra);
+
+  if (!eos && bsiz == n + crlf)
+    return 0;
+
+  if (hr->hr_class->hc_hash == msg_unknown_hash)
+    name_len = 0, name_len_set = 1;
+
+  if (error) {
+    msg->m_extract_err |= hr->hr_flags;
+    if (hr->hr_class->hc_critical)
+      mo->msg_flags |= MSG_FLG_ERROR;
+    hr = mc->mc_error;
+    copy_buffer = 1;
+    h = error_header_parse(msg, mo, hr);
+  }
+  else {
+    if (!name_len_set)
+      /* Empty header - nothing but name, COLON and LWS */
+      name_len = n;
+    else
+      /* Strip extra whitespace at the end of header */
+      while (n > name_len && IS_LWS(b[n - 1]))
+	n--, crlf++;
+
+    h = header_parse(msg, mo, hr, b + name_len, n - name_len, copy_buffer);
+  }
+
+  if (h == NULL)
+    return -1;
+
+  len = n + crlf;
+
+  /*
+   * If the header contains multiple header fields, set the pointer to the
+   * encodeded data correctly
+   */
+  while (h) {
+    if (copy_buffer)
+      h->sh_data = b, h->sh_len = len;
+    b += len, len = 0;
+    if (h->sh_succ)
+      assert(&h->sh_succ == h->sh_succ->sh_prev);
+    h = h->sh_next;
+  }
+
+  return n + crlf;
+}
+
+static
+msg_header_t *header_parse(msg_t *msg, msg_pub_t *mo,
+			   msg_href_t const *hr,
+			   char s[], isize_t slen,
+			   int copy_buffer)
+{
+  su_home_t *home = msg_home(msg);
+  msg_header_t *h, **hh;
+  msg_hclass_t *hc = hr->hr_class;
+  int n;
+  int add_to_list, clear = 0;
+
+  hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+
+  add_to_list = (hc->hc_kind == msg_kind_list && !copy_buffer && *hh);
+
+  if (add_to_list)
+    h = *hh;
+  else
+    h = msg_header_alloc(home, hc, copy_buffer ? slen + 1 : 0);
+
+  if (!h)
+    return NULL;
+
+  if (copy_buffer)
+    s = memcpy(MSG_HEADER_DATA(h), s, slen);
+
+  s[slen] = '\0';
+
+  if (hc->hc_kind == msg_kind_list && *hh) {
+    n = hc->hc_parse(home, *hh, s, slen);
+    /* Clear if adding new header disturbs existing headers */
+    clear = *hh != h && !copy_buffer;
+    if (clear)
+      msg_fragment_clear((*hh)->sh_common);
+  }
+  else
+    n = hc->hc_parse(home, h, s, slen);
+
+  if (n < 0) {
+    msg->m_extract_err |= hr->hr_flags;
+
+    if (hc->hc_critical)
+      mo->msg_flags |= MSG_FLG_ERROR;
+
+    clear = 0;
+
+    if (!add_to_list) {
+      /* XXX - This should be done by msg_header_free_all() */
+      msg_header_t *h_next;
+      msg_param_t *h_params;
+
+      while (h) {
+	h_next = h->sh_next;
+	if (hc->hc_params) {
+	  h_params = *(msg_param_t **)((char *)h + hc->hc_params);
+	  if (h_params)
+	    su_free(home, h_params);
+	}
+	su_free(home, h);
+	h = h_next;
+      }
+      /* XXX - This should be done by msg_header_free_all() */
+      hr = msg->m_class->mc_error;
+      h = msg_header_alloc(home, hr->hr_class, 0);
+      if (!h)
+	return h;
+
+      h->sh_error->er_name = hc->hc_name;
+      hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+    }
+  }
+
+  if (clear)
+    for (hh = &(*hh)->sh_next; *hh; *hh = (*hh)->sh_next)
+      msg_chain_remove(msg, *hh);
+  else if (h != *hh)
+    append_parsed(msg, mo, hr, h, 0);
+
+  return h;
+}
+
+static
+msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
+				 msg_href_t const *hr)
+{
+  msg_header_t *h;
+
+  h = msg_header_alloc(msg_home(msg), hr->hr_class, 0);
+  if (h)
+    append_parsed(msg, mo, hr, h, 0);
+
+  return h;
+}
+
+/** Complete this header field and parse next header field. 
+ *
+ * This function completes parsing a multi-field header like @Accept,
+ * @Contact, @Via or @Warning. It scans for the next header field and 
+ * if one is found, it calls the parsing function recursively.
+ *
+ * @param home 	 memory home used ot allocate 
+ *             	 new header structures and parameter lists
+ * @param prev 	 pointer to header structure already parsed
+ * @param s    	 header content to parse; should point to the area after 
+ *             	 current header field (either end of line or to a comma
+ *             	 separating header fields)
+ * @param slen 	 ignored
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ */
+issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev, 
+			      char *s, isize_t slen)
+{
+  msg_hclass_t *hc = prev->sh_class;
+  msg_header_t *h;
+  char *end = s + slen;
+
+  if (*s && *s != ',')
+    return -1;
+
+  if (msg_header_update_params(prev->sh_common, 0) < 0)
+    return -1;
+
+  while (*s == ',') /* Skip comma and following whitespace */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if (*s == 0)
+    return 0;
+  
+  h = msg_header_alloc(home, hc, 0);
+  if (!h)
+    return -1;
+
+  prev->sh_succ = h, h->sh_prev = &prev->sh_succ;
+  prev->sh_next = h;
+
+  return hc->hc_parse(home, h, s, end - s);
+}
+
+/** Decode a message header. */
+msg_header_t *msg_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_href_t const *hr = mc->mc_unknown;
+  isize_t n;			/* Length of header contents */
+  isize_t name_len, xtra;
+  msg_header_t *h;
+  char *bb;
+
+  n = strlen(b);
+  hr = msg_find_hclass(mc, b, &name_len);
+  if (hr == NULL)
+    return NULL;
+
+  /* Strip extra whitespace at the end and begin of header */
+  while (n > name_len && IS_LWS(b[n - 1]))
+    n--;
+  if (name_len < n && IS_LWS(b[name_len]))
+    name_len++;
+
+  xtra = (n - name_len);
+  if (!(h = msg_header_alloc(home, hr->hr_class, xtra + 1)))
+    return NULL;
+
+  bb = memcpy(MSG_HEADER_DATA(h), b + name_len, xtra), bb[xtra] = 0;
+
+  if (hr->hr_class->hc_parse(home, h, bb, xtra) >= 0)
+    return h;
+
+  hr = mc->mc_unknown;
+  su_free(home, h);
+  if (!(h = msg_header_alloc(home, hr->hr_class, n + 1)))
+    return NULL;
+  bb = memcpy(MSG_HEADER_DATA(h), b, n), bb[n] = 0;
+  if (hr->hr_class->hc_parse(home, h, bb, n) < 0)
+    su_free(home, h), h = NULL;
+
+  return h;
+}
+
+/** Extract a separator line */
+issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
+			       char b[], isize_t bsiz, int eos)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_href_t const *hr = mc->mc_separator;
+  int l = CRLF_TEST(b);  /* Separator length */
+  msg_header_t *h;
+
+  /* Even if a single CR *may* be a payload separator we cannot be sure */
+  if (l == 0 || (!eos && bsiz == 1 && b[0] == '\r'))
+    return 0;
+
+  /* Separator */
+  if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+    return -1;
+  if (hr->hr_class->hc_parse(msg_home(msg), h, b, l) < 0)
+    return -1;
+
+  h->sh_data = b, h->sh_len = l;
+
+  append_parsed(msg, mo, hr, h, 0);
+
+  return l;
+}
+
+static inline msg_header_t **msg_chain_tail(msg_t const *msg);
+
+/** Extract a message body of @a body_len bytes.
+  */
+issize_t msg_extract_payload(msg_t *msg, msg_pub_t *mo,
+			     msg_header_t **return_payload,
+			     usize_t body_len,
+			     char b[], isize_t bsiz,
+			     int eos)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_href_t const *hr = mc->mc_payload;
+  msg_header_t *h, *h0;
+  msg_payload_t *pl;
+  char *x;
+
+  if (msg == NULL || mo == NULL)
+    return -1;
+
+  assert(!msg->m_chunk);
+
+  if (return_payload == NULL)
+    return_payload = &h0;
+  *return_payload = NULL;
+
+  assert(body_len > 0);
+
+  /* Allocate header structure for payload */
+  if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+    return -1;
+
+  append_parsed(msg, mo, hr, h, 0);
+  pl = h->sh_payload;
+  *return_payload = h;
+
+  if (bsiz >= body_len) {
+    /* We have a complete body. */
+    h->sh_data = b, h->sh_len = body_len;
+    pl->pl_data = b, pl->pl_len = body_len;
+    return body_len;
+  }
+
+  if (msg->m_maxsize != 0 && body_len > msg->m_maxsize) {
+    mo->msg_flags |= MSG_FLG_TOOLARGE;
+    return -1;
+  }
+
+  assert(msg->m_buffer->mb_commit == bsiz);
+  assert(b == msg->m_buffer->mb_data + msg->m_buffer->mb_used);
+
+  if (msg->m_buffer->mb_used + body_len <= msg->m_buffer->mb_size) {
+    /* We don't have a complete body, but we have big enough buffer for it. */
+    msg->m_chunk = pl;
+
+    h->sh_data = b, h->sh_len  = bsiz;
+    pl->pl_data = b, pl->pl_len  = body_len;
+
+    if (msg->m_buffer->mb_used + body_len < msg->m_buffer->mb_size)
+      /* NUL-terminate payload */
+      b[body_len++] = '\0';
+
+    /* Mark the rest of the body as used in the buffer */
+    /* msg_buf_commit(msg, body_len - bsiz, eos); */
+    msg_buf_used(msg, body_len);
+
+    return bsiz;
+  }
+
+  /* We don't have big enough buffer for body. */
+
+  if (msg_get_flags(msg, MSG_FLG_CHUNKING)) {
+    /* Application supports chunking, use multiple chunks for payload */
+    usize_t current, rest;
+
+    current = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
+    rest = body_len - current;
+
+    /* Use all the data from our current buffer */
+    msg_buf_used(msg, current);
+
+    msg->m_chunk = pl;
+
+    h->sh_data = b, h->sh_len = bsiz;
+    pl->pl_data = b, pl->pl_len  = current;
+
+    for (;current < body_len; current += rest) {
+      msg_header_t *h0 = h;
+
+      /* Allocate header structure for next payload chunk */
+      if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+	return -1;
+      if (msg->m_chain)
+	msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
+      h0->sh_next = h;
+
+      rest = body_len - current;
+
+      if (!msg->m_streaming) {
+	x = msg_buf_exact(msg, rest);
+	if (x == NULL) {
+	  mo->msg_flags |= MSG_FLG_TOOLARGE;
+	  return -1;
+	}
+      }
+      else {
+	x = NULL;
+      }
+
+      if (x) {
+	/* Mark the just-allocated buffer as used */
+	rest = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
+	msg_buf_used(msg, rest);
+      }
+
+      pl = h->sh_payload;
+
+      h->sh_len = 0, pl->pl_len = rest;
+      h->sh_data = x, pl->pl_data = x;
+    }
+  }
+  else {
+    /* No chunking.
+     *
+     * Allocate a single buffer that contains enough free space for body.
+     *
+     * msg_buf_exact() also copies committed but un-used data
+     * from the old buffer (b[0] .. b[bsiz])
+     * to the new buffer (x[-bsiz-1]..b[-1])
+     */
+    if (!(x = msg_buf_exact(msg, body_len - bsiz + 1))) {
+      if (mo->msg_flags & MSG_FLG_TOOLARGE) {
+	msg_mark_as_complete(msg, MSG_FLG_TRUNC);
+	return bsiz;
+      }
+      return -1;
+    }
+
+    /* Fake un-received data as already received and then use it */
+    /* msg_buf_commit(msg, body_len - bsiz + 1, eos); */
+    msg_buf_used(msg, body_len + 1);
+
+    msg->m_chunk = h->sh_payload;
+
+    x -= bsiz; /* Start of un-used data */
+    x[body_len] = '\0';
+
+    h->sh_data = x, h->sh_len = bsiz;
+    pl->pl_data = x, pl->pl_len = body_len;
+
+    assert(MSG_CHUNK_AVAIL(pl) == body_len - bsiz);
+  }
+
+  return bsiz;
+}
+
+/** Extract incomplete chunks.
+ */
+static inline
+int extract_incomplete_chunks(msg_t *msg, int eos)
+{
+  msg_payload_t *chunk;
+
+  for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) {
+    if (MSG_CHUNK_AVAIL(chunk) != 0)
+      break;
+
+    /* The incomplete payload fragment is now complete */
+    assert(MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len);
+
+    msg->m_size += chunk->pl_common->h_len;
+  }
+
+  msg->m_chunk = chunk;
+
+  if (chunk) {
+    if (eos) {
+      msg_mark_as_complete(msg, MSG_FLG_TRUNC);
+      return 1;
+    }
+  }
+  else {
+    if (msg_get_flags(msg, MSG_FLG_FRAGS))
+      msg_mark_as_complete(msg, 0);
+  }
+
+  /**@retval 1 when message is complete
+   * @retval 0 when message is incomplete
+   * @retval -1 upon an error
+   */
+  return chunk == NULL;
+}
+
+/* Extract trailers */
+static inline issize_t
+extract_trailers(msg_t *msg, msg_pub_t *mo,
+		 char *b, isize_t bsiz, int eos, int copy)
+{
+  if (IS_CRLF(b[0])) {
+    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+    return CRLF_TEST(b);
+  }
+  else
+    return extract_header(msg, mo, b, bsiz, eos, copy);
+}
+
+/* ====================================================================== */
+/* Preparing (printing/encoding) a message structure for sending */
+
+/* Internal prototypes */
+static inline size_t
+msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags);
+static size_t msg_header_prepare(msg_mclass_t const *, int flags,
+				 msg_header_t *h, msg_header_t **return_next,
+				 char *b, size_t bsiz);
+
+/**Encode all message fragments.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_prepare() prepares a message for sending. It encodes all
+ * serialized fragments in the message. You have to call msg_serialize()
+ * before calling msg_headers_prepare() in order to make sure that all the
+ * heades and other message fragments are included in the chain.
+ *
+ * After encoding, the msg_common_s::h_data field will point to the encoding
+ * result of size msg_common_s::h_len bytes in in each fragment.
+ *
+ * When multiple header fields are represented as a comma-separated list
+ * within a single header line, the first fragment in the header will
+ * contain all the text belonging to the header. The rest of the header
+ * fields will have zero-length encoding with msg_common_s::h_data that
+ * points to the end of the line.
+ *
+ * @return Total size of the encoded message in bytes, or -1 upon an error.
+ *
+ * @sa msg_extract(), msg_serialize()
+ */
+int msg_prepare(msg_t *msg)
+{
+  int total;
+
+  assert(msg->m_chain);
+  assert(msg_chain_errors(msg->m_chain) == 0);
+
+  /* Get rid of data that was received but not yet used (parsed) */
+  msg_clear_committed(msg);
+
+  total = msg_headers_prepare(msg, msg->m_chain, msg_object(msg)->msg_flags);
+
+  if (total != -1) {
+    msg->m_size = total;
+    msg->m_prepared = 1;
+  }
+
+  return total;
+}
+
+/** Clear 'prepared' flag. */
+void msg_unprepare(msg_t *msg)
+{
+  if (msg) msg->m_prepared = 0;
+}
+
+/** Return true if message is prepared. */
+int msg_is_prepared(msg_t const *msg)
+{
+  return msg && msg->m_prepared;
+}
+
+/**Encode headers in chain.
+ *
+ * The function msg_headers_prepare() encodes all the headers in the header
+ * chain. You have to call msg_serialize() before calling
+ * msg_headers_prepare() in order to make sure that all the heades and other
+ * message fragments are included in the chain.
+ *
+ * @return
+ * The size of all the headers in chain, or -1 upon an error.
+ */
+issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_header_t *h, *next;
+  ssize_t n = 0;
+  size_t bsiz = 0, used = 0;
+  char *b;
+  size_t total = 0;
+
+  b = msg_buf_alloc(msg, msg_min_size);
+  bsiz = msg_buf_size(msg);
+
+  if (!b)
+    return -1;
+
+  for (h = headers; h;) {
+
+    if (h->sh_data) {
+      total += h->sh_len;
+      h = h->sh_succ;
+      continue;
+    }
+
+    for (next = h->sh_succ; next; next = next->sh_succ)
+      if (next->sh_class != h->sh_class || next->sh_data)
+	break;
+
+    n = msg_header_prepare(mc, flags, h, &next, b, bsiz - used);
+
+    if (n == (ssize_t)-1) {
+      errno = EINVAL;
+      return -1;
+    }
+
+    if (used + n >= bsiz) {
+      /* Allocate next buffer */
+      if ((b = msg_buf_alloc(msg, n + 1)) == NULL)
+	return -1;
+      bsiz = msg_buf_size(msg); used = 0;
+      continue;
+    }
+
+    h->sh_data = b, h->sh_len = n;
+
+    for (h = h->sh_succ; h != next; h = h->sh_succ)
+      h->sh_data = b + n, h->sh_len = 0;
+
+    msg_buf_used(msg, n);
+
+    total += n;
+    used += n;
+    b += n;
+  }
+
+  return total;
+}
+
+/** Encode a header or a list of headers */
+static
+size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
+			  msg_header_t *h, msg_header_t **return_next,
+			  char *b, size_t bsiz)
+{
+  msg_header_t *h0, *next;
+  msg_hclass_t *hc;
+  char const *s;
+  size_t n; ssize_t m;
+  int compact, one_line_list, comma_list;
+
+  assert(h); assert(h->sh_class);
+
+  hc = h->sh_class;
+  compact = MSG_IS_COMPACT(flags);
+  one_line_list = hc->hc_kind == msg_kind_apndlist;
+  comma_list = compact || one_line_list || MSG_IS_COMMA_LISTS(flags);
+
+  for (h0 = h, n = 0; ; h = next) {
+    next = h->sh_succ;
+
+    if (h == h0 && hc->hc_name && hc->hc_name[0])
+      n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags);
+
+    if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) == -1) {
+      if (bsiz >= n + 64)
+	m = 2 * (bsiz - n);
+      else
+	m = 128;
+    }
+
+    n += m;
+
+    if (hc->hc_name) {
+      if (!comma_list || !next || next == *return_next)
+	s = CRLF, m = 2;
+      /* Else encode continuation */
+      else if (compact)
+	s = ",", m = 1;
+      else if (one_line_list)
+	s = ", ", m = 2;
+      else
+	s = "," CRLF "\t", m = 4;
+
+      if (bsiz > n + m)
+	memcpy(b + n, s, m);
+      n += m;
+    }
+
+    if (!comma_list || !next || next == *return_next)
+      break;
+  }
+
+  *return_next = next;
+
+  return n;
+}
+
+/** Encode a header.
+ *
+ * The function msg_header_e() encodes a header field in the buffer @a
+ * b[]. The encoding includes its name and trailing CRLF.  The function
+ * returns the length of the encoding in bytes, excluding the final @c NUL.
+ * The buffer @a b must be large enough for whole encoding, including the
+ * final @c NUL.
+ *
+ * The @a flags parameter define how the encoding is done.  If the flags
+ * specify @c MSG_DO_COMPACT, the encoding is compact (short form with
+ * minimal whitespace).
+ */
+issize_t msg_header_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  size_t n, m;
+
+  assert(h); assert(h->sh_class);
+
+  if (h == NULL || h->sh_class == NULL)
+    return -1;
+
+  n = msg_header_name_e(b, bsiz, h, flags);
+  m = h->sh_class->hc_print(b + n, bsiz > n ? bsiz - n : 0, h, flags);
+  if (h->sh_class->hc_name) {
+    /* Ordinary header */
+    if (bsiz > n + m + strlen(CRLF))
+      strcpy(b + n + m, CRLF);
+    return n + m + strlen(CRLF);
+  }
+  else
+    return m;
+}
+
+/** Encode header name */
+static inline
+size_t
+msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags)
+{
+  int compact = MSG_IS_COMPACT(flags);
+  char const *name;
+  size_t n, n2;
+
+  if (compact && h->sh_class->hc_short[0])
+    name = h->sh_class->hc_short, n = 1;
+  else
+    name = h->sh_class->hc_name, n = h->sh_class->hc_len;
+
+  if (!name || !name[0])
+    return 0;
+
+  n2 = compact ? n + 1 : n + 2;
+
+  if (n2 < bsiz) {
+    memcpy(b, name, n);
+    b[n++] = ':';
+    if (!compact)
+      b[n++] = ' ';
+    b[n++] = '\0';
+  }
+
+  return n2;
+}
+
+/** Convert a message to a string.
+ *
+ * A message is encoded and the encoding result is returned as a string. 
+ * Because the message may contain binary payload (or NUL in headers), the
+ * message length is returned separately in @a *return_len, too.
+ *
+ * Note that the message is serialized as a side effect. 
+ *
+ * @param home memory home used to allocate the string
+ * @param msg  message to encode
+ * @param pub  message object to encode (may be NULL)
+ * @param flags flags used when encoding
+ * @param return_len return-value parameter for encoded message length
+ * 
+ * @return Encoding result as a C string. 
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_make(), msg_prepare(), msg_serialize().
+ */
+char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
+		    size_t *return_len)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_header_t *h, *next;
+  ssize_t n = 0;
+  size_t bsiz = 0, used = 0;
+  char *b, *b2;
+
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  if (msg_serialize(msg, pub) < 0)
+    return NULL;
+
+  if (return_len == NULL)
+    return_len = &used;
+
+  b = su_alloc(home, bsiz = msg_min_size);
+
+  if (!b)
+    return NULL;
+
+  if (pub == msg->m_object)
+    h = msg->m_chain;
+  else
+    h = pub->msg_common->h_succ;
+
+  while (h) {
+    for (next = h->sh_succ; next; next = next->sh_succ)
+      if (next->sh_class != h->sh_class)
+	break;
+
+    n = msg_header_prepare(mc, flags, h, &next, b + used, bsiz - used);
+
+    if (n == -1) {
+      errno = EINVAL;
+      su_free(home, b);
+      return NULL;
+    }
+
+    if (bsiz > used + n) {
+      used += n;
+      h = next;
+    }
+    else {
+      /* Realloc */
+      if (h->sh_succ)
+	bsiz = (used + n + msg_min_size) / msg_min_size * msg_min_size;
+      else
+	bsiz = used + n + 1;
+
+      b2 = su_realloc(home, b, bsiz);
+
+      if (b2 == NULL || bsiz < msg_min_size) {
+	errno = ENOMEM; 
+	su_free(home, b);
+	return NULL;
+      }
+
+      continue;
+    }
+  }
+
+  *return_len = used;
+
+  b[used] = '\0';		/* NUL terminate */
+
+  return su_realloc(home, b, used + 1);
+}
+
+/* ====================================================================== */
+/* Handling header chain */
+
+static inline void serialize_first(msg_t *msg, msg_header_t *h);
+static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h,
+				    msg_header_t **prev);
+
+/** Return head of the fragment chain */
+msg_header_t **msg_chain_head(msg_t const *msg)
+{
+  return msg ? (msg_header_t **)&msg->m_chain : NULL;
+}
+
+static inline msg_header_t **_msg_chain_head(msg_t const *msg)
+{
+  return msg ? (msg_header_t **)&msg->m_chain : NULL;
+}
+
+/** Return tail of the fragment chain */
+static inline msg_header_t **msg_chain_tail(msg_t const *msg)
+{
+  return msg ? msg->m_tail : NULL;
+}
+
+/** Serialize headers into the fragment chain.
+ *
+ * The msg_serialize() collects the headers and other message components in
+ * the fragment chain. It should be called before msg_prepare().
+ *
+ * @relatesalso msg_s
+ *
+ * @param msg pointer to message object
+ * @param pub public message structure
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int msg_serialize(msg_t *msg, msg_pub_t *pub)
+{
+  msg_header_t *h, **hh, **end;
+  msg_header_t **separator;
+  msg_header_t **payload;
+  msg_header_t **multipart;
+  msg_mclass_t const *mc = msg->m_class;
+  msg_header_t **tail, ***ptail;
+
+  if (!msg)
+    return errno = EINVAL, -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  /* There must be a first line */
+  if (pub->msg_request)
+    h = pub->msg_request;
+  else if (pub->msg_status)
+    h = pub->msg_status;
+  else
+    return errno = EINVAL, -1;
+
+  serialize_first(msg, h);
+
+  separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
+  payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
+  if (mc->mc_multipart->hr_class)
+    multipart = (msg_header_t **)((char *)pub + mc->mc_multipart->hr_offset);
+  else
+    multipart = NULL;
+
+  /* Find place to insert headers: before separator, payload and multipart */
+  if (*separator && !msg_header_is_removed(*separator))
+    ptail = &(*separator)->sh_prev;
+  else if (*payload && !msg_header_is_removed(*payload))
+    ptail = &(*payload)->sh_prev;
+  else if (multipart && *multipart && !msg_header_is_removed(*multipart))
+    ptail = &(*multipart)->sh_prev;
+  else
+    ptail = &msg->m_tail;
+
+  tail = *ptail;
+
+  end = (msg_header_t **)((char *)pub + pub->msg_size);
+
+  for (hh = pub->msg_headers; hh < end; hh++) {
+    if (!*hh)
+      continue;
+    if (hh == separator || hh == payload || hh == multipart)
+      continue;
+    tail = serialize_one(msg, *hh, tail);
+  }
+
+  /* Serialize separator, payload and multipart last */
+  if (*separator)
+    tail = serialize_one(msg, *separator, tail);
+
+  *ptail = tail;
+
+  /* Payload comes after separator but before multipart */
+  if (ptail != &(*separator)->sh_prev)
+    ;
+  else if (*payload && !msg_header_is_removed(*payload))
+    ptail = &(*payload)->sh_prev;
+  else if (multipart && *multipart && !msg_header_is_removed(*multipart))
+    ptail = &(*multipart)->sh_prev;
+  else
+    ptail = &msg->m_tail;
+
+  tail = *ptail;
+
+  if (*payload) {
+    tail = serialize_one(msg, *payload, tail);
+    *ptail = tail;
+  }
+
+  if (multipart && *multipart) {
+    msg_header_t *last;
+
+    last = msg_multipart_serialize(tail, (msg_multipart_t *)*multipart);
+
+    msg->m_tail = &last->sh_succ;
+  }
+
+  assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0);
+
+  return 0;
+}
+
+static inline
+void serialize_first(msg_t *msg, msg_header_t *h)
+{
+  if (msg_header_is_removed(h)) {
+    if ((h->sh_succ = msg->m_chain))
+      h->sh_succ->sh_prev = &h->sh_succ;
+    else
+      msg->m_tail = &h->sh_succ;
+    *(h->sh_prev = &msg->m_chain) = h;
+  }
+}
+
+static
+msg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev)
+{
+  msg_header_t *last;
+  msg_header_t *succ = *prev;
+
+  if (msg_header_is_removed(h)) {
+    /* Add the first header in the list to the chain */
+    *prev = h; h->sh_prev = prev;
+    for (last = h; last->sh_succ; last = last->sh_succ) {
+      /* Ensure that chain is connected */
+      assert(last->sh_next == last->sh_succ);
+      assert(last->sh_succ->sh_prev = &last->sh_succ);
+    }
+    prev = &last->sh_succ;
+  }
+
+  if ((h = h->sh_next)) {
+    assert(!msg_is_single(h));
+
+    if (msg_is_single(h)) {
+      for (; h; h = h->sh_next)
+	if (!msg_header_is_removed(h))
+	  msg_chain_remove(msg, h);
+    }
+    /* Add the rest of the headers in the list to the chain */
+    else for (; h; h = h->sh_next) {
+      if (msg_header_is_removed(h)) {
+	*prev = h; h->sh_prev = prev;
+	for (;h->sh_succ; h = h->sh_succ)
+	  assert(h->sh_succ == h->sh_next);
+	prev = &h->sh_succ;
+      }
+    }
+  }
+
+  *prev = succ;
+
+  return prev;
+}
+
+/**Fill an I/O vector with message contents.
+ *
+ * @relatesalso msg_s
+ *
+ * Calculate number of entries in the I/O vector
+ * required to send a message @a msg. It also fills in the I/O vector array,
+ * if it is provided by the caller and it is large enough.
+ *
+ * @param msg   pointer to message object
+ * @param vec   I/O vector (may be NULL)
+ * @param veclen length of I/O vector in @a vec
+ *
+ * @return
+ * Number of entries of I/O
+ * vector required by @a msg, or 0 upon an error.
+ *
+ * @note The caller should check that the I/O vector @a vec has enough
+ * entries. If the @a vec is too short, it should allocate big enough
+ * vector and re-invoke msg_iovec().
+ *
+ * @sa msg_recv_iovec(), su_vsend()
+ */
+isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen)
+{
+  size_t len = 0, n = 0;
+  char const *p = NULL;
+  msg_header_t *h;
+
+  size_t total = 0;
+
+  if (veclen <= 0)
+    veclen = 0;
+
+  for (h = msg->m_chain; h; h = h->sh_succ) {
+    if (h->sh_data != p) {
+      p = h->sh_data; len = h->sh_len;
+
+      if (p == NULL)
+	return 0;
+
+      if (vec && n != veclen)
+	/* new iovec entry */
+	vec[n].mv_base = (void *)p, vec[n].mv_len = (su_ioveclen_t)len;
+      else
+	vec = NULL;
+
+      p += len; n++;
+    }
+    else {
+      /* extend old entry */
+      len = h->sh_len;
+      if (vec)
+	vec[n-1].mv_len += (su_ioveclen_t)len;
+      p += len;
+    }
+
+    total += len;
+  }
+
+  msg->m_size = total;
+
+  return n;
+}
+
+/** Insert a header to existing header chain.
+ *
+ * Headers are either inserted just before the payload, or after the first
+ * line, depending on their type.
+ *
+ * @param[in]     msg  message object 
+ * @param[in,out] pub  public message structure 
+ * @param prepend if true, add before same type of headers (instead after them)
+ * @param head head of chain
+ * @param h    header to insert
+ *
+ */
+static
+void msg_insert_chain(msg_t *msg,
+		      msg_pub_t *pub,
+		      int prepend,
+		      msg_header_t **head,
+		      msg_header_t *h)
+{
+  msg_mclass_t const *mc = msg->m_class;
+  msg_header_t **hh;
+  msg_header_t **separator;
+  msg_header_t **payload;
+  
+  assert(msg && pub && head && h);
+
+  separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
+  payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
+
+  if (msg_is_request(h)) {
+    if (pub->msg_status)
+      pub->msg_status = NULL;
+    hh = head;
+  }
+  else if (msg_is_status(h)) {
+    if (pub->msg_request)
+      pub->msg_request = NULL;
+    hh = head;
+  }
+  else if (msg_is_payload(h)) {
+    /* Append */
+    hh = msg_chain_tail(msg);
+  }
+  else if (prepend) {
+    if (!msg_is_request(*head) && !msg_is_status(*head))
+      hh = head;
+    else
+      hh = &((*head)->sh_succ);
+  }
+  /* Append headers before separator or payload */
+  else if (*separator && (*separator)->sh_prev)
+    hh = (*separator)->sh_prev;
+  else if (*payload && (*payload)->sh_prev)
+    hh = (*payload)->sh_prev;
+  else
+    hh = msg_chain_tail(msg);
+
+  msg_insert_here_in_chain(msg, hh, h);
+}
+
+/** Insert one or more message header to the chain.
+ *
+ * The function msg_insert_here_in_chain() appends message header to the
+ * chain of headers after the given header.
+ *
+ * @param msg  message
+ * @param prev pointer to h_succ of previous fragment in the list
+ * @param h    header to be inserted.
+ *
+ * @return The pointer to the last header inserted.
+ */
+static
+void msg_insert_here_in_chain(msg_t *msg,
+			      msg_header_t **prev,
+			      msg_header_t *h)
+{
+  if (h) {
+    msg_header_t *last, *next;
+    assert(h->sh_prev == NULL);
+    assert(prev);
+    assert(!msg_chain_errors(h));
+
+    for (last = h; last->sh_succ; last = last->sh_succ)
+      ;
+
+    last->sh_succ = next = *prev;
+    *prev = h;
+    h->sh_prev = prev;
+    if (next)
+      next->sh_prev = &last->sh_succ;
+    else
+      msg->m_tail = &last->sh_succ;
+
+    assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0);
+  }
+}
+
+/**
+ * Remove a message from header chain.
+ *
+ * The function @c msg_chain_remove() removes a message header from the header
+ * chain.
+ *
+ * @param msg  pointer to the message
+ * @param h    pointer to the header in the list to be removed
+ *
+ * @return The pointer to the header just removed.
+ */
+static inline
+msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h)
+{
+  if (h) {
+    if (h->sh_prev) {
+      assert(*h->sh_prev == h);
+      assert(h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ);
+
+      *h->sh_prev = h->sh_succ;
+    }
+
+    if (h->sh_succ)
+      h->sh_succ->sh_prev = h->sh_prev;
+    else if (msg && h->sh_prev)
+      msg->m_tail = h->sh_prev;
+
+    h->sh_succ = NULL; h->sh_prev = NULL;
+
+    if (msg)
+      assert(msg_chain_errors(msg->m_chain) == 0);
+  }
+  return h;
+}
+
+#ifndef NDEBUG
+/**Check if header chain contains any loops.
+ *
+ * @return
+ * Return 0 if no loop, -1 otherwise.
+ */
+static
+int msg_chain_loop(msg_header_t const *h)
+{
+  msg_header_t const *h2;
+
+  if (!h) return 0;
+
+  for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) {
+    if (h == h2 || h == h2->sh_succ)
+      return 1;
+
+    h2 = h2->sh_succ->sh_succ;
+
+    if (h == h2)
+      return 1;
+  }
+
+  return 0;
+}
+
+/** Check header chain consistency.
+ *
+ * @return
+ * Return 0 if consistent, number of errors otherwise.
+ */
+static
+int msg_chain_errors(msg_header_t const *h)
+{
+  if (msg_chain_loop(h))
+    return -1;
+
+  for (; h; h = h->sh_succ) {
+    if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ)
+      return -1;
+    if (h->sh_prev && h != (*h->sh_prev))
+      return -1;
+  }
+
+  return 0;
+}
+#endif
+
+/* ====================================================================== */
+/* Handling message structure - allocating, adding and removing headers */
+
+/** Allocate a header structure
+ *
+ * The msg_header_alloc() function allocates a generic MO header structure
+ * and returns a pointer to it.
+ *
+ * @param home  memory home
+ * @param hc    header class
+ * @param extra amount of extra memory to be allocated after header structure
+ *
+ * @return
+ * A pointer to the newly created header object, or @c NULL upon an error.
+ */
+msg_header_t *msg_header_alloc(su_home_t *home,
+			       msg_hclass_t *hc,
+			       isize_t extra)
+{
+  isize_t size = hc->hc_size;
+  msg_header_t *h = su_alloc(home, size + extra);
+
+  if (h) {
+    memset(h, 0, size);
+    h->sh_class = hc;
+  }
+
+  return h;
+}
+
+/**Add a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c msg_header_add() adds a header or list of headers into
+ * the given place within the message structure. It also inserts the headers
+ * into the the message fragment chain, if it exists.
+ *
+ * If the header is a prepend header, the new header is inserted before
+ * existing headers of the same class. If the header is an append header,
+ * the new header is inserted after existing headers of the same class. If
+ * the header is a singleton, existing headers of the same class are
+ * removed. If the header is a list header, the values in the new header are
+ * added to the existing list.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure
+ * @param hh  place in message structure to which header is added
+ * @param h   list of header(s) to be added
+ */
+int msg_header_add(msg_t *msg,
+		   msg_pub_t *pub,
+		   msg_header_t **hh,
+		   msg_header_t *h)
+{
+  msg_header_t **head, *old = NULL, *end;
+
+  if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || hh == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  head = _msg_chain_head(msg);
+
+  if (*head) {
+    msg_header_t *sh, **prev;
+
+    for (sh = h, prev = NULL; sh; sh = sh->sh_next) {
+      sh->sh_succ = sh->sh_next;
+      sh->sh_prev = prev;
+      prev = &sh->sh_succ;
+    }
+  }
+
+  switch (h->sh_class->hc_kind) {
+  case msg_kind_single:
+  case msg_kind_list:
+    old = (*hh);
+    break;
+  case msg_kind_append:
+  case msg_kind_apndlist:
+    while (*hh)
+      hh = &(*hh)->sh_next;
+    break;
+  case msg_kind_prepend:
+    for (end = h; end->sh_next; end = end->sh_next)
+      ;
+    end->sh_next = *hh;
+  }
+
+  if (*head) {
+    /* Insert into existing fragment chain */
+    msg_insert_chain(msg, pub, msg_is_prepend(h), head, h);
+
+    /* Remove replaced fragment */
+    if (old)
+      msg_chain_remove(msg, old);
+  }
+
+  /* Insert into header list */
+  *hh = h;
+
+  return 0;
+}
+
+/**Prepend a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c msg_header_prepend() adds a header or list of headers into
+ * the given place within the message structure. It also inserts the headers
+ * into the the message fragment chain, if it exists.
+ *
+ * Unlike msg_header_add(), msg_header_prepend() always inserts header @a h
+ * before other headers of the same class. If the header is a singleton,
+ * existing headers of the same class are removed. If the header is a list
+ * header, the values in the new header are prepended to the existing list.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure
+ * @param hh  place in message structure to which header is added
+ * @param h   list of header(s) to be added
+ */
+int msg_header_prepend(msg_t *msg,
+		       msg_pub_t *pub,
+		       msg_header_t **hh,
+		       msg_header_t *h)
+{
+  msg_header_t **head, *old = NULL, *end;
+
+  assert(msg && pub);
+
+  if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || hh == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  head = _msg_chain_head(msg);
+
+  if (*head) {
+    msg_header_t *sh, **prev;
+
+    for (sh = h, prev = NULL; sh; sh = sh->sh_next) {
+      sh->sh_succ = sh->sh_next;
+      sh->sh_prev = prev;
+      prev = &sh->sh_succ;
+    }
+  }
+
+  switch (h->sh_class->hc_kind) {
+  case msg_kind_single:
+  case msg_kind_list:
+    old = (*hh);
+    break;
+  case msg_kind_append:
+  case msg_kind_apndlist:
+  case msg_kind_prepend:
+    for (end = h; end->sh_next; end = end->sh_next)
+      ;
+    end->sh_next = *hh;
+    break;
+  }
+
+  if (*head) {
+    /* Insert into existing fragment chain */
+    msg_insert_chain(msg, pub, 1, head, h);
+
+    /* Remove replaced fragment */
+    if (old)
+      msg_chain_remove(msg, old);
+  }
+
+  /* Insert into header list */
+  *hh = h;
+
+  return 0;
+}
+
+
+/** Find place to insert header of the class @a hc. */
+msg_header_t **
+msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t const *mo, msg_hclass_t *hc)
+{
+  int i;
+
+  assert(mc && hc);
+
+  if (mc == NULL || hc == NULL)
+    return NULL;
+
+  if (hc->hc_hash > 0) {
+    unsigned j, N = mc->mc_hash_size;
+    for (j = hc->hc_hash % N; mc->mc_hash[j].hr_class; j = (j + 1) % N)
+      if (mc->mc_hash[j].hr_class == hc) {
+	return (msg_header_t **)((char *)mo + mc->mc_hash[j].hr_offset);
+      }
+  }
+  else
+    /* Header has no name. */
+    for (i = 0; i <= 6; i++)
+      if (hc->hc_hash == mc->mc_request[i].hr_class->hc_hash)
+	return (msg_header_t **)((char *)mo + mc->mc_request[i].hr_offset);
+
+  return NULL;
+}
+
+/** Append a parsed header object into the message structure */
+static inline void
+append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
+	      int always_into_chain)
+{
+  msg_header_t **hh;
+
+  assert(msg); assert(hr->hr_offset);
+
+  hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+
+  if (msg->m_chain || always_into_chain)
+    msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
+
+  if (*hh && msg_is_single(h)) {
+    /* If there is multiple instances of single headers,
+       put the extra headers into the list of erroneous headers */
+    msg_error_t **e;
+
+    for (e = &mo->msg_error; *e; e = &(*e)->er_next)
+      ;
+    *e = (msg_error_t *)h;
+
+    msg->m_extract_err |= hr->hr_flags;
+    if (hr->hr_class->hc_critical)
+      mo->msg_flags |= MSG_FLG_ERROR;
+
+    return;
+  }
+
+  while (*hh)
+    hh = &(*hh)->sh_next;
+  *hh = h;
+}
+
+static int _msg_header_add_list_items(msg_t *msg, 
+				      msg_header_t **hh,
+				      msg_header_t const *src);
+
+/**Duplicate and add a (list of) header(s) to the message.
+ *
+ * The function @c msg_header_add_dup() duplicates and adds a (list of)
+ * header(s) into a message structure.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status).  Other
+ * headers are inserted after the request or status.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param src list of header(s) to be added
+ */
+int msg_header_add_dup(msg_t *msg,
+		       msg_pub_t *pub,
+		       msg_header_t const *src)
+{
+  msg_header_t *h, **hh = NULL;
+  msg_hclass_t *hc = NULL;
+
+  if (msg == NULL)
+    return -1;
+  if (src == NULL || src == MSG_HEADER_NONE)
+    return 0;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  for ( ;src; src = src->sh_next) {
+    assert(src->sh_class);
+
+    if (!src->sh_class)
+      return -1;
+
+    if (hc != src->sh_class)
+      hh = msg_hclass_offset(msg->m_class, pub, hc = src->sh_class);
+
+    if (hh == NULL)
+      return -1;
+
+    if (!*hh || hc->hc_kind != msg_kind_list) {
+      int size = hc->hc_size;
+      isize_t xtra = hc->hc_dxtra(src, size) - size;
+      char *end;
+
+      if (!(h = msg_header_alloc(msg_home(msg), hc, xtra)))
+	return -1;			/* error */
+
+      if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
+	return -1;			/* error */
+
+      if (hc->hc_update)
+	msg_header_update_params(h->sh_common, 0);
+
+      assert(end == (char *)h + size + xtra);
+
+      if (msg_header_add(msg, pub, hh, h) < 0)
+	return -1;
+
+      hh = &h->sh_next;
+    }
+    else {
+      if (_msg_header_add_list_items(msg, hh, src) < 0)
+	break;
+    }
+  }
+
+  if (src)
+    return -1;
+
+  return 0;
+}
+
+/**Duplicate a header as a given type and add the duplicate into message.
+ *
+ * The function @c msg_header_add_dup_as() duplicates a header as a instance
+ * of the given header class. It adds the new copy into the message.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status).  Other
+ * headers are inserted after the request or status.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param hc  header class for header target type
+ * @param src list of header(s) to be duplicated and added
+ */
+int msg_header_add_dup_as(msg_t *msg,
+			  msg_pub_t *pub,
+			  msg_hclass_t *hc,
+			  msg_header_t const *src)
+{
+  if (msg == NULL || hc == NULL)
+    return -1;
+  if (src == NULL || src == MSG_HEADER_NONE)
+    return 0;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  return _msg_header_add_dup_as(msg, pub, hc, src);
+}
+
+/** Duplicate and add a (list of) header to a message */
+static
+int _msg_header_add_dup_as(msg_t *msg,
+			   msg_pub_t *pub,
+			   msg_hclass_t *hc,
+			   msg_header_t const *src)
+{
+  msg_header_t *h, **hh;
+
+  hh = msg_hclass_offset(msg->m_class, pub, hc);
+
+  if (hh == NULL)
+    return -1;
+
+  if (*hh && hc->hc_kind == msg_kind_list)
+    return _msg_header_add_list_items(msg, hh, src);
+
+  if (!(h = msg_header_dup_as(msg_home(msg), hc, src)))
+    return -1;
+
+  return msg_header_add(msg, pub, hh, h);
+}
+
+/* Add list items */
+static int _msg_header_add_list_items(msg_t *msg, 
+				      msg_header_t **hh,
+				      msg_header_t const *src)
+{
+  msg_header_t *h = *hh;
+  msg_param_t **s = msg_header_params(src->sh_common);
+
+  if (!s || !*s)
+    return 0;
+  
+  msg_fragment_clear(h->sh_common);
+  
+  /* Remove empty headers */
+  for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
+    msg_chain_remove(msg, *hh);
+  
+  if (msg_header_join_items(msg_home(msg), h->sh_common, src->sh_common, 1)
+      < 0)
+    return -1;
+  
+  return 0;
+}
+
+/** Parse a string as a given header field and add result to the message. */
+int msg_header_add_make(msg_t *msg,
+			msg_pub_t *pub,
+			msg_hclass_t *hc,
+			char const *s)
+{
+  msg_header_t *h, **hh;
+
+  if (msg == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  hh = msg_hclass_offset(msg->m_class, pub, hc);
+
+  if (hh == NULL)
+    return -1;
+
+  if (!s)
+    return 0;
+
+  if (*hh && hc->hc_kind == msg_kind_list) {
+    /* Add list items */
+    msg_header_t *h = *hh;
+    msg_param_t **d;
+    char *s0;
+
+    skip_lws(&s);
+
+    d = msg_header_params(h->sh_common); assert(d);
+
+    msg_fragment_clear(h->sh_common);
+
+    /* Remove empty headers */
+    for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
+      msg_chain_remove(msg, *hh);
+
+    s0 = su_strdup(msg_home(msg), s);
+
+    if (!s0 || msg_commalist_d(msg_home(msg), &s0, d, msg_token_scan) < 0)
+      return -1;
+
+    return 0;
+  }
+
+  if (!(h = msg_header_make(msg_home(msg), hc, s)))
+    return -1;
+
+  return msg_header_add(msg, pub, hh, h);
+}
+
+/**Add string contents to message.
+ *
+ * Duplicate a string containing headers (or a message body, if the string
+ * starts with linefeed), parse it and add resulting header objects to the
+ * message object.
+ *
+ * @param msg  message object
+ * @param pub  message header structure where heades are added (may be NULL)
+ * @param str  string to be copied and parsed (not modified, may be NULL)
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int msg_header_add_str(msg_t *msg,
+		       msg_pub_t *pub,
+		       char const *str)
+{
+  char *s;
+
+  if (!msg)
+    return -1;
+  if (!str)
+    return 0;
+
+  s = su_strdup(msg_home(msg), str);
+
+  if (s == NULL)
+    return -1;
+
+  return msg_header_parse_str(msg, pub, s);
+}
+  
+/**Add string to message.
+ *
+ * Parse a string containing headers (or a message body, if the string
+ * starts with linefeed) and add resulting header objects to the message
+ * object. 
+ *
+ * @param msg  message object
+ * @param pub  message header structure where heades are added (may be NULL)
+ * @param s    string to be parsed (and modified)
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_str(), url_headers_as_string()
+ * 
+ * @since New in @VERSION_1_12_4.
+ */
+int msg_header_parse_str(msg_t *msg,
+			 msg_pub_t *pub,
+			 char *s)
+{
+  if (!msg)
+    return -1;
+
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  if (s) {
+    size_t ssiz = strlen(s), used = 0;
+    ssize_t n = 1;
+
+    while (ssiz > used) {
+      if (IS_CRLF(s[used]))
+	break;
+      n = msg_extract_header(msg, pub, s + used, ssiz - used, 1);
+      if (n <= 0)
+	break;
+      used += n;
+    }
+
+    if (n > 0 && ssiz > used) {
+      used += CRLF_TEST(s + used);
+      if (ssiz > used)
+	msg_extract_payload(msg, pub, NULL, ssiz - used,
+			    s + used, ssiz - used, 1);
+    }
+
+    if (n <= 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Insert a (list of) header(s) to the fragment chain.
+ *
+ * The function @c msg_header_insert() inserts header or list of headers
+ * into a message structure.  It also inserts them into the the message
+ * fragment chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status).  Other
+ * headers are inserted after the request or status.
+ *
+ * If there can be only one header field of this type (hc_kind is
+ * msg_kind_single), existing header objects with the same class are
+ * removed.
+ *
+ * @param msg message object owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h   list of header(s) to be added
+ */
+int msg_header_insert(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+  msg_header_t **hh;
+
+  assert(msg);
+
+  if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || 
+      h->sh_class == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  hh = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+
+  return msg_header_add(msg, pub, hh, h);
+}
+
+/**Remove a header from the header structure and fragment chain.
+ *
+ * The function @c msg_header_remove() removes a header from a message
+ * structure.  It also removes the message from the message fragment chain
+ * and clears the encoding of other headers objects that share same
+ * encoding.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h   header to be removed
+ */
+int msg_header_remove(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+  msg_header_t **hh, **hh0;
+
+  if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || 
+      h->sh_class == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  /* First, remove from public structure (msg_pub_t) */
+  hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+  if (!hh0)
+    return -1;
+
+  for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+    if (*hh == h) {
+      *hh = h->sh_next;
+      break;
+    }
+  }
+
+  if (h->sh_data) {
+    void const *data = (char *)h->sh_data + h->sh_len;
+    for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+      if (data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+	(*hh)->sh_data = NULL, (*hh)->sh_len = 0;
+      }
+    }
+  }
+
+  msg_chain_remove(msg, h);
+
+  return 0;
+}
+
+
+/**Remove a header list from the header structure and fragment chain.
+ *
+ * The function @c msg_header_remove_all() removes a list of headers from a
+ * message structure. It also removes the message from the message fragment
+ * chain and clears the encoding of other headers objects that share same
+ * encoding.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h   header list to be removed
+ */
+int msg_header_remove_all(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+  msg_header_t **hh, **hh0;
+  void const *data;
+
+  if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || 
+      h->sh_class == NULL)
+    return -1;
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+  if (!hh0)
+    return -1;
+
+  data = (char *)h->sh_data + h->sh_len;
+
+  /* First, remove from public structure (msg_pub_t) */
+  for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+    if (*hh == h) {
+      break;
+    }
+    if (data && data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+      h->sh_data = NULL, h->sh_len = 0;
+      (*hh)->sh_data = NULL, (*hh)->sh_len = 0;
+    }
+  }
+
+  /* Remove from header chain */
+  while (h) {
+    h->sh_data = NULL, h->sh_len = 0;
+    msg_chain_remove(msg, h);
+    h = h->sh_next;
+  }
+
+  *hh = NULL;
+
+  return 0;
+}
+
+
+/** Replace a header item with a (list of) header(s).
+ *
+ * The function @c msg_header_replace() removes a header structure from
+ * message and replaces it with a new one or a list of headers. It inserts
+ * the new headers into the the message fragment chain, if it exists.
+ *
+ * @param msg message object owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param replaced   old header to be removed
+ * @param h   list of header(s) to be added
+ */
+int msg_header_replace(msg_t *msg,
+		       msg_pub_t *pub,
+		       msg_header_t *replaced,
+		       msg_header_t *h)
+{
+  msg_header_t *h0, *last, **hh, **hh0;
+
+  if (msg == NULL || replaced == NULL)
+    return -1;
+  if (h == NULL || h == MSG_HEADER_NONE || h->sh_class == NULL)
+    return msg_header_remove(msg, pub, replaced);
+  if (pub == NULL)
+    pub = msg->m_object;
+
+  hh = hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+  if (hh == NULL)
+    return -1;
+  if (replaced == NULL)
+    return msg_header_add(msg, pub, hh, h);
+
+  assert(h->sh_prev == NULL);	/* Must not be in existing chain! */
+
+  for (last = h; last->sh_next; last = last->sh_next) {
+    if ((last->sh_succ = last->sh_next))
+      last->sh_next->sh_prev = &last->sh_succ;
+  }
+
+  for (h0 = *hh; h0; hh = &h0->sh_next, h0 = *hh) {
+    if (replaced == h0)
+      break;
+  }
+
+  if (h0 == NULL)
+    return -1;
+
+  *hh = h;			/* Replace in list */
+  last->sh_next = replaced->sh_next;
+
+  if (replaced->sh_prev) {
+    *replaced->sh_prev = h;
+    h->sh_prev = replaced->sh_prev;
+    if ((last->sh_succ = replaced->sh_succ))
+      last->sh_succ->sh_prev = &last->sh_succ;
+    if (msg->m_tail == &replaced->sh_succ)
+      msg->m_tail = &last->sh_succ;
+  }
+
+  assert(msg->m_tail != &replaced->sh_succ);
+
+  replaced->sh_next = NULL;
+  replaced->sh_prev = NULL;
+  replaced->sh_succ = NULL;
+
+  if (replaced->sh_data) {
+    /* Remove cached encoding if it is shared with more than one header fragments */
+    int cleared = 0;
+    void const *data = (char *)replaced->sh_data + replaced->sh_len;
+
+    for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+      if (data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+	(*hh)->sh_data = NULL, (*hh)->sh_len = 0, cleared = 1;
+      }
+    }
+
+    if (cleared)
+      replaced->sh_data = NULL, replaced->sh_len = 0;
+  }
+
+  return 0;
+}
+
+/** Free a header structure */
+void msg_header_free(su_home_t *home, msg_header_t *h)
+{
+  su_free(home, h);
+}
+
+/** Free a (list of) header structures */
+void msg_header_free_all(su_home_t *home, msg_header_t *h)
+{
+  msg_header_t *h_next;
+
+  while (h) {
+    h_next = h->sh_next;
+    su_free(home, h);
+    h = h_next;
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1991 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_parser_util.c
+ *
+ * Text-message parser helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 28 16:26:34 2001 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#include <stdarg.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/bnf.h"
+
+#include "sofia-sip/url.h"
+
+static issize_t msg_comma_scanner(char *start);
+
+/**
+ * Parse first line.
+ *
+ * Splits the first line from a message into three whitespace-separated
+ * parts.
+ */
+int msg_firstline_d(char *s, char **return_part2, char **return_part3)
+{
+  char *s1 = s, *s2, *s3;
+  size_t n;
+
+  /* Split line into three segments separated by whitespace */
+  if (s1[n = span_non_ws(s1)]) {
+    s1[n] = '\0';
+    s2 = s1 + n + 1;
+    while (IS_WS(*s2))
+      s2++;
+  }
+  else {
+    /* Hopeless - no WS in first line */
+    return -1;
+  }
+
+  n = span_non_ws(s2);
+
+  if (s2[n]) {
+    s2[n++] = '\0';
+    while (IS_WS(s2[n]))
+      n++;
+  }
+
+  s3 = s2 + n;
+
+  *return_part2 = s2;
+
+  *return_part3 = s3;
+
+  return 0;
+}
+
+/**Parse a token.
+ *
+ * Parses a token from string pointed by @a *ss. It stores the token value
+ * in @a return_token, and updates the @a ss to the end of token and
+ * possible whitespace.
+ */
+issize_t msg_token_d(char **ss, char const **return_token) 
+{
+  char *s = *ss;
+  size_t n = span_token(s);
+  if (n) {
+    for (; IS_LWS(s[n]); n++)
+      s[n] = '\0';
+    *return_token = s;
+    *ss = s + n;
+    return n;
+  }
+  else
+    return -1;
+}
+
+/** Parse a 32-bit unsigned int.
+ *
+ * The function msg_uint32_d() parses a 32-bit unsigned integer in string
+ * pointed by @a *ss. It stores the value in @a return_token and updates the
+ * @a ss to the end of integer and possible whitespace.
+ *
+ * @retval length of parsed integer, or -1 upon an error.
+ */
+issize_t msg_uint32_d(char **ss, uint32_t *return_value)
+{
+  char const *s = *ss, *s0 = s;
+  uint32_t value;
+  unsigned digit;
+
+  if (!IS_DIGIT(*s))	
+    return -1;
+
+  for (value = 0; IS_DIGIT(*s); s++) {
+    digit = *s - '0';
+    if (value > 429496729U)
+      return -1;
+    else if (value == 429496729U && digit > 5)
+      return -1;
+    value = 10 * value + digit;
+  }
+
+  if (*s) {
+    if (!IS_LWS(*s))
+      return (issize_t)-1;
+    skip_lws(&s);
+  }
+
+  *ss = (char *)s;
+  *return_value = value;
+
+  return s - s0;
+}
+
+
+/** Parse any list.
+ *
+ * Parses a list of items, separated by @a sep. The parsed string is passed
+ * in @a *ss, which is updated to point to the first non-linear-whitespace
+ * character after the list. The function modifies the string as it parses
+ * it.
+ *
+ * The parsed items are appended to the list @a *append_list. If there the
+ * list in @a *append_list is NULL, allocate a new list and return it in @a
+ * *append_list. Empty list items are ignored, and are not appended to the
+ * list.
+ *
+ * The function @b must be passed a scanning function @a scanner. The
+ * scanning function scans for a legitimate list item, for example, a token. 
+ * It should also compact the list item, for instance, if the item consists
+ * of @c name=value parameter definitions it should remove whitespace around
+ * "=" sign. The scanning function returns the length of the scanned item,
+ * including any linear whitespace after it.
+ *
+ * @param[in]     home    memory home for allocating list pointers 
+ * @param[in,out] ss      pointer to pointer to string to be parsed 
+ * @param[in,out] append_list  pointer to list
+ *                             where parsed list items are appended
+ * @param[in]     sep     separator character 
+ * @param[in]     scanner pointer to function for scanning a single item
+ * 
+ * @retval 0  if successful.
+ * @retval -1 upon an error.
+ */
+issize_t msg_any_list_d(su_home_t *home, 
+			char **ss, 
+			msg_param_t **append_list,
+			issize_t (*scanner)(char *s), 
+			int sep)
+{
+  char const *auto_list[MSG_N_PARAMS];
+  char const **list = auto_list, **re_list;
+  int N = MSG_N_PARAMS, n = 0;
+  issize_t tlen;
+  char *s = *ss;
+  char const **start;
+
+  if (!scanner)
+    return -1;
+
+  if (*append_list) {
+    list = *append_list;
+    while (list[n])
+      n++;
+    N = MSG_PARAMS_NUM(n + 1);
+  }
+
+  start = &list[n];
+
+  skip_lws(&s);
+
+  while (*s) {
+    tlen = scanner(s);
+
+    if (tlen < 0 || (s[tlen] && s[tlen] != sep && s[tlen] != ','))
+      goto error;
+
+    if (tlen > 0) {
+      if (n + 1 == N) {		/* Reallocate list? */
+	N = MSG_PARAMS_NUM(N + 1);
+	if (list == auto_list || list == *append_list) {
+	  re_list = su_alloc(home, N * sizeof(*list));
+	  if (re_list)
+	    memcpy(re_list, list, n * sizeof(*list));
+	}
+	else
+	  re_list = su_realloc(home, list, N * sizeof(*list));
+	if (!re_list)
+	  goto error;
+	list = re_list;
+      }
+      
+      list[n++] = s;
+      s += tlen;
+    }
+
+    if (*s == sep) {
+      *s++ = '\0';
+      skip_lws(&s);
+    } 
+    else if (*s)
+      break;
+  }
+
+  *ss = s;
+
+  if (n > 0 && list == auto_list) {
+    size_t size = sizeof(*list) * MSG_PARAMS_NUM(n + 1);
+    list = su_alloc(home, size);
+    if (!list) return -1;
+    memcpy((void *)list, auto_list, n * sizeof(*list));
+  }
+
+  list[n] = NULL;
+  if (n == 0)
+    list = NULL;
+
+  *append_list = list;
+  return 0;
+
+ error:
+  *start = NULL;
+  if (list != auto_list && list != *append_list)
+    su_free(home, list);
+  return -1;
+}
+
+/** Scan an attribute (name [= value]) pair.
+ *
+ * The attribute consists of name (a token) and optional value, separated by
+ * equal sign. The value can be a token or quoted string.
+ *
+ * This function compacts the scanned value. It removes the
+ * whitespace around equal sign "=" by moving the equal sign character and
+ * value towards name.
+ * 
+ * If there is whitespace within the scanned value or after it, 
+ * NUL-terminates the scanned attribute.
+ *
+ * @retval > 0 number of characters scanned, 
+ *             including the whitespace within the value
+ * @retval -1 upon an error
+ */
+issize_t msg_attribute_value_scanner(char *s)
+{
+  char *p = s;
+  size_t tlen;
+
+  skip_token(&s);
+
+  if (s == p)		/* invalid parameter name */
+    return -1;
+
+  tlen = s - p;
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+  if (*s == '=') {
+    char *v;
+    s++;
+    skip_lws(&s);
+
+    /* get value */
+    if (*s == '"') {
+      size_t qlen = span_quoted(s);
+      if (!qlen)
+	return -1;
+      v = s; s += qlen;
+    }
+    else {
+      v = s; 
+      skip_param(&s);
+      if (s == v) 
+	return -1;
+    }
+
+    if (p + tlen + 1 != v) {
+      memmove(p + tlen + 1, v, s - v);
+      p[tlen] = '=';
+      p[tlen + 1 + (s - v)] = '\0';
+    }
+  }
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+  return s - p;
+}
+
+/**Parse an attribute-value list.
+ *
+ * Parses an attribute-value list, which has syntax as follows:
+ * @code
+ *  av-list = (av-pair *(";" av-pair)
+ *  av-pair = token ["=" ( value / quoted-string) ]        ; optional value
+ * @endcode
+ *
+ * @param[in]     home      pointer to a memory home 
+ * @param[in,out] ss        pointer to string at the start of parameter list 
+ * @param[in,out] append_list  pointer to list
+ *                             where parsed list items are appended
+ *
+ * @retval >= 0 if successful
+ * @retval -1 upon an error
+ */
+issize_t msg_avlist_d(su_home_t *home, 
+		      char **ss, 
+		      msg_param_t const **append_list)
+{
+  char const *stack[MSG_N_PARAMS];
+  char const **params;
+  size_t n = 0, N;
+  char *s = *ss;
+
+  if (!*s)
+    return -1;
+
+  if (*append_list) {
+    params = (char const **)*append_list;
+    for (n = 0; params[n]; n++)
+      ;
+    N = MSG_PARAMS_NUM(n + 1);
+  } else {
+    params = stack;
+    N = MSG_PARAMS_NUM(1);
+  }
+  
+  for (;;) {
+    char *p;
+    size_t tlen;
+
+    /* XXX - we should handle also quoted parameters */
+
+    skip_lws(&s);
+    p = s;
+    skip_token(&s);
+    tlen = s - p;
+    if (!tlen)		/* invalid parameter name */
+      goto error;
+
+    if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+    if (*s == '=') {
+      char *v;
+      s++;
+      skip_lws(&s);
+
+      /* get value */
+      if (*s == '"') {
+	size_t qlen = span_quoted(s);
+	if (!qlen)
+	  goto error;
+	v = s; s += qlen;
+      }
+      else {
+	v = s; 
+	skip_param(&s);
+	if (s == v) 
+	  goto error;
+      }
+      if (p + tlen + 1 != v) {
+	p = memmove(v - tlen - 1, p, tlen);
+	p[tlen] = '=';
+      }
+
+    }
+
+    if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+    if (n == N) {
+      /* Reallocate params */
+      char **nparams = su_alloc(home,
+				(N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params));
+      if (!nparams) {
+	goto error;
+      }
+      params = memcpy(nparams, params, n * sizeof(*params));
+    }
+
+    params[n++] = p;
+
+    if (*s != ';')
+      break;
+
+    *s++ = '\0';
+  }
+
+  *ss = s;
+
+  if (params == stack) {
+    size_t size = sizeof(*params) * MSG_PARAMS_NUM(n + 1);
+    params = su_alloc(home, size);
+    if (!params) return -1;
+    memcpy((void *)params, stack, n * sizeof(*params));
+  }
+  else if (n == N) {
+    /* Reallocate params */
+    char **nparams = su_alloc(home, 
+			      (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params));
+    if (!nparams) {
+      goto error;
+    }
+    params = memcpy(nparams, params, n * sizeof(*params));
+  }
+
+  params[n] = NULL;
+
+  *append_list = params;
+
+  return 0;
+
+ error:
+  if (params != stack)
+    su_free(home, params);
+  return -1;
+}
+
+/**Parse a semicolon-separated parameter list starting with semicolon.
+ *
+ * Parse a parameter list, which has syntax as follows:
+ * @code
+ *  *(";" token [ "=" (token | quoted-string)]).
+ * @endcode
+ *
+ * @param[in]     home      pointer to a memory home 
+ * @param[in,out] ss        pointer to string at the start of parameter list 
+ * @param[in,out] append_list  pointer to list
+ *                             where parsed list items are appended
+ *
+ * @retval >= 0 if successful
+ * @retval -1 upon an error
+ *
+ * @sa msg_avlist_d()
+ */
+issize_t msg_params_d(su_home_t *home, 
+		      char **ss, 
+		      msg_param_t const **append_list)
+{
+  if (**ss == ';') {
+    *(*ss)++ = '\0';
+    *append_list = NULL;
+    return msg_avlist_d(home, ss, append_list);
+  }
+
+  if (IS_LWS(**ss)) { 
+    *(*ss)++ = '\0'; skip_lws(ss);
+  }
+
+  return 0;
+}
+
+/** Encode a list of parameters */
+isize_t msg_params_e(char b[], isize_t bsiz, msg_param_t const pparams[])
+{
+  int i;
+  char *end = b + bsiz, *b0 = b;
+  msg_param_t p;
+
+  if (pparams) 
+    for (i = 0; (p = pparams[i]); i++) {
+      if (p[0]) {
+	MSG_CHAR_E(b, end, ';');
+	MSG_STRING_E(b, end, p);
+      }
+    }
+
+  return b - b0;
+}
+
+/** Duplicate a parameter list */
+char *msg_params_dup(msg_param_t const **d, msg_param_t const s[],
+		     char *b, isize_t xtra)
+{
+  char *end = b + xtra;
+  char **pp;
+  int i;
+  isize_t n;
+
+  n = msg_params_count(s);
+
+  if (n == 0) {
+    *d = NULL;
+    return b;
+  }
+
+  MSG_STRUCT_ALIGN(b);
+  pp = (char **)b;
+
+  b += sizeof(*pp) * MSG_PARAMS_NUM(n + 1);
+
+  for (i = 0; s[i]; i++) {
+    MSG_STRING_DUP(b, pp[i], s[i]);
+  }
+  pp[i] = NULL;
+ 
+  assert(b <= end); (void)end;
+ 
+  *d = (msg_param_t const *)pp;
+
+  return b;
+} 
+
+
+/** Parse a comma-separated list.
+ *
+ * Parses a comma-separated list. The parsed string is passed in @a *ss,
+ * which is updated to point to the first non-linear-whitespace character
+ * after the list. The function modifies the string as it parses it.
+ *
+ * A pointer to the resulting list is returned in @a *retval. If there
+ * already is a list in @a *retval, new items are appended. Empty list items
+ * are ignored, and are not included in the list.
+ *
+ * The function can be passed an optional scanning function. The scanning
+ * function scans for a legitimate list item, for example, a token. It also
+ * compacts the list item, for instance, if the item consists of @c
+ * name=value parameter definitions.  The scanning function returns the
+ * length of the scanned item, including any linear whitespace after it.
+ *
+ * By default, the scanning function accepts tokens, quoted strings or
+ * separators (except comma, of course).
+ *
+ * @param[in]     home    memory home for allocating list pointers 
+ * @param[in,out] ss      pointer to pointer to string to be parsed 
+ * @param[in,out] append_list  pointer to list
+ *                             where parsed list items are appended
+ * @param[in]     scanner pointer to function scanning a single item 
+ *                        (optional)
+ * 
+ * @retval 0  if successful.
+ * @retval -1 upon an error.
+ */
+issize_t msg_commalist_d(su_home_t *home, 
+			 char **ss, 
+			 msg_param_t **append_list,
+			 issize_t (*scanner)(char *s))
+{
+  scanner = scanner ? scanner : msg_comma_scanner;
+  return msg_any_list_d(home, ss, append_list, scanner, ',');
+}
+
+/** Token scanner for msg_commalist_d() accepting also empty entries. */
+issize_t msg_token_scan(char *start)
+{
+  char *s = start;
+  skip_token(&s);
+
+  if (IS_LWS(*s))
+    *s++ = '\0';
+  skip_lws(&s);
+
+  return s - start;
+}
+
+/** Scan and compact a comma-separated item */
+static
+issize_t msg_comma_scanner(char *start)
+{
+  size_t tlen;
+  char *s, *p;
+  
+  s = p = start;
+
+  if (s[0] == ',')
+    return 0;
+
+  for (;;) {
+    /* Grab next section - token, quoted string, or separator character */
+    char c = *s;
+
+    if (IS_TOKEN(c)) 
+      tlen = span_token(s);
+    else if (c == '"')
+      tlen = span_quoted(s);
+    else /* if (IS_SEPARATOR(c)) */
+      tlen = 1;
+    
+    if (tlen == 0)
+      return -1;
+
+    if (p != s)
+      memmove(p, s, tlen);	/* Move section to end of paramexter */
+    p += tlen; s += tlen;
+    
+    skip_lws(&s);		/* Skip possible LWS */
+    
+    if (*s == '\0' || *s == ',') {		/* Test for possible end */
+      if (p != s) *p = '\0';
+      return s - start;
+    }
+
+    if (IS_TOKEN(c) && IS_TOKEN(*s))
+      *p++ = ' ';		/* Two tokens must be separated by LWS */
+  }
+}
+
+/** Parse a comment.
+ *
+ * Parses a multilevel comment. The comment assigned to return-value
+ * parameter @a return_comment is NUL-terminated. The string at return-value
+ * parameter @a ss is updated to point to first non-linear-whitespace
+ * character after the comment.
+ */
+issize_t msg_comment_d(char **ss, char const **return_comment)
+{
+  /* skip comment */
+  int level = 1;
+  char *s = *ss;
+
+  assert(s[0] == '(');
+
+  if (*s != '(')
+    return -1;
+
+  *s++ = '\0';
+
+  if (return_comment)
+    *return_comment = s;
+      
+  while (level) switch (*s++) {
+  case '(': level++; break;
+  case ')': level--; break;
+  case '\0': /* ERROR */ return -1;
+  }
+      
+  assert(s[-1] == ')');
+      
+  s[-1] = '\0';
+  skip_lws(&s);
+  *ss = s;
+
+  return 0;
+}
+
+/** Parse a quoted string */
+issize_t msg_quoted_d(char **ss, char **return_quoted)
+{
+  char *s= *ss, *s0 = s;
+  ssize_t n = span_quoted(s);
+
+  if (n <= 0)
+    return -1;
+
+  *return_quoted = s;
+  s += n;
+  if (IS_LWS(*s)) {
+    *s++ = '\0';
+    skip_lws(&s);		/* skip linear whitespace */
+  }
+
+  *ss = s;
+
+  return s - s0;
+}
+
+#if 0
+/** Calculate length of string when quoted. */
+int msg_quoted_len(char const *u)
+{
+  int rv;
+
+  if (!u)
+    return 0;
+
+  rv = span_token_lws(u);
+  if (u[rv]) {
+    /* We need to quote string */
+    int n;
+    int extra = 2; /* quote chars */
+
+    /* Find all characters to quote */
+    for (n = strcspn(u + rv, "\\\""); u[rv + n]; rv += n)
+      extra++;
+
+    rv += extra;
+  }
+
+  return rv;
+}
+#endif
+
+/**Parse @e host[":"port] pair.
+ *
+ * Parses a @e host[":"port] pair. The caller passes function a pointer to a
+ * string via @a ss, and pointers to which parsed host and port are assigned
+ * via @a hhost and @a pport, respectively. The value-result parameter @a
+ * *pport must be initialized to default value (e.g., NULL).
+ * 
+ * @param ss    pointer to pointer to string to be parsed
+ * @param return_host value-result parameter for @e host
+ * @param return_port value-result parameter for @e port
+
+ * @return 
+ * Returns zero when successful, and a negative value upon an error. The
+ * parsed values for host and port are assigned via @a return_host and @a
+ * return_port, respectively. The function also updates the pointer @a *ss,
+ * so if call is successful, the @a *ss points to first
+ * non-linear-whitespace character after @e host[":"port] pair.
+ *
+ * @note
+ * If there is no whitespace after @e port, the value in @a *pport may not be
+ * NUL-terminated.  The calling function @b must NUL terminate the value by
+ * setting the @a **ss to NUL after first examining its value.
+ */
+int msg_hostport_d(char **ss, 
+		   char const **return_host, 
+		   char const **return_port)
+{
+  char *host, *s = *ss;
+  char *port = NULL;
+
+  /* Host name */
+  host = s; 
+  if (s[0] != '[') {
+    skip_token(&s); if (host == s) return -1;
+  }
+  else {
+    /* IPv6 */
+    size_t n = strspn(++s, HEX ":.");
+    if (s[n] != ']') return -1;
+    s += n + 1;
+  }
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+  if (s[0] == ':') {
+    unsigned long nport;
+    *s++ = '\0'; skip_lws(&s);
+    if (!IS_DIGIT(*s))
+      return -1;
+    port = s;
+    nport = strtoul(s, &s, 10);
+    if (nport > 65535)
+      return -1;
+    if (IS_LWS(*s)) {
+      *s++ = '\0';
+      skip_lws(&s);
+    }
+  }
+
+  *return_host = host;
+  *return_port = port;
+  
+  *ss = s;
+
+  return 0;
+}
+
+/** Find a header parameter.
+ *
+ * Searches for given parameter @a name from the header. If parameter is
+ * found, it returns a non-NULL pointer to the parameter value. If there is
+ * no value for the name (in form "name" or "name=value"), the returned pointer
+ * points to a NUL character.
+ *
+ * @param h     pointer to header structure
+ * @param name  parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter value, or NULL if parameter was not found.
+ */
+char const *msg_header_find_param(msg_common_t const *h, char const *name)
+{
+  if (h && h->h_class->hc_params) {
+    msg_param_t const **params = (msg_param_t const **)
+      ((char *)h + h->h_class->hc_params);
+    return msg_params_find(*params, name);
+  }
+
+  return NULL;
+}
+
+/**Modify a parameter value or list item in a header.
+ * 
+ * A header parameter @a param can be just a C-string (@a is_item > 0), or
+ * it can have internal format <i>name [ "=" value]</i>. In the latter case,
+ * the value part following = is ignored when replacing or removing the
+ * parameter.
+ *
+ * @param home      memory home used to re-allocate parameter list in header
+ * @param h         pointer to a header
+ * @param param     parameter to be replaced or added
+ * @param is_item   how to interpret @a param:
+ *                  - 1 case-sensitive, no structure
+ *                  - 0 case-insensitive, <i>name [ "=" value ]</i>
+ * @param remove_replace_add  what operation to do:
+ *                  - -1 remove
+ *                  - 0 replace
+ *                  - 1 add
+ *
+ * @retval 1 if parameter was replaced or removed successfully
+ * @retval 0 if parameter was added successfully, 
+ *           or there was nothing to remove
+ * @retval -1 upon an error
+ */
+static 
+int msg_header_param_modify(su_home_t *home, msg_common_t *h,
+			    char const *param,
+			    int is_item,
+			    int remove_replace_add)
+{
+  msg_param_t *params, **pointer_to_params;
+  size_t plen, n;
+
+  if (!h || !h->h_class->hc_params || !param)
+    return -1;
+
+  pointer_to_params = (msg_param_t **)((char *)h + h->h_class->hc_params);
+  params = *pointer_to_params;
+
+  plen = is_item > 0 ? strlen(param) : strcspn(param, "=");
+  n = 0;
+  
+  if (params) {
+    /* Existing list, try to replace or remove  */
+    for (; params[n]; n++) {
+      char const *maybe = params[n];
+      
+      if (remove_replace_add > 0)
+	continue;
+
+      if (is_item > 0) {
+	if (strcmp(maybe, param) == 0) {
+	  if (remove_replace_add == 0)
+	    return 1;
+	}
+      }
+      else {
+	if (strncasecmp(maybe, param, plen) == 0 &&
+	    (maybe[plen] == '=' || maybe[plen] == 0))
+	  break;
+      }
+    }
+  }
+  
+  /* Not found? */
+  if (!params || !params[n]) {
+    if (remove_replace_add < 0)
+      return 0;		/* Nothing to remove */
+    else
+      remove_replace_add = 1;	/* Add instead of replace */
+  }
+  
+  if (remove_replace_add < 0) { /* Remove */
+    for (; params[n]; n++) 
+      params[n] = params[n + 1];
+  }
+  else {
+    if (remove_replace_add > 0) { /* Add */
+      size_t m_before = MSG_PARAMS_NUM(n + 1);
+      size_t m_after =  MSG_PARAMS_NUM(n + 2);
+      
+      assert(!params || !params[n]);
+      
+      if (m_before != m_after || !params) {
+	msg_param_t *p;
+	/* XXX - we should know when to do realloc */
+	p = su_alloc(home, m_after * sizeof(*p)); 
+	if (!p) return -1;
+	if (n > 0)
+	  memcpy(p, params, n * sizeof(p[0]));
+	*pointer_to_params = params = p;
+      }
+      params[n + 1] = NULL;
+    }
+    
+    params[n] = param;	/* Add .. or replace */
+  }
+  
+  msg_fragment_clear(h);
+
+  if (h->h_class->hc_update) {
+    /* Update shortcuts */
+    size_t namelen;
+    char const *name, *value;
+    
+    name = param;
+    namelen = strcspn(name, "=");
+    
+    if (remove_replace_add < 0)
+      value = NULL;
+    else
+      value = param + namelen + (name[namelen] == '=');
+    
+    h->h_class->hc_update(h, name, namelen, value);
+  }
+
+  return remove_replace_add <= 0; /* 0 when added, 1 otherwise */
+}
+
+/** Add a parameter to a header.
+ *
+ * You should use this function only when the header accepts multiple
+ * parameters (or list items) with the same name. If that is not the case,
+ * you should use msg_header_replace_param().
+ *
+ * @note This function @b does @b not duplicate @p param. The caller should
+ * have allocated the @a param from the memory home associated with header
+ * @a h.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field. The shortcut is usully
+ * a pointer to the parameter value. If the parameter was
+ * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field
+ * would be a pointer to "127.0.0.1". If the parameter was "received=" or
+ * "received", the shortcut would be a pointer to an empty string, "".
+ *
+ * @param home      memory home used to re-allocate parameter list in header
+ * @param h         pointer to a header
+ * @param param     parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_replace_param(), msg_header_remove_param(), 
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t, 
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param)
+{
+  return msg_header_param_modify(home, h, param, 
+				 0 /* case-insensitive name=value */, 
+				 1 /* add */);
+}
+
+
+
+/** Replace or add a parameter to a header. 
+ *
+ * A header parameter @a param is a string of format <i>name "=" value</i>
+ * or just name. The value part following "=" is ignored when selecting a
+ * parameter to replace.
+ *
+ * @note This function @b does @b not duplicate @p param. The caller should
+ * have allocated the @a param from the memory home associated with header
+ * @a h.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field.
+ *
+ * @param home      memory home used to re-allocate parameter list in header
+ * @param h         pointer to a header
+ * @param param     parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval 1 if parameter was replaced
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_remove_param(), 
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t, 
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_replace_param(su_home_t *home, 
+			     msg_common_t *h, 
+			     char const *param)
+{
+  return msg_header_param_modify(home, h, param, 
+				 0 /* case-insensitive name=value */, 
+				 0 /* replace */);
+}
+
+/** Remove a parameter from header.
+ *
+ * The parameter name is given as token optionally followed by "=" sign and
+ * value. The "=" and value after it are ignored when selecting a parameter
+ * to remove.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field. The shortcut to
+ * removed parameter would be set to NULL.
+ *
+ * @param h         pointer to a header
+ * @param name      name of parameter to be removed
+ *
+ * @retval 1 if a parameter was removed
+ * @retval 0 if no parameter was not removed
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_replace_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t, 
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_remove_param(msg_common_t *h, char const *name)
+{
+  return msg_header_param_modify(NULL, h, name, 
+				 0 /* case-insensitive name=value */, 
+				 -1 /* remove */);
+}
+
+/** Update shortcuts to parameter values.
+ *
+ * Update the shortcuts to parameter values in parameter list. For example,
+ * the "received" parameter in @Via header has shortcut in structure
+ * #sip_via_t, the @ref sip_via_s::v_received "v_received" field. The
+ * shortcut is usully a pointer to the parameter value. If the parameter was
+ * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field
+ * would be a pointer to "127.0.0.1". If the parameter was "received=" or
+ * "received", the shortcut would be a pointer to an empty string, "".
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_replace_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t, 
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_update_params(msg_common_t *h, int clear)
+{
+  msg_hclass_t *hc;
+  unsigned char offset;
+  msg_update_f *update;
+  int retval;
+  msg_param_t const *params;
+  size_t n;
+  char const *p, *v;
+  
+  if (h == NULL)
+    return errno = EFAULT, -1;
+
+  hc = h->h_class; offset = hc->hc_params; update = hc->hc_update;
+
+  if (offset == 0 || update == NULL)
+    return 0;
+
+  if (clear)
+    update(h, NULL, 0, NULL);
+
+  params = *(msg_param_t **)((char *)h + offset);
+  if (params == NULL)
+    return 0;
+
+  retval = 0;
+
+  for (p = *params; p; p = *++params) {
+    n = strcspn(p, "=");
+    v = p + n + (p[n] == '=');
+    if (update(h, p, n, v) < 0)
+      retval = -1;
+  }
+
+  return retval;
+}
+
+
+/** Find a header item.
+ *
+ * Searches for given item @a name from the header. If item is found, the
+ * function returns a non-NULL pointer to the item.
+ *
+ * @param h     pointer to header structure
+ * @param item  item
+ *
+ * @return
+ * A pointer to item, or NULL if it was not found.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_header_replace_item(), msg_header_remove_item(), 
+ * @Allow, @AllowEvents
+ */
+char const *msg_header_find_item(msg_common_t const *h, char const *item)
+{
+  if (h && h->h_class->hc_params) {
+    char const * const * items = 
+      *(char const * const * const *)
+      ((char *)h + h->h_class->hc_params);
+
+    if (items)
+      for (; *items; items++) {
+	if (strcmp(item, *items) == 0) {
+	  return *items;
+	}
+      }
+  }
+
+  return NULL;
+}
+
+
+/**Add an item to a header.
+ *
+ * This function treats a #msg_header_t as set of C strings. The @a item is
+ * a C string. If no identical string is found from the list, it is added to
+ * the list.
+ *
+ * The shortcuts, if any, to item values are updated accordingly.
+ *
+ * @param home      memory home used to re-allocate list in header
+ * @param h         pointer to a header
+ * @param item      item to be removed
+ *
+ * @retval 0 if item was added
+ * @retval 1 if item was replaced
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa msg_header_remove_item(), @Allow, @AllowEvents,
+ * msg_header_replace_param(), msg_header_remove_param(), 
+ * #msg_common_t, #msg_header_t, #msg_list_t
+ * #msg_hclass_t, msg_hclass_t::hc_params
+ */
+int msg_header_replace_item(su_home_t *home, 
+			    msg_common_t *h, 
+			    char const *item)
+{
+  return msg_header_param_modify(home, h, item, 
+				 1 /* string item */, 
+				 0 /* replace */);
+}
+
+/**Remove an item from a header.
+ *
+ * This function treats a #msg_header_t as set of C strings. The @a item is a 
+ * C string. If identical string is found from the list, it is removed.
+ *
+ * The shortcuts, if any, to item values are updated accordingly.
+ *
+ * @param h        pointer to a header
+ * @param name     item to be removed
+ *
+ * @retval 0 if item was added
+ * @retval 1 if item was replaced
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa msg_header_replace_item(), @Allow, @AllowEvents,
+ * msg_header_replace_param(), msg_header_remove_param(), 
+ * #msg_common_t, #msg_header_t, #msg_list_t
+ * #msg_hclass_t, msg_hclass_t::hc_params
+ */
+int msg_header_remove_item(msg_common_t *h, char const *name)
+{
+  return msg_header_param_modify(NULL, h, name, 
+				 1 /* item */, 
+				 -1 /* remove */);
+}
+
+
+/** Find a parameter from a parameter list.
+ *
+ * Searches for given parameter @a token from the parameter list. If
+ * parameter is found, it returns a non-NULL pointer to the parameter value. 
+ * If there is no value for the parameter (the parameter is of form "name"
+ * or "name="), the returned pointer points to a NUL character.
+ *
+ * @param params list (or vector) of parameters 
+ * @param token  parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter value, or NULL if parameter was not found.
+ */
+msg_param_t msg_params_find(msg_param_t const params[], msg_param_t token)
+{
+  if (params && token) {
+    size_t i, n = strcspn(token, "=");
+
+    assert(n > 0);
+
+    for (i = 0; params[i]; i++) {
+      msg_param_t param = params[i];
+      if (strncasecmp(param, token, n) == 0) {
+	if (param[n] == '=')
+	  return param + n + 1;
+        else if (param[n] == 0)
+	  return param + n;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+/** Find a slot for parameter from a parameter list.
+ *
+ * Searches for given parameter @a token from the parameter list. If
+ * parameter is found, it returns a non-NULL pointer to the item containing
+ * the parameter.
+ *
+ * @param params list (or vector) of parameters 
+ * @param token  parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter slot, or NULL if parameter was not found.
+ */
+msg_param_t *msg_params_find_slot(msg_param_t params[], msg_param_t token)
+{
+  if (params && token) {
+    int i;
+	size_t n = strlen(token);
+
+    assert(n > 0);
+
+    for (i = 0; params[i]; i++) {
+      msg_param_t param = params[i];
+      if (strncasecmp(param, token, n) == 0) {
+	if (param[n] == '=')
+	  return params + i;
+        else if (param[n] == 0 || token[n - 1] == '=')
+	  return params + i;
+      }
+    }
+
+  }
+
+  return NULL;
+}
+
+/** Replace or add a parameter from a list. 
+ *
+ * A non-NULL parameter list must have been created by msg_params_d()
+ * or by msg_params_dup().
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home      memory home
+ * @param inout_params   pointer to pointer to parameter list
+ * @param param     parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval 1 if parameter was replaced
+ * @retval -1 upon an error
+ */
+int msg_params_replace(su_home_t *home,
+		       msg_param_t **inout_params, 
+		       msg_param_t param)
+{
+  msg_param_t *params;
+  size_t i, n;
+
+  assert(inout_params);
+
+  if (param == NULL || param[0] == '=' || param[0] == '\0')
+    return -1;
+
+  params = *inout_params;
+
+  n = strcspn(param, "=");
+
+  if (params) {
+    /* Existing list, try to replace or remove  */
+    for (i = 0; params[i]; i++) {
+      msg_param_t maybe = params[i];
+
+      if (!(strncasecmp(maybe, param, n))) {
+	if (maybe[n] == '=' || maybe[n] == 0) {
+	  params[i] = param;	
+	  return 1;
+	}
+      }
+    }
+  }
+
+  /* Not found on list */
+  return msg_params_add(home, inout_params, param);
+}
+
+/** Remove a parameter from a list. 
+ *
+ * @retval 1 if parameter was removed
+ * @retval 0 if parameter was not found
+ * @retval -1 upon an error
+ */
+int msg_params_remove(msg_param_t *params, msg_param_t param)
+{
+  size_t i, n;
+
+  if (!params || !param || !param[0])
+    return -1;
+
+  n = strcspn(param, "=");
+  assert(n > 0);
+
+  for (i = 0; params[i]; i++) {
+    msg_param_t maybe = params[i];
+
+    if (strncasecmp(maybe, param, n) == 0) {
+      if (maybe[n] == '=' || maybe[n] == 0) {
+	/* Remove */
+	do {
+	  params[i] = params[i + 1];
+	} while (params[i++]);
+	return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+/** Calculate number of parameters in a parameter list */
+size_t msg_params_length(char const * const * params)
+{
+  size_t len;
+
+  if (!params)
+    return 0;
+
+  for (len = 0; params[len]; len++)
+    ;
+
+  return len;
+}
+
+
+/**
+ * Add a parameter to a list.
+ *
+ * Add a parameter to the list; the list must have been created by @c
+ * msg_params_d() or by @c msg_params_dup() (or it may contain only @c
+ * NULL).
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home      memory home
+ * @param inout_params   pointer to pointer to parameter list
+ * @param param     parameter to be added
+ *
+ * @retval 0 if parameter was added 
+ * @retval -1 upon an error
+ */
+int msg_params_add(su_home_t *home,
+		   msg_param_t **inout_params,
+		   msg_param_t param)
+{
+  size_t n, m_before, m_after;
+  msg_param_t *p = *inout_params;  
+
+  if (param == NULL)
+    return -1;
+
+  /* Count number of parameters */
+  for (n = 0; p && p[n]; n++)
+    ;
+
+  m_before = MSG_PARAMS_NUM(n + 1);
+  m_after =  MSG_PARAMS_NUM(n + 2);
+  
+  if (m_before != m_after || !p) {
+    p = su_alloc(home, m_after * sizeof(*p)); 
+    assert(p); if (!p) return -1;
+    if (n)
+      memcpy(p, *inout_params, n * sizeof(*p));
+    *inout_params = p;
+  }
+
+  p[n] = param;
+  p[n + 1] = NULL;
+
+  return 0;
+}
+
+static 
+int msg_param_prune(msg_param_t const d[], msg_param_t p, unsigned prune)
+{
+  size_t i, nlen;
+
+  if (prune == 1)
+    nlen = strcspn(p, "=");
+  else
+    nlen = 0;
+
+  for (i = 0; d[i]; i++) {
+    if ((prune == 1 && 
+	 strncasecmp(p, d[i], nlen) == 0 
+	 && (d[i][nlen] == '=' || d[i][nlen] == '\0'))
+	|| 
+	(prune == 2 && strcasecmp(p, d[i]) == 0)
+	||
+	(prune == 3 && strcmp(p, d[i]) == 0))
+      return 1;
+  }
+
+  return 0;
+}
+
+/**Join two parameter lists.
+ *
+ * The function @c msg_params_join() joins two parameter lists; the
+ * first list must have been created by @c msg_params_d() or by @c
+ * msg_params_dup() (or it may contain only @c NULL).
+ *
+ * @param home    memory home
+ * @param dst     pointer to pointer to destination parameter list
+ * @param src     source list
+ * @param prune   prune duplicates 
+ * @param dup     duplicate parameters in src list
+ *
+ * @par Pruning 
+ * <table>
+ * <tr><td>0<td>do not prune</tr>
+ * <tr><td>1<td>prune parameters with identical names</tr>
+ * <tr><td>2<td>case-insensitive values</tr>
+ * <tr><td>3<td>case-sensitive values</tr>
+ * </table>
+ *
+ * @return
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ */
+issize_t msg_params_join(su_home_t *home,
+			 msg_param_t **dst,
+			 msg_param_t const *src,
+			 unsigned prune,
+			 int dup)
+{
+  size_t n, m, n_before, n_after, pruned, total = 0;
+  msg_param_t *d = *dst;  
+
+  if (prune > 3)
+    return -1;
+
+  if (src == NULL || *src == NULL)
+    return 0;
+
+  /* Count number of parameters */
+  for (n = 0; d && d[n]; n++)
+    ;
+
+  n_before = MSG_PARAMS_NUM(n + 1);
+
+  for (m = 0, pruned = 0; src[m]; m++) {
+    if (n > 0 && prune > 0 && msg_param_prune(d, src[m], prune)) {
+      pruned++;
+      if (prune > 1)
+	continue;
+    }
+    if (dup)
+      total += strlen(src[m]) + 1;
+  }
+
+  n_after = MSG_PARAMS_NUM(n + m - pruned + 1);
+  
+  if (n_before != n_after || !d) {
+    d = su_alloc(home, n_after * sizeof(*d)); 
+    assert(d); if (!d) return -1;
+    if (n)
+      memcpy(d, *dst, n * sizeof(*d));
+    *dst = d;
+  }
+
+  for (m = 0; src[m]; m++) {
+    if (pruned && msg_param_prune(d, src[m], prune)) {
+      pruned--;
+      if (prune > 1)
+	continue;
+    }
+
+    if (dup)
+      d[n++] = su_strdup(home, src[m]);	/* XXX */
+    else
+      d[n++] = src[m];
+  }  
+
+  d[n] = NULL;
+
+  return 0;
+}
+
+/**Join header item lists.
+ *
+ * Join items from a source header to the destination header. The item are
+ * compared with the existing ones. If a match is found, it is not added to
+ * the list. If @a duplicate is true, the entries are duplicated while they
+ * are added to the list.
+ *
+ * @param home       memory home
+ * @param dst        destination header
+ * @param src        source header
+ * @param duplicate  if true, allocate and copy items that are added
+ *
+ * @return
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ *
+ * @NEW_1_12_5.
+ */
+int msg_header_join_items(su_home_t *home,
+			  msg_common_t *dst,
+			  msg_common_t const *src,
+			  int duplicate)
+{
+  size_t N, m, M, i, n_before, n_after, total;
+  char *dup = NULL;
+  msg_param_t *d, **dd, *s;
+  msg_param_t t, *temp, temp0[16];
+  size_t *len, len0[(sizeof temp0)/(sizeof temp0[0])];
+  msg_update_f *update = NULL;
+
+  if (dst == NULL || dst->h_class->hc_params == 0 ||
+      src == NULL || src->h_class->hc_params == 0)
+    return -1;
+
+  s = *(msg_param_t **)((char *)src + src->h_class->hc_params);
+  if (s == NULL)
+    return 0;
+
+  for (M = 0; s[M]; M++);
+
+  if (M == 0)
+    return 0;
+
+  if (M <= (sizeof temp0) / (sizeof temp0[0])) {
+    temp = temp0, len = len0;
+  }
+  else {
+    temp = malloc(M * (sizeof *temp) + M * (sizeof *len));
+    if (!temp) return -1;
+    len = (void *)(temp + M);
+  }
+
+  dd = (msg_param_t **)((char *)dst + dst->h_class->hc_params);
+  d = *dd;
+
+  for (N = 0; d && d[N]; N++);
+
+  for (m = 0, M = 0, total = 0; s[m]; m++) {
+    t = s[m];
+    for (i = 0; i < N; i++)
+      if (strcmp(t, d[i]) == 0)
+	break;
+    if (i < N)
+      continue;
+
+    for (i = 0; i < M; i++)
+      if (strcmp(t, temp[i]) == 0)
+	break;
+    if (i < M)
+      continue;
+
+    temp[M] = t;
+    len[M] = strlen(t);
+    total += len[M++] + 1;
+  }
+
+  if (M == 0)
+    goto success;
+
+  dup = su_alloc(home, total); if (!dup) goto error;
+
+  n_before = MSG_PARAMS_NUM(N + 1);
+  n_after = MSG_PARAMS_NUM(N + M + 1);
+
+  if (d == NULL || n_before != n_after) {
+    d = su_alloc(home, n_after * sizeof(*d)); if (!d) goto error;
+    if (N)
+      memcpy(d, *dd, N * sizeof(*d));
+    *dd = d;
+  }
+
+  update = dst->h_class->hc_update;
+
+  for (m = 0; m < M; m++) {
+    d[N++] = memcpy(dup, temp[m], len[m] + 1);
+    
+    if (update)
+      update(dst, dup, len[m], dup + len[m]);
+
+    dup += len[m] + 1;
+  }  
+
+  d[N] = NULL;
+
+ success:
+  if (temp != temp0)
+    free(temp);
+  return 0;
+
+ error:
+  if (temp != temp0)
+    free(temp);
+  su_free(home, dup);
+  return -1;
+}
+
+/**Compare parameter lists.
+ * 
+ * Compares parameter lists.
+ *
+ * @param a pointer to a parameter list
+ * @param b pointer to a parameter list
+ *
+ * @retval an integer less than zero if @a is less than @a b
+ * @retval an integer zero if @a match with @a b
+ * @retval an integer greater than zero if @a is greater than @a b
+ */
+int msg_params_cmp(char const * const a[], char const * const b[])
+{
+  int c;
+  size_t nlen;
+
+  if (a == NULL || b == NULL)
+    return (a != NULL) - (b != NULL);
+
+  for (;;) {
+    if (*a == NULL || *b == NULL)
+      return (*a != NULL) - (*b != NULL);
+    nlen = strcspn(*a, "=");
+    if ((c = strncasecmp(*a, *b, nlen)))
+      return c;
+    if ((c = strcmp(*a + nlen, *b + nlen)))
+      return c;
+    a++, b++;
+  }
+}
+
+
+/** Unquote string 
+ *
+ * Duplicates the string @a q in unquoted form.
+ */
+char *msg_unquote_dup(su_home_t *home, char const *q)
+{
+  char *d;
+  size_t total, n, m;
+
+  /* First, easy case */
+  if (q[0] == '"')
+    q++;
+  n = strcspn(q, "\"\\");
+  if (q[n] == '\0' || q[n] == '"')
+    return su_strndup(home, q, n);
+
+  /* Hairy case - backslash-escaped chars */
+  total = n;
+  for (;;) {
+    if (q[n] == '\0' || q[n] == '"' || q[n + 1] == '\0')
+      break;
+    m = strcspn(q + n + 2, "\"\\");
+    total += m + 1;
+    n += m + 2; 
+  }
+
+  if (!(d = su_alloc(home, total + 1)))
+    return NULL;
+
+  for (n = 0;;) {
+    m = strcspn(q, "\"\\");
+    memcpy(d + n, q, m); 
+    n += m, q += m;
+    if (q[0] == '\0' || q[0] == '"' || q[1] == '\0')
+      break;
+    d[n++] = q[1]; 
+    q += 2;
+  }
+  assert(total == n);
+  d[n] = '\0';
+  
+  return d;
+}
+
+/** Unquote string */
+char *msg_unquote(char *dst, char const *s)
+{
+  int copy = dst != NULL;
+  char *d = dst;
+
+  if (*s++ != '"')
+    return NULL;
+
+  for (;;) {
+    size_t n = strcspn(s, "\"\\");
+    if (copy)
+      memmove(d, s, n);
+    s += n;
+    d += n;
+
+    if (*s == '\0')
+      return NULL;
+    else if (*s == '"') {
+      if (copy) *d = '\0';
+      return dst;
+    }
+    else {
+      /* Copy quoted char */
+      if ((copy ? (*d++ = *++s) : *++s) == '\0')
+	return NULL;
+      s++;
+    }
+  }
+}
+
+/** Quote string */
+issize_t msg_unquoted_e(char *b, isize_t bsiz, char const *s)
+{
+  char *begin = b;
+  char *end = b + bsiz;
+
+  if (b && b + 1 < end)
+    *b = '"';
+  b++;
+  
+  for (;*s;) {
+    size_t n = strcspn(s, "\"\\");
+
+    if (n == 0) {
+      if (b && b + 2 < end)
+	b[0] = '\\', b[1] = s[0];
+      b += 2;
+      s++;
+    }
+    else {
+      if (b && b + n < end)
+	memcpy(b, s, n);
+      b += n;
+      s += n;
+    }
+  }
+
+  if (b && b + 1 < end)
+    *b = '"';
+  b++;
+
+  return b - begin;
+}
+
+
+/** Calculate a simple hash over a string. */
+unsigned long msg_hash_string(char const *id)
+{
+  unsigned long hash = 0;
+
+  if (id)
+    for (; *id; id++) {
+      hash += (unsigned)*id;
+      hash *= 38501U;
+    }
+  else
+    hash *= 38501U;
+
+  if (hash == 0)
+    hash = (unsigned long)-1;
+  
+  return hash;
+}
+
+
+/** Calculate the size of a duplicate of a header structure. */
+isize_t msg_header_size(msg_header_t const *h)
+{
+  if (h == NULL || h == MSG_HEADER_NONE)
+    return 0;
+  else
+    return h->sh_class->hc_dxtra(h, h->sh_class->hc_size);
+}
+
+
+/** Encode a message to the buffer. 
+ *
+ * The function msg_encode_e encodes a message to a given buffer.
+ * It returns the length of the message to be encoded, even if the
+ * buffer is too small (just like snprintf() is supposed to do).
+ *
+ * @param b        buffer (may be NULL)
+ * @param size     size of buffer 
+ * @param mo       public message structure (#sip_t, #http_t)
+ * @param flags    see #
+ */
+issize_t msg_object_e(char b[], isize_t size, msg_pub_t const *mo, int flags)
+{
+  size_t rv = 0;
+  ssize_t n;
+  msg_header_t const *h;
+
+  if (mo->msg_request)
+    h = mo->msg_request;
+  else
+    h = mo->msg_status;
+
+  for (; h; h = h->sh_succ) {
+    n = msg_header_e(b, size, h, flags);
+    if (n < 0)
+      return -1;
+    if ((size_t)n < size)
+      b += n, size -= n;
+    else
+      b = NULL, size = 0;
+    rv += n;
+  }
+
+  return rv;
+}
+
+/** Encode header contents. */
+issize_t msg_header_field_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  assert(h); assert(h->sh_class); 
+
+  return h->sh_class->hc_print(b, bsiz, h, flags);
+}
+
+/** Get offset of header @a h from structure @a mo. */
+msg_header_t **
+msg_header_offset(msg_t const *msg, msg_pub_t const *mo, msg_header_t const *h)
+{
+  if (h == NULL || h->sh_class == NULL) 
+    return NULL;
+
+  return msg_hclass_offset(msg->m_class, mo, h->sh_class);
+}
+
+/**Get a header from the public message structure.
+ *
+ * Gets a pointer to header from a message structure.
+ *
+ * @param pub public message structure from which header is obtained
+ * @param hc  header class
+ */
+msg_header_t *
+msg_header_access(msg_pub_t const *pub, msg_hclass_t *hc)
+{
+  msg_header_t * const * hh;
+
+  if (pub == NULL || hc == NULL)
+    return NULL;
+
+  hh = msg_hclass_offset((void *)pub->msg_ident, (msg_pub_t *)pub, hc);
+
+  if (hh)
+    return *hh;
+  else 
+    return NULL;
+}
+
+#include <sofia-sip/su_uniqueid.h>
+
+/** Generates a random token.
+ *
+ */
+issize_t msg_random_token(char token[], isize_t tlen, 
+			  void const *rmemp, isize_t rsize)
+{
+  uint32_t random = 0, rword;
+  uint8_t rbyte;
+  uint8_t const *rmem = rmemp;
+  size_t i;
+  ssize_t n;
+
+  static char const token_chars[33] = 
+    /* Create aesthetically pleasing raNDom capS LooK */
+    "aBcDeFgHjKmNpQrStUvXyZ0123456789";
+
+  if (rmem == NULL && rsize == 0)
+    rsize = UINT_MAX;
+
+  if (rsize == 0) {
+    if (token && tlen > 0)
+      strcpy(token, "+");
+    return 1;
+  }
+
+  if (token == NULL) {
+    if (rsize >= tlen * 5 / 8)
+      return tlen;
+    else
+      return rsize / 5 * 8;
+  }
+    
+  for (i = 0, n = 0; i < tlen;) {
+    if (n < 5) {
+      if (rsize == 0)
+	;
+      else if (rmem) {
+	rbyte = *rmem++, rsize--;
+	random = random | (rbyte << n);
+	n += 8;
+      } else {
+	rword = su_random();
+	random = (rword >> 13) & 31;
+	n = 6;
+      }
+    }
+
+    token[i] = token_chars[random & 31];
+    random >>= 5;
+    i++, n -= 5;
+
+    if (n < 0 || (n == 0 && rsize == 0))
+      break;
+  }
+  
+  token[i] = 0;
+
+  return i;
+}
+
+
+/** Parse a message.
+ *
+ * Parse a text message with parser @a mc. The @a data is copied and it is
+ * not modified or referenced by the parsed message.
+ *
+ * @par Example
+ * Parse a SIP message fragment (e.g., payload of NOTIFY sent in response to
+ * REFER):
+ * @code
+ * msg_t *m = msg_make(sip_default_mclass(), 0, pl->pl_data, pl->pl_len);
+ * sip_t *frag = sip_object(m);
+ * @endcode
+ *
+ * @param mc message class (parser table)
+ * @param flags message flags (see #msg_flg_user)
+ * @param data message text
+ * @param len size of message text (if -1, use strlen(data))
+ * 
+ * @retval A pointer to a freshly allocated and parsed message.
+ *
+ * Upon parsing error, the header structure may be left incomplete. The
+ * #MSG_FLG_ERROR is set in @a msg_object(msg)->msg_flags.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_as_string(), msg_extract()
+ */
+msg_t *msg_make(msg_mclass_t const *mc, int flags,
+		void const *data, ssize_t len)
+{
+  msg_t *msg;
+  msg_iovec_t iovec[2];
+
+  if (len == -1)
+    len = strlen(data);
+  if (len == 0) 
+    return NULL;
+
+  msg = msg_create(mc, flags);
+
+  su_home_preload(msg_home(msg), 1, len + 1024);
+
+  if (msg_recv_iovec(msg, iovec, 2, len, 1) < 0) {
+    perror("msg_recv_iovec");
+  }
+  assert((ssize_t)iovec->mv_len == len);
+  memcpy(iovec->mv_base, data, len);
+  msg_recv_commit(msg, len, 1);
+
+  if (msg_extract(msg) < 0)
+    msg->m_object->msg_flags |= MSG_FLG_ERROR;
+
+  return msg;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,371 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE msg_tag.c  Message tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+#define TAG_NAMESPACE "msg"
+
+#include "msg_internal.h"
+#include "sofia-sip/msg_header.h"
+#include "sofia-sip/msg_parser.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/su_tagarg.h>
+#include "sofia-sip/msg_tag_class.h"
+
+#define NONE ((void*)-1)
+
+int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  msg_header_t const *h;
+
+  assert(t);
+
+  if (!t) { 
+    if (size) b[0] = 0; 
+    return 0; 
+  }
+
+  h = (msg_header_t const *)t->t_value;
+
+  if (h != MSG_HEADER_NONE && h != NULL) {
+    return msg_header_field_e(b, size, h, 0);
+  }
+  else {
+    return snprintf(b, size, "<NONE>");
+  }
+}
+
+size_t msghdrtag_xtra(tagi_t const *t, size_t offset)
+{
+  msg_header_t const *h;
+  size_t rv;
+  msg_hclass_t *hc = (msg_hclass_t *)t->t_tag->tt_magic;
+  assert(t);
+
+  for (h = (msg_header_t const *)t->t_value, rv = offset;
+       h != NULL;
+       h = h->sh_next) {
+    if (h == MSG_HEADER_NONE)
+      break;
+    MSG_STRUCT_SIZE_ALIGN(rv);
+    if (hc)
+      rv = hc->hc_dxtra(h, rv + h->sh_class->hc_size);
+    else
+      rv = h->sh_class->hc_dxtra(h, rv + h->sh_class->hc_size);
+  }
+
+  return rv - offset;
+}
+
+tagi_t *msghdrtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  msg_header_t const *o;
+  msg_header_t *h, *h0 = NULL, **hh;
+  msg_hclass_t *hc, *hc0 = (msg_hclass_t *)src->t_tag->tt_magic;
+  char *b;
+  size_t size;
+
+  assert(src); assert(*bb); 
+
+  dst->t_tag = src->t_tag;
+  dst->t_value = 0L;
+
+  b = *bb;
+  hh = &h0;
+
+  for (o = (msg_header_t const *)src->t_value;
+       o != NULL;
+       o = o->sh_next) {
+    if (o == MSG_HEADER_NONE) {
+      *hh = (msg_header_t *)o;
+      break;
+    }
+
+    /* XXX assert(msg_hdr_p(o)); */
+
+    MSG_STRUCT_ALIGN(b);
+    h = (msg_header_t *)b;
+    hc = hc0 ? hc0 : o->sh_class;
+    b += hc->hc_size;
+    memset(h, 0, hc->hc_size);
+    h->sh_class = hc;
+
+    size = SIZE_MAX - (uintptr_t)b;
+    if (size > ISSIZE_MAX)
+      size = ISSIZE_MAX;
+    b = hc->hc_dup_one(h, o, b, size);
+
+    if (hc->hc_update)
+      msg_header_update_params(h->sh_common, 0);
+
+    *hh = h; hh = &h->sh_next;
+
+    assert(b != NULL);
+  }
+  *bb = b;
+
+  dst->t_value = (tag_value_t)h0;
+
+  return dst + 1;
+}
+
+
+/** Convert a string to a header structure based on to the tag. */
+int msghdrtag_scan(tag_type_t tt, su_home_t *home, 
+		   char const *s, 
+		   tag_value_t *return_value)
+{
+  msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
+  msg_header_t *h;
+  int retval;
+
+  h = msg_header_make(home, hc, s);
+  
+  if (h)
+    *return_value = (tag_value_t)h, retval = 1;
+  else
+    *return_value = (tag_value_t)NULL, retval = -1;
+  
+  return retval;
+}
+
+
+tagi_t *msgstrtag_filter(tagi_t *dst,
+			 tagi_t const f[],
+			 tagi_t const *src, 
+			 void **bb);
+
+int msgobjtag_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  msg_pub_t const *mo;
+
+  assert(t);
+
+  if (!t || !t->t_value) { 
+    if (size) b[0] = 0; 
+    return 0; 
+  }
+
+  mo = (msg_pub_t *)t->t_value;
+
+  return (int)msg_object_e(b, size, mo, MSG_DO_CANONIC);
+}
+
+
+size_t msgobjtag_xtra(tagi_t const *t, size_t offset)
+{
+  msg_header_t const *h;
+  msg_pub_t const *mo;
+  size_t rv;
+
+  assert(t);
+
+  mo = (msg_pub_t const *)t->t_value;
+
+  if (mo == NULL || mo == NONE)
+    return 0;
+
+  rv = offset;
+
+  MSG_STRUCT_SIZE_ALIGN(rv);
+  rv += mo->msg_size;
+
+  if (mo->msg_request)
+    h = (msg_header_t const *)mo->msg_request;
+  else
+    h = (msg_header_t const *)mo->msg_status;
+
+  for (; h; h = h->sh_succ) {
+    MSG_STRUCT_SIZE_ALIGN(rv);
+    rv += msg_header_size(h);
+  }
+
+  return rv - offset;
+}
+
+
+tagi_t *msgobjtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  msg_pub_t const *omo;
+  msg_pub_t *mo;
+  msg_header_t *h;
+  msg_header_t const *o;
+  char *b;
+
+  assert(src); assert(*bb); 
+
+  omo = (msg_pub_t const *)src->t_value;
+
+  dst->t_tag = src->t_tag;
+  dst->t_value = 0;
+
+  if (omo == NULL || omo == NONE) {
+    dst->t_value = src->t_value;
+    return dst + 1;
+  }
+
+  b = *bb;
+  MSG_STRUCT_ALIGN(b);
+  mo = (msg_pub_t *)b;
+  b += omo->msg_size;
+
+  memset(mo, 0, omo->msg_size);
+  mo->msg_size = omo->msg_size;
+  mo->msg_flags = omo->msg_flags;
+
+  if (mo->msg_request)
+    o = mo->msg_request;
+  else
+    o = mo->msg_status;
+
+  for (; o; o = o->sh_succ) {
+    size_t size;
+    MSG_STRUCT_ALIGN(b);
+    h = (msg_header_t *)b;
+    b += o->sh_class->hc_size;
+    memset(h, 0, o->sh_class->hc_size);
+    h->sh_class = o->sh_class;
+    size = SIZE_MAX - (uintptr_t)b;
+    if (size > ISSIZE_MAX)
+      size = ISSIZE_MAX;
+    b = o->sh_class->hc_dup_one(h, o, b, size);
+    if (o->sh_class->hc_update)
+      msg_header_update_params(h->sh_common, 0);
+    assert(b != NULL);
+  }
+
+  dst->t_value = (tag_value_t)mo;
+  *bb = b;
+
+  return dst + 1;
+}
+
+#if 0
+
+int msgtag_multipart_xtra(tagi_t const *t, int offset)
+{
+  msg_header_t const *h;
+  msg_multipart_t const *mp;
+  int rv;
+
+  assert(t);
+
+  mp = (msg_multipart_t const *)t->t_value;
+
+  if (mp == NULL || mp == NONE)
+    return 0;
+
+  rv = offset;
+
+  MSG_STRUCT_SIZE_ALIGN(rv);
+  rv += mo->msg_size;
+
+  if (mo->msg_request)
+    h = (msg_header_t const *)mo->msg_request;
+  else
+    h = (msg_header_t const *)mo->msg_status;
+
+  for (; h; h = h->sh_succ) {
+    MSG_STRUCT_SIZE_ALIGN(rv);
+    rv += msg_header_size(h);
+  }
+
+  return rv - offset;
+}
+
+
+tagi_t *msgtag_multipart_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  msg_pub_t const *omo;
+  msg_pub_t *mo;
+  msg_header_t *h;
+  msg_header_t const *o;
+  char *b;
+
+  assert(src); assert(*bb); 
+
+  omo = (msg_pub_t const *)src->t_value;
+
+  dst->t_tag = src->t_tag;
+  dst->t_value = 0;
+
+  if (omo == NULL || omo == NONE) {
+    dst->t_value = src->t_value;
+    return dst + 1;
+  }
+
+  b = *bb;
+  MSG_STRUCT_ALIGN(b);
+  mo = (msg_pub_t *)b;
+  b += omo->msg_size;
+
+  memset(mo, 0, omo->msg_size);
+  mo->msg_size = omo->msg_size;
+  mo->msg_flags = omo->msg_flags;
+
+  if (mo->msg_request)
+    o = mo->msg_request;
+  else
+    o = mo->msg_status;
+
+  for (; o; o = o->sh_succ) {
+    size_t size;
+    MSG_STRUCT_ALIGN(b);
+    h = (msg_header_t *)b;
+    b += o->sh_class->hc_size;
+    memset(h, 0, o->sh_class->hc_size);
+    h->sh_class = o->sh_class;
+    size = SIZE_MAX - (uintptr_t)b;
+    if (size > ISSIZE_MAX)
+      size = ISSIZE_MAX;
+    b = o->sh_class->hc_dup_one(h, o, b, size);
+    if (o->sh_class->hc_update)
+      msg_header_update_params(h->sh_common, 0);
+    assert(b != NULL);
+  }
+
+  dst->t_value = (long)mo;
+  *bb = b;
+
+  return dst + 1;
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,173 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_H
+/** Defined when <sofia-sip/msg.h> has been included */
+#define MSG_H
+/**@file sofia-sip/msg.h
+ *
+ * Base message interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 18 08:54:48 2000 ppessi
+ */
+
+#include <sofia-sip/msg_types.h>
+#include <sofia-sip/su_alloc.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN msg_t *msg_create(msg_mclass_t const *mc, int flags);
+SOFIAPUBFUN void msg_destroy(msg_t *);
+
+SOFIAPUBFUN msg_t *msg_copy(msg_t *);
+SOFIAPUBFUN msg_t *msg_dup(msg_t const *);
+
+SOFIAPUBFUN msg_t *msg_make(msg_mclass_t const *mc, int flags,
+			    void const *data, ssize_t len);
+SOFIAPUBFUN char *msg_as_string(su_home_t *home,
+				msg_t *msg, msg_pub_t *pub, int flags,
+				size_t *return_len);
+
+SOFIAPUBFUN void msg_set_parent(msg_t *kid, msg_t *dad);
+
+SOFIAPUBFUN msg_t *msg_ref_create(msg_t *);
+SOFIAPUBFUN void msg_ref_destroy(msg_t *);
+     
+SOFIAPUBFUN msg_pub_t *msg_public(msg_t const *msg, void *tag);
+SOFIAPUBFUN msg_pub_t *msg_object(msg_t const *msg);
+SOFIAPUBFUN msg_mclass_t const *msg_mclass(msg_t const *msg);
+
+SOFIAPUBFUN int msg_extract(msg_t *msg);
+SOFIAPUBFUN unsigned msg_extract_errors(msg_t const *msg);
+SOFIAPUBFUN int msg_is_complete(msg_t const *msg);
+SOFIAPUBFUN int msg_has_error(msg_t const *msg);
+SOFIAPUBFUN msg_header_t **msg_chain_head(msg_t const *msg);
+
+SOFIAPUBFUN int msg_serialize(msg_t *msg, msg_pub_t *mo);
+SOFIAPUBFUN int msg_prepare(msg_t *msg);
+SOFIAPUBFUN void msg_unprepare(msg_t *msg);
+SOFIAPUBFUN int msg_is_prepared(msg_t const *msg);
+
+SOFIAPUBFUN usize_t msg_size(msg_t const *msg);
+SOFIAPUBFUN usize_t msg_maxsize(msg_t *msg, usize_t maxsize);
+
+/** Cast a #msg_t pointer to a #su_home_t pointer. */
+#define msg_home(h) ((su_home_t*)(h))
+
+/** Streaming state of a #msg_t object. */
+enum msg_streaming_status {
+  /** Disable streaming */
+  msg_stop_streaming = 0,
+  /** Enable streaming */
+  msg_start_streaming = 1
+};
+
+SOFIAPUBFUN int msg_is_streaming(msg_t const *msg);
+SOFIAPUBFUN void msg_set_streaming(msg_t *msg, enum msg_streaming_status what);
+
+SOFIAPUBFUN unsigned msg_mark_as_complete(msg_t *msg, unsigned mask);
+
+SOFIAPUBFUN unsigned msg_get_flags(msg_t const *msg, unsigned mask);
+SOFIAPUBFUN unsigned msg_set_flags(msg_t *msg, unsigned mask);
+SOFIAPUBFUN unsigned msg_zap_flags(msg_t *msg, unsigned mask);
+
+/** Flags controlling parser/printer. */
+enum msg_flg_user {
+  /** Use compact form when printing. */
+  MSG_FLG_COMPACT = (1<<0),
+  /** Use canonic representation when printing. */
+  MSG_FLG_CANONIC = (1<<1),
+  /** Cache a copy of headers when parsing. */
+  MSG_FLG_EXTRACT_COPY = (1<<2),
+  /** Print comma-separated lists instead of separate headers */
+  MSG_FLG_COMMA_LISTS = (1<<3),	
+
+  /**Use mailbox format when parsing - in mailbox format 
+   * message has no body unless Content-Length header is present.
+   */
+  MSG_FLG_MAILBOX = (1<<4),
+
+  /** Use multiple parts for message body */
+  MSG_FLG_CHUNKING = (1<<5),
+
+  /** Enable streaming - parser gives completed message fragments when they
+   * are ready to upper layers */
+  MSG_FLG_STREAMING = (1<<6),
+
+  /** Make messages threadsafe. */
+  MSG_FLG_THRDSAFE = (1<<15),
+
+  MSG_FLG_USERMASK = (1<<16) - 1
+};
+
+/** Flags used by parser. */
+enum  msg_flg_parser {
+  /** Extract headers for this message */
+  MSG_FLG_HEADERS = (1<<16),
+  /** Extract body for this message */
+  MSG_FLG_BODY = (1<<17),
+  /** Extract chunks for this message */
+  MSG_FLG_CHUNKS = (1<<18),
+  /** Extract trailers for this message */
+  MSG_FLG_TRAILERS = (1<<19),
+  /** Extract last component of this message */
+  MSG_FLG_FRAGS = (1<<20),
+  /** This message has been completely extracted */
+  MSG_FLG_COMPLETE = (1<<24),
+
+  /** This message has parsing errors */
+  MSG_FLG_ERROR = (1<<25),
+  /** This message is too large */
+  MSG_FLG_TOOLARGE = (1<<26),
+  /** This message is truncated */
+  MSG_FLG_TRUNC = (1<<27),
+  /** This message has timeout */
+  MSG_FLG_TIMEOUT = (1<<28),
+
+  MSG_FLG_PARSERMASK = ((-1) ^ ((1<<16) - 1))
+};
+
+#define MSG_DO_COMPACT      MSG_FLG_COMPACT
+#define MSG_DO_CANONIC      MSG_FLG_CANONIC
+#define MSG_DO_EXTRACT_COPY MSG_FLG_EXTRACT_COPY
+
+/** Test if all the flags in @a v are set in @a f. */
+#define MSG_FLAGS(f, v) (((f) & (v)) == v)
+
+#define MSG_IS_COMPACT(f)      MSG_FLAGS((f), MSG_FLG_COMPACT)
+#define MSG_IS_CANONIC(f)      MSG_FLAGS((f), MSG_FLG_CANONIC)
+#define MSG_IS_EXTRACT_COPY(f) MSG_FLAGS((f), MSG_FLG_EXTRACT_COPY)
+#define MSG_IS_COMMA_LISTS(f)  MSG_FLAGS((f), MSG_FLG_COMMA_LISTS)
+#define MSG_IS_MAILBOX(f)      MSG_FLAGS((f), MSG_FLG_MAILBOX)
+
+#define MSG_HAS_COMPLETE(f)    MSG_FLAGS((f), MSG_FLG_COMPLETE)
+#define MSG_HAS_ERROR(f)       MSG_FLAGS((f), MSG_FLG_ERROR)
+
+#define MSG_IS_COMPLETE(mo) (((mo)->msg_flags & MSG_FLG_COMPLETE) != 0)
+
+SOFIA_END_DECLS
+
+#endif /* MSG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_ADDR_H
+/** Defined when <sofia-sip/msg_addr.h> has been included. */
+#define MSG_ADDR_H 
+
+
+/**@file sofia-sip/msg_addr.h 
+ * @brief Addressing and I/O interface for messages.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN void msg_addr_zero(msg_t *msg);
+SOFIAPUBFUN su_addrinfo_t *msg_addrinfo(msg_t *msg);
+
+SOFIAPUBFUN su_sockaddr_t *msg_addr(msg_t *msg);
+
+SOFIAPUBFUN int msg_get_address(msg_t *msg, su_sockaddr_t *, socklen_t *);
+SOFIAPUBFUN int msg_set_address(msg_t *msg, su_sockaddr_t const *, socklen_t);
+
+SOFIAPUBFUN void msg_addr_copy(msg_t *dst, msg_t const *src);
+
+SOFIAPUBFUN int msg_errno(msg_t const *msg);
+SOFIAPUBFUN void msg_set_errno(msg_t *msg, int err);
+
+enum {
+  /** Minimum size of a message buffer */
+  msg_min_size = 512,
+  /** Minimum size of external buffer */
+  msg_min_block = 8192,
+  /** Number of external buffers */
+  msg_n_fragments = 8
+};
+
+/** I/O vector type. 
+ * @sa msg_recv_iovec(), msg_iovec(), #su_iovec_s, su_vsend(), su_vrecv(). 
+ */
+typedef struct su_iovec_s msg_iovec_t;
+#define mv_base siv_base
+#define mv_len  siv_len
+
+SOFIAPUBFUN isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen);
+
+SOFIAPUBFUN issize_t msg_recv_iovec(msg_t *msg,
+				    msg_iovec_t vec[], isize_t veclen, usize_t n,
+				    int exact);
+SOFIAPUBFUN isize_t msg_recv_commit(msg_t *msg, usize_t n, int eos);
+
+SOFIAPUBFUN issize_t msg_recv_buffer(msg_t *msg, void **return_buffer);
+
+SOFIAPUBFUN msg_t *msg_next(msg_t *msg);
+
+SOFIAPUBFUN int msg_set_next(msg_t *msg, msg_t *next);
+
+SOFIAPUBFUN void msg_clear_committed(msg_t *msg);
+
+SOFIAPUBFUN issize_t msg_buf_external(msg_t *msg, 
+				      usize_t N, 
+				      usize_t blocksize);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(MSG_ADDR_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_BUFFER_H
+/** Defined when <sofia-sip/msg_buffer.h> has been included. */
+#define MSG_BUFFER_H
+
+/**@file sofia-sip/msg_buffer.h
+ * @brief Internal buffer management functions. 
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri Nov  8 12:23:00 2002 ppessi
+ *
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN void *msg_buf_alloc(msg_t *msg, usize_t size);
+SOFIAPUBFUN void *msg_buf_exact(msg_t *msg, usize_t size);
+SOFIAPUBFUN usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos);
+SOFIAPUBFUN usize_t msg_buf_committed(msg_t const *msg);
+SOFIAPUBFUN void *msg_buf_committed_data(msg_t const *msg);
+SOFIAPUBFUN usize_t msg_buf_size(msg_t const *msg);
+
+SOFIAPUBFUN void *msg_buf_move(msg_t *dst, msg_t const *src);
+
+SOFIAPUBFUN void msg_buf_set(msg_t *msg, void *b, usize_t size);
+
+SOFIA_END_DECLS
+
+#endif /* !defined MSG_BUFFER_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_DATE_H
+/** Defined when <sofia-sip/msg_date.h> has been included. */
+#define MSG_DATE_H 
+
+/**@ingroup msg_parser
+ * @file sofia-sip/msg_date.h 
+ * @brief Types and functions for handling dates and times.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ * 
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef MSG_TIME_T_DEFINED
+#define MSG_TIME_T_DEFINED
+/** Time in seconds since epoch (1900-Jan-01 00:00:00). */
+typedef unsigned long msg_time_t;
+#endif
+
+#ifndef MSG_TIME_MAX
+/** Latest time that can be expressed with msg_time_t. @HIDE */
+#define MSG_TIME_MAX ((msg_time_t)ULONG_MAX)
+#endif
+
+/* Current time. */
+SOFIAPUBFUN msg_time_t msg_now(void);
+
+SOFIAPUBFUN issize_t msg_date_delta_d(char const **inout_string,
+				      msg_time_t *return_date,
+				      msg_time_t *return_delta);
+
+SOFIAPUBFUN issize_t msg_delta_d(char const **ss, msg_time_t *return_delta);
+SOFIAPUBFUN issize_t msg_delta_e(char b[], isize_t bsiz, msg_time_t delta);
+
+/** Decode RFC1123-date, RFC822-date or asctime-date. */
+SOFIAPUBFUN issize_t msg_date_d(char const **ss, msg_time_t *date);
+
+/** Encode RFC1123-date. */
+SOFIAPUBFUN issize_t msg_date_e(char b[], isize_t bsiz, msg_time_t date);
+
+enum { msg_date_string_size = 29 };
+
+SOFIA_END_DECLS
+
+#endif /* !defined(MSG_DATE_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,304 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_HEADER_H
+/** Defined when <sofia-sip/msg_header.h> has been included. */
+#define MSG_HEADER_H
+/**@ingroup msg_headers
+ * @file sofia-sip/msg_header.h
+ *
+ * @brief Message headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 27 15:44:27 2001 ppessi
+ * 
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN msg_header_t *msg_header_alloc(su_home_t *,
+					   msg_hclass_t *hc,
+					   isize_t extra)
+  __attribute__((__malloc__));
+
+SOFIAPUBFUN isize_t msg_header_size(msg_header_t const *h);
+
+SOFIAPUBFUN msg_header_t **msg_header_offset(msg_t const *,
+					 msg_pub_t const *,
+					 msg_header_t const *);
+SOFIAPUBFUN msg_header_t **msg_hclass_offset(msg_mclass_t const *,
+					     msg_pub_t const *,
+					     msg_hclass_t *);
+SOFIAPUBFUN msg_header_t *msg_header_access(msg_pub_t const *pub,
+					    msg_hclass_t *hc);
+
+SOFIAPUBFUN msg_header_t *msg_header_copy_as(su_home_t *home,
+					     msg_hclass_t *hc,
+					     msg_header_t const *o)
+  __attribute__((__malloc__));
+SOFIAPUBFUN msg_header_t *msg_header_copy(su_home_t *home,
+					  msg_header_t const *o)
+  __attribute__((__malloc__));
+SOFIAPUBFUN msg_header_t *msg_header_copy_one(su_home_t *home,
+					      msg_header_t const *o)
+  __attribute__((__malloc__));
+SOFIAPUBFUN msg_header_t *msg_header_dup_as(su_home_t *home,
+					    msg_hclass_t *hc,
+					    msg_header_t const *o)
+  __attribute__((__malloc__));
+SOFIAPUBFUN msg_header_t *msg_header_dup(su_home_t *home,
+					 msg_header_t const *h)
+  __attribute__((__malloc__));
+SOFIAPUBFUN msg_header_t *msg_header_dup_one(su_home_t *home,
+					     msg_header_t const *h)
+  __attribute__((__malloc__));
+
+SOFIAPUBFUN msg_header_t *msg_header_d(su_home_t *home,
+				       msg_t const *msg,
+				       char const *b);
+SOFIAPUBFUN issize_t msg_header_e(char b[], isize_t bsiz,
+				  msg_header_t const *h,
+				  int flags);
+SOFIAPUBFUN issize_t msg_object_e(char b[], isize_t size,
+				  msg_pub_t const *mo,
+				  int flags);
+
+SOFIAPUBFUN issize_t msg_header_field_e(char b[], isize_t bsiz,
+					msg_header_t const *h,
+					int flags);
+
+SOFIAPUBFUN int msg_header_remove(msg_t *msg,
+				  msg_pub_t *mo,
+				  msg_header_t *h);
+
+SOFIAPUBFUN int msg_header_remove_all(msg_t *msg,
+				      msg_pub_t *mo,
+				      msg_header_t *h);
+
+SOFIAPUBFUN int msg_header_insert(msg_t *msg, msg_pub_t *mo,
+				  msg_header_t *h);
+
+SOFIAPUBFUN int msg_header_replace(msg_t *msg, msg_pub_t *mo,
+				   msg_header_t *old_header,
+				   msg_header_t *new_header);
+
+SOFIAPUBFUN int msg_header_add_dup(msg_t *msg,
+				   msg_pub_t *pub,
+				   msg_header_t const *o);
+
+SOFIAPUBFUN int msg_header_add_str(msg_t *msg,
+				   msg_pub_t *pub,
+				   char const *str);
+
+SOFIAPUBFUN int msg_header_parse_str(msg_t *msg,
+				     msg_pub_t *pub,
+				     char *s);
+
+SOFIAPUBFUN int msg_header_add_dup_as(msg_t *msg,
+				      msg_pub_t *pub,
+				      msg_hclass_t *hc,
+				      msg_header_t const *o);
+
+SOFIAPUBFUN int msg_header_add_make(msg_t *msg,
+				    msg_pub_t *pub,
+				    msg_hclass_t *hc,
+				    char const *s);
+
+SOFIAPUBFUN int msg_header_prepend(msg_t *msg,
+				   msg_pub_t *pub,
+				   msg_header_t **hh,
+				   msg_header_t *h);
+
+SOFIAPUBFUN msg_header_t *msg_header_make(su_home_t *home,
+					  msg_hclass_t *hc,
+					  char const *s)
+     __attribute__((__malloc__));
+
+SOFIAPUBFUN msg_header_t *msg_header_format(su_home_t *home,
+					    msg_hclass_t *hc,
+					    char const *fmt, ...)
+     __attribute__ ((__malloc__, __format__ (printf, 3, 4)));
+
+SOFIAPUBFUN msg_header_t *msg_header_vformat(su_home_t *home,
+					     msg_hclass_t *hc,
+					     char const *fmt,
+					     va_list ap)
+     __attribute__((__malloc__));
+
+
+SOFIAPUBFUN void msg_header_free(su_home_t *home,
+				 msg_header_t *h);
+
+SOFIAPUBFUN void msg_header_free_all(su_home_t *home,
+				     msg_header_t *h);
+
+SOFIAPUBFUN msg_payload_t *msg_payload_create(su_home_t *home,
+					      void const *data,
+					      usize_t len)
+     __attribute__((__malloc__));
+
+SOFIAPUBFUN msg_separator_t *msg_separator_create(su_home_t *home)
+  __attribute__((__malloc__));
+
+/* Chunk handling macros */
+
+/** Get pointer to beginning of available buffer space */
+#define MSG_CHUNK_BUFFER(pl) \
+  ((char *)pl->pl_common->h_data + (pl)->pl_common->h_len)
+/** Get size of available buffer space */
+#define MSG_CHUNK_AVAIL(pl) \
+  ((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common->h_data) - \
+   (pl)->pl_common->h_len)
+/** Get next chunk in list */
+#define MSG_CHUNK_NEXT(pl) \
+  ((pl)->pl_next)
+
+SOFIAPUBFUN issize_t msg_headers_prepare(msg_t *,
+					 msg_header_t *headers,
+					 int flags);
+
+#ifdef SU_HAVE_INLINE
+/** Clear encoded data from header structure. */
+static inline void msg_fragment_clear(msg_common_t *h) 
+{
+  h->h_data = NULL, h->h_len = 0;
+}
+
+/** Pointer to header parameters. */
+static inline 
+msg_param_t **msg_header_params(msg_common_t const *h)
+{
+  if (h && h->h_class->hc_params) {
+    return (msg_param_t **)((char *)h + h->h_class->hc_params);
+  }
+  return NULL;
+}
+#else
+#define msg_fragment_clear(h) ((h)->h_data = NULL, (h)->h_len = 0)
+#define msg_header_params(h) \
+ (((h) && ((msg_common_t *)h)->h_class->hc_params) ? \
+  (msg_param_t **)((char *)(h) + ((msg_common_t *)h)->h_class->hc_params) : NULL)
+#endif
+
+SOFIAPUBFUN char const *msg_header_find_param(msg_common_t const *,
+					      char const *name);
+SOFIAPUBFUN int msg_header_add_param(su_home_t *, msg_common_t *h,
+				     char const *param);
+SOFIAPUBFUN int msg_header_replace_param(su_home_t *, msg_common_t *h,
+					 char const *param);
+SOFIAPUBFUN int msg_header_remove_param(msg_common_t *h, char const *name);
+
+SOFIAPUBFUN char const *msg_header_find_item(msg_common_t const *h,
+					     char const *item);
+
+SOFIAPUBFUN int msg_header_replace_item(su_home_t *, msg_common_t *h,
+					char const *item);
+SOFIAPUBFUN int msg_header_remove_item(msg_common_t *h, char const *name);
+
+/** Append a list of constant items to a list. */
+SOFIAPUBFUN int msg_list_append_items(su_home_t *home,
+				      msg_list_t *k,
+				      msg_param_t const items[]);
+
+/** Replace a list of constant items on a list */
+SOFIAPUBFUN int msg_list_replace_items(su_home_t *home,
+				       msg_list_t *k,
+				       msg_param_t const items[]);
+
+SOFIAPUBFUN int msg_header_join_items(su_home_t *home,
+				      msg_common_t *dst,
+				      msg_common_t const *src,
+				      int duplicate);
+
+SOFIAPUBFUN issize_t msg_random_token(char token[], isize_t tlen,
+				      void const *d, isize_t dlen);
+
+SOFIAPUBFUN msg_param_t msg_params_find(msg_param_t const pp[],
+					char const *name);
+SOFIAPUBFUN msg_param_t *msg_params_find_slot(msg_param_t [],
+					      char const *name);
+SOFIAPUBFUN int msg_params_add(su_home_t *sh,
+			       msg_param_t **pp,
+			       char const *param);
+SOFIAPUBFUN int msg_params_cmp(char const * const a[],
+			       char const * const b[]);
+SOFIAPUBFUN int msg_params_replace(su_home_t *,
+				   char const * **inout_paramlist,
+				   char const *);
+SOFIAPUBFUN int msg_params_remove(char const **paramlist,
+				  char const *name);
+SOFIAPUBFUN size_t msg_params_length(char const * const * params);
+
+/** Unquote a string, return a duplicate. */
+SOFIAPUBFUN char *msg_unquote_dup(su_home_t *home, char const *q)
+     __attribute__((__malloc__));
+
+SOFIAPUBFUN char *msg_unquote(char *dst, char const *s);
+
+/** Calculate a hash over a string. */
+SOFIAPUBFUN unsigned long msg_hash_string(char const *id);
+
+/* Align pointer p for multiple of t (which must be a power of 2) */
+#define MSG_ALIGN(p, t) (((uintptr_t)(p) + (t) - 1) & (0 - (uintptr_t)(t)))
+#define MSG_STRUCT_SIZE_ALIGN(rv) ((rv) = MSG_ALIGN(rv, sizeof(void *)))
+#define MSG_STRUCT_ALIGN(p) ((p) = (void*)MSG_ALIGN(p, sizeof(void *)))
+
+enum {
+ msg_n_params = 8,	/* allocation size of parameter string list */
+#define MSG_N_PARAMS msg_n_params
+};
+
+/** Initialize a header structure. @HIDE */
+#define MSG_HEADER_INIT(h, msg_class, size)			\
+  ((void)memset((h), 0, (size)),				\
+   (void)(((msg_common_t *)(h))->h_class = (msg_class)),	\
+   (h))
+
+/** No header. */
+#define MSG_HEADER_NONE ((msg_header_t *)-1)
+
+SOFIA_END_DECLS
+
+#ifndef MSG_PROTOS_H
+#include <sofia-sip/msg_protos.h>
+#endif
+
+#endif /** !defined(MSG_HEADER_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_MCLASS_H
+/** Defined when <sofia-sip/msg_mclass.h> has been included. */
+#define MSG_MCLASS_H
+/**@ingroup msg_parser
+ * @file sofia-sip/msg_mclass.h
+ *
+ * @brief Parser table and message factory object.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 27 15:44:27 2001 ppessi
+ */
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+enum { 
+  /** Default size of hash table */
+  MC_HASH_SIZE = 127, 
+  /** Size of short form table */
+  MC_SHORT_SIZE = 'Z' - 'A' + 1 
+};
+
+/**Header reference.
+ *
+ * A header reference object contains a pointer to a 
+ * @ref msg_hclass_s "header class" 
+ * and a offset to the header objects within the @ref msg_pub_t "public
+ * message structure".
+ * 
+ * The @a hr_flags field is used to provide classification of headers. For
+ * instance, the msg_extract_errors() returns bitwise or of all hr_flags
+ * belonging to headers with parsing errors.
+ */
+struct msg_href_s
+{
+  msg_hclass_t  *hr_class;	/**< Header class */
+  unsigned short hr_offset;	/**< Offset within public message struct. */
+  unsigned short hr_flags;	/**< Header flags */
+};
+
+/**Factory object for protocol messages.
+ *
+ * The message class is a kind of a factory object used to create new
+ * message objects for the protocol it represents (see msg_create()).
+ *
+ * The message class object contains all the information needed to parse a
+ * message. It used when headers are added or removed from the message. When
+ * a message is sent, the message class is used to order message components
+ * and print (encode) the message in text format.
+ *
+ * The message class contains reference objects to headers and other components
+ * within the message. Each reference contains a pointer to a @ref
+ * msg_hclass_s "header class" and a offset to the header objects within
+ * public message structure. The parser engine uses these references when it
+ * adds a newly parsed header object to the message structure. The function
+ * msg_find_hclass() searches for the reference of the named header.
+
+ * The application can make a copy of existing message class object using
+ * the function msg_mclass_clone(). New headers can be added to the message
+ * class with the msg_mclass_insert_header() and msg_mclass_insert()
+ * functions. The message class of an existing message object can be found
+ * out with the function msg_mclass().
+ *
+ * @sa sip_default_mclass(), http_default_mclass(), msg_create(),
+ * msg_mclass(), msg_mclass_clone(), msg_mclass_insert_header(),
+ * msg_mclass_insert_with_mask(), msg_mclass_insert().
+ */
+struct msg_mclass_s
+{
+  struct msg_hclass_s
+                mc_hclass[1];	/**< Recursive header class */
+  char const   *mc_name;	/**< Protocol name, e.g., "SIP/2.0" */
+  void         *mc_tag;		/**< Protocol-specific tag */
+  unsigned      mc_flags;	/**< Default flags */
+  unsigned      mc_msize;	/**< Size of public message structure */
+  /** Function extracting the message contents. */
+  issize_t    (*mc_extract_body)(msg_t *msg, msg_pub_t *pub, 
+				 char b[], isize_t bsiz, int eos);
+
+  msg_href_t    mc_request[1];	/**< Request line reference */
+  msg_href_t    mc_status[1];	/**< Status line reference */
+  msg_href_t    mc_separator[1];/**< Separator line reference */
+  msg_href_t    mc_payload[1];	/**< Message body reference */
+  msg_href_t    mc_unknown[1];	/**< Reference for unknown headers */
+  msg_href_t    mc_error[1];	/**< Reference for erroneous header */
+  msg_href_t    mc_multipart[1];/**< Multipart body reference */
+  msg_href_t const *
+                mc_short;	/**< Short forms (or NULL) */
+  short         mc_hash_size;	/**< Size of parsing table  */
+  short         mc_hash_used;	/**< Number of headers in parsing table */
+  /** Hash table for parsing containing reference for each header. */
+  msg_href_t    mc_hash[MC_HASH_SIZE]; 
+};
+
+enum { msg_mclass_copy = 0, msg_mclass_empty = 1 };
+
+SOFIAPUBFUN msg_mclass_t *msg_mclass_clone(msg_mclass_t const *old,
+					   int newsize, int empty);
+
+SOFIAPUBFUN int msg_mclass_insert(msg_mclass_t *mc, msg_href_t const *hr);
+
+SOFIAPUBFUN
+int msg_mclass_insert_header(msg_mclass_t *mc, 
+			     msg_hclass_t *hc,
+			     unsigned short offset);
+
+SOFIAPUBFUN
+int msg_mclass_insert_with_mask(msg_mclass_t *mc, 
+				msg_hclass_t *hc,
+				unsigned short offset,
+				unsigned short mask);
+
+SOFIAPUBFUN
+msg_href_t const *msg_find_hclass(msg_mclass_t const *, char const *, isize_t *);
+
+SOFIAPUBFUN msg_mclass_t const *msg_mclass(msg_t const *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(MSG_MCLASS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_MCLASS_HASH_H
+/** Defined when <sofia-sip/msg_mclass_hash.h> has been included. */
+#define MSG_MCLASS_HASH_H 
+
+/**@ingroup msg_parser
+ * @file sofia-sip/msg_mclass_hash.h
+ *
+ * Hash function for header names.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 16:03:45 2001 ppessi
+ * 
+ */
+
+#include <sofia-sip/su_config.h>
+
+#ifndef BNF_H
+#include <sofia-sip/bnf.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Hash the header name */
+#define MC_HASH(s, n)     (msg_header_name_hash(s, NULL) % (unsigned)(n))
+
+/** Hash header name */
+static inline 
+unsigned short msg_header_name_hash(char const *s, isize_t *llen)
+{
+  unsigned short hash = 0;
+  size_t i;
+
+  for (i = 0; s[i]; i++) {
+    unsigned char c = s[i];
+    if (!(_bnf_table[c] & bnf_token))
+      break;
+    if (c >= 'A' && c <= 'Z')
+      hash += (c + 'a' - 'A');
+    else
+      hash += c;
+    hash *= 38501U;
+  }
+
+  if (llen)
+    *llen = i;
+
+  return hash;
+}
+
+SOFIA_END_DECLS
+
+#endif /** MSG_MCLASS_HASH_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,242 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_MIME_H
+/** Defined when <sofia-sip/msg_mime.h> has been included. */
+#define MSG_MIME_H 
+
+/**@ingroup msg_mime
+ * @file sofia-sip/msg_mime.h
+ *
+ * MIME headers and multipart messages (@RFC2045).
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi
+ * 
+ */
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct msg_accept_any_s     msg_accept_any_t;
+
+typedef struct msg_accept_s  	    msg_accept_t;
+
+typedef msg_accept_any_t            msg_accept_charset_t;
+typedef msg_accept_any_t      	    msg_accept_encoding_t;
+typedef msg_accept_any_t     	    msg_accept_language_t;
+
+typedef struct msg_content_disposition_s 
+                                    msg_content_disposition_t;
+typedef msg_list_t	      	    msg_content_encoding_t;
+typedef msg_generic_t               msg_content_id_t;
+typedef struct msg_content_length_s msg_content_length_t;
+typedef msg_generic_t               msg_content_location_t;
+typedef msg_list_t                  msg_content_language_t;
+typedef msg_generic_t               msg_content_md5_t;
+typedef msg_generic_t	     	    msg_content_transfer_encoding_t;
+typedef struct msg_content_type_s   msg_content_type_t;
+typedef msg_generic_t	     	    msg_mime_version_t;
+typedef struct msg_warning_s	    msg_warning_t;
+
+/** Multipart body object. */
+typedef struct msg_multipart_s      msg_multipart_t;
+
+/**@ingroup msg_accept
+ * @brief Structure for @b Accept header.
+ */
+struct msg_accept_s
+{
+  msg_common_t        ac_common[1]; /**< Common fragment info */
+  msg_accept_t       *ac_next;	    /**< Pointer to next Accept header */
+  char const         *ac_type;	    /**< Pointer to type/subtype */
+  char const         *ac_subtype;   /**< Points after first slash in type */
+  msg_param_t const  *ac_params;    /**< List of parameters */
+  char const         *ac_q;	    /**< Value of q parameter */
+};
+
+/**@ingroup msg_accept_encoding
+ * @brief Structure for @b Accept-Charset, @b Accept-Encoding and
+ * @b Accept-Language headers.
+ */
+struct msg_accept_any_s
+{
+  msg_common_t        aa_common[1]; /**< Common fragment info */
+  msg_accept_any_t   *aa_next;	    /**< Pointer to next Accept-* header */
+  char const         *aa_value;	    /**< Token */
+  msg_param_t const  *aa_params;    /**< List of parameters */
+  char const         *aa_q;	    /**< Value of q parameter */
+};
+
+/**@ingroup msg_content_disposition 
+ * @brief Structure for @b Content-Disposition header.
+ */
+struct msg_content_disposition_s
+{
+  msg_common_t       cd_common[1];  /**< Common fragment info */
+  msg_error_t       *cd_next;	    /**< Link to next (dummy) */
+  char const        *cd_type;	    /**< Disposition type */
+  msg_param_t const *cd_params;	    /**< List of parameters */
+  char const        *cd_handling;   /**< Value of @b handling parameter */
+  unsigned           cd_required:1; /**< True if handling=required */
+  unsigned           cd_optional:1; /**< True if handling=optional */
+  unsigned           :0;	    /* pad */
+};
+
+/**@ingroup msg_content_length
+ * @brief Structure for Content-Length header.
+ */
+struct msg_content_length_s
+{
+  msg_common_t   l_common[1];	    /**< Common fragment info */
+  msg_error_t   *l_next;	    /**< Link to next (dummy) */
+  unsigned long  l_length;	    /**< Digits */
+};
+
+
+/**@ingroup msg_content_type
+ * @brief Structure for Content-Type header.
+ */
+struct msg_content_type_s
+{
+  msg_common_t        c_common[1];  /**< Common fragment info */
+  msg_error_t        *c_next;	    /**< Dummy link to next */
+  char const         *c_type;	    /**< Pointer to type/subtype */
+  char const         *c_subtype;    /**< Points after first slash in type */
+  msg_param_t const  *c_params;	    /**< List of parameters */
+};
+
+
+/**@ingroup sip_warning
+ * @brief Structure for @b Warning header.
+ */
+struct msg_warning_s
+{
+  msg_common_t        w_common[1];  /**< Common fragment info */
+  msg_warning_t      *w_next;	    /**< Link to next Warning header */
+  unsigned            w_code;       /**< Warning code */
+  char const         *w_host;	    /**< Hostname or pseudonym */
+  char const         *w_port;	    /**< Port number */
+  char const         *w_text;       /**< Warning text */
+};
+
+
+/**@ingroup msg_multipart
+ *
+ * @brief Structure for a part in MIME multipart message.
+ */
+struct msg_multipart_s
+{
+  msg_common_t            mp_common[1];	/**< Common fragment information */
+  msg_multipart_t        *mp_next;      /**< Next part in multipart body */
+  /* Preamble for this part */
+  char                   *mp_data;	/**< Boundary string. */
+  usize_t                 mp_len;	/**< Length of boundary (mp_data).*/
+  unsigned                mp_flags;
+  msg_error_t            *mp_error;
+
+  /* === Headers start here */
+  msg_content_type_t     *mp_content_type;	/**< Content-Type */
+  msg_content_disposition_t *mp_content_disposition;
+                                                /**< Content-Disposition */
+  msg_content_location_t *mp_content_location;	/**< Content-Location */
+  msg_content_id_t       *mp_content_id;        /**< Content-ID */
+  msg_content_language_t *mp_content_language;	/**< Content-Language */
+  msg_content_encoding_t *mp_content_encoding;	/**< Content-Encoding */
+  msg_content_transfer_encoding_t *mp_content_transfer_encoding;
+                                        /**< Content-Transfer-Encoding */
+#if 0
+  /* === Hash headers end here */
+  /* These MIME headers are here for msg_parser.awk */
+  msg_accept_t           *mp_accept;		/**< Accept */
+  msg_accept_charset_t   *mp_accept_charset;	/**< Accept-Charset */
+  msg_accept_encoding_t  *mp_accept_encoding;	/**< Accept-Encoding */
+  msg_accept_language_t  *mp_accept_language;	/**< Accept-Language */
+  msg_mime_version_t     *mp_mime_version;	/**< MIME-Version */
+  msg_content_md5_t      *mp_content_md5;	/**< Content-MD5 */
+  msg_content_length_t   *mp_content_length;	/**< Content-Length */
+  msg_multipart_t        *mp_multipart;		/**< Recursive multipart */
+  msg_warning_t          *mp_warning;           /**< Warning */
+#endif
+  /* === Headers end here */
+
+  /** Unknown and extra headers. */
+  msg_unknown_t          *mp_unknown;           /**< Unknown headers */
+
+  msg_separator_t        *mp_separator;	        /**< Separator */
+  msg_payload_t          *mp_payload;	        /**< Body part */
+
+  msg_multipart_t        *mp_multipart;		/**< Recursive multipart */
+
+  msg_payload_t          *mp_close_delim;       /**< Closing delimiter */
+};
+
+SOFIAPUBFUN
+msg_multipart_t *msg_multipart_create(su_home_t *home,
+				      char const *content_type,
+				      void const *data,
+				      isize_t dlen);
+SOFIAPUBFUN 
+msg_multipart_t *msg_multipart_parse(su_home_t *home, 
+				     msg_content_type_t const *c,
+				     msg_payload_t *pl);
+SOFIAPUBFUN
+int msg_multipart_complete(su_home_t *home, 
+			   msg_content_type_t *c,
+			   msg_multipart_t *mp);
+SOFIAPUBFUN msg_header_t *msg_multipart_serialize(msg_header_t **head0,
+						  msg_multipart_t *mp);
+
+SOFIAPUBFUN issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags);
+
+SOFIAPUBFUN isize_t msg_accept_any_dup_xtra(msg_header_t const *h, isize_t offset);
+
+SOFIAPUBFUN char *msg_accept_any_dup_one(msg_header_t *dst,
+					 msg_header_t const *src,
+					 char *b, isize_t xtra);
+
+SOFIAPUBFUN
+msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n);
+
+/** MIME multipart protocol name. @HIDE */
+#define MSG_MULTIPART_VERSION_CURRENT msg_mime_version_1_0
+SOFIAPUBVAR char const msg_mime_version_1_0[];
+
+/** MIME multipart parser table identifier. @HIDE */
+#define MSG_MULTIPART_PROTOCOL_TAG   ((void *)0x4d494d45)	/* 'MIME' */
+
+SOFIA_END_DECLS
+
+#endif /** MSG_MIME_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,323 @@
+/**@ingroup msg  -*- c -*-
+ * @file sofia-sip/msg_mime_protos.h.in
+ *
+ * Template for <msg_mime_protos.h>.
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_MIME_PROTOS_H
+/** Defined when <sofia-sip/msg_mime_protos.h> has been included. */
+#define MSG_MIME_PROTOS_H 
+
+/**@ingroup msg_mime
+ * @file sofia-sip/msg_mime_protos.h
+ *
+ * Prototypes for MIME headers (@RFC2045).
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#ifndef MSG_PARSER_H
+#include <sofia-sip/msg_parser.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+#ifndef MSG_MCLASS_H
+#include <sofia-sip/msg_mclass.h>
+#endif
+#ifndef MSG_MCLASS_H
+#include <sofia-sip/msg_mclass.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+MSG_DLL extern msg_mclass_t const msg_multipart_mclass[1];
+
+#define msg_multipart_class ((msg_hclass_t *)msg_multipart_mclass)
+
+
+/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
+
+/**@addtogroup msg_#xxxxxx# 
+ * @{ 
+ */
+
+enum { 
+  /** Hash of #xxxxxxx_xxxxxxx#. @internal */
+  msg_#xxxxxx#_hash = #hash# 
+};
+
+/** Parse a #xxxxxxx_xxxxxxx#. @internal */
+MSG_DLL msg_parse_f msg_#xxxxxx#_d;
+
+/** Print a #xxxxxxx_xxxxxxx#. @internal */
+MSG_DLL msg_print_f msg_#xxxxxx#_e;
+
+MSG_DLL msg_xtra_f msg_#xxxxxx#_dup_xtra;
+MSG_DLL msg_dup_f msg_#xxxxxx#_dup_one;
+
+/**Header class for #xxxxxxx_xxxxxxx#.
+ * 
+ * The header class msg_#xxxxxx#_class defines how a 
+ * #xxxxxxx_xxxxxxx# header is parsed and printed.  It also
+ * contains methods used by message parser and other functions
+ * to manipulate the #msg_#xxxxxx#_t header structure.
+ * 
+ */
+#ifndef msg_#xxxxxx#_class
+MSG_DLL extern msg_hclass_t msg_#xxxxxx#_class[];
+#endif
+
+/**Initializer for an #msg_#xxxxxx#_t structure.
+ * 
+ * A static msg_#xxxxxx#_t structure must be initialized
+ * with the MSG_#XXXXXX#_INIT() macro. For instance,
+ * @code 
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
+ * 
+ * @endcode
+ * @HI
+ */
+#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
+
+/**Initialize an #msg_#xxxxxx#_t structure.
+ * 
+ * An #msg_#xxxxxx#_t structure can be initialized with the
+ * msg_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx#;
+ * 
+ *  msg_#xxxxxx#_init(&msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @param x pointer to #msg_#xxxxxx#_t structure 
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
+{
+  return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
+}
+#else
+#define msg_#xxxxxx#_init(x) \
+  MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
+#endif
+
+/**Test if header object is an instance of #msg_#xxxxxx#_t.
+ * 
+ * The function msg_is_#xxxxxx#() returns true (nonzero) if
+ * the header class is an instance of #xxxxxxx_xxxxxxx#
+ * object and false (zero) otherwise.
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @return The function msg_is_#xxxxxx#() returns true (nonzero) if the
+ * header object is an instance of header #xxxxxxx_xxxxxxx# and false (zero)
+ * otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
+{
+  return header && header->sh_class->hc_hash == msg_#xxxxxx#_hash;
+}
+#else
+int msg_is_#xxxxxx#(msg_header_t const *header);
+#endif
+
+#define msg_#xxxxxx#_p(h) msg_is_#xxxxxx#((h))
+
+/**Duplicate (deep copy) #msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_dup() duplicates a header structure @a
+ * header. If the header structure @a header contains a reference
+ * (@c header->x_next) to a list of headers, all the headers in the
+ * list are duplicated, too.
+ * 
+ * @param home   memory home used to allocate new structure
+ * @param header header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant strings
+ * attached to the header are copied, too. The function uses given
+ * memory @a home to allocate all the memory areas used to copy the
+ * header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_dup(home, msg->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_dup() returns a pointer to the
+ * newly duplicated #msg_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, 
+				 msg_#xxxxxx#_t const *header);
+
+#if SU_HAVE_INLINE
+su_inline
+msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, 
+				 msg_#xxxxxx#_t const *header)
+{
+  return (msg_#xxxxxx#_t *)
+    msg_header_dup_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header); 
+}
+#endif
+
+
+/**Copy an #msg_#xxxxxx#_t header structure.
+ * 
+ * The function msg_#xxxxxx#_copy() copies a header structure @a
+ * header. If the header structure @a header contains a reference
+ * (@c header->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home to
+ * allocate all the memory areas used to copy the header structure
+ * @a header.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param header  pointer to the header structure to be duplicated
+ * 
+ * When copying, only the header structure and parameter lists
+ * attached to it are duplicated. The new header structure retains
+ * all the references to the strings within the old @a header,
+ * including the encoding of the old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_copy(home, msg->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home, 
+				  msg_#xxxxxx#_t const *header);
+
+#if SU_HAVE_INLINE
+su_inline
+msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home, 
+				  msg_#xxxxxx#_t const *header)
+{
+  return (msg_#xxxxxx#_t *)
+    msg_header_copy_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header); 
+}
+#endif
+
+
+/**Make a header structure #msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_make() makes a new #msg_#xxxxxx#_t header
+ * structure. It allocates a new header structure, and decodes the string @a
+ * s as the value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @note This function may be implemented as a macro calling
+ * msg_header_make().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_make() returns a pointer to newly maked
+ * #msg_#xxxxxx#_t header structure, or NULL upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+  return (msg_#xxxxxx#_t*)msg_header_make(home, msg_#xxxxxx#_class, s);
+}
+#else
+msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s);
+#endif
+
+
+/**Make a #xxxxxxx_xxxxxxx# from formatting result.
+ * 
+ * The function msg_#xxxxxx#_format() makes a new #xxxxxxx_xxxxxxx# object
+ * using snprintf-formatted result as its value. The function first
+ * prints the arguments according to the format @a fmt specified. Then it
+ * allocates a new header structure, and uses the formatting result as the
+ * header value.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @note This function may be implemented as a macro calling
+ * msg_header_format().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((__format__ (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+  msg_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
+  va_end(ap);
+ 
+  return (msg_#xxxxxx#_t*)h;
+}
+#endif
+
+/** @} */
+
+
+/* Internal prototypes */
+MSG_DLL msg_update_f msg_accept_update;
+MSG_DLL msg_update_f msg_accept_any_update;
+MSG_DLL msg_update_f msg_content_disposition_update;
+
+SOFIA_END_DECLS
+
+#endif /** !defined(MSG_MIME_PROTOS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,309 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_PARSER_H
+/** Defined when <sofia-sip/msg_parser.h> has been included. */
+#define MSG_PARSER_H 
+
+/**@ingroup msg_parser
+ * @file sofia-sip/msg_parser.h
+ *
+ * Message parser interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 16:03:45 2001 ppessi
+ *
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+#ifndef BNF_H
+#include <sofia-sip/bnf.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------------
+ * 1) Header class definitions.
+ */
+
+#if HAVE_STRUCT_KEYWORDS
+/** Define a header class */
+#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd)	\
+  {{								\
+    hc_hash:	pr##c##_hash,					\
+    hc_parse:	pr##c##_d,					\
+    hc_print:	pr##c##_e,					\
+    hc_dxtra:	dup##_dup_xtra,					\
+    hc_dup_one: dup##_dup_one,					\
+    hc_update:	upd##_update,					\
+    hc_name:	l,						\
+    hc_len:	sizeof(l) - 1,					\
+    hc_short:	s,						\
+    hc_size:	MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)),	\
+    hc_params:	offsetof(pr##c##_t, params),			\
+    hc_kind:	msg_kind_##kind,				\
+  }}
+#else
+#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd)	\
+  {{ \
+     pr##c##_hash, \
+     pr##c##_d, \
+     pr##c##_e, \
+     dup##_dup_xtra, \
+     dup##_dup_one, \
+     upd##_update, \
+     l, \
+     sizeof(l) - 1, \
+     s, \
+     MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
+     offsetof(pr##c##_t, params), \
+     msg_kind_##kind, \
+  }}
+#endif
+
+/* Mark headers critical for understanding the message */
+#define msg_kind_single_critical msg_kind_single, 1
+#define msg_kind_list_critical   msg_kind_list, 1
+
+SOFIAPUBFUN issize_t msg_extract_header(msg_t *msg, msg_pub_t *mo,
+				   char b[], isize_t bsiz, int eos);
+SOFIAPUBFUN issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
+					   char b[], isize_t bsiz, int eos);
+SOFIAPUBFUN issize_t msg_extract_payload(msg_t *msg, msg_pub_t *mo, 
+					 msg_header_t **return_payload, 
+					 usize_t body_len,
+					 char b[], isize_t bsiz, int eos);
+
+/* ---------------------------------------------------------------------------
+ * 2) Header processing methods for common headers.
+ */
+
+SOFIAPUBFUN int msg_firstline_d(char *s, char **ss2, char **ss3);
+
+SOFIAPUBFUN isize_t msg_default_dup_xtra(msg_header_t const *header, isize_t offset);
+SOFIAPUBFUN char *msg_default_dup_one(msg_header_t *dst, 
+				      msg_header_t const *src,
+				      char *b, 
+				      isize_t xtra);
+
+SOFIAPUBFUN issize_t msg_numeric_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
+SOFIAPUBFUN issize_t msg_numeric_e(char [], isize_t, msg_header_t const *, int);
+
+SOFIAPUBFUN issize_t msg_list_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
+SOFIAPUBFUN issize_t msg_list_e(char [], isize_t, msg_header_t const *, int);
+SOFIAPUBFUN isize_t msg_list_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_list_dup_one(msg_header_t *dst,
+				   msg_header_t const *src,
+				   char *b, isize_t xtra);
+
+SOFIAPUBFUN issize_t msg_generic_d(su_home_t *, msg_header_t *, char *, isize_t);
+SOFIAPUBFUN issize_t msg_generic_e(char [], isize_t, msg_header_t const *, int);
+SOFIAPUBFUN isize_t msg_generic_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_generic_dup_one(msg_header_t *dst,
+				      msg_header_t const *src,
+				      char *b, 
+				      isize_t xtra);
+
+SOFIAPUBFUN isize_t msg_unknown_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_unknown_dup_one(msg_header_t *dst,
+				      msg_header_t const *src,
+				      char *b, isize_t xtra);
+
+SOFIAPUBFUN isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_error_dup_one(msg_header_t *dst,
+				    msg_header_t const *src,
+				    char *b, isize_t xtra);
+
+SOFIAPUBFUN issize_t msg_payload_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
+SOFIAPUBFUN issize_t msg_payload_e(char b[], isize_t bsiz, msg_header_t const *, int f);
+SOFIAPUBFUN isize_t msg_payload_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_payload_dup_one(msg_header_t *dst,
+				      msg_header_t const *src,
+				      char *b, isize_t xtra);
+
+SOFIAPUBFUN issize_t msg_separator_d(su_home_t *, msg_header_t *, char *, isize_t);
+SOFIAPUBFUN issize_t msg_separator_e(char [], isize_t, msg_header_t const *, int);
+
+SOFIAPUBFUN issize_t msg_auth_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
+SOFIAPUBFUN issize_t msg_auth_e(char b[], isize_t bsiz, msg_header_t const *h, int f);
+SOFIAPUBFUN isize_t msg_auth_dup_xtra(msg_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *msg_auth_dup_one(msg_header_t *dst, msg_header_t const *src, 
+				   char *b, isize_t xtra);
+
+/* ---------------------------------------------------------------------------
+ * 2) Macros and prototypes for building header decoding/encoding functions.
+ */
+
+#define MSG_HEADER_DATA(h) ((char *)(h) + (h)->sh_class->hc_size)
+
+#define MSG_HEADER_TEST(h) ((h) && (h)->sh_class)
+
+su_inline void *msg_header_data(msg_frg_t *h);
+
+SOFIAPUBFUN int msg_hostport_d(char **ss,
+			       char const **return_host,
+			       char const **return_port);
+
+SOFIAPUBFUN issize_t msg_token_d(char **ss, char const **return_token);
+SOFIAPUBFUN issize_t msg_uint32_d(char **ss, uint32_t *return_value);
+SOFIAPUBFUN issize_t msg_comment_d(char **ss, char const **return_comment);
+SOFIAPUBFUN issize_t msg_quoted_d(char **ss, char **return_unquoted);
+SOFIAPUBFUN issize_t msg_unquoted_e(char *b, isize_t bsiz, char const *s);
+
+SOFIAPUBFUN issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
+					  char *s, isize_t slen);
+
+/** Terminate encoding. @HI */
+#define MSG_TERM_E(p, e) ((p) < (e) ? (p)[0] = '\0' : '\0')
+
+/** Encode a character. @HI */
+#define MSG_CHAR_E(p, e, c) (++(p) < (e) ? ((p)[-1]=(c)) : (c)) 
+
+/** Calculate separator and string length. @HI */
+#define MSG_STRING_LEN(s, sep_size) ((s) ? (strlen(s) + sep_size) : 0)
+
+/** Encode a string. @HI */
+#define MSG_STRING_E(p, e, s) do { \
+  size_t _n = strlen(s); if (p + _n+1 < e) memcpy(p, s, _n+1); p+= _n; } while(0)
+
+/** Duplicate string. @HI */
+#define MSG_STRING_DUP(p, d, s) \
+  (void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,SIZE_MAX))\
+	    :((d)=NULL))
+
+/** Calculate string size. @HI */
+#define MSG_STRING_SIZE(s) ((s) ? (strlen(s) + 1) : 0)
+
+SOFIAPUBFUN issize_t msg_commalist_d(su_home_t *, char **ss,
+				     msg_param_t **append_list,
+				     issize_t (*scanner)(char *s));
+SOFIAPUBFUN issize_t msg_token_scan(char *start);
+SOFIAPUBFUN issize_t msg_attribute_value_scanner(char *s);
+
+SOFIAPUBFUN issize_t msg_any_list_d(su_home_t *, char **ss, 
+				    msg_param_t **append_list,
+				    issize_t (*scanner)(char *s),
+				    int sep);
+
+/** Encode a comma-separated parameter list */
+#define MSG_COMMALIST_E(b, end, params, compact) do { \
+  char const * const *p_; char const * c_ = ""; \
+  for (p_ = (params); p_ && *p_; p_++, c_ = (compact ? "," : ", ")) \
+    { MSG_STRING_E(b, (end), c_); MSG_STRING_E(b, (end), *p_); } \
+} while(0)
+
+/* Parameter lists */
+
+SOFIAPUBFUN int msg_header_update_params(msg_common_t *h, int clear);
+
+/** Match a parameter with any value. @HI */
+#define MSG_PARAM_MATCH(v, s, name) \
+  (strncasecmp(s, name "=", sizeof(name)) == 0 ? (v = s + sizeof(name)) : NULL)
+
+/** Match a parameter with known value. @HI */
+#define MSG_PARAM_MATCH_P(v, s, name) \
+  ((strncasecmp((s), name "", sizeof(name) - 1) == 0 &&			\
+    ((s)[sizeof(name) - 1] == '=' || (s)[sizeof(name) - 1] == '\0')) ? \
+   ((v) = 1) : 0)
+
+/** Calculate allocated number of items in parameter list. @HI */
+#define MSG_PARAMS_NUM(n) (((n) + MSG_N_PARAMS - 1) & (size_t)(0 - MSG_N_PARAMS))
+
+/** Parse a semicolong-separated attribute-value list. @HI */
+SOFIAPUBFUN issize_t msg_avlist_d(su_home_t *, char **ss,
+				  msg_param_t const **return_params);
+
+/** Parse a semicolon-separated parameter list starting with semicolon. @HI */
+SOFIAPUBFUN issize_t msg_params_d(su_home_t *, char **ss,
+				  msg_param_t const **return_params);
+
+/** Encode a list of parameters. */
+SOFIAPUBFUN isize_t msg_params_e(char b[], isize_t bsiz, msg_param_t const pparams[]);
+
+/** Join list of parameters */
+SOFIAPUBFUN issize_t msg_params_join(su_home_t *,
+				     msg_param_t **dst,
+				     msg_param_t const *src,
+				     unsigned prune,
+				     int dup);
+
+/** Encode a list of parameters. @HI */
+#define MSG_PARAMS_E(b, end, params, flags) \
+  (b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b) : 0), (params))
+
+/** Calculate extra size of parametes. @HI */
+#define MSG_PARAMS_SIZE(rv, params) (rv = msg_params_dup_xtra(params, rv))
+
+/** Duplicate a parameter list */
+SOFIAPUBFUN char *msg_params_dup(msg_param_t const **d, msg_param_t const *s, 
+				 char *b, isize_t xtra);
+
+/** Count number of parameters in the list */
+su_inline isize_t msg_params_count(msg_param_t const params[])
+{
+  if (params) {
+    size_t n;
+    for (n = 0; params[n]; n++)
+      ;
+    return n;
+  }
+  else {
+    return 0;
+  }
+}
+
+/** Calculate memory size required by parameter list */
+su_inline isize_t msg_params_dup_xtra(msg_param_t const params[], isize_t offset)
+{
+  isize_t n = msg_params_count(params);
+  if (n) {
+    MSG_STRUCT_SIZE_ALIGN(offset);
+    offset += MSG_PARAMS_NUM(n + 1) * sizeof(msg_param_t);
+    for (n = 0; params[n]; n++)
+      offset += strlen(params[n]) + 1;
+  }
+  return offset;
+}
+
+/** Return pointer to extra data after header structure */
+su_inline void *msg_header_data(msg_frg_t *h)
+{
+  if (h)
+    return (char *)h + h->h_class->hc_size;
+  else
+    return NULL;
+}
+
+SOFIA_END_DECLS
+
+#endif /** MSG_PARSER_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,311 @@
+/**@ingroup msg_headers  -*- C -*-
+ * @file sofia-sip/msg_protos.h.in
+ *
+ * Template for <msg_protos.h>.
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_PROTOS_H
+/** Defined when <sofia-sip/msg_protos.h> has been included. */
+#define MSG_PROTOS_H 
+
+/**@ingroup msg_headers
+ * @file sofia-sip/msg_protos.h
+ *
+ * Prototypes for common headers
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi
+ */
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+enum {
+  msg_request_hash = -1,
+  msg_status_hash = -2
+};
+
+
+/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
+
+/**@addtogroup msg_#xxxxxx# 
+ * @{ 
+ */
+
+enum { 
+  /** Hash of #xxxxxxx_xxxxxxx#. @internal */
+  msg_#xxxxxx#_hash = #hash# 
+};
+
+/** Parse a #xxxxxxx_xxxxxxx#. @internal */
+MSG_DLL msg_parse_f msg_#xxxxxx#_d;
+
+/** Print a #xxxxxxx_xxxxxxx#. @internal */
+MSG_DLL msg_print_f msg_#xxxxxx#_e;
+
+/**Header class for #xxxxxxx_xxxxxxx#.
+ * 
+ * The header class msg_#xxxxxx#_class defines how a 
+ * #xxxxxxx_xxxxxxx# header is parsed and printed.  It also
+ * contains methods used by message parser and other functions
+ * to manipulate the msg_#xxxxxx#_t header structure.
+ * 
+ */
+MSG_DLL extern msg_hclass_t msg_#xxxxxx#_class[];
+
+/**Initializer for structure msg_#xxxxxx#_t.
+ * 
+ * A static msg_#xxxxxx#_t structure must be initialized
+ * with the MSG_#XXXXXX#_INIT() macro. For instance,
+ * @code 
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
+ * 
+ * @endcode
+ * @HI
+ */
+#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure msg_#xxxxxx#_t.
+ * 
+ * An msg_#xxxxxx#_t structure can be initialized with the
+ * msg_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx#;
+ * 
+ *  msg_#xxxxxx#_init(&msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @param x pointer to msg_#xxxxxx#_t structure 
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
+{
+  return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
+}
+#else
+#define msg_#xxxxxx#_init(x) \
+  MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of msg_#xxxxxx#_t.
+ * 
+ * The function msg_is_#xxxxxx#() returns true (nonzero) if
+ * the header class is an instance of #xxxxxxx_xxxxxxx#
+ * object and false (zero) otherwise.
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @return
+ * The function msg_is_#xxxxxx#() returns true (nonzero) if
+ * the header object is an instance of header #xxxxxx# and
+ * false (zero) otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
+{
+  msg_generic_t const *h = (msg_generic_t *)header;
+  return h && h->g_common->h_class->hc_hash == msg_#xxxxxx#_hash;
+}
+#else
+int msg_is_#xxxxxx#(msg_header_t const *header);
+#endif
+
+/**Duplicate (deep copy) @c msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_dup() duplicates a header structure @a
+ * header. If the header structure @a header contains a reference
+ * (@c header->x_next) to a list of headers, all the headers in the
+ * list are duplicated, too.
+ * 
+ * @param home   memory home used to allocate new structure
+ * @param header header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant strings
+ * attached to the header are copied, too. The function uses given
+ * memory @a home to allocate all the memory areas used to copy the
+ * header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_dup(home, msg->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_dup() returns a pointer to the
+ * newly duplicated msg_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, 
+				 msg_#xxxxxx#_t const *header)
+     __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, 
+				 msg_#xxxxxx#_t const *header)
+{
+  return (msg_#xxxxxx#_t *)
+    msg_header_dup_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header); 
+}
+#endif
+
+
+/**Copy a msg_#xxxxxx#_t header structure.
+ * 
+ * The function msg_#xxxxxx#_copy() copies a header structure @a
+ * header. If the header structure @a header contains a reference
+ * (@c header->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home to
+ * allocate all the memory areas used to copy the header structure
+ * @a header.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param header  pointer to the header structure to be duplicated
+ * 
+ * When copying, only the header structure and parameter lists
+ * attached to it are duplicated. The new header structure retains
+ * all the references to the strings within the old @a header,
+ * including the encoding of the old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_copy(home, msg->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home, 
+				  msg_#xxxxxx#_t const *header)
+     __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home, 
+				  msg_#xxxxxx#_t const *header)
+{
+  return (msg_#xxxxxx#_t *)
+    msg_header_copy_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header); 
+}
+#endif
+
+/**Make a header structure msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_make() makes a new
+ * msg_#xxxxxx#_t header structure.  It allocates a new
+ * header structure, and decodes the string @a s as the
+ * value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_make().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_make() returns a pointer to
+ * newly maked msg_#xxxxxx#_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+  return (msg_#xxxxxx#_t*)msg_header_make(home, msg_#xxxxxx#_class, s);
+}
+#else
+msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
+     __attribute__((__malloc__));
+#endif
+
+/**Make a #xxxxxxx_xxxxxxx# from formatting result.
+ * 
+ * The function msg_#xxxxxx#_format() makes a new
+ * #xxxxxxx_xxxxxxx# object using formatting result as its
+ * value.  The function first prints the arguments according to
+ * the format @a fmt specified.  Then it allocates a new header
+ * structure, and uses the formatting result as the header
+ * value.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_format().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((__malloc__, __format__ (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+  msg_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
+  va_end(ap);
+ 
+  return (msg_#xxxxxx#_t*)h;
+}
+#endif
+
+/** @} */
+
+
+SOFIA_END_DECLS
+
+#endif /** !defined(MSG_PROTOS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_TAG_CLASS_H
+/** Defined when <sofia-sip/msg_tag_class.h> has been included */
+#define MSG_TAG_CLASS_H 
+
+/**@file sofia-sip/msg_tag_class.h
+ * @brief Functions for constructing per-protocol tag classes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN size_t msghdrtag_xtra(tagi_t const *t, size_t offset);
+SOFIAPUBFUN tagi_t *msghdrtag_dup(tagi_t *dst, tagi_t const *src,
+				  void **inout_buffer);
+SOFIAPUBFUN int msghdrtag_scan(tag_type_t tt, su_home_t *home, 
+			       char const *s, 
+			       tag_value_t *return_value);
+SOFIAPUBFUN tagi_t *msghdrtag_filter(tagi_t *dst, tagi_t const f[], 
+				     tagi_t const *src, 
+				     void **inout_buffer);
+
+SOFIAPUBFUN tagi_t *msgstrtag_filter(tagi_t *dst, tagi_t const f[],
+				     tagi_t const *src, 
+				     void **inout_buffer);
+
+SOFIAPUBFUN int msgobjtag_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN size_t msgobjtag_xtra(tagi_t const *t, size_t offset);
+SOFIAPUBFUN tagi_t *msgobjtag_dup(tagi_t *dst, tagi_t const *src,
+				  void **inout_buffer);
+
+SOFIA_END_DECLS
+
+#endif /** !defined(MSG_TAG_CLASS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef MSG_TYPES_H
+/** Defined when <sofia-sip/msg_types.h> has been included. */
+#define MSG_TYPES_H
+
+/**@file sofia-sip/msg_types.h
+ * @brief Types for messages and common headers
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Jan 23 15:43:17 2003 ppessi
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Message class. */
+typedef struct msg_mclass_s       msg_mclass_t;
+
+/** Header class. */
+typedef struct msg_hclass_s const msg_hclass_t;
+
+/** Header reference. */
+typedef struct msg_href_s         msg_href_t;
+
+/** Message object. */
+typedef struct msg_s              msg_t;
+
+#ifndef MSG_TIME_T_DEFINED
+#define MSG_TIME_T_DEFINED
+/** Time in seconds since epoch (1900-Jan-01 00:00:00). */
+typedef unsigned long msg_time_t;
+#endif
+
+#ifndef MSG_TIME_MAX
+/** Latest time that can be expressed with msg_time_t. @HIDE */
+#define MSG_TIME_MAX ((msg_time_t)ULONG_MAX)
+#endif
+
+#ifndef MSG_PUB_T
+#ifdef MSG_OBJ_T 
+#define MSG_PUB_T MSG_OBJ_T
+#else
+#define MSG_PUB_T struct msg_pub_s
+#endif
+#endif
+
+/**Public protocol-specific message structure for accessing the message. 
+ * 
+ * This type can be either #sip_t, #http_t, or #msg_multipart_t, depending
+ * on the message. The base structure used by msg module is defined in
+ * struct #msg_pub_s.
+ */
+typedef MSG_PUB_T msg_pub_t;
+
+#ifndef MSG_HDR_T
+#define MSG_HDR_T union msg_header_u
+#endif
+/** Any protocol-specific header object */
+typedef MSG_HDR_T msg_header_t;
+
+typedef struct msg_common_s         msg_common_t;
+
+typedef struct msg_separator_s      msg_separator_t;
+typedef struct msg_payload_s        msg_payload_t;
+typedef struct msg_unknown_s        msg_unknown_t;
+typedef struct msg_error_s          msg_error_t;
+
+typedef msg_common_t msg_frg_t;
+
+typedef char const            	   *msg_param_t;
+typedef struct msg_numeric_s  	    msg_numeric_t;
+typedef struct msg_generic_s  	    msg_generic_t;
+typedef struct msg_list_s     	    msg_list_t;
+typedef struct msg_auth_s     	    msg_auth_t;
+typedef struct msg_auth_info_s      msg_auth_info_t;
+
+#define MSG_HEADER_N 16377
+
+/** Common part of the header objects (or message fragments). 
+ *
+ * This structure is also known as #msg_common_t or #sip_common_t.
+ */
+struct msg_common_s {
+  msg_header_t       *h_succ;	/**< Pointer to succeeding fragment. */
+  msg_header_t      **h_prev;	/**< Pointer to preceeding fragment. */
+  msg_hclass_t       *h_class;	/**< Header class. */
+  void const         *h_data;	/**< Fragment data */
+  usize_t             h_len;    /**< Fragment length (including CRLF) */
+};
+
+
+/** Message object, common view */
+struct msg_pub_s {
+  msg_common_t        msg_common[1]; /**< Recursive */
+  msg_pub_t          *msg_next;
+  void               *msg_user;
+  unsigned            msg_size;
+  unsigned            msg_flags;
+  msg_error_t        *msg_error;
+  msg_header_t       *msg_request;
+  msg_header_t       *msg_status;
+  msg_header_t       *msg_headers[MSG_HEADER_N];
+};
+
+#define msg_ident msg_common->h_class
+
+/** Numeric header. 
+ *
+ * A numeric header has a 32-bit integer as its value.
+ */
+struct msg_numeric_s {
+  msg_common_t   x_common[1];	    /**< Common fragment info */
+  msg_numeric_t *x_next;	    /**< Link to next header */
+  unsigned long  x_value;	    /**< Numeric header value */
+};
+
+/** Generic header. 
+ *
+ * A generic header does not have any internal structure. Its value is
+ * represented as a string.
+ */
+struct msg_generic_s {
+  msg_common_t   g_common[1];	    /**< Common fragment info */
+  msg_generic_t *g_next;	    /**< Link to next header */
+  char const    *g_string;	    /**< Header value */
+};
+
+/** List header. 
+ * 
+ * A list header consists of comma-separated list of tokens.
+ */
+struct msg_list_s {
+  msg_common_t       k_common[1];   /**< Common fragment info */
+  msg_list_t        *k_next;	    /**< Link to next header */
+  msg_param_t       *k_items;	    /**< List of items */
+};
+
+/** Authentication header. 
+ *
+ * An authentication header has authentication scheme name and
+ * comma-separated list of parameters as its value.
+ */
+struct msg_auth_s {
+  msg_common_t       au_common[1];  /**< Common fragment info */
+  msg_auth_t        *au_next;	    /**< Link to next header */
+  char const        *au_scheme;	    /**< Auth-scheme like Basic or Digest */
+  msg_param_t const *au_params;	    /**< Comma-separated parameters */
+};
+
+/**Authentication-Info header
+ *
+ * An Authentication-Info header has comma-separated list of parameters as its value.
+ */
+struct msg_auth_info_s
+{
+  msg_common_t        ai_common[1]; /**< Common fragment info */
+  msg_error_t        *ai_next;	    /**< Dummy link to next */
+  msg_param_t const  *ai_params;    /**< List of ainfo */
+};
+
+/** Unknown header. */
+struct msg_unknown_s {
+  msg_common_t    un_common[1];  /**< Common fragment info */
+  msg_unknown_t  *un_next;	 /**< Link to next unknown header */
+  char const     *un_name;	 /**< Header name */
+  char const     *un_value;	 /**< Header field value */
+};
+
+/** Erroneus header. */
+struct msg_error_s {
+  msg_common_t    er_common[1];  /**< Common fragment info */
+  msg_error_t    *er_next;	 /**< Link to next header */
+  char const     *er_name;       /**< Name of bad header (if any). */
+};
+
+
+/** Separator. */
+struct msg_separator_s {
+  msg_common_t    sep_common[1]; /**< Common fragment info */
+  msg_error_t    *sep_next;	 /**< Dummy link to next header */
+  char            sep_data[4];	 /**< NUL-terminated separator */
+};
+
+/** Message payload. */
+struct msg_payload_s {
+  msg_common_t    pl_common[1];	    /**< Common fragment info */
+  msg_payload_t  *pl_next;	    /**< Next payload chunk */
+  char           *pl_data;	    /**< Data - may contain NUL */
+  usize_t         pl_len;	    /**< Length of message payload */
+};
+
+/** Any header. */
+union msg_header_u {
+  msg_common_t    sh_common[1];	    /**< Common fragment info */
+  struct {
+    msg_common_t  shn_common;
+    msg_header_t *shn_next;
+  }               sh_header_next[1];
+#define sh_next   sh_header_next->shn_next
+#define sh_class  sh_common->h_class
+#define sh_succ   sh_common->h_succ
+#define sh_prev   sh_common->h_prev
+#define sh_data   sh_common->h_data
+#define sh_len    sh_common->h_len
+
+  msg_generic_t   sh_generic[1];
+  msg_numeric_t   sh_numeric[1];
+  msg_list_t      sh_list[1];
+  msg_auth_t      sh_auth[1];
+  msg_separator_t sh_separator[1];
+  msg_payload_t   sh_payload[1];
+  msg_unknown_t   sh_unknown[1];
+  msg_error_t     sh_error[1];
+};
+
+/* ====================================================================== */
+
+/**Define how to handle existing headers 
+ * when a new header is added to a message. 
+ */
+typedef enum {
+  msg_kind_single,		/**< Only one header is allowed */
+  msg_kind_append,		/**< New header is appended */
+  msg_kind_list,		/**< A token list header, 
+				 * new header is combined with old one. */
+  msg_kind_apndlist,		/**< A complex list header. */
+  msg_kind_prepend		/**< New header is prepended */
+} msg_header_kind_t;
+
+struct su_home_s;
+
+typedef issize_t msg_parse_f(struct su_home_s *, msg_header_t *, char *, isize_t);
+typedef issize_t msg_print_f(char buf[], isize_t bufsiz, 
+			     msg_header_t const *, int flags);
+typedef char *msg_dup_f(msg_header_t *dst, msg_header_t const *src, 
+			char *buf, isize_t bufsiz);
+typedef isize_t msg_xtra_f(msg_header_t const *h, isize_t offset);
+
+typedef int msg_update_f(msg_common_t *, char const *name, isize_t namelen,
+			 char const *value);
+
+/** Factory object for a header. 
+ * 
+ * The #msg_hclass_t object, "header class", defines how a header is
+ * handled. It has parsing and printing functions, functions used to copy
+ * header objects, header name and other information used when parsing,
+ * printing, removing, adding and replacing headers within a message.
+ */
+struct msg_hclass_s
+{
+  /* XXX size of header class missing. Someone has saved bits in wrong place. */
+  int               hc_hash;	/**< Header name hash or ID */
+  msg_parse_f      *hc_parse;	/**< Parse header. */
+  msg_print_f      *hc_print;	/**< Print header. */
+  msg_xtra_f       *hc_dxtra;	/**< Calculate extra size for dup */
+  msg_dup_f        *hc_dup_one;	/**< Duplicate one header. */
+  msg_update_f     *hc_update;	/**< Update parameter(s) */
+  char const 	   *hc_name;	/**< Full name. */
+  short             hc_len;	/**< Length of hc_name. */
+  char              hc_short[2];/**< Short name, if any. */
+  unsigned char     hc_size;	/**< Size of header structure. */
+  unsigned char     hc_params;	/**< Offset of parameter list */
+  unsigned          hc_kind:3;	/**< Kind of header (#msg_header_kind_t):
+				 * single, append, list, apndlist, prepend. */
+  unsigned          hc_critical:1; /**< True if header is critical */
+  unsigned          /*pad*/:0;
+};
+
+#define HC_LEN_MAX SHRT_MAX
+
+SOFIA_END_DECLS
+
+#endif /* !defined MSG_TYPES_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ * @file test_class.c
+ * 
+ * Message class for testing parser and transports.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Mar  5 11:57:20 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define TAG_NAMESPACE "tst"
+
+#include <test_class.h>
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_mclass.h>
+#include <test_protos.h>
+#include <sofia-sip/msg_addr.h>
+
+extern msg_mclass_t const msg_test_mclass[1];
+
+extern msg_mclass_t const *msg_test_default(void)
+{
+  return msg_test_mclass;
+}
+
+#define msg_generic_update NULL
+
+/**@ingroup test_msg
+ * @defgroup msg_test_request Request Line for Testing
+ */
+
+static msg_xtra_f msg_request_dup_xtra;
+static msg_dup_f msg_request_dup_one;
+
+msg_hclass_t msg_request_class[] =
+MSG_HEADER_CLASS(msg_, request, NULL, "", rq_common, 
+		 single_critical, msg_request, msg_generic);
+
+/** Decode a request line */
+issize_t msg_request_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_request_t *rq = (msg_request_t *)h;
+  char *uri, *version;
+
+  if (msg_firstline_d(s, &uri, &version) < 0 || !uri ||
+      url_d(rq->rq_url, uri) < 0)
+    return -1;
+
+  rq->rq_method_name = s;
+  rq->rq_version = version;
+
+  return 0;
+}
+
+/**Encode a request line. */
+issize_t msg_request_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  msg_request_t const *rq = (msg_request_t const *)h;
+
+  return snprintf(b, bsiz, "%s " URL_FORMAT_STRING " %s" CRLF,
+		  rq->rq_method_name,
+		  URL_PRINT_ARGS(rq->rq_url),
+		  rq->rq_version);
+}
+
+isize_t msg_request_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  isize_t rv = offset;
+  msg_request_t const *rq = (msg_request_t const *)h;
+
+  rv += url_xtra(rq->rq_url);
+  rv += MSG_STRING_SIZE(rq->rq_method_name);
+  rv += MSG_STRING_SIZE(rq->rq_version);
+
+  return rv;
+}
+
+/** Duplicate one request header. */
+char *msg_request_dup_one(msg_header_t *dst, msg_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  msg_request_t *rq = (msg_request_t *)dst;
+  msg_request_t const *o = (msg_request_t const *)src;
+  char *end = b + xtra;
+
+  URL_DUP(b, end, rq->rq_url, o->rq_url);
+
+  MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
+  MSG_STRING_DUP(b, rq->rq_version, o->rq_version);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/**@ingroup test_msg
+ * @defgroup msg_test_status Status Line for Testing
+ */
+
+static msg_xtra_f msg_status_dup_xtra;
+static msg_dup_f msg_status_dup_one;
+
+msg_hclass_t msg_status_class[1] =
+MSG_HEADER_CLASS(msg_, status, NULL, "", st_common, 
+		 single_critical, msg_status, msg_generic);
+
+/** Parse status line */
+issize_t msg_status_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  msg_status_t *st = (msg_status_t *)h;
+  char *status, *phrase;
+  unsigned long code;
+
+  if (msg_firstline_d(s, &status, &phrase) < 0 ||
+      (code = strtoul(status, &status, 10)) >= 1000 || *status)
+    return -1;
+
+  st->st_status = code;
+  st->st_phrase = phrase;
+  st->st_version = s;
+
+  return 0;
+}
+
+issize_t msg_status_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  msg_status_t const *st = (msg_status_t const *)h;
+  int status = st->st_status;
+
+  if (status > 999 || status < 100)
+    status = 0;
+
+  return snprintf(b, bsiz, "%s %03u %s" CRLF, 
+		  st->st_version, status, st->st_phrase);
+}
+
+/** Extra size of a msg_status_t object. */
+isize_t msg_status_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+  isize_t rv = offset;
+  msg_status_t const *st = (msg_status_t const *)h;
+  rv += MSG_STRING_SIZE(st->st_version);
+  rv += MSG_STRING_SIZE(st->st_phrase);
+  return rv;
+}
+
+/** Duplicate one status header. */
+char *msg_status_dup_one(msg_header_t *dst, msg_header_t const *src,
+			 char *b, isize_t xtra)
+{
+  msg_status_t *st = (msg_status_t *)dst;
+  msg_status_t const *o = (msg_status_t const *)src;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, st->st_version, o->st_version);
+  st->st_status = o->st_status;
+  MSG_STRING_DUP(b, st->st_phrase, o->st_phrase);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Extract the message body, including separator line. 
+ *
+ * @param[in,out] msg  message object 
+ * @param[in,out] pub  public message structure 
+ * @param[in]     b    buffer containing unparsed data 
+ * @param[in]     bsiz buffer size 
+ * @param[in]     eos  true if buffer contains whole message
+ *
+ * @retval -1     error
+ * @retval 0      message is incomplete
+ * @retval other  number of bytes extracted
+ */
+issize_t msg_test_extract_body(msg_t *msg, msg_pub_t *pub, 
+			       char b[], isize_t bsiz, int eos)
+{
+  msg_test_t *tst = (msg_test_t *)pub;
+  ssize_t m = 0;
+  size_t body_len;
+
+  if (!(tst->msg_flags & MSG_FLG_BODY)) {
+    /* We are looking at a potential empty line */
+    m = msg_extract_separator(msg, (msg_pub_t *)tst, b, bsiz, eos);
+    if (m == 0 || m == -1)
+      return m;
+    tst->msg_flags |= MSG_FLG_BODY;
+    b += m;
+    bsiz -= m;
+  }
+
+  if (tst->msg_content_length)
+    body_len = tst->msg_content_length->l_length;
+  else if (MSG_IS_MAILBOX(tst->msg_flags)) /* message fragments */
+    body_len = 0;
+  else if (eos)
+    body_len = bsiz;
+  else
+    return -1;
+
+  if (body_len == 0) {
+    tst->msg_flags |= MSG_FLG_COMPLETE;
+    return m;
+  }
+
+  if (m)
+    return m;
+
+  if ((m = msg_extract_payload(msg, (msg_pub_t *)tst, NULL, body_len, b, bsiz, eos) ) == -1)
+    return -1;
+  
+  tst->msg_flags |= MSG_FLG_FRAGS;
+  if (bsiz >= body_len)
+    tst->msg_flags |= MSG_FLG_COMPLETE;
+  return m;
+}
+
+msg_href_t const msg_content_length_href[1] = 
+  {{
+    msg_content_length_class,
+    offsetof(msg_test_t, msg_content_length)
+  }};
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/msg_tag_class.h>
+
+tagi_t *tsttag_filter(tagi_t *dst,
+		      tagi_t const f[],
+		      tagi_t const *src, 
+		      void **bb);
+
+/** Tag class for test header tags. @HIDE */
+tag_class_t tsthdrtag_class[1] = 
+  {{
+    sizeof(tsthdrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msghdrtag_xtra,
+    /* tc_dup */      msghdrtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msghdrtag_snprintf,
+    /* tc_filter */   tsttag_filter,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     msghdrtag_scan,
+  }};
+
+/** Tag class for TST header string tags. @HIDE */
+tag_class_t tststrtag_class[1] = 
+  {{
+    sizeof(tststrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     t_str_xtra,
+    /* tc_dup */      t_str_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_str_snprintf,
+    /* tc_filter */   NULL /* msgtag_str_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     t_str_scan
+  }};
+
+/** Tag class for TST message tags. @HIDE */
+tag_class_t tstmsgtag_class[1] = 
+  {{
+    sizeof(tstmsgtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msgobjtag_xtra,
+    /* tc_dup */      msgobjtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msgobjtag_snprintf,
+    /* tc_filter */   NULL /* tsttag_tst_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+  }};
+
+tag_typedef_t tsttag_header = 
+	{{ TAG_NAMESPACE, "header", tsthdrtag_class, 0 }};
+
+tag_typedef_t tsttag_header_str = STRTAG_TYPEDEF(header_str);
+
+/** Filter a TST header structure. */
+tagi_t *tsttag_filter(tagi_t *dst,
+		      tagi_t const f[],
+		      tagi_t const *src, 
+		      void **bb)
+{
+  tagi_t stub[2] = {{ NULL }};
+  tag_type_t sctt, tt = f->t_tag;
+  msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
+
+  assert(src);
+
+  sctt = src->t_tag;
+
+  if (sctt && sctt->tt_class == tstmsgtag_class) {
+    msg_test_t const *tst = (msg_test_t const *)src->t_value;
+    msg_mclass_t *mc = (msg_mclass_t *)tst->msg_ident;
+    msg_header_t const **hh = (msg_header_t const **)
+      msg_hclass_offset(mc, (msg_pub_t *)tst, hc);
+    msg_header_t const *h;
+
+    if (tst == NULL || 
+	(char *)hh >= ((char *)tst + tst->msg_size) ||
+	(char *)hh < (char const *)&tst->msg_request)
+      return dst;
+
+    h = *hh;
+
+    if (h == NULL)
+      return dst;
+
+    stub[0].t_tag = tt;
+    stub[0].t_value = (tag_value_t)h;
+    src = stub; sctt = tt;
+  }
+
+  if (tt != sctt)
+    return dst;
+
+  if (!src->t_value)
+    return dst;
+  else if (dst) {
+    return t_dup(dst, src, bb);
+  }
+  else {
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst + 1;
+  }
+}
+
+/** Add duplicates of headers from taglist to the TST message. */
+int tst_add_tl(msg_t *msg, msg_test_t *tst,
+	       tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t const *t;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  for (t = ta_args(ta); t; t = tl_next(t)) {
+    if (!(tag = t->t_tag) || !(value = t->t_value))
+      continue;
+
+    if (TSTTAG_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      msg_header_t *h = (msg_header_t *)value, **hh;
+
+      if (h == NULL)
+	;
+      else if (h == MSG_HEADER_NONE) {	/* Remove header */
+	hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)tst, hc);
+	while (hh && *hh)
+	  msg_header_remove(msg, (msg_pub_t *)tst, *hh);
+      } else if (msg_header_add_dup_as(msg, (msg_pub_t *)tst, hc, h) < 0)
+	break;
+    }
+    else if (TSTTAG_STR_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      char const *s = (char const *)value;
+      if (s && msg_header_add_make(msg, (msg_pub_t *)tst, hc, s) < 0)
+	break;
+    }
+    else if (tag == tsttag_header_str) {
+      if (msg_header_add_str(msg, (msg_pub_t *)tst, (char const *)value) < 0)
+	break;
+    }
+  }
+
+  ta_end(ta);
+
+  return t ? -1 : 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_CLASS_H
+/** Defined when <test_class.h> has been included. */
+#define TEST_CLASS_H 
+
+/**@ingroup test_msg
+ * @file test_class.h
+ * @brief Message and header classes for testing.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ */
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+#ifndef MSG_MCLASS_H
+#include <sofia-sip/msg_mclass.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define MSG_TEST_PROTOCOL_TAG ((void *)(size_t)0xdeadbeef)
+
+#define MSG_TEST_VERSION_CURRENT "msg/1.0"
+
+extern msg_mclass_t const msg_test_mclass[1];
+
+extern msg_href_t const msg_content_length_href[1];
+
+typedef struct msg_request_s msg_request_t;
+typedef struct msg_status_s  msg_status_t;
+
+/** Request line. */
+struct msg_request_s { 
+  msg_common_t     rq_common[1];   /**< Common fragment info */
+  msg_header_t    *rq_next;	   /**< Link to next header */
+  char const      *rq_method_name; /**< Method name */
+  url_t            rq_url[1];	   /**< RequestURI */
+  char const      *rq_version;     /**< Protocol version */
+}; 
+
+/** Status line. */
+struct msg_status_s { 
+  msg_common_t   st_common[1];	/**< Common fragment info */
+  msg_header_t *st_next;	/**< Link to next (dummy) */
+  char const    *st_version;	/**< Protocol version */
+  int            st_status;	/**< Status code */
+  char const    *st_phrase;	/**< Status phrase */
+};
+
+/** Message object for tests. */
+typedef struct msg_test_s {
+  msg_common_t        msg_common[1]; /**< For recursive inclusion */
+  msg_pub_t          *msg_next;
+  void               *msg_user;	     /**< User data */
+  unsigned            msg_size;
+  unsigned            msg_flags;
+  msg_error_t        *msg_error;
+
+  msg_request_t      *msg_request;
+  msg_status_t       *msg_status;
+
+  /* === Headers start here */
+  msg_content_type_t     *msg_content_type;     /**< Content-Type */
+  msg_content_disposition_t *msg_content_disposition;
+                                                /**< Content-Disposition */
+  msg_content_location_t *msg_content_location; /**< Content-Location */
+  msg_content_language_t *msg_content_language; /**< Content-Language */
+
+  msg_accept_t           *msg_accept;           /**< Accept */
+  msg_accept_charset_t   *msg_accept_charset;	/**< Accept-Charset */
+  msg_accept_encoding_t  *msg_accept_encoding;	/**< Accept-Encoding */
+  msg_accept_language_t  *msg_accept_language;	/**< Accept-Language */
+  msg_mime_version_t     *msg_mime_version;	/**< MIME-Version */
+  msg_content_md5_t      *msg_content_md5;	/**< Content-MD5 */
+  msg_content_encoding_t *msg_content_encoding; 
+						/**< Content-Encoding */
+  msg_content_length_t   *msg_content_length;	/**< Content-Length */
+  /* === Headers end here */
+
+  msg_unknown_t      *msg_unknown;
+  msg_separator_t    *msg_separator;
+  msg_payload_t      *msg_payload;
+  msg_multipart_t    *msg_multipart;
+} msg_test_t;
+
+union msg_test_u
+{
+  msg_common_t    sh_common[1];
+  struct {
+    msg_common_t  shn_common;
+    msg_header_t *shn_next;
+  }               sh_header_next[1];
+
+  msg_request_t             sh_request[1];
+  msg_status_t              sh_status[1];
+  msg_accept_t              sh_accept[1];
+  msg_accept_charset_t      sh_accept_charset[1];
+  msg_accept_encoding_t     sh_accept_encoding[1];
+  msg_accept_language_t     sh_accept_language[1];
+  msg_content_disposition_t sh_content_disposition[1];
+  msg_content_encoding_t    sh_content_encoding[1];
+  msg_content_id_t          sh_content_id[1];
+  msg_content_md5_t         sh_content_md5[1];
+  msg_content_language_t    sh_content_language[1];
+  msg_content_length_t      sh_content_length[1]; 
+  msg_content_location_t    sh_content_location[1];
+  msg_content_type_t        sh_content_type[1];
+  msg_mime_version_t        sh_mime_version[1];
+
+  msg_generic_t   sh_generic[1];
+  msg_numeric_t   sh_numeric[1];
+  msg_list_t      sh_list[1];
+  msg_auth_t      sh_auth[1];
+  msg_separator_t sh_separator[1];
+  msg_payload_t   sh_payload[1];
+  msg_unknown_t   sh_unknown[1];
+};
+
+issize_t msg_test_extract_body(msg_t *, msg_pub_t *,
+			       char b[], isize_t bsiz, int eos);
+
+static inline
+msg_test_t *msg_test_public(msg_t *msg)
+{
+  return (msg_test_t *)msg_public(msg, MSG_TEST_PROTOCOL_TAG);
+}
+
+SOFIA_END_DECLS
+
+#endif /* !defined(TEST_CLASS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1718 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ *
+ * @CFILE test_msg.c
+ *
+ * Torture tests for message parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include "test_class.h"
+#include "test_protos.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_addr.h"
+#include "sofia-sip/msg_date.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_mclass_hash.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "test_msg";
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int msg_time_test(void)
+{
+  char buf[32];
+  char const *s;
+  char date1900[] = "Mon,  1 Jan 1900 00:00:00 GMT";
+  char date1900_1[] = "Mon, 01 Jan 1900 00:00:01 GMT";
+  char date822[] = "Thursday, 01-Jan-70 00:00:01 GMT";
+  char date822b[] = "Wednesday, 09-Nov-99 23:12:40 GMT";
+  char date822c[] = "Wednesday, 01-Sep-04 23:12:40 GMT";
+  char date2822[] = "Monday, 01-Jan-1900 00:00:01 GMT";
+  char dateasc[] = "Mon Jan  1 00:00:01 1900";
+  msg_time_t now = msg_now(), date = now;
+
+  BEGIN();
+  s = date1900;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 0);
+  TEST_SIZE(msg_date_e(buf, sizeof(buf), date), strlen(date1900));
+  TEST_SIZE(msg_date_e(buf, sizeof(buf), 1), strlen(date1900_1));
+  TEST_S(buf, date1900_1);
+
+  s = date822;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 2208988801U);
+
+  s = date822b;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 3151177960U);
+
+  s = date822c;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 3303069160U);
+
+  s = date2822;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 1);
+
+  s = dateasc;
+  TEST_1(msg_date_d(&s, &date) == 0);
+  TEST(date, 1);
+
+  {
+    char error1[] = "Mo";
+    char error2[] = "Mon,  1 Jan 19100 00:00:00 GMT";
+    char error3[] = "Mon,  1 Jan 1900 00:00:";
+    char error4[] = "Mon,  1 Jan 1900 25:00:00 GMT";
+    char noerror5[] = "Mon,  1 Jan 1899 24:00:00 GMT";
+    char error6[] = "Mon, 30 Feb 1896 23:59:59 GMT";
+    char noerror7[] = "Mon, 29 Feb 1896 23:59:59 GMT";
+    char error8[] = "Mon, 32 Jan 1900 24:00:00 GMT";
+    char error9[] = "Mon, 27 Fev 1900 24:00:00 GMT";
+
+    s = error1; TEST_1(msg_date_d(&s, &date) < 0);
+    s = error2; TEST_1(msg_date_d(&s, &date) < 0);
+    s = error3; TEST_1(msg_date_d(&s, &date) < 0);
+    s = error4; TEST_1(msg_date_d(&s, &date) < 0);
+    s = noerror5; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0);
+    s = error6; TEST_1(msg_date_d(&s, &date) < 0);
+    s = noerror7; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0);
+    s = error8; TEST_1(msg_date_d(&s, &date) < 0);
+    s = error9; TEST_1(msg_date_d(&s, &date) < 0);
+  }
+
+  {
+    char error1[] = "4294967297";
+    char *s;
+    msg_numeric_t x[1];
+
+    memset(x, 0, sizeof (x));
+
+    TEST_1(msg_numeric_d(NULL, (msg_header_t *)x, s = error1, strlen(error1)) < 0);
+  }
+
+  END();
+  return 0;
+}
+
+static int addr_test(void)
+{
+  BEGIN();
+  
+  /* It *will* fail. */
+  /* TEST(sizeof(socklen_t), sizeof(msg_addrlen(NULL))); */
+
+  END();
+}
+
+int test_header_parsing(void)
+{
+  BEGIN();
+
+  {
+    /* Test quoting/unquoting */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    char *quoted = "\"foo \\b\\a\\r\\\"\\\\\"extra";
+    char *unquoted;
+
+    TEST_1(unquoted = msg_unquote_dup(home, quoted));
+    TEST_S(unquoted, "foo bar\"\\");
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test parameter list */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_param_t const *params = NULL;
+    char str[] = ";uffe;duffe = \"entten\" ; doo = [::1]  ", *s = str;
+    char const canonic[] = ";uffe;duffe=\"entten\";doo=[::1]";
+    char *end = str + strlen(str);
+    char b[sizeof(canonic) + 8];
+
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params != 0);
+    TEST_P(s, end);
+    TEST_S(params[0], "uffe");
+    TEST_S(params[1], "duffe=\042entten\042");
+    TEST_S(params[2], "doo=[::1]");
+    TEST_1(params[3] == NULL);
+    TEST_SIZE(msg_params_e(NULL, 0, params), strlen(canonic));
+    TEST_SIZE(msg_params_e(b, sizeof(b), params), strlen(canonic));
+    TEST_S(b, canonic);
+
+    TEST_S(msg_params_find(params, "uffe"), "");
+    TEST_S(msg_params_find(params, "uffe="), "");
+    TEST_S(msg_params_find(params, "duffe"), "\"entten\"");
+    TEST_S(msg_params_find(params, "duffe="), "\"entten\"");
+    TEST_S(msg_params_find(params, "doo"), "[::1]");
+    TEST_S(msg_params_find(params, "doo="), "[::1]");
+
+    TEST(msg_params_remove((msg_param_t *)params, "uffe"), 1);
+    TEST_S(params[0], "duffe=\042entten\042");
+    TEST_S(params[1], "doo=[::1]");
+    TEST_1(params[2] == NULL);
+
+    TEST(msg_params_remove((msg_param_t *)params, "doo"), 1);
+    TEST_S(params[0], "duffe=\042entten\042");
+    TEST_1(params[1] == NULL);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test that parameter list of length MSG_PARAMS_N is handled correctly */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_param_t const *params = NULL;
+    char list1[] = ";one;two;three;four;five;six;seven;eight", *s = list1;
+    char list2[] = ";one;two;three;four;five;six;seven";
+    char list3[] = ";one;two;three;four;five;six;seven, humppaa";
+    char *end3 = strchr(list3, ',');
+    char list4[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+      ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen";
+    char list5[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+      ";eleven;twelve;thirteen;fourteen;fiveteen";
+    char list6[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+      ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen;seventeen";
+    int i;
+
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params);
+    for (i = 0; i < 8; i++)
+      TEST_1(params[i]);
+    TEST_1(params[8] == NULL);
+
+    s = list2, params = NULL;
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params);
+    for (i = 0; i < 7; i++)
+      TEST_1(params[i]);
+    TEST_1(params[7] == NULL);
+
+    s = list3; params = NULL;
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_S(s, end3);
+    TEST_1(params);
+    for (i = 0; i < 7; i++)
+      TEST_1(params[i]);
+    TEST_1(params[7] == NULL);
+
+    s = list4; params = NULL;
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params);
+    for (i = 0; i < 16; i++)
+      TEST_1(params[i]);
+    TEST_1(params[16] == NULL);
+
+    s = list5; params = NULL;
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params);
+    for (i = 0; i < 15; i++)
+      TEST_1(params[i]);
+    TEST_1(params[15] == NULL);
+
+    s = list6 ; params = NULL;
+    TEST_1(msg_params_d(home, &s, &params) >= 0);
+    TEST_1(params);
+    for (i = 0; i < 17; i++)
+      TEST_1(params[i]);
+    TEST_1(params[17] == NULL);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test parameter lists */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    unsigned i, j;
+
+    msg_param_t const *p = NULL;
+    char *master = ";0", *list, *end;
+    
+    for (i = 1; i < 256; i++) {
+      master = su_sprintf(home, "%s; %u", master, i); TEST_1(master);
+      list = end = su_strdup(home, master);
+      TEST_1(msg_params_d(home, &end, &p) >= 0);
+      TEST_S(end, "");
+      TEST_1(p);
+      for (j = 0; j <= i; j++) {
+	char number[10];
+	snprintf(number, sizeof number, "%u", j);
+	TEST_S(p[j], number);
+      }
+      TEST_1(p[i + 1] == NULL);
+      su_free(home, list);
+      su_free(home, (void *)p), p = NULL;
+    }
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test comma-separated list */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+
+    msg_list_t k1[1] = {{{{ 0 }}}};
+    char list1[] = "foo, bar, baz  zi  \"baz\"";
+    
+    TEST_1(msg_list_d(home, (msg_header_t *)k1, list1, strlen(list1)) >= 0);
+    TEST_1(k1->k_items);
+    TEST_S(k1->k_items[0], "foo");
+    TEST_S(k1->k_items[1], "bar");
+    TEST_S(k1->k_items[2], "baz zi\042baz\042");
+    TEST_1(!k1->k_items[3]);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test that list of length MSG_PARAMS_N is handled correctly */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_list_t k2[1] = {{{{ 0 }}}};
+    char list2[] = "one, two, three, four, five, six, seven, eight";
+    
+    TEST_1(
+	  msg_list_d(home, (msg_header_t *)k2, list2, strlen(list2)) >= 0);
+    TEST_1(k2->k_items);
+    TEST_1(k2->k_items[7]);
+    TEST_1(k2->k_items[8] == NULL);
+
+    su_home_deinit(home);
+  }
+    
+  {
+    /* Test that list longer than MSG_PARAMS_N is handled correctly */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_list_t k3[1] = {{{{ 0 }}}};
+    char list3[] = "one, two, three, four, five, six, seven, eight, nine";
+    
+    TEST_1(
+	  msg_list_d(home, (msg_header_t *)k3, list3, strlen(list3)) >= 0);
+    TEST_1(k3->k_items);
+    TEST_1(k3->k_items[7]);
+    TEST_1(k3->k_items[8]);
+    TEST_1(k3->k_items[9] == NULL);
+  
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test that long lists are handled correctly */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    
+    msg_param_t *k = NULL;
+    char *s;
+    char list1[] = "one, two, three, four, five, six, seven, eight";
+    char list2[] = "one, two, three, four, five, six, seven, eight";
+    char list3[] = "one, two, three, four, five, six, seven, eight";
+    char list4[] = "one, two, three, four, five, six, seven, eight, nine";    
+
+    s = list1; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+    TEST_1(k);
+    TEST_1(k[7]);
+    TEST_1(k[8] == NULL);
+
+    s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+    s = list3; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+    s = list4; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test parameter lists */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    unsigned i, j;
+
+    msg_param_t *p = NULL;
+    char *master = "0", *list, *end;
+    
+    for (i = 1; i < 256; i++) {
+      master = su_sprintf(home, "%s, %u", master, i); TEST_1(master);
+      list = end = su_strdup(home, master);
+      TEST_1(msg_commalist_d(home, &end, &p, msg_token_scan) >= 0);
+      TEST_S(end, "");
+      TEST_1(p);
+      for (j = 0; j <= i; j++) {
+	char number[10];
+	snprintf(number, sizeof number, "%u", j);
+	TEST_S(p[j], number);
+      }
+      TEST_1(p[i + 1] == NULL);
+      su_free(home, list);
+      su_free(home, (void *)p), p = NULL;
+    }
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test that errors in lists are handled correctly */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    
+    msg_param_t *k = NULL;
+    char *s;
+    char list1[] = "one, two, three, four, five, six, seven, foo=\"eight";
+    char list2[] = "one, two, three,,@,$ four, five, six, seven, eight";
+
+    s = list1; TEST_1(msg_commalist_d(home, &s, &k, NULL) < 0);
+    TEST_1(k == NULL);
+
+    s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) < 0);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test empty parameter list */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+
+    msg_list_t k4[1] = {{{{ 0 }}}};
+    char list4[] = ", ,\t,\r\n\t,  ,   ";
+    
+    TEST_1(
+	  msg_list_d(home, (msg_header_t *)k4, list4, strlen(list4)) >= 0);
+    TEST_1(k4->k_items == NULL);
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test authentication headers */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_auth_t au[1] = {{{{ 0 }}}};
+    char s[] = "Basic foo = \"bar==\" ,, bar=baari,"
+      "baz=\"bof,\\\\ \\\" baff\", base\t64/ - is== ,,";
+    
+    TEST_1(msg_auth_d(home, (msg_header_t *)au, s, strlen(s)) >= 0);
+    TEST_S(au->au_scheme, "Basic");
+    TEST_1(au->au_params);
+    TEST_S(au->au_params[0], "foo=\042bar==\042");
+    TEST_S(au->au_params[1], "bar=baari");
+    TEST_S(au->au_params[2], "baz=\042bof,\\\\ \\\042 baff\042");
+    TEST_S(au->au_params[3], "base 64/- is==");
+    TEST_1(!au->au_params[4]);
+
+    su_home_deinit(home);
+  }
+
+  /* Test that msg_*_format() works */
+  {
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+
+    msg_content_type_t *c;
+    
+    c = msg_content_type_format(home, "%s/%s;%s;%s;%s;%s;%s;%s",
+				"text", "plain",
+				"charset=iso-8859-15",
+				"format=flowed",
+				"q=0.999",
+				"msg-size=782572564",
+				"name-space-url=\"http://www.nokia.com/foo\"",
+				"foo=bar");
+
+    su_home_deinit(home);
+  }
+
+  {
+    /* Test parameter handling */
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    msg_content_encoding_t *ce;
+
+    ce = msg_content_encoding_make(home, "zip, zap, zup, lz, zl, zz, ll");
+    TEST_1(ce);
+    TEST_S(msg_header_find_param(ce->k_common, "zz"), "");
+    TEST_S(msg_header_find_item(ce->k_common, "zz"), "zz");
+    TEST_P(msg_header_find_param(ce->k_common, "k"), NULL);
+    TEST(msg_header_add_param(home, ce->k_common, "zip"), 0);
+    TEST(msg_header_remove_param(ce->k_common, "zip"), 1);
+    TEST_S(msg_header_find_param(ce->k_common, "zip"), "");
+    TEST(msg_header_remove_param(ce->k_common, "zip"), 1);
+    TEST_P(msg_header_find_param(ce->k_common, "zip"), NULL);
+    TEST(msg_header_remove_param(ce->k_common, "zip"), 0);
+    TEST(msg_header_replace_param(home, ce->k_common, "zip=zap"), 0);
+    TEST_S(msg_header_find_param(ce->k_common, "zip=1"), "zap");
+    TEST(msg_header_replace_param(home, ce->k_common, "zip=zup"), 1);
+    TEST_S(msg_header_find_param(ce->k_common, "zip"), "zup");
+
+    su_home_deinit(home);
+  }
+
+
+  END();
+}
+
+int hash_test(void)
+{
+  int i, j, hash = 0;
+  msg_mclass_t const *mc = msg_test_mclass;
+  msg_hclass_t *hc;
+  
+  BEGIN();
+
+  for (i = 0; i < mc->mc_hash_size; i++) {
+    hc = mc->mc_hash[i].hr_class;
+    if (hc == NULL)
+      continue;
+
+    hash = msg_header_name_hash(hc->hc_name, NULL);
+    TEST(hash, hc->hc_hash);
+
+    /* Cross-check hashes */
+    for (j = i + 1; j < mc->mc_hash_size; j++) {
+      if (mc->mc_hash[j].hr_class == NULL)
+	continue;
+      if (hc->hc_hash == mc->mc_hash[j].hr_class->hc_hash)
+	fprintf(stderr, "\t%s and %s have same hash\n",
+		hc->hc_name, mc->mc_hash[j].hr_class->hc_name);
+      TEST_1(hc->hc_hash != mc->mc_hash[j].hr_class->hc_hash);
+    }
+  }
+
+  END();
+}
+
+msg_t *read_msg(char const buffer[])
+{
+  return msg_make(msg_test_mclass, MSG_DO_EXTRACT_COPY, buffer, -1);
+}
+
+/**Check if header chain contains any loops. 
+ *
+ * @return
+ * Return 0 if no loop, -1 otherwise.
+ */
+static 
+int msg_chain_loop(msg_header_t const *h)
+{
+  msg_header_t const *h2;
+
+  if (!h) return 0;
+
+  for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) {
+    if (h == h2 || h == h2->sh_succ)
+      return 1;
+
+    h2 = h2->sh_succ->sh_succ;
+
+    if (h == h2)
+      return 1;
+  }
+
+  return 0;
+}
+
+/** Check header chain consistency. 
+ *
+ * @return
+ * Return 0 if consistent, number of errors otherwise.
+ */
+static
+int msg_chain_errors(msg_header_t const *h)
+{
+  if (msg_chain_loop(h))
+    return -1;
+  
+  for (; h; h = h->sh_succ) {
+    if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ)
+      return -1;
+    if (h->sh_prev && h != (*h->sh_prev))
+      return -1;
+  }
+
+  return 0;
+}
+
+int test_msg_parsing(void)
+{
+  msg_t *msg, *orig;
+  su_home_t *home;
+  msg_test_t *tst, *otst;
+  msg_request_t *request;
+  msg_status_t *status;
+  msg_content_location_t *location;
+  msg_content_language_t *language;
+  msg_accept_language_t *se;
+  msg_separator_t *separator;
+  msg_payload_t *payload;
+
+  BEGIN();
+
+  msg = read_msg("GET a-life HTTP/1.1" CRLF
+		 "Content-Length: 6" CRLF
+		 "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF
+		 "Foo: bar" CRLF
+		 CRLF
+		 "test" CRLF);
+
+  home = msg_home(msg);
+  tst = msg_test_public(msg);
+
+  TEST_1(msg);
+  TEST_1(home);
+  TEST_1(tst);
+
+  TEST_P(tst->msg_error, NULL);
+
+  TEST_1(tst->msg_accept_language);
+
+  TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0);
+  TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL);
+
+  TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0);
+  TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL);
+
+  TEST_1(separator = msg_separator_make(home, "\r\n"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0);
+  TEST_P(tst->msg_separator, separator); 
+  TEST_P(separator->sep_common->h_succ, tst->msg_payload);
+
+  /* Try to add a new payload */
+  TEST_1(payload = msg_payload_make(home, "foofaa\r\n"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0);
+  /* It is appended */
+  TEST_P(tst->msg_payload->pl_next, payload); 
+  TEST_P(tst->msg_payload->pl_common->h_succ, payload);
+
+  {
+    msg_param_t vs;
+    int vi = 0;
+    msg_param_t foo = "foo=bar";
+
+    vs = NULL;
+    MSG_PARAM_MATCH(vs, foo, "foo"); 
+    TEST_S(vs, "bar");
+    vs = NULL;
+    MSG_PARAM_MATCH(vs, foo, "fo"); 
+    TEST_P(vs, NULL);
+    vi = 0;
+    MSG_PARAM_MATCH_P(vi, foo, "foo");
+    TEST(vi, 1);
+    MSG_PARAM_MATCH_P(vi, foo, "fo");
+    TEST(vi, 1);
+    vi = 0;
+    MSG_PARAM_MATCH_P(vi, foo, "fo");
+    TEST(vi, 0);
+  }
+
+  msg_destroy(msg);
+
+  /* Bug #2624: */
+  msg = read_msg("GET /replaces HTTP/1.1" CRLF
+		 "Accept-Encoding: gzip" CRLF
+		 "Accept-Encoding: bzip2" CRLF
+		 "Accept-Encoding: deflate" CRLF
+		 "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF
+		 );
+  TEST_1(msg);
+  tst = msg_test_public(msg);
+  TEST_1(tst);
+
+  {
+    msg_accept_encoding_t *gzip, *bzip2, *deflate;
+    msg_accept_encoding_t *lzss;
+    msg_accept_language_t *en, *fi, *se;
+    msg_accept_language_t *de, *sv, *sv_fi;
+
+    TEST_1(gzip = tst->msg_accept_encoding);
+    TEST_1(bzip2 = gzip->aa_next);
+    TEST_1(deflate = bzip2->aa_next);
+
+    TEST_1(gzip->aa_common->h_data);
+    TEST_1(lzss = msg_accept_encoding_make(msg_home(msg), "lzss"));
+    TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)bzip2, (void *)lzss), 0);
+    TEST_1(gzip->aa_common->h_data);
+
+    TEST_1(en = tst->msg_accept_language);
+    TEST_1(fi = en->aa_next);
+    TEST_1(se = fi->aa_next);
+
+    TEST_S(en->aa_value, "en");
+    TEST_M(en->aa_common->h_data, 
+	   "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF,
+	   en->aa_common->h_len);
+
+    TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len, 
+	   fi->aa_common->h_data);
+    TEST(fi->aa_common->h_len, 0);
+    TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len, 
+	   se->aa_common->h_data);
+    TEST(se->aa_common->h_len, 0);
+
+    TEST_1(de = msg_accept_language_make(msg_home(msg), "de;q=0.3"));
+
+    TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)se, (void *)de), 0);
+    TEST_P(en->aa_common->h_data, NULL);
+    TEST_P(en->aa_next, fi);
+    TEST_P(fi->aa_next, de);
+    TEST_P(de->aa_next, NULL);
+
+    TEST_P(en->aa_common->h_succ, fi); 
+    TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ);
+    TEST_P(fi->aa_common->h_succ, de); 
+    TEST_P(fi->aa_common->h_prev, &en->aa_common->h_succ);
+    TEST_P(de->aa_common->h_succ, NULL);
+    TEST_P(de->aa_common->h_prev, &fi->aa_common->h_succ);
+
+    TEST_P(se->aa_next, NULL);
+    TEST_P(se->aa_common->h_succ, NULL);
+    TEST_P(se->aa_common->h_prev, NULL);
+
+    TEST_1(sv = msg_accept_language_make(msg_home(msg), 
+					 "sv;q=0.6,sv_FI;q=0.7"));
+    TEST_1(sv_fi = sv->aa_next);
+
+    TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)fi, (void *)sv), 0);
+
+    TEST_P(en->aa_next, sv);
+    TEST_P(sv->aa_next->aa_next, de); 
+    TEST_P(de->aa_next, NULL);
+
+    TEST_P(en->aa_common->h_succ, sv); 
+    TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ);
+    TEST_P(sv->aa_common->h_succ, sv_fi); 
+    TEST_P(sv->aa_common->h_prev, &en->aa_common->h_succ);
+    TEST_P(sv_fi->aa_common->h_succ, de); 
+    TEST_P(sv_fi->aa_common->h_prev, &sv->aa_common->h_succ);
+    TEST_P(de->aa_common->h_succ, NULL);
+    TEST_P(de->aa_common->h_prev, &sv_fi->aa_common->h_succ);
+
+    TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  }
+
+  /* Bug #2429 */
+  orig = read_msg("GET a-life HTTP/1.1" CRLF
+		 "Foo: bar" CRLF
+		 "Content-Length: 6" CRLF
+		 CRLF
+		 "test" CRLF 
+		 "extra stuff" CRLF);
+  TEST_1(orig);
+  otst = msg_test_public(orig);
+  TEST_1(otst);
+
+  msg = msg_copy(orig);
+  tst = msg_test_public(msg);
+  TEST_1(tst);
+
+  home = msg_home(msg);
+
+  TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.1"));
+
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)request), 0);
+
+  TEST_1(location = 
+	 msg_content_location_make(home, "http://localhost:8080/wife"));
+
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)location), 0);
+
+  TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  TEST_1(msg_prepare(msg) > 0);
+
+  TEST_1(language = 
+	 msg_content_language_make(home, "se-FI, fi-FI, sv-FI"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)language), 0);
+
+  TEST_1(se = msg_accept_language_make(home, "se, fi, sv"));
+  TEST_1(se->aa_next);  TEST_1(se->aa_next->aa_next);
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)se), 0);
+  
+  TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  TEST_1(msg_prepare(msg) > 0);
+
+  {
+    char const encoded[] =
+      "GET a-wife HTTP/1.1\r\n";
+
+    TEST_SIZE(request->rq_common->h_len, strlen(encoded));
+    TEST_M(request->rq_common->h_data, encoded, request->rq_common->h_len);
+  }
+
+  {
+    char const encoded[] =
+      "Content-Location: http://localhost:8080/wife\r\n";
+
+    TEST_SIZE(location->g_common->h_len, strlen(encoded));
+    TEST_M(location->g_common->h_data, encoded, location->g_common->h_len);
+  }
+
+  {
+    char const encoded[] =
+      "Content-Language: se-FI, fi-FI, sv-FI\r\n";
+    TEST_SIZE(language->k_common->h_len, strlen(encoded));
+    TEST_M(language->k_common->h_data, encoded, language->k_common->h_len);
+  }
+
+  {
+    char const encoded[] = "Accept-Language: se, fi, sv\r\n";
+    TEST_SIZE(se->aa_common->h_len, strlen(encoded));
+    TEST_M(se->aa_common->h_data, encoded, se->aa_common->h_len);
+    TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len, 
+	   se->aa_next->aa_common->h_data);
+    TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len, 
+	   se->aa_next->aa_next->aa_common->h_data);
+  }
+
+  {
+    size_t size = SIZE_MAX;
+    char *s = msg_as_string(msg_home(msg), msg, NULL, 0, &size);
+    TEST_S(s, 
+"GET a-wife HTTP/1.1" CRLF
+"Foo: bar" CRLF
+"Content-Length: 6" CRLF
+"Content-Location: http://localhost:8080/wife\r\n"
+"Content-Language: se-FI, fi-FI, sv-FI\r\n"
+"Accept-Language: se, fi, sv\r\n"
+CRLF
+"test" CRLF);
+  }
+
+  msg_destroy(msg);
+
+  END();
+}
+
+static int test_warning(void)
+{
+  msg_warning_t *w;
+  su_home_t *home;
+  char buf[64];
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  TEST_1((w = msg_warning_make(home, 
+			       "399 host:5060 \"Ok\", "
+			       "399 [::1]:39999 \"foo\\\" bar\"")));
+  TEST(w->w_code, 399);
+  TEST_S(w->w_host, "host");
+  TEST_S(w->w_port, "5060");
+  TEST_S(w->w_text, "Ok");
+  TEST_1(w = w->w_next);
+
+  TEST(w->w_code, 399);
+  TEST_S(w->w_host, "[::1]");
+  TEST_S(w->w_port, "39999");
+  TEST_S(w->w_text, "foo\" bar");
+  TEST_1(w->w_next == NULL);
+
+  TEST_1(msg_warning_e(buf, sizeof buf, (msg_header_t *)w, 0) > 0);
+
+  TEST_S(buf, "399 [::1]:39999 \"foo\\\" bar\"");
+
+  su_home_unref(home);
+
+  END();
+}
+
+
+/* Test error handling */
+int test_msg_error(void)
+{
+  msg_t *msg;
+  su_home_t *home;
+  msg_test_t *tst;
+
+  BEGIN();
+
+  msg = read_msg("GET a-life HTTP/1.1" CRLF
+		 "Content-Length: 6" CRLF
+		 "Content-Language: fi" CRLF
+		 "Content-Language: <se>" CRLF
+		 "Accept-Language: en;q=0.8, fi, \"\", se ; q = 0.6" CRLF
+		 "Foo bar baf: bar" CRLF
+		 CRLF
+		 "test" CRLF);
+
+  home = msg_home(msg);
+  tst = msg_test_public(msg);
+
+  TEST_1(msg);
+  TEST_1(home);
+  TEST_1(tst);
+
+  TEST_1(tst->msg_error);
+
+  msg_destroy(msg);
+
+  END();
+}
+
+int test_mclass(void)
+{
+  msg_t *msg;
+  su_home_t *home;
+  msg_test_t *tst;
+  msg_request_t *request;
+  msg_status_t *status;
+  msg_separator_t *separator;
+  msg_payload_t *payload;
+  msg_content_length_t *l;
+  msg_content_language_t *la;
+  msg_content_encoding_t *k0, *k;
+  msg_unknown_t *foo;
+
+  BEGIN();
+
+  /* Test that critical errors are signaled */
+  msg = read_msg("GET a-life HTTP/1.1" CRLF
+		 "Content-Length: 6bytes" CRLF
+		 "Content-Type: *" CRLF
+		 "Foo: bar" CRLF
+		 "Content-Encoding: identity" CRLF
+		 "Content-Language: en" CRLF
+		 "Content-Language: en-us" CRLF
+		 CRLF
+		 "test" CRLF);
+
+  tst = msg_test_public(msg);
+  TEST_1(msg);
+  TEST_1(tst);
+  TEST_1(MSG_HAS_ERROR(tst->msg_flags)); /* Content-Length is critical */
+  msg_destroy(msg);
+
+  msg = read_msg("GET a-life HTTP/1.1" CRLF
+		 "Content-Length: 6" CRLF
+		 "Content-Type: *" CRLF
+		 "Foo: bar" CRLF
+		 "Content-Encoding: " CRLF /* XXX */
+		 "Content-Language: en" CRLF
+		 "Content-Language: en-us" CRLF
+		 CRLF
+		 "test" CRLF);
+
+  home = msg_home(msg);
+  tst = msg_test_public(msg);
+
+  TEST_1(msg);
+  TEST_1(home);
+  TEST_1(tst);
+
+  TEST_SIZE(msg_iovec(msg, NULL, 0), 1);
+
+  TEST_1(tst->msg_unknown);	/* Foo */
+  TEST_1(tst->msg_content_type == NULL);
+  TEST_1(tst->msg_error);	/* Content-Type */
+  TEST_1(tst->msg_error->er_next == NULL);
+
+  TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Content-type is not critical */
+
+  TEST_1(la = tst->msg_content_language);
+  TEST_1(la->k_common->h_data);
+  TEST_1(la->k_items);
+  TEST_S(la->k_items[0], "en");
+  TEST_S(la->k_items[1], "en-us");
+  TEST_P(la->k_items[2], NULL);
+  TEST_1(la->k_next);
+  TEST_1(la->k_next->k_common->h_data);
+  TEST_1(la->k_next->k_items == NULL);
+
+  TEST(msg_header_add_make(msg, (msg_pub_t *)tst, 
+			   msg_content_language_class, 
+			   "en-gb"), 0);
+  TEST_P(la, tst->msg_content_language);
+  TEST_P(la->k_common->h_data, NULL);
+  TEST_S(la->k_items[2], "en-gb");
+  TEST_P(la->k_next, NULL);
+
+  TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0);
+  TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL);
+
+  TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0);
+  TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL);
+
+  TEST_1(separator = msg_separator_make(home, "\r\n"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0);
+  TEST_P(tst->msg_separator, separator); 
+  TEST_P(separator->sep_common->h_succ, tst->msg_payload);
+
+  /* Try to add a new payload */
+  TEST_1(payload = msg_payload_make(home, "foofaa\r\n"));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0);
+  /* The new payload should be appended */
+  TEST_P(tst->msg_payload->pl_next, payload); 
+  TEST_P(tst->msg_payload->pl_common->h_succ, payload);
+
+  /* Try to add a new header */
+  TEST_1(l = msg_content_length_create(home, 
+				       tst->msg_payload->pl_len + 
+				       payload->pl_len));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)l), 0);
+  /* The new header should be last before separator */
+  TEST_P(l->l_common->h_succ, separator);
+
+  TEST_1(foo = tst->msg_unknown);
+  TEST_S(foo->un_name, "Foo");
+  TEST_S(foo->un_value, "bar");
+  foo->un_value = "baz";
+  TEST_1(foo = msg_unknown_dup(home, foo));
+  TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)foo), 0);
+  TEST_P(tst->msg_unknown->un_next, foo);
+
+  TEST_1(k = msg_content_encoding_make(home, "gzip, compress"));
+  k0 = tst->msg_content_encoding;
+  TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0);
+  TEST_P(k0, tst->msg_content_encoding);
+  TEST_1(k0->k_items);
+  TEST_S(k0->k_items[0], "gzip");
+  TEST_S(k0->k_items[1], "compress");
+  TEST_P(k0->k_items[2], NULL);
+
+  TEST_1(k = msg_content_encoding_make(home, "gzip, deflate, compress"));
+  TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0);
+  TEST_P(k0, tst->msg_content_encoding);
+  TEST_1(k0->k_items);
+  TEST_S(k0->k_items[0], "gzip");
+  TEST_S(k0->k_items[1], "compress");
+  TEST_S(k0->k_items[2], "deflate");
+  TEST_P(k0->k_items[3], NULL);
+
+  msg_destroy(msg);
+
+  END();
+}
+
+int test_copy(void)
+{
+  msg_t *msg0, *msg, *msg1, *msg2;
+  su_home_t *home;
+  msg_test_t *tst0, *tst, *copy, *dup;
+  msg_request_t *request;
+  msg_common_t *h, *h_succ;
+  msg_iovec_t iovec[8];
+
+  char const s[] = 
+    "GET /a-life HTTP/1.1" CRLF
+    "Content-Length: 6" CRLF
+    "Content-Type: *" CRLF
+    "Foo: bar" CRLF
+    "Content-Language: " CRLF
+    CRLF
+    "test" CRLF;
+
+  BEGIN();
+
+  msg0 = read_msg(s);
+
+  TEST_1(msg0);
+  TEST_1(tst0 = msg_test_public(msg0));
+
+  TEST_SIZE(msg_iovec(msg0, iovec, 8), 1);
+
+  TEST_1(msg = msg_copy(msg0));
+  TEST_1(copy = msg_test_public(msg));
+  TEST_1(copy->msg_request);
+  TEST_1(tst0->msg_request);
+  TEST_S(copy->msg_request->rq_url->url_path, 
+	 tst0->msg_request->rq_url->url_path);
+  TEST_S(copy->msg_request->rq_url->url_path, "a-life");
+  TEST_P(copy->msg_request->rq_url->url_path, 
+	 tst0->msg_request->rq_url->url_path);
+
+  msg_destroy(msg);
+
+  TEST_1(msg = msg_dup(msg0));
+  TEST_1(dup = msg_test_public(msg));
+  TEST_1(dup->msg_request);
+  TEST_1(tst0->msg_request);
+  TEST_S(dup->msg_request->rq_url->url_path, 
+	 tst0->msg_request->rq_url->url_path);
+  TEST_S(dup->msg_request->rq_url->url_path, "a-life");
+  TEST_1(dup->msg_request->rq_url->url_path != 
+	 tst0->msg_request->rq_url->url_path);
+
+  msg_destroy(msg);
+
+  TEST_1(msg = msg_copy(msg0)); msg_destroy(msg0);
+
+  TEST_1(home = msg_home(msg));
+  TEST_1(tst = msg_test_public(msg));
+
+  TEST_1(tst->msg_unknown);	/* Foo */
+  TEST_1(tst->msg_content_type == NULL);
+  TEST_1(tst->msg_error); /* Content-Type */
+
+  TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Flags are not copied */
+
+  TEST_1(tst0->msg_request);
+  TEST_1(request = tst->msg_request);
+  TEST_P(tst0->msg_request->rq_url->url_path, request->rq_url->url_path);
+
+  TEST_SIZE(msg_iovec(msg, iovec, 8), 1);
+
+  TEST_S(iovec->siv_base, s);
+
+  TEST_1(msg1 = msg_dup(msg));
+  TEST_1(tst = msg_test_public(msg1));
+  TEST_1(tst->msg_request);
+
+  for (h = tst->msg_request->rq_common; h; h = h_succ) {
+    if (h->h_prev)
+      *h->h_prev = NULL;
+    h_succ = (msg_common_t*)h->h_succ;
+    h->h_succ = NULL;
+  }
+
+  TEST_1(msg2 = msg_copy(msg1));
+  msg_destroy(msg2);
+
+  TEST_1(msg2 = msg_dup(msg1));
+  msg_destroy(msg2);
+
+  msg_destroy(msg1);
+  msg_destroy(msg);
+
+  END();
+}
+
+int test_mime(void)
+{
+  msg_t *msg;
+  su_home_t *home;
+  int n;
+  msg_test_t *tst;
+  msg_header_t *h, *h_succ, *head;
+  void *removed;
+  msg_accept_t *ac, *ac0;
+  msg_accept_charset_t *aa;
+  msg_multipart_t *mp, *mp0, *mpX, *mpnew;
+  msg_payload_t *pl;
+  msg_content_type_t *c;
+  msg_content_id_t *cid;
+  msg_content_transfer_encoding_t *cte;
+
+  char const s[] = 
+    "GET /a-life HTTP/1.1" CRLF
+    "Accept: text/html;level=4;q=1" CRLF
+    "Accept: text / plain;q=0.9" CRLF
+    "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF
+    "Accept-Encoding: gzip;q=0.9, deflate" CRLF
+    "Accept-Encoding: , identity ," CRLF
+    "Accept: */*;q=0.2" CRLF
+    "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF
+    "Content-Language: fi, se" CRLF
+    "Content-Language: en, de" CRLF
+    "Content-Disposition: render; required" CRLF
+    "Content-Encoding: gzip, deflate" CRLF
+    "Content-Base: http://localhost/foo" CRLF
+    "MIME-Version: 1.0" CRLF
+    "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF
+    /* "Content-Length: 305" CRLF */
+    "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF
+    CRLF
+    "test" CRLF			
+    CRLF			/* 1 */
+    "--LaGqGt4BI6Ho" "  " CRLF	
+    CRLF			/* 2 */
+    "part 1" CRLF		/* 3 */
+    CRLF			/* 4 */
+    "--LaGqGt4BI6Ho" CRLF	
+    "Content-Type: text/plain ; charset = iso-8859-1" CRLF /* 5 */
+    "Content-ID: <m7ZvEEm49xdTT0WCDUgnww at localhost>" CRLF /* 6 */
+    "Content-Transfer-Encoding: quoted-unreadable" CRLF	/* 7 */
+    CRLF			/* 8 */
+    "part 2"			/* 9 */
+    CRLF "--LaGqGt4BI6Ho"	/* 10 */
+    "Content-Type: text/html" CRLF /* 11 */
+    "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ at localhost>" CRLF /* 12 */
+    CRLF			/* 13 */
+#define BODY3 "<html><body>part 3</body></html>" CRLF 
+    BODY3			/* 14 */
+    CRLF			/* 15 */
+    "--LaGqGt4BI6Ho--" CRLF;	
+
+  BEGIN();
+
+  msg = read_msg(s);
+  home = msg_home(msg);
+  tst = msg_test_public(msg);
+
+  TEST_1(msg);
+  TEST_1(home);
+  TEST_1(tst);
+
+  TEST_1(tst->msg_error == NULL);
+  TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0);
+
+  TEST_1(ac = tst->msg_accept);
+  TEST_1(ac = ac->ac_next);
+  TEST_S(ac->ac_type, "text/plain");
+  TEST_S(ac->ac_q, "0.9");
+  TEST_1(ac = msg_accept_dup(home, ac));
+  TEST_S(ac->ac_type, "text/plain");
+  TEST_S(ac->ac_q, "0.9");
+  TEST_S(tst->msg_accept->ac_next->ac_q, "0.9");
+  TEST_1(ac->ac_q != tst->msg_accept->ac_next->ac_q);
+
+  TEST_1(ac = msg_accept_make(home, "text / plain"));
+  ac->ac_q = "1.0";
+  TEST_1(ac = msg_accept_dup(home, ac0 = ac));
+  TEST_1(ac->ac_q != ac0->ac_q);
+
+  for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) {
+    TEST_1(h->sh_data);
+    if (h->sh_succ)
+      TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data);
+  }
+
+  TEST_1(aa = tst->msg_accept_charset);
+  TEST_S(aa->aa_value, "*");   TEST_S(aa->aa_q, "0.1");
+
+  mp = msg_multipart_parse(home, tst->msg_content_type, tst->msg_payload);
+
+  TEST_1(mp0 = mp);
+
+  TEST_1(mp->mp_data);
+  TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len), 0);
+  TEST_1(mp->mp_common->h_data);
+  TEST_M(mp->mp_common->h_data, CRLF "--" "LaGqGt4BI6Ho" "  " CRLF, 
+	 mp->mp_common->h_len);
+
+  TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+  TEST_SIZE(strlen("part 1" CRLF), pl->pl_len);
+  TEST(memcmp(pl->pl_data, "part 1" CRLF, pl->pl_len), 0);
+
+  TEST_1(mp = mp->mp_next);
+
+  TEST_1(mp->mp_data);
+  TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CR LF, mp->mp_len), 0);
+
+  TEST_1(c = mp->mp_content_type);
+  TEST_S(c->c_type, "text/plain"); TEST_S(c->c_subtype, "plain");
+  TEST_1(c->c_params);   TEST_1(c->c_params[0]); 
+  TEST_S(c->c_params[0], "charset=iso-8859-1");
+
+  TEST_1(cid = mp->mp_content_id);
+
+  TEST_1(cte = mp->mp_content_transfer_encoding);
+  TEST_S(cte->g_string, "quoted-unreadable");
+
+  TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+  TEST_SIZE(strlen("part 2"), pl->pl_len);
+  TEST(memcmp(pl->pl_data, "part 2", pl->pl_len), 0);
+  
+  TEST_1(mp = mp->mp_next);
+
+  TEST_1(mp->mp_data);
+  TEST_M(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len);
+
+  TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+  TEST_SIZE(strlen(BODY3), pl->pl_len);
+  TEST(memcmp(pl->pl_data, BODY3, pl->pl_len), 0);
+
+  mpX = mp;
+
+  TEST_1(!(mp = mp->mp_next));
+
+  /* Test serialization */
+  head = NULL;
+  TEST_1(h = msg_multipart_serialize(&head, mp0));
+  TEST_P((void *)h, mpX->mp_close_delim);
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  /* Remove chain */
+  for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+    h_succ = h->sh_succ;
+    if (h->sh_prev) *h->sh_prev = NULL;
+    h->sh_prev = NULL;
+    h->sh_succ = NULL;
+  }
+
+  TEST(n, 15);
+
+  head = NULL; 
+  TEST_1(h = msg_multipart_serialize(&head, mp0));
+  TEST_P(h, mpX->mp_close_delim);
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+    h_succ = h->sh_succ;
+  }
+
+  TEST(n, 15);
+
+  /* Add a new part to multipart */   
+  mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew); 
+  removed = mpX->mp_close_delim;
+  mpX->mp_next = mpnew; mpX = mpnew;
+  mpnew->mp_content_type = msg_content_type_make(home, "multipart/mixed");
+  TEST_1(mpnew->mp_content_type);
+  TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0);
+
+  head = NULL; 
+  TEST_1(h = msg_multipart_serialize(&head, mp0));
+  TEST_P((void *)h, mpX->mp_close_delim);
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+    h_succ = h->sh_succ;
+    TEST_1(h != removed);
+  }
+
+  TEST(n, 19);
+
+#define remove(h) \
+  (((*((msg_header_t*)(h))->sh_prev = ((msg_header_t*)(h))->sh_succ) ? \
+   (((msg_header_t*)(h))->sh_succ->sh_prev = ((msg_header_t*)(h))->sh_prev) \
+   : NULL), \
+   ((msg_header_t*)(h))->sh_succ = NULL, \
+   ((msg_header_t*)(h))->sh_prev = NULL)
+
+  remove(mp0->mp_separator);
+  remove(mp0->mp_next->mp_payload);
+  remove(mp0->mp_next->mp_next->mp_content_type);
+  remove(mp0->mp_next->mp_next->mp_next->mp_close_delim);
+
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  head = NULL;
+  TEST_1(h = msg_multipart_serialize(&head, mp0));
+  TEST_P(h, mpX->mp_close_delim);
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+    h_succ = h->sh_succ;
+    if (h_succ == NULL)
+      TEST_P(h, mpX->mp_close_delim);
+    TEST_1(h != removed);
+  }
+
+  TEST(n, 19);
+
+  /* Add an recursive multipart */
+  mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew); 
+  mpX->mp_multipart = mpnew;
+  mpnew->mp_content_type = msg_content_type_make(home, "text/plain");
+  TEST_1(mpnew->mp_content_type);
+  TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0);
+  TEST_1(mpnew->mp_close_delim);
+
+  head = NULL; 
+  TEST_1(h = msg_multipart_serialize(&head, mp0));
+  TEST_P(h, mpX->mp_close_delim);
+
+  TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+  for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++)
+    h_succ = h->sh_succ;
+
+  TEST(n, 24);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+/** Test MIME encoding */
+int test_mime2(void)
+{
+  msg_t *msg;
+  su_home_t *home;
+  int n, m, len;
+  msg_test_t *tst;
+  msg_header_t *h;
+  msg_accept_charset_t *aa;
+  msg_multipart_t *mp;
+  msg_content_type_t *c;
+  msg_payload_t *pl;
+  char const *end;
+
+  char const s[] = 
+    "GET /a-life HTTP/1.1" CRLF
+    "Accept: text/html;level=4;q=1" CRLF
+    "Accept: text / plain;q=0.9" CRLF
+    "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF
+    "Accept-Encoding: gzip;q=0.9, deflate" CRLF
+    "Accept-Encoding: , identity ," CRLF
+    "Accept: */*;q=0.2" CRLF
+    "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF
+    "Content-Language: fi, se" CRLF
+    "Content-Language: en, de" CRLF
+    "Content-Disposition: render; required" CRLF
+    "Content-Encoding: gzip, deflate" CRLF
+    "Content-Base: http://localhost/foo" CRLF
+    "MIME-Version: 1.0" CRLF
+    "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF
+    "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF
+    CRLF
+    "test" CRLF			
+    CRLF			/* 1 */
+    "--LaGqGt4BI6Ho" "  " CRLF	
+    CRLF			/* 2 */
+    "part 1" CRLF		/* 3 */
+    CRLF			/* 4 */
+    "--LaGqGt4BI6Ho" CRLF	
+    "Content-Type: text/plain;charset=iso-8859-1" CRLF /* 5 */
+    "Content-ID: <m7ZvEEm49xdTT0WCDUgnww at localhost>" CRLF /* 6 */
+    "Content-Transfer-Encoding: quoted-unreadable" CRLF	/* 7 */
+    CRLF			/* 8 */
+    "part 2"			/* 9 */
+    CRLF "--LaGqGt4BI6Ho"	/* 10 */
+    "Content-Type: text/html" CRLF /* 11 */
+    "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ at localhost>" CRLF /* 12 */
+    CRLF			/* 13 */
+#define BODY3 "<html><body>part 3</body></html>" CRLF 
+    BODY3			/* 14 */
+    CRLF			/* 15 */
+    "--LaGqGt4BI6Ho--" CRLF;	
+
+  char const part1[] = "This is text\n";
+  char const part2[] = "<html><body>This is html</body></html>";
+  char const part3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+  BEGIN();
+
+  msg = read_msg(s);
+  home = msg_home(msg);
+  tst = msg_test_public(msg);
+
+  TEST_1(msg);
+  TEST_1(home);
+  TEST_1(tst);
+
+  TEST_1(tst->msg_error == NULL);
+  TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0);
+
+  for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) {
+    TEST_1(h->sh_data);
+    if (h->sh_succ)
+      TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data);
+  }
+
+  TEST_1(aa = tst->msg_accept_charset);
+  TEST_S(aa->aa_value, "*");   TEST_S(aa->aa_q, "0.1");
+
+  TEST_1(c = tst->msg_content_type);
+  TEST_1(tst->msg_payload);
+
+  {
+    su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+    pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+  
+    mp = msg_multipart_parse(home, c, pl); TEST_1(mp);
+
+    for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) 
+      h->sh_data = NULL, h->sh_len = 0;
+    TEST(n, 15);
+    
+    n = msg_multipart_prepare(msg, mp, 0);
+    
+    TEST_1(end = strstr(s, "--LaGqGt4BI6Ho  "));
+    len = strlen(end);
+    TEST(len, n);
+    
+    TEST_1(mp = msg_multipart_dup(h0, mp));
+
+    su_home_check(h0);
+    su_home_deinit(h0);
+  }
+
+  /* Test parsing without explicit boundary */
+  {
+    su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+    pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+  
+    mp = msg_multipart_parse(h0, NULL, pl);
+    TEST_1(mp);
+
+    for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) 
+      h->sh_data = NULL, h->sh_len = 0;
+    TEST(n, 15);
+    
+    n = msg_multipart_prepare(msg, mp, 0);
+    
+    TEST_1(end = strstr(s, "--LaGqGt4BI6Ho  "));
+    len = strlen(end);
+    TEST(len, n);
+    
+    TEST_1(mp = msg_multipart_dup(h0, mp));
+
+    su_home_check(h0);
+    su_home_deinit(h0);
+  }
+
+  /* Test parsing without preamble and explicit boundary */
+  {
+    su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+    pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+  
+    n = strstr(pl->pl_data, "--LaGqGt4BI6Ho") - (char *)pl->pl_data;
+    pl->pl_data = n + (char *)pl->pl_data; pl->pl_len -= n;
+
+    len = pl->pl_len;
+
+    mp = msg_multipart_parse(h0, NULL, pl); TEST_1(mp);
+
+    for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) 
+      h->sh_data = NULL, h->sh_len = 0;
+    TEST(n, 15);
+    
+    n = msg_multipart_prepare(msg, mp, 0);
+
+    TEST(len, n);
+    
+    TEST_1(mp = msg_multipart_dup(h0, mp));
+
+    su_home_check(h0);
+    su_home_deinit(h0);
+  }
+
+  /* Test parsing without CR's */
+  {
+    su_home_t h0[1] = { SU_HOME_INIT(h0) };
+    char *b;
+
+    pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+  
+    /* Remove CRs */
+    b = pl->pl_data, len = pl->pl_len;
+    for (n = m = 0; n < len; n++) {
+      if ((b[m] = b[n]) != '\r')
+	m++;
+    }
+    pl->pl_len = m;
+    
+    mp = msg_multipart_parse(h0, NULL, pl);
+    TEST_1(mp);
+    
+    for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) 
+      h->sh_data = NULL, h->sh_len = 0;
+    TEST(n, 15);
+    
+    n = msg_multipart_prepare(msg, mp, 0);
+    TEST_1(n > 0);
+
+    TEST_1(mp = msg_multipart_dup(h0, mp));
+
+    su_home_check(h0);
+    su_home_deinit(h0);
+  }
+
+  /* Create a new multipart from three parts */
+  TEST_1(c = msg_content_type_make(home, "multipart/related"));
+
+  TEST_1(mp = msg_multipart_create(home, "text/plain", part1, strlen(part1)));
+  TEST_1(mp->mp_next = 
+	 msg_multipart_create(home, "text/html", part2, strlen(part2)));
+  TEST_1(mp->mp_next->mp_next = 
+	 msg_multipart_create(home, "application/octet-stream", 
+			      part3, sizeof part3));
+
+  TEST(msg_multipart_complete(home, c, mp), 0);
+
+  h = NULL;
+  TEST_P(msg_multipart_serialize(&h, mp), mp->mp_next->mp_next->mp_close_delim);
+
+  TEST_1(msg_multipart_prepare(msg, mp, 0));
+
+  TEST_1(mp = msg_multipart_dup(home, mp));
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+
+/* Test serialization */
+int test_serialize(void)
+{
+  msg_t *msg;
+  su_home_t *home;
+  msg_test_t *tst;
+  msg_mime_version_t *mime;
+  msg_separator_t *sep;
+  msg_payload_t *pl;
+  msg_accept_encoding_t *aen;
+  msg_accept_language_t *ala;
+
+  char const s[] = 
+    "GET /a-life HTTP/1.1" CRLF
+    "Accept-Language: fi" CRLF
+    "Accept-Encoding: z0" CRLF
+    "Accept-Language: se, de" CRLF
+    "Accept-Encoding: z1, z2" CRLF
+    "Accept-Language: en, sv" CRLF
+    "Accept-Encoding: z3, z4" CRLF
+    "Content-Length: 6" CRLF
+    CRLF
+    "test" CRLF;
+
+  BEGIN();
+
+  msg = read_msg(s);
+
+  TEST_1(msg); home = msg_home(msg);
+  TEST_1(tst = msg_test_public(msg));
+  TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+
+  TEST_1(ala = tst->msg_accept_language->aa_next->aa_next);
+  TEST(msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)ala), 0);
+  TEST_S(ala->aa_value, "de");
+
+  TEST_1(ala = tst->msg_accept_language); 
+  TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "se");
+  /* Make sure that cached encoding of se is reset */
+  TEST_1(ala->aa_common->h_data == NULL);
+  TEST_1(ala->aa_common->h_len == 0);
+  TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "en");
+  /* Make sure that cached encoding of en is kept intact */
+  TEST_1(ala->aa_common->h_data != NULL);
+  TEST_1(ala->aa_common->h_len != 0);
+
+  TEST_1(aen = tst->msg_accept_encoding->aa_next->aa_next);
+  TEST(msg_header_remove_all(msg, (msg_pub_t *)tst, (msg_header_t *)aen), 0);
+
+  TEST_1(aen = tst->msg_accept_encoding); 
+  TEST_1(aen = aen->aa_next); TEST_S(aen->aa_value, "z1");
+  /* Make sure that cached encoding of z1 is reset */
+  TEST_1(aen->aa_common->h_data == NULL);
+  TEST_1(aen->aa_common->h_len == 0);
+  TEST_1(aen->aa_next == NULL); 
+
+  TEST_1(aen->aa_common->h_succ == (void *)ala);
+  TEST_1(ala->aa_next->aa_common);
+  TEST_1(ala->aa_next->aa_common->h_succ == (void *)tst->msg_content_length);
+
+  TEST_1(mime = msg_mime_version_make(home, "1.0"));
+  tst->msg_mime_version = mime;
+
+  TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+  TEST_P(tst->msg_content_length->l_common->h_succ, mime);
+  TEST_P(mime->g_common->h_succ, tst->msg_separator);
+
+  msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_separator);
+  TEST_1(sep = msg_separator_make(home, CRLF));
+  tst->msg_separator = sep;
+  TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+  TEST_P(mime->g_common->h_succ, sep);
+  TEST_P(sep->sep_common->h_succ, tst->msg_payload);
+
+  msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_payload);
+  TEST_1(pl = msg_payload_make(home, "foobar" CRLF));
+  pl->pl_next = tst->msg_payload;
+  tst->msg_payload = pl;
+  TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+  TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+  TEST_P(mime->g_common->h_succ, sep);
+  TEST_P(sep->sep_common->h_succ, pl);
+  TEST_P(pl->pl_common->h_succ, pl->pl_next);
+
+  msg_destroy(msg);
+
+  END();
+}
+
+static int random_test(void)
+{
+  struct { uint64_t low, mid, hi; } seed = { 0, 0, 0 };
+  uint8_t zeros[24] = { 0 };
+  uint8_t ones[24];
+
+  char token[33];
+
+  BEGIN();
+
+  memset(ones, 255, sizeof ones);
+
+  TEST_SIZE(msg_random_token(token, 32, (void *)&seed, sizeof(seed)), 32);
+  TEST_S(token, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+  TEST_SIZE(msg_random_token(token, 32, zeros, 4), 7);
+  TEST_S(token, "aaaaaaa");
+  TEST_SIZE(msg_random_token(token, 32, ones, 4), 7);
+  /* Last char may vary.. */
+  token[6] = 0;  TEST_S(token, "999999");
+  TEST_SIZE(msg_random_token(token, 32, zeros, 8), 13);
+  TEST_S(token, "aaaaaaaaaaaaa");
+  TEST_SIZE(msg_random_token(token, 32, zeros, 12), 20);
+  TEST_S(token, "aaaaaaaaaaaaaaaaaaaa");
+  
+  END();
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      test_flags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= msg_time_test(); fflush(stdout);
+  retval |= addr_test(); fflush(stdout);
+  retval |= hash_test(); fflush(stdout);
+  retval |= random_test(); fflush(stdout);
+  retval |= test_header_parsing(); fflush(stdout);
+  retval |= test_msg_parsing(); fflush(stdout);
+  retval |= test_warning(); fflush(stdout);
+  retval |= test_msg_error(); fflush(stdout);
+  retval |= test_mclass(); fflush(stdout);
+  retval |= test_copy(); fflush(stdout);
+  retval |= test_mime(); fflush(stdout);
+  retval |= test_mime2(); fflush(stdout);
+  retval |= test_serialize(); fflush(stdout);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,359 @@
+/**-*- c -*- 
+ * @ingroup msg
+ * @internal @file test_protos.h.in
+ *
+ * Template for "test_protos.h".
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_PROTOS_H
+/** Defined when <test_protos.h> has been included. */
+#define TEST_PROTOS_H 
+
+/**@ingroup test_msg
+ * @file test_protos.h
+ *
+ * Prototypes and macros for dummy testing protocol headers.
+ * 
+ * #AUTO#
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include <sofia-sip/su_config.h>
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+#ifndef MSG_MIME_PROTOS_H
+#include <sofia-sip/msg_mime_protos.h>
+#endif
+
+#ifndef TEST_CLASS_H
+#include <test_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Test if tag type marks a msg_test_t structure. @HIDE */
+#define TSTTAG_P(tt)     ((tt)->tt_class == tsthdrtag_class)
+/** Test if tag type marks a TST header string. @HIDE */
+#define TSTTAG_STR_P(tt) ((tt)->tt_class == tststrtag_class)
+/** Test if tag type marks a TST header structure. @HIDE */
+#define TSTTAG_TST_P(tt) ((tt)->tt_class == tstmsgtag_class)
+
+/** Test if tag item contains msg_test_t structure. @HIDE */
+#define TSTTAGI_P(t)     (TSTTAG_P((t)->t_tag))
+/** Test if tag item contains a TST header string. @HIDE */
+#define TSTTAGI_STR_P(t) (TSTTAG_STR_P((t)->t_tag))
+/** Test if tag item contains a TST header structure. @HIDE */
+#define TSTTAGI_TST_P(t) (TSTTAG_TST_P((t)->t_tag))
+
+/** Tag class for TST headers */
+extern tag_class_t tsthdrtag_class[1];
+/** Tag class for string values of TST headers */
+extern tag_class_t tststrtag_class[1];
+/** Tag class for TST message */
+extern tag_class_t tstmsgtag_class[1];
+
+/**Tag list item for header string.
+ *
+ * The TSTTAG_HEADER_STR() macro is used to include a tag item containing a
+ * header string in the tag list, e.g., 
+ * @code 
+ * TSTTAG_HEADER_STR("Priority: urgent").
+ * @endcode
+ *
+ * @param x pointer to a string, or NULL.
+ *
+ * @HIDE
+ */
+#define TSTTAG_HEADER(x)       tsttag_header, tsttag_header_v((x))
+
+/** Tag for header string */
+extern tag_typedef_t tsttag_header;
+
+#define TSTTAG_HEADER_REF(x)   tsttag_header_ref, tsttag_header_vr(&(x))
+extern tag_typedef_t tsttag_header_ref;
+
+#if HAVE_INLINE
+static inline tag_value_t
+tsttag_header_v(msg_header_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+tsttag_header_vr(msg_header_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define tsttag_header_v(v)   (tag_value_t)(v)
+#define tsttag_header_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * The TSTTAG_HEADER_STR() macro is used to include a tag item containing a
+ * header string in the tag list.
+ *
+ * @param x pointer to a string, or NULL.
+ *
+ * @HIDE
+ */
+#define TSTTAG_HEADER_STR(x)       tsttag_header_str, tag_str_v((x))
+
+/** Tag for header string */
+extern tag_typedef_t tsttag_header_str;
+
+#define TSTTAG_HEADER_STR_REF(x)   tsttag_header_str_ref, tag_str_vr(&(x))
+extern tag_typedef_t tsttag_header_str_ref;
+
+#if HAVE_INLINE
+static inline
+tag_value_t tsttag_tst_v(msg_test_t const *v) { return (tag_value_t)v; }
+static inline 
+tag_value_t tsttag_tst_vr(msg_test_t const **vp) { return (tag_value_t)vp; }
+#else
+#define tsttag_tst_v(v)   (tag_value_t)(v)
+#define tsttag_tst_vr(vp) (tag_value_t)(vp)
+#endif
+
+
+
+/**@addtogroup test_msg_#xxxxxx#*//**@{*/
+
+/** Parse a #xxxxxxx_xxxxxxx#. @internal */
+msg_parse_f msg_#xxxxxx#_d;
+
+/** Print a #xxxxxxx_xxxxxxx#. @internal */
+msg_print_f msg_#xxxxxx#_e;
+
+
+/**Header class for #xxxxxxx_xxxxxxx#.
+ * 
+ * The header class msg_#xxxxxx#_class defines how a 
+ * #xxxxxxx_xxxxxxx# is parsed and printed.  It also
+ * contains methods used by message parser and other functions
+ * to manipulate the msg_#xxxxxx#_t header structure.
+ */
+extern msg_hclass_t msg_#xxxxxx#_class[];
+
+/**Initializer for structure msg_#xxxxxx#_t.
+ * 
+ * A static msg_#xxxxxx#_t structure must be initialized
+ * with the MSG_#XXXXXX#_INIT() macro. For instance,
+ * @code 
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
+ * 
+ * @endcode
+ * @HI
+ */
+#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure msg_#xxxxxx#_t.
+ * 
+ * An msg_#xxxxxx#_t structure can be initialized with the
+ * msg_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ * 
+ *  msg_#xxxxxx#_t msg_#xxxxxx#;
+ * 
+ *  msg_#xxxxxx#_init(&msg_#xxxxxx#);
+ * 
+ * @endcode
+ * @HI
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
+{
+  return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
+}
+#else
+#define msg_#xxxxxx#_init(x) \
+  MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of msg_#xxxxxx#_t.
+ * 
+ * The function msg_is_#xxxxxx#() returns true (nonzero) if
+ * the header class is an instance of #xxxxxxx_xxxxxxx#
+ * object and false (zero) otherwise.
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @return
+ * The function msg_is_x#xxxxxx#() returns true (nonzero) if
+ * the header object is an instance of header #xxxxxx# and
+ * false (zero) otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
+{
+  return header && header->sh_class->hc_hash == msg_#xxxxxx#_hash;
+}
+#else
+int msg_is_#xxxxxx#(msg_header_t const *header);
+#endif
+
+#define msg_#xxxxxx#_p(h) msg_is_#xxxxxx#((h))
+
+/**Duplicate (deep copy) @c msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_dup() duplicates a header
+ * structure @a hdr.  If the header structure @a hdr
+ * contains a reference (@c hdr->x_next) to a list of
+ * headers, all the headers in the list are duplicated, too.
+ * 
+ * @param home  memory home used to allocate new structure
+ * @param hdr   header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant
+ * strings attached to the header are copied, too.  The
+ * function uses given memory @a home to allocate all the
+ * memory areas used to copy the header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_dup(home, tst->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_dup() returns a pointer to the
+ * newly duplicated msg_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ */
+msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, msg_#xxxxxx#_t const *hdr);
+
+/**Copy a msg_#xxxxxx#_t header structure.
+ * 
+ * The function msg_#xxxxxx#_copy() copies a header structure @a
+ * hdr.  If the header structure @a hdr contains a reference (@c
+ * hdr->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home
+ * to allocate all the memory areas used to copy the header
+ * structure @a hdr.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param hdr     pointer to the header structure to be duplicated
+ * 
+ * When copying, only the header structure and parameter lists
+ * attached to it are duplicated.  The new header structure
+ * retains all the references to the strings within the old @a
+ * header, including the encoding of the old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = msg_#xxxxxx#_copy(home, tst->msg_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function msg_#xxxxxx#_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home, 
+				  msg_#xxxxxx#_t const *hdr);
+
+/**Make a header structure msg_#xxxxxx#_t.
+ * 
+ * The function msg_#xxxxxx#_make() makes a new
+ * msg_#xxxxxx#_t header structure.  It allocates a new
+ * header structure, and decodes the string @a s as the
+ * value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_make().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_make() returns a pointer to
+ * newly maked msg_#xxxxxx#_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+  return (msg_#xxxxxx#_t *)msg_header_make(home, msg_#xxxxxx#_class, s);
+}
+#else
+msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s);
+#endif
+
+/**Make a #xxxxxxx_xxxxxxx# from formatting result.
+ * 
+ * The function msg_#xxxxxx#_format() makes a new
+ * #xxxxxxx_xxxxxxx# object using formatting result as its
+ * value.  The function first prints the arguments according to
+ * the format @a fmt specified.  Then it allocates a new header
+ * structure, and uses the formatting result as the header
+ * value.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_format().
+ * 
+ * @return
+ * The function msg_#xxxxxx#_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((__format__ (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+  msg_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
+  va_end(ap);
+ 
+  return (msg_#xxxxxx#_t *)h;
+}
+#endif
+
+/** @} */
+
+
+
+SOFIA_END_DECLS
+
+#endif /* !defined(TEST_PROTOS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+/**@ingroup test_msg
+ * @IFILE test_table.c.in
+ *
+ * Template for <test_table.c>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ * 
+ * @CFILE test_table.c 
+ * @brief Parser table used for testing.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jan 22 19:03:21 EET 2003 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <test_class.h>
+#include <test_protos.h>
+#include <sofia-sip/msg_mime_protos.h>
+
+#include <sofia-sip/msg_mclass.h>
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+PROJECT_NAME         = "nea"
+OUTPUT_DIRECTORY     = ../docs/html/nea
+
+INPUT 		     = nea.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+EXCLUDE_PATTERNS     = test*.c torture*.c
+
+TAGFILES            += \
+	"../docs/su.doxytags=../su" \
+	"../docs/ipt.doxytags=../ipt" \
+	"../docs/bnf.doxytags=../bnf" \
+	"../docs/url.doxytags=../url" \
+	"../docs/msg.doxytags=../msg" \
+	"../docs/sip.doxytags=../sip" \
+	"../docs/nta.doxytags=../nta"
+
+GENERATE_TAGFILE    = ../docs/nea.doxytags
+
+ALIASES            +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+#
+# Makefile.am for nea module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../nta -I../nta \
+		-I$(srcdir)/../sip -I../sip \
+		-I$(srcdir)/../sresolv -I../sresolv \
+		-I$(srcdir)/../tport -I../tport \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libnea.la
+
+TESTS = 
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		nea_tag_ref.c
+
+nobase_include_sofia_HEADERS =\
+			sofia-sip/nea.h sofia-sip/nea_tag.h
+
+libnea_la_SOURCES = 	nea.c nea_event.c \
+			nea_server.c nea_debug.h nea_debug.c \
+			nea_tag.c nea_tag_ref.c
+
+COVERAGE_INPUT = 	$(libnea_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libnea.la \
+			../nta/libnta.la \
+			../ipt/libipt.la \
+			../sip/libsip.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../http/libhttp.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la 
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile nea.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,700 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nea module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnea_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nea
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnea_la_LIBADD =
+am_libnea_la_OBJECTS = nea.lo nea_event.lo nea_server.lo nea_debug.lo \
+	nea_tag.lo nea_tag_ref.lo
+libnea_la_OBJECTS = $(am_libnea_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libnea_la_SOURCES)
+DIST_SOURCES = $(libnea_la_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../nta -I../nta \
+		-I$(srcdir)/../sip -I../sip \
+		-I$(srcdir)/../sresolv -I../sresolv \
+		-I$(srcdir)/../tport -I../tport \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnea.la
+TESTS = 
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nea_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nea.h sofia-sip/nea_tag.h
+
+libnea_la_SOURCES = nea.c nea_event.c \
+			nea_server.c nea_debug.h nea_debug.c \
+			nea_tag.c nea_tag_ref.c
+
+COVERAGE_INPUT = $(libnea_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnea.la \
+			../nta/libnta.la \
+			../ipt/libipt.la \
+			../sip/libsip.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../http/libhttp.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la 
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/nea/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/nea/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnea.la: $(libnea_la_OBJECTS) $(libnea_la_DEPENDENCIES) 
+	$(LINK)  $(libnea_la_LDFLAGS) $(libnea_la_OBJECTS) $(libnea_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_debug.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_event.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_tag_ref.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-generic clean-libtool clean-noinstLTLIBRARIES ctags \
+	distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,597 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea.c  Nokia Event Client API agent implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#define SU_TIMER_ARG_T       struct nea_s
+#define NTA_LEG_MAGIC_T      struct nea_s
+#define NTA_OUTGOING_MAGIC_T struct nea_s
+
+#define NEA_TIMER_DELTA 2 /* time to resubscribe without expiration */
+#define EXPIRES_DEFAULT       3600
+
+#include <sofia-sip/su_wait.h>
+
+#include "sofia-sip/nea.h"
+
+struct nea_s {
+  su_home_t         nea_home[1];
+  su_timer_t       *nea_timer;
+
+  nta_agent_t      *nea_agent;
+  nta_leg_t        *nea_leg;
+  nta_outgoing_t   *nea_oreq;		/**< Outstanding request */
+  sip_to_t         *nea_to;		/**< The other end of subscription :) */
+  nea_notify_f      nea_callback;	/**< Notify callback  */
+  nea_magic_t      *nea_context;	/**< Application context */
+   
+  sip_contact_t    *nea_contact;	/**< */
+  sip_expires_t    *nea_expires;	/**< Proposed expiration time */
+
+  nea_state_t       nea_state;	        /**< State of our subscription */
+  sip_time_t        nea_deadline;	/**< When our subscription expires */
+  tagi_t           *nea_args;
+
+  unsigned          nea_dialog : 1;     /**< Dialog has been established */
+  unsigned          nea_notify_received : 1;
+  unsigned          nea_terminating : 1;
+  unsigned          nea_strict_3265 : 1;       /**< Strict mode */
+};
+
+int details = 0;
+
+static int process_nea_request(nea_t *nea,
+			       nta_leg_t *leg,
+			       nta_incoming_t *ireq, 
+			       sip_t const *sip);
+
+static int handle_notify(nta_leg_magic_t *lmagic, 
+			 nta_leg_t *leg,
+			 nta_incoming_t *ireq, 
+			 sip_t const *sip);
+
+static int response_to_subscribe(nea_t *nea,
+				 nta_outgoing_t *req,
+				 sip_t const *sip);
+
+static int response_to_unsubscribe(nea_t *nea,
+				   nta_outgoing_t *req,
+				   sip_t const *sip);
+
+static void nea_expires_renew(su_root_magic_t *magic,
+		       su_timer_t *timer,
+		       nea_t *nea);
+
+/* ---------------------------------------------------------- */
+
+/** Create a event watcher object.
+ *
+ */
+nea_t *nea_create(nta_agent_t *agent,
+		  su_root_t *root,
+		  nea_notify_f no_callback,
+		  nea_magic_t *context,
+		  tag_type_t tag, tag_value_t value, ...)
+{
+  nea_t *nea = NULL;
+  ta_list ta;
+  int have_from, have_to, have_contact;
+  sip_expires_t const *expires = NULL;
+  char const *expires_str = NULL;
+  sip_method_t method = sip_method_subscribe;
+  char const *SUBSCRIBE = "SUBSCRIBE";
+  char const *method_name = SUBSCRIBE;
+
+  ta_start(ta, tag, value);
+
+  have_to = 
+    tl_find(ta_args(ta), siptag_to) || tl_find(ta_args(ta), siptag_to_str);
+  have_from = 
+    tl_find(ta_args(ta), siptag_from) || tl_find(ta_args(ta), siptag_from_str);
+  have_contact =
+    tl_find(ta_args(ta), siptag_contact) || 
+    tl_find(ta_args(ta), siptag_contact_str);    
+
+  if (have_to && (nea = su_home_new(sizeof(nea_t)))) {
+    su_home_t      *home = nea->nea_home;
+    sip_contact_t  *m = nta_agent_contact(agent);
+    sip_from_t     *from;
+    sip_to_t const *to;
+    int strict = 0;
+
+    nea->nea_agent = agent;
+    nea->nea_callback = no_callback;
+    nea->nea_context = context;
+
+    if (!have_from) 
+      from = sip_from_create(home, (url_string_t*)m->m_url);
+    else
+      from = NULL;
+
+    nea->nea_args = tl_tlist(home,
+			     TAG_IF(!have_contact, SIPTAG_CONTACT(m)),
+			     ta_tags(ta));
+
+    /* Get and remove Expires header from tag list */
+    tl_gets(nea->nea_args, 
+	    SIPTAG_EXPIRES_REF(expires),
+	    SIPTAG_EXPIRES_STR_REF(expires_str),
+	    SIPTAG_TO_REF(to),
+	    NEATAG_STRICT_3265_REF(strict),
+	    NTATAG_METHOD_REF(method_name),
+	    TAG_END());
+
+    nea->nea_strict_3265 = strict;
+
+    if (to)
+      nea->nea_to = sip_to_dup(home, to);
+
+    if (expires)
+      nea->nea_expires = sip_expires_dup(home, expires);
+    else if (expires_str)
+      nea->nea_expires = sip_expires_make(home, expires_str);
+    else
+      nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);
+
+    tl_tremove(nea->nea_args, 
+	       SIPTAG_EXPIRES(0), 
+	       SIPTAG_EXPIRES_STR(0),
+	       TAG_END());
+
+    if (method_name != SUBSCRIBE)
+      method = sip_method_code(method_name);
+
+    if (method != sip_method_invalid)
+      /* Create the timer object */
+      nea->nea_timer = su_timer_create(su_root_task(root), 0L);
+
+    if (nea->nea_timer) {
+      /* Create leg for NOTIFY requests */
+      nea->nea_leg = nta_leg_tcreate(nea->nea_agent, 
+				     process_nea_request, nea,
+				     TAG_IF(!have_from, SIPTAG_FROM(from)),
+				     TAG_NEXT(nea->nea_args));
+
+      if (nea->nea_leg) {
+	nta_leg_tag(nea->nea_leg, NULL);
+	nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,
+					     response_to_subscribe, nea,
+					     NULL,
+					     method, method_name,
+					     NULL,
+					     SIPTAG_EXPIRES(nea->nea_expires),
+					     TAG_NEXT(nea->nea_args));
+      }
+    }
+
+    if (!nea->nea_leg ||
+	!nea->nea_oreq ||
+	!nea->nea_timer) 
+      nea_destroy(nea), nea = NULL;
+  }
+
+  ta_end(ta);
+  return nea;
+}
+
+
+int nea_update(nea_t *nea, 
+	       tag_type_t tag,
+	       tag_value_t value,
+	       ...)
+{
+  ta_list ta;
+  sip_expires_t const *expires = NULL;
+  sip_payload_t const *pl = NULL;
+  sip_content_type_t const *ct = NULL;
+  char const *cts = NULL;
+
+  /* char const *expires_str = NULL; */
+  su_home_t *home = nea->nea_home;
+
+  /* XXX - hack, previous request still waiting for response */
+  if (!nea->nea_leg || nea->nea_oreq)
+    return -1;
+    
+  ta_start(ta, tag, value);
+  
+  tl_gets(ta_args(ta),
+	  SIPTAG_CONTENT_TYPE_REF(ct),
+	  SIPTAG_CONTENT_TYPE_STR_REF(cts),
+	  SIPTAG_PAYLOAD_REF(pl),
+	  SIPTAG_EXPIRES_REF(expires),
+	  TAG_NULL());
+  
+  if (!pl || (!ct && !cts)) {
+    ta_end(ta);
+    return -1;
+  }
+
+  tl_tremove(nea->nea_args, 
+	     SIPTAG_CONTENT_TYPE(0),
+	     SIPTAG_CONTENT_TYPE_STR(0),
+	     SIPTAG_PAYLOAD(0),
+	     SIPTAG_PAYLOAD_STR(0),
+	     TAG_END());
+
+  su_free(home, nea->nea_expires);
+
+  if (expires)
+    nea->nea_expires = sip_expires_dup(home, expires);
+  else
+    nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);
+
+  /* nta_leg_tag(nea->nea_leg, NULL); */
+  nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,
+				       response_to_subscribe, nea,
+				       NULL,
+				       SIP_METHOD_SUBSCRIBE,
+				       NULL, 
+				       SIPTAG_TO(nea->nea_to),
+				       SIPTAG_PAYLOAD(pl),
+				       TAG_IF(ct, SIPTAG_CONTENT_TYPE(ct)), 
+				       TAG_IF(cts, SIPTAG_CONTENT_TYPE_STR(cts)),
+				       SIPTAG_EXPIRES(nea->nea_expires),
+				       TAG_NEXT(nea->nea_args));
+
+  ta_end(ta);
+
+  if (!nea->nea_oreq) 
+    return -1;
+
+  return 0;
+}
+
+
+/** Unsubscribe the agent. */
+void nea_end(nea_t *nea)
+{
+  if (nea == NULL)
+    return;
+
+  nea->nea_terminating = 1;
+
+  su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;
+
+  if (nea->nea_leg && nea->nea_deadline) {
+    nea->nea_oreq =
+      nta_outgoing_tcreate(nea->nea_leg,
+			   response_to_unsubscribe,
+			   nea,
+			   NULL,
+			   SIP_METHOD_SUBSCRIBE,
+			   NULL,
+			   SIPTAG_EXPIRES_STR("0"),
+			   TAG_NEXT(nea->nea_args));
+  }
+}
+
+void nea_destroy(nea_t *nea)
+{
+  if (nea == NULL)
+    return;
+
+  if (nea->nea_oreq)
+    nta_outgoing_destroy(nea->nea_oreq), nea->nea_oreq = NULL;
+
+  if (nea->nea_leg)
+    nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+
+  if (nea->nea_timer) {
+    su_timer_reset(nea->nea_timer);
+    su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;
+  }
+
+  su_free(NULL, nea);
+}
+
+
+/* Function called by NTA to handle incoming requests belonging to the leg */
+int process_nea_request(nea_t *nea, 
+			nta_leg_t *leg,
+			nta_incoming_t *ireq, 
+			sip_t const *sip)
+{
+
+  switch (sip->sip_request->rq_method) {
+  case sip_method_notify:
+    return handle_notify(nea, leg, ireq, sip);
+  case sip_method_ack:  
+    return 400;
+  default:
+    nta_incoming_treply(ireq, SIP_405_METHOD_NOT_ALLOWED,
+			SIPTAG_ALLOW_STR("NOTIFY"), TAG_END());
+    return 405;
+  }
+}
+
+
+/* Callback function to handle subscription requests */
+int response_to_subscribe(nea_t *nea,
+			  nta_outgoing_t *oreq,
+			  sip_t const *sip)
+{
+  int status = sip->sip_status->st_status;
+  int error = status >= 300;
+
+  if (status >= 200 && oreq == nea->nea_oreq)
+    nea->nea_oreq = NULL;
+
+  nea->nea_callback(nea, nea->nea_context, sip);
+
+  if (status < 200)
+    return 0;
+
+  nea->nea_oreq = NULL;
+
+  if (status < 300) {
+    sip_time_t now = sip_now();
+    if (!nea->nea_notify_received) {
+      nea->nea_deadline = now +
+	sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, 
+			    EXPIRES_DEFAULT, now);
+      if (sip->sip_to->a_tag && !nea->nea_dialog) {
+	nea->nea_dialog = 1;
+	nta_leg_rtag(nea->nea_leg, sip->sip_to->a_tag);
+	nta_leg_client_route(nea->nea_leg, 
+			     sip->sip_record_route, sip->sip_contact);
+      }
+    }
+  }
+  else {
+    nea->nea_deadline = 0;
+    nea->nea_state = nea_terminated;
+    if (status == 301 || status == 302 || status == 305) {
+      sip_contact_t *m;
+
+      for (m = sip->sip_contact; m; m = m->m_next) {
+	if (m->m_url->url_type == url_sip ||
+	    m->m_url->url_type == url_sips)
+	  break;
+      }
+
+      if (m) {
+	url_string_t const *proxy, *url;
+	if (status == 305)
+	  url = NULL, proxy = (url_string_t *)m->m_url;
+	else
+	  url = (url_string_t *)m->m_url, proxy = NULL;
+
+	nea->nea_oreq =
+	  nta_outgoing_tcreate(nea->nea_leg,
+			       response_to_subscribe,
+			       nea,
+			       proxy,
+			       SIP_METHOD_SUBSCRIBE,
+			       url,
+			       SIPTAG_EXPIRES(nea->nea_expires),
+			       TAG_NEXT(nea->nea_args));
+      }
+    } else if (status == 423 && sip->sip_min_expires) {
+      unsigned value = sip->sip_min_expires->me_delta;
+      su_free(nea->nea_home, nea->nea_expires);
+      nea->nea_expires = sip_expires_format(nea->nea_home, "%u", value);
+
+      nea->nea_oreq =
+	nta_outgoing_tcreate(nea->nea_leg,
+			     response_to_subscribe,
+			     nea,
+			     NULL,
+			     SIP_METHOD_SUBSCRIBE,
+			     NULL,
+			     SIPTAG_EXPIRES(nea->nea_expires),
+			     TAG_NEXT(nea->nea_args));
+    }
+  }
+
+  if (status >= 200)
+    nta_outgoing_destroy(oreq);
+
+  if (nea->nea_oreq || !error) {
+    su_time_t now = su_now();
+    now.tv_sec = nea->nea_deadline;
+    su_timer_set_at(nea->nea_timer, 
+		    nea_expires_renew, 
+		    nea,
+		    now);
+  }
+  else
+    nea->nea_callback(nea, nea->nea_context, NULL);
+    
+  return 0;
+}
+
+
+int response_to_unsubscribe(nea_t *nea,
+			    nta_outgoing_t *orq,
+			    sip_t const *sip)
+{
+  int status = sip->sip_status->st_status;
+
+  nea->nea_callback(nea, nea->nea_context, sip);
+
+  if (status >= 200)
+    nta_outgoing_destroy(orq), nea->nea_oreq = NULL;
+  if (status >= 300) 
+    nea->nea_callback(nea, nea->nea_context, NULL);
+
+  return 0;
+}
+
+/** handle notifications */
+int handle_notify(nea_t *nea, 
+		  nta_leg_t *leg,
+		  nta_incoming_t *irq, 
+		  sip_t const *sip)
+{
+  sip_subscription_state_t *ss = sip->sip_subscription_state;
+  sip_subscription_state_t ss0[1];
+  char expires[32];
+
+  if (nea->nea_strict_3265) {
+    char const *phrase = NULL;
+
+    if (ss == NULL)
+      phrase = "NOTIFY Has No Subscription-State Header";
+    else if (sip->sip_event == NULL) 
+      phrase = "Event Header Missing";
+      
+    if (phrase) {
+      nta_incoming_treply(irq, 400, phrase, TAG_END());
+      nta_incoming_destroy(irq);
+      nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+      nea->nea_state = nea_terminated;
+      nea->nea_callback(nea, nea->nea_context, NULL);
+      return 0;
+    }
+  }
+
+  if (ss == NULL) {
+    /* Do some compatibility stuff here */
+    unsigned long delta = 3600;
+
+    sip_subscription_state_init(ss = ss0);
+
+    if (sip->sip_expires)
+      delta = sip->sip_expires->ex_delta;
+
+    if (delta == 0)
+      ss->ss_substate = "terminated";
+    else
+      ss->ss_substate = "active";
+
+    if (delta > 0) {
+      snprintf(expires, sizeof expires, "%lu", delta);
+      ss->ss_expires = expires;
+    }
+  }
+
+  if (!nea->nea_dialog) {
+    nea->nea_dialog = 1;
+    nta_leg_rtag(nea->nea_leg, sip->sip_from->a_tag);
+    nta_leg_server_route(nea->nea_leg, 
+			 sip->sip_record_route, sip->sip_contact);
+  }
+
+  nea->nea_notify_received = 1;
+  nea->nea_callback(nea, nea->nea_context, sip);
+
+  if (strcasecmp(ss->ss_substate, "terminated") == 0) {
+    nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+    nea->nea_state = nea_terminated;
+
+    if (str0casecmp(ss->ss_reason, "deactivated") == 0) {
+      nea->nea_state = nea_embryonic;
+      nea->nea_deadline = sip_now();
+    } else if (str0casecmp(ss->ss_reason, "probation") == 0) {
+      sip_time_t retry = sip_now() + NEA_TIMER_DELTA;
+
+      if (ss->ss_retry_after)
+	retry += strtoul(ss->ss_retry_after, NULL, 10);
+      else
+	retry += NEA_TIMER_DELTA;
+
+      nea->nea_state = nea_embryonic;
+      nea->nea_deadline = retry;
+    } else {
+      nea->nea_deadline = 0;
+      nea->nea_callback(nea, nea->nea_context, NULL);
+      return 200;
+    }
+  }
+  else if (strcasecmp(ss->ss_substate, "pending") == 0) 
+    nea->nea_state = nea_pending;
+  else if (strcasecmp(ss->ss_substate, "active") == 0) 
+    nea->nea_state = nea_active;
+  else
+    nea->nea_state = nea_extended;
+
+  if (nea->nea_state != nea_embryonic && ss->ss_expires) {
+    unsigned retry = strtoul(ss->ss_expires, NULL, 10);
+    if (retry > 60) retry -= 30; else retry /= 2;
+    nea->nea_deadline = sip_now() + retry;
+  }
+
+  {
+    su_time_t now = su_now();
+    now.tv_sec = nea->nea_deadline;
+    su_timer_set_at(nea->nea_timer, 
+		    nea_expires_renew, 
+		    nea,
+		    now);
+  }
+
+  return 200;
+}
+
+void nea_expires_renew(su_root_magic_t *magic,
+		       su_timer_t *timer,
+		       nea_t *nea)
+{
+  sip_time_t now = sip_now();
+
+  /* re-subscribe if expires soon */
+  if (nea->nea_state == nea_terminated ||
+      nea->nea_deadline == 0 || 
+      nea->nea_deadline > now + NEA_TIMER_DELTA)
+    return;
+
+  if (!nea->nea_notify_received)	/* Hmph. */
+    return;
+
+  nea->nea_notify_received = 0;
+
+  nea->nea_oreq =
+    nta_outgoing_tcreate(nea->nea_leg,
+			 response_to_subscribe,
+			 nea,
+			 NULL,
+			 SIP_METHOD_SUBSCRIBE,
+			 NULL,
+			 SIPTAG_EXPIRES(nea->nea_expires),
+			 TAG_NEXT(nea->nea_args));
+    
+  return;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,123 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nea" - SIP Events Module
+ * 
+ * @section nea_meta Module Meta Information
+ *
+ * Sofia Event API provides an interface to different events used in SIP
+ * presence and conferencing. Interface used both in client and server sides
+ * is presented in <nea.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section Creating NEA server and events
+ *
+ * @section nea_server_create Creating NEA server
+ *
+ * NEA server generates, receives and sends events to subscribed
+ * parties. The server is presentity specific, ie. a different server
+ * is created for every presentity.
+ *
+ * First, a server object is created. The object uses the NTA @e agent
+ * (#nta_agent_t) that handles incoming and outgoing SIP messages.
+ *
+ * The example below provides a way to create the NEA server. The
+ * function nea_server_create() creates the server. Parameters @e
+ * agent, @e root define the transaction engine. Third parameter is
+ * the address of the presentity. event_callback is a callback
+ * function pointer and is called every time a new user subscribes to
+ * an event that does not exist or requests for payload type that
+ * doesn't match.
+ *
+ * @code
+ * presence_t *presence_create(su_root_t *root,
+ * 			     nta_agent_t *agent,
+ * 			     sip_contact_t const *m)
+ * {
+ *   presentity_t *pr = su_home_clone(p->p_home, sizeof (*pr));
+ *   ...
+ *   pr->pr_nes = 
+ *     nea_server_create(agent, root,
+ * 		       m->m_url, 
+ * 		       MAX_SUBSCRIBERS,
+ * 		       event_callback, pr,
+ * 		       SIPTAG_CONTACT(m),
+ * 		       SIPTAG_SERVER_STR("Sofia-SIP NEA"),
+ * 		       TAG_NULL());
+ * ...
+ * }
+ * @endcode
+ * 
+ * @section nea_event_create Creating Events
+ *
+ * Next, events are created. The function nea_event_create () defines
+ * an event, its package and content types (a comma separated
+ * list). The parameter presence_callback defines the callback
+ * function that is called when a someone subscribes to a defined
+ * event.
+ *
+ * @code
+ * #define PRESENCE_PACKAGE "presence"
+ * #define XPIDF_MIME_TYPE "application/xpidf+xml"
+ * #define PIDF_MIME_TYPE "application/cpim-pidf+xml"
+
+ * ne = nea_event_create(pr->pr_nes, presence_callback, ep, 
+ * 		       PRESENCE_PACKAGE, NULL,
+ * 		       PIDF_MIME_TYPE,
+ * 		       PIDF_MIME_TYPE "," XPIDF_MIME_TYPE);
+ * @endcode
+ *
+ * @section nea_server_update Operating with event payloads
+ *
+ * A new payload can be inserted to a event with the function
+ * nea_server_update(). The 4th parameter describes if the updated
+ * content is a fake (for unauthorized subscribers). A real payload is
+ * inserted (updated) with the 4th parameter being 0. If the event is
+ * not updated with the content type @a ct before, a new content type
+ * format for the event is created. Otherwise the old payload is
+ * replaced with the new one.
+ *
+ * After the update, subscribers of the event are notified (with SIP
+ * NOTIFY) of the changed payload with nea_server_update ().
+ * 
+ * @code
+ * nea_server_update(pr->pr_nes, home, event, 1,
+ *		   SIPTAG_CONTENT_TYPE(ct),
+ * 		   SIPTAG_PAYLOAD(pl),
+ * 		   TAG_END());
+ 
+ * nea_server_notify(pr->pr_nes, event);
+ * @endcode
+ * 
+ * Obtaining the event's payload and removing it is presented in the
+ * example below. The event is defined as a part of the @a package_t
+ * structure. Function nea_payloads_get() is used to return a payload
+ * (in this case content type being predefined
+ * "application/cpim-pidf+xml"). The real and fake payloads are stored
+ * in the structure #nea_payloads_t. Finally, the payload is removed
+ * with nea_payload_remove().
+ *
+ * @code
+ * int remove_old_payload(package_t *ep)
+ * {
+ *   nea_payloads_t *np;
+ *   sip_content_type_t *ct;
+ *   sip_payload_t *real;
+ *   sip_payload_t *fake;
+
+ *   event = ep->ep_event;
+
+ *   np = nea_payloads_get(event, PIDF_MIME_TYPE);
+ *   ct = nea_content_type_get(np);
+ *   real = nea_payload_get(np);
+ *   fake = nea_fake_get(np);
+ *   nea_payload_remove(ep->ep_home, np);
+
+ *   return 0;
+ * }
+ * @endcode
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea_debug.c  Debug Log for Nokia Event Client API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#include <stddef.h>
+
+#include "nea_debug.h"
+
+/**@var NEA_DEBUG
+ *
+ * Environment variable determining the debug log level for @b nea
+ * module.
+ *
+ * The NEA_DEBUG environment variable is used to determine the debug
+ * logging level for @b nea module. The default level is 3.
+ * 
+ * @sa <su_debug.h>, nea_log, SOFIA_DEBUG
+ */
+extern char const NEA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b nea module. 
+ * 
+ * The nea_log is the log object used by @b nea module. The level of
+ * #nea_log is set using #NEA_DEBUG environment variable.
+ */
+su_log_t nea_log[] = { SU_LOG_INIT("nea", "NEA_DEBUG", SU_DEBUG) };

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_DEBUG_H
+/** Defined when <nea_debug.h> has been included. */
+#define NEA_DEBUG_H
+
+/**@file nea_debug.h
+ * @brief Debug log for @b nea module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Sep  6 19:06:40 2001 ppessi
+ */
+
+#define SU_LOG (nea_log)
+#include <sofia-sip/su_debug.h>
+
+#endif /* !defined(NEA_DEBUG_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file nea_event.c
+ * @brief Default MIME type for certain events.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Dec 11 20:28:46 2003 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+char const *nea_default_content_type(char const *event)
+{
+  char const *template = strrchr(event, '.');
+
+  if (strcmp(event, "presence") == 0)
+    return "application/pidf+xml";
+  else if (strcmp(event, "cpl") == 0)
+    return "application/cpl+xml";
+  else if (strcmp(event, "reg") == 0)
+    return "application/reginfo+xml";
+  else if (strcmp(event, "presencelist") == 0)
+    return "application/cpim-plidf+xml";
+  else if (strcmp(event, "message-summary") == 0)
+    return "application/simple-message-summary";
+  else if (template && strcmp(template, ".acl") == 0)
+    return "application/vnd.nokia-acl+xml";
+  else if (template && strcmp(template, ".winfo") == 0)
+    return "application/watcherinfo+xml";
+  else if (template && strcmp(template, ".list") == 0)
+    return "application/rlmi+xml";
+  else if (strcmp(event, "rlmi") == 0)
+    return "application/rlmi+xml";
+  else
+    return NULL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2375 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nea_server.c
+ * @brief Nokia Event API - event notifier implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:37:04 EET 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "nea_debug.h"
+
+#define NONE ((void *)- 1)
+
+#define SU_ROOT_MAGIC_T      struct nea_server_s
+#define SU_MSG_ARG_T         tagi_t
+
+#define NTA_AGENT_MAGIC_T    struct nea_server_s
+#define NTA_LEG_MAGIC_T      struct nea_sub_s
+#define NTA_INCOMING_MAGIC_T struct nea_sub_s
+#define NTA_OUTGOING_MAGIC_T struct nea_sub_s
+
+#include <sofia-sip/nea.h>
+#include <sofia-sip/htable.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <limits.h>
+
+/** Number of primary views (with different MIME type or content) */
+#define NEA_VIEW_MAX (8)
+
+/** Server object, created for every notifier.
+ */
+struct nea_server_s {
+  su_home_t                 nes_home[1];
+  su_root_t                *nes_root;
+  su_timer_t               *nes_timer;
+  
+  nta_agent_t              *nes_agent;
+  nta_leg_t                *nes_leg;
+
+  nea_sub_t                *nes_subscribers;
+
+  sip_require_t            *nes_require;
+
+  sip_time_t                nes_min_expires;
+  sip_time_t                nes_expires;
+  sip_time_t                nes_max_expires;
+
+  int                       nes_max_subs;
+  unsigned                  nes_throttle; /**< Default throttle */
+  unsigned                  nes_min_throttle; /**< Minimum throttle */
+  unsigned                  nes_eventlist:1; /**< Eventlist only */
+  unsigned                  nes_in_callback : 1;
+  unsigned                  nes_pending_destroy : 1;
+  unsigned                  nes_pending_flush : 1;
+  unsigned                  nes_202_before_notify:1;
+
+  unsigned                  nes_in_list;
+
+  unsigned                  nes_throttled; /**< Throttled notifications? */
+
+  char const               *nes_server;
+
+  sip_contact_t            *nes_eventity_uri;
+  sip_allow_events_t       *nes_allow_events;
+
+  sip_allow_t              *nes_allow_methods;
+
+  nea_new_event_f          *nes_callback;
+  nea_smagic_t             *nes_context;
+
+  /** Events.  
+   * Each subscriber will be added to one of these. */ 
+  nea_event_t              *nes_events;
+};
+
+
+/** Supported events and their subscribers  */
+struct nea_event_s {
+  nea_event_t              *ev_next;
+  nea_event_t             **ev_prev;
+
+  nea_watcher_f            *ev_callback;
+  nea_emagic_t             *ev_magic;
+
+  unsigned                  ev_throttle; /**< Default throttle */
+  unsigned                  ev_min_throttle; /**< Minimum throttle */
+  unsigned                  ev_eventlist:1; /**< Eventlist is supported */
+  unsigned                  ev_reliable:1;  /**< Keep all notifications */
+  unsigned                  :0;
+
+  /** Sequence number of first unsent update */
+  unsigned                  ev_throttling;
+  unsigned                  ev_updated;	/**< Sequence number for updates */
+  sip_require_t            *ev_require; /**< Required features */
+  sip_supported_t          *ev_supported; /**< Supported features */
+
+  sip_event_t              *ev_event;
+  sip_accept_t const       *ev_default;/**< Default content type */
+  sip_accept_t const       *ev_accept; /**< Supported content types */
+
+  nea_event_view_t         *ev_views[NEA_VIEW_MAX + 1];
+};
+
+typedef struct nea_event_queue_s nea_event_queue_t;
+
+/** Object representing particular view of event */
+struct nea_event_view_s
+{
+  nea_event_view_t *evv_next;
+  nea_event_view_t *evv_primary; 	/**< Backpointer to the primary view */
+
+  nea_evmagic_t    *evv_magic;
+
+  unsigned          evv_throttle; /**< Default throttle */
+  unsigned          evv_min_throttle; /**< Minimum throttle */
+  unsigned          evv_fake:1;		/**< This is "fake" (ie. default) view */
+  unsigned          evv_private:1;	/**< This is private view */
+  unsigned          evv_reliable:1;     /**< Keep all notifications */
+  unsigned:0;
+
+  /** Queued notification */
+  struct nea_event_queue_s
+  {
+    nea_event_queue_t  *evq_next;
+    unsigned            evq_updated;
+    unsigned            evq_version;
+    sip_content_type_t *evq_content_type;
+    sip_payload_t      *evq_payload;
+  } evv_head[1];
+};
+
+#define evv_version evv_head->evq_version
+#define evv_updated evv_head->evq_updated
+#define evv_content_type evv_head->evq_content_type
+#define evv_payload evv_head->evq_payload
+
+
+/** Subscription object 
+ */
+struct nea_sub_s {
+  nea_sub_t        *s_next;
+  nea_sub_t       **s_prev;
+  
+  nta_leg_t        *s_leg;
+  nta_incoming_t   *s_irq;
+  nta_outgoing_t   *s_oreq;
+  
+  nea_server_t     *s_nes;
+
+  sip_contact_t    *s_local;	/**< Local contact */
+
+  sip_from_t       *s_from;
+  sip_contact_t    *s_remote;	/**< Remote contact  */
+  /* sip_accept_t  *s_accept; */
+  sip_event_t      *s_id;
+
+  nea_event_t      *s_event;
+  nea_event_view_t *s_view;
+  nea_state_t       s_state;
+
+  char const       *s_extended;
+
+  sip_content_type_t *s_content_type; /** Content-Type of SUBSCRIBE body. */
+  sip_payload_t    *s_payload;      /**< Body of SUBSCRIBE. */
+
+  unsigned          s_processing : 1;
+  unsigned          s_rejected : 1; 
+  unsigned          s_pending_flush : 1;
+  unsigned          s_garbage : 1;
+  unsigned          s_fake : 1; /**< Do not send real information to user */
+  unsigned          s_eventlist : 1; /**< Subscriber supported eventlist */
+
+  sip_time_t        s_subscribed; /**< When first SUBSCRIBE was recv */
+  sip_time_t        s_notified; /**< When last notification was sent */
+  sip_time_t        s_expires;  /**< Expiration time. */
+
+  unsigned          s_version;	/**< Version number set by application */
+
+  unsigned          s_latest;	/**< External version of latest payload */
+  unsigned          s_updated;	/**< Internal version of latest payload */
+  unsigned          s_throttle;	/**< Minimum time between notifications */
+};
+
+/* Prototypes */
+
+static void nea_server_pending_flush(nea_server_t *nes);
+
+static int nea_view_update(nea_server_t *nes,
+			   nea_event_t *ev,
+			   nea_event_view_t **evvp,
+			   int private,
+			   int fake,
+			   tag_type_t tag,
+			   tag_value_t value,
+			   ...);
+
+static nea_sub_t *nea_sub_create(nea_server_t *nes);
+static int nea_sub_is_removed(nea_sub_t const *s);
+static void nea_sub_remove(nea_sub_t *s);
+static void nea_sub_destroy(nea_sub_t *s);
+
+static
+int nea_server_callback(nea_sub_t *nes_as_sub,
+			nta_leg_t *leg,
+			nta_incoming_t *irq, 
+			sip_t const *sip);
+
+static int nea_sub_process_incoming(nea_sub_t *s,
+				    nta_leg_t *leg,
+				    nta_incoming_t *irq,
+				    sip_t const *sip);
+
+static int nea_sub_process_subscribe(nea_sub_t *s,
+				     nta_leg_t *leg,
+				     nta_incoming_t *irq,
+				     sip_t const *sip);
+
+static int nea_sub_notify(nea_server_t *nes, 
+			  nea_sub_t *s, 
+			  sip_time_t now, 
+			  tag_type_t tag, tag_value_t value, ...);
+
+static int response_to_notify(nea_sub_t *s,
+			      nta_outgoing_t *oreq,
+			      sip_t const *sip);
+
+static void nes_event_timer(nea_server_t *nes,
+			    su_timer_t *timer,
+			    su_timer_arg_t *arg);
+
+static int nea_view_queue(nea_server_t *nes, 
+			  nea_event_view_t *evv, 
+			  nea_event_queue_t *evq);
+
+/** Assign an event view to subscriber. */
+static inline
+void nea_sub_assign_view(nea_sub_t *s, nea_event_view_t *evv)
+{
+  if (s->s_view != evv)
+    /* Make sure we send a notification */
+    s->s_updated = evv->evv_updated - 1;
+  s->s_view = evv;
+  s->s_throttle = evv->evv_throttle;
+}
+
+static inline 
+void nea_subnode_init(nea_subnode_t *sn, nea_sub_t *s, sip_time_t now)
+{
+  sn->sn_state = s->s_state;
+  sn->sn_fake = s->s_fake;
+  sn->sn_subscriber = s;
+  sn->sn_event = s->s_event;
+  sn->sn_remote = s->s_from;
+  sn->sn_contact = s->s_remote;
+  sn->sn_content_type = s->s_content_type;
+  sn->sn_payload = s->s_payload;
+  if (s->s_expires != 0 && (int)(s->s_expires - now) > 0)
+    sn->sn_expires = s->s_expires - now;
+  else
+    sn->sn_expires = 0;
+  sn->sn_latest = s->s_latest;
+  sn->sn_throttle = s->s_throttle;
+  sn->sn_eventlist = s->s_eventlist;
+  sn->sn_version = s->s_version;
+  sn->sn_subscribed = now - s->s_subscribed;
+  sn->sn_notified = s->s_notified;
+  sn->sn_view = s->s_view;
+}
+
+/** Create an event server.
+ *
+ * The function nea_server_create() initializes an event server object and
+ * registers it with @b nta. An event server object takes care of all events
+ * for a particular URI (@em eventity).
+ * 
+ * @param agent       pointer to an @b nta agent object
+ * @param root        pointer to an @b root object
+ * @param url         url of the server to be created
+ * @param max_subs    maximum number of subscriptions
+ * @param callback    authorization function, 
+ *                    or @c NULL if no authorization is required
+ * @param context     server context (pointer to application data)
+ * @param tag, value, ... optional list of tag parameters
+ *
+ * @TAGS
+ * The function nea_server_create() takes the following tag values as its 
+ * arguments:
+ * <dl>
+ *
+ * <dt>SIPTAG_CONTACT() or SIPTAG_CONTACT_STR()
+ * <dd>The target address of the event server.
+ *
+ * <dt>SIPTAG_ALLOW_EVENTS()
+ * <dd>The initial list of events supported by eventity. This list is
+ * extended whenever a new event is created with nea_event_tcreate().
+ *
+ * <dt>SIPTAG_SERVER_STR()
+ * <dd>The @b Server header for the event server.
+ *
+ * <dt>NEATAG_MINSUB()
+ * <dd>Minimum duration of a subscription.
+ * 
+ * <dt>NEATAG_THROTTLE()
+ * <dd>Default value for event throttle (by default, 5 seconds).
+ * Throttle determines the minimum interval betweeen notifications. Note
+ * that the notification indicating that the subscription has terminated
+ * will be sent regardless of throttle.
+ * 
+ * The default throttle value is used if the subscriber does not include
+ * a throttle parameter in @ref sip_event "Event" header of SUBSCRIBE request.
+ * 
+ * <dt>NEATAG_MINTHROTTLE()
+ * <dd>Minimum allowed throttle value (by default, 5 seconds).
+ * 
+ * <dt>NEATAG_EVENTLIST()
+ * <dd>If true, the subscribers must support eventlists. If SIPTAG_REQUIRE()
+ * is given, it must contain the "eventlist" feature.
+ *
+ * <dt>NEATAG_DIALOG()
+ * <dd>Give an optional NTA destination leg to event server.
+ * 
+ * <dt>SIPTAG_REQUIRE()/SIPTAG_REQUIRE_STR()
+ * <dd>The @b Require header for the event server. The subscribers must
+ * indicate support the specified features.
+ *
+ * </dl>
+ *
+ * @return
+ * The function nea_server_create() returns a pointer to an event server
+ * object, or @c NULL upon an error.
+ */
+nea_server_t *nea_server_create(nta_agent_t *agent,
+				su_root_t *root,
+				url_t const *url,
+				int max_subs,
+				nea_new_event_f *callback,
+				nea_smagic_t *context,
+				tag_type_t tag, tag_value_t value, ...)
+{
+  nea_server_t *nes = NULL;
+  sip_contact_t const *contact = NULL;
+  sip_allow_events_t const *allow_events = NULL;
+  sip_require_t const *rq = NULL;
+  char const *contact_str = NULL;
+  char const *server_str = NULL;
+  char const *rq_str = NULL;
+  unsigned 
+    min_expires = 15 * 60, 
+    expires = NEA_DEFAULT_EXPIRES,
+    max_expires = 24 * 60 * 60;
+  nta_leg_t *leg = NONE;
+  unsigned throttle = 5, min_throttle = throttle;
+  int eventlist = 0;
+
+  {
+    ta_list ta;
+
+    ta_start(ta, tag, value);
+
+    tl_gets(ta_args(ta), 
+	    SIPTAG_CONTACT_REF(contact),
+	    SIPTAG_CONTACT_STR_REF(contact_str),
+	    SIPTAG_ALLOW_EVENTS_REF(allow_events),
+	    SIPTAG_SERVER_STR_REF(server_str),
+	    SIPTAG_REQUIRE_REF(rq),
+	    SIPTAG_REQUIRE_STR_REF(rq_str),
+	    NEATAG_MIN_EXPIRES_REF(min_expires),
+	    NEATAG_EXPIRES_REF(expires),
+	    NEATAG_MAX_EXPIRES_REF(max_expires),
+	    NEATAG_DIALOG_REF(leg),
+	    NEATAG_THROTTLE_REF(throttle),
+	    NEATAG_MINTHROTTLE_REF(min_throttle),
+	    NEATAG_EVENTLIST_REF(eventlist),
+	    TAG_NULL());
+
+    ta_end(ta);
+  }
+
+  if (throttle < min_throttle)
+    throttle = min_throttle;
+
+  if (!url) {
+    SU_DEBUG_5(("nea_server_create(): invalid url\n"));
+    return NULL;
+  }
+
+  if (min_expires > expires || expires > max_expires) {
+    SU_DEBUG_5(("nea_server_create(): invalid expiration range\n"));
+    return NULL;
+  }
+  
+  nes = su_home_new(sizeof(nea_server_t));
+
+  if (nes) {
+    su_home_t *home = nes->nes_home;
+
+    nes->nes_root = root;
+    nes->nes_agent = agent;
+
+    nes->nes_max_subs = max_subs;
+
+    nes->nes_min_expires = min_expires;
+    nes->nes_expires = expires;
+    nes->nes_max_expires = max_expires;
+
+    nes->nes_throttle = throttle;
+    nes->nes_min_throttle = min_throttle;
+
+    if (allow_events)
+      nes->nes_allow_events = sip_allow_events_dup(home, allow_events);
+    else
+      nes->nes_allow_events = sip_allow_events_make(home, "");
+
+    nes->nes_allow_methods = sip_allow_make(home, "SUBSCRIBE");
+
+    nes->nes_server = 
+      su_sprintf(home, "%s%snea/" NEA_VERSION_STR " %s", 
+		 server_str ? server_str : "",
+		 server_str ? " " : "", 
+		 nta_agent_version(agent));
+
+    if (contact)
+      nes->nes_eventity_uri = sip_contact_dup(home, contact);
+    else if (contact_str)
+      nes->nes_eventity_uri = sip_contact_make(home, contact_str);
+    else
+      nes->nes_eventity_uri = sip_contact_create(home, (url_string_t *)url, NULL);
+
+    if (leg != NONE) {
+      nes->nes_leg = leg;
+      if (leg != NULL)
+	nta_leg_bind(leg, nea_server_callback, (nea_sub_t*)nes);
+    } else {
+      nes->nes_leg = nta_leg_tcreate(agent, 
+				     nea_server_callback, 
+				     (nea_sub_t*)nes, 
+				     NTATAG_NO_DIALOG(1),
+				     NTATAG_METHOD("SUBSCRIBE"),
+				     URLTAG_URL(url),
+				     TAG_END());
+    }
+				     
+    nes->nes_eventlist = eventlist; /* Every event is a list */
+    if (eventlist && rq == NULL && rq_str == NULL)
+      rq_str = "eventlist";
+
+    if (rq)
+      nes->nes_require = sip_require_dup(nes->nes_home, rq);
+    else if (rq_str)
+      nes->nes_require = sip_require_make(nes->nes_home, rq_str);
+
+    nes->nes_timer = su_timer_create(su_root_task(nes->nes_root), 
+				     nes->nes_min_throttle
+				     ? 500L * nes->nes_min_throttle 
+				     : 500L);
+
+    if (nes->nes_allow_events &&
+	nes->nes_eventity_uri &&
+	(nes->nes_leg || leg == NULL) &&
+	nes->nes_timer) {
+      SU_DEBUG_5(("nea_server_create(%p): success\n", nes));
+      su_timer_set(nes->nes_timer, nes_event_timer, nes);
+
+      nes->nes_callback = callback;
+      nes->nes_context = context;
+    }
+    else {
+      SU_DEBUG_5(("nea_server_create(%p): failed\n", nes));
+      nea_server_destroy(nes), nes = NULL;
+    }
+  }
+
+  return nes;
+}
+
+/** Invoke the new event callback.
+ *
+ * The function nes_event_callback() calls the callback provided by the 
+ * application using the notifier object. 
+ *
+ * @param nes pointer to notifier object
+ * @param ev  pointer to event view
+ * @param s   pointer to subscription object
+ * @param sip pointer to subscribe request
+ *
+ * @return
+ * The function nes_event_callback() returns -1 if the notifier object
+ * has been destroyed by the callback function, 0 otherwise.
+ */
+static
+int nes_new_event_callback(nea_server_t *nes, 
+			   nea_event_t **ev_p, 
+			   nea_event_view_t **view_p, 
+			   nta_incoming_t *irq,
+			   sip_t const *sip)
+{
+  if (nes->nes_callback)
+    return nes->nes_callback(nes->nes_context, nes, ev_p, view_p, irq, sip);
+  else
+    return -1;
+}
+
+/** Shutdown event server.
+ */
+int nea_server_shutdown(nea_server_t *nes,
+			int retry_after)
+{
+  nea_sub_t *s;
+  int status = 200;
+  int in_callback;
+
+  if (nes == NULL)
+    return 500;
+
+  if (nes->nes_in_callback) {
+    SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", nes));
+    return 100;
+  }
+  
+  SU_DEBUG_5(("nea_server_shutdown(%p)\n", nes));
+
+  in_callback = nes->nes_in_callback; nes->nes_in_callback = 1;
+
+  for (s = nes->nes_subscribers; s; s = s->s_next) {
+    if (s->s_state == nea_terminated)
+      continue;
+    if (s->s_pending_flush)
+      continue;
+    if (s->s_oreq == NULL)
+      nea_sub_auth(s, nea_terminated, 
+		   TAG_IF(retry_after, NEATAG_REASON("probation")),
+		   TAG_IF(!retry_after, NEATAG_REASON("deactivated")),
+		   TAG_IF(retry_after, NEATAG_RETRY_AFTER(retry_after)),
+		   TAG_END());
+    else
+      status = 180;
+  }    
+
+  nes->nes_in_callback = in_callback;   
+
+  return 200;
+}
+
+void nea_server_destroy(nea_server_t *nes)
+{
+  if (nes == NULL)
+    return;
+
+  if (nes->nes_in_callback) {
+    SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", nes));
+    nes->nes_pending_destroy = 1;
+    return;
+  }
+  
+  SU_DEBUG_5(("nea_server_destroy(%p)\n", nes));
+  
+  nta_leg_destroy(nes->nes_leg), nes->nes_leg = NULL;
+  
+  while (nes->nes_subscribers)
+    nea_sub_destroy(nes->nes_subscribers);
+  
+  su_timer_destroy(nes->nes_timer), nes->nes_timer = NULL;
+  
+  su_home_unref(nes->nes_home);
+}
+
+/* ----------------------------------------------------------------- */
+
+/**Update server payload.
+ *
+ * A nea event server has typed content that is delivered to the
+ * subscribers. Different content types are each assigned a separate primary
+ * view. There can be also primary views with "fake" content, content
+ * delivered to politely blocked subscribers. 
+ *
+ * In addition to primary views, there can be secondary views, views
+ * assigned to a single subscriber only. 
+ *
+ * @TAGS
+ * The following tagged arguments are accepted:
+ * <dl>
+ *
+ * <dt>SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR()
+ * <dd>Updated event content.
+ *
+ * <dt>SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR().
+ * <dd>MIME type of the content.
+ *
+ * <dt>NEATAG_FAKE(fak)
+ * <dd>If @a fake is true, 'fake' view is updated.
+ *
+ * <dt>NEATAG_VIEW(view) 
+ * <dd>If included in tagged arguments, @a view is * updated. Used when
+ * updating secondary view.
+ *
+ * <dt>NEATAG_VERSION(version)
+ * <dd>The application-provided @a version for
+ * event content. After updated content has been sent to subscriber, @a
+ * version is copied to subscriber information structure.
+ *
+ * <dt>NEATAG_EVMAGIC(context)
+ * <dd>Application-provided @a context pointer.
+ * The @a context pointer is returned by nea_view_magic() function.
+ *
+ * <dt>NEATAG_RELIABLE(reliable) 
+ * <dd>The @a reliable flag determines how overlapping updates are handled. 
+ * If @a reliable is true, all updates are delivered to the subscribers.
+ *
+ * <dt>NEATAG_THROTTLE(throttl)
+ * <dd>Default value for event throttle for updated event view. Throttle
+ * determines the minimum interval in seconds betweeen notifications. Note
+ * that the notification indicating that the subscription has terminated
+ * will be sent regardless of throttle.
+ * 
+ * The default throttle value is used if the subscriber does not include
+ * a throttle parameter in @ref sip_event "Event" header of SUBSCRIBE request.
+ * 
+ * <dt>NEATAG_MINTHROTTLE()
+ * <dd>Minimum allowed throttle value for updated event view.
+ *
+ * </dl>
+ *
+ * @retval -1 upon an error.
+ * @retval 0  if event document was not updated.
+ * @retval 1  if event document was updated.
+ */
+int nea_server_update(nea_server_t *nes,
+		      nea_event_t *ev,
+		      tag_type_t tag,
+		      tag_value_t value,
+		      ...)
+{
+  nea_event_view_t *evv = NULL;
+  int fake = 0, updated;
+
+  ta_list ta;
+
+  if (ev == NULL)
+    ev = nes->nes_events;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  NEATAG_FAKE_REF(fake),
+	  NEATAG_VIEW_REF(evv),
+	  TAG_NULL());
+  
+  updated = nea_view_update(nes, ev, &evv, 0, fake, ta_tags(ta));
+
+  ta_end(ta);
+
+  return updated;
+}
+
+static
+int nea_view_update(nea_server_t *nes,
+		    nea_event_t *ev,
+		    nea_event_view_t **evvp,
+		    int private,
+		    int fake,
+		    tag_type_t tag,
+		    tag_value_t value,
+		    ...)
+{
+  ta_list ta;
+
+  su_home_t *home = nes->nes_home;
+
+  sip_content_type_t const *ct = NULL;
+  char const *cts = NULL, *pls = NULL;
+  sip_payload_t const *pl = NULL;
+  sip_payload_t *new_pl;
+  nea_event_view_t *evv, **eevv = &evv;
+  nea_event_view_t *primary = NULL, **primary_p = &primary;
+  unsigned version = UINT_MAX;
+  nea_evmagic_t *evmagic = NULL;
+  int reliable = ev->ev_reliable;
+  unsigned throttle = ev->ev_throttle;
+  unsigned min_throttle = ev->ev_min_throttle;
+
+  nea_event_queue_t evq[1] = {{ NULL }};
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  SIPTAG_CONTENT_TYPE_REF(ct),
+	  SIPTAG_CONTENT_TYPE_STR_REF(cts),
+	  SIPTAG_PAYLOAD_REF(pl),
+	  SIPTAG_PAYLOAD_STR_REF(pls),
+	  NEATAG_VERSION_REF(version),
+	  NEATAG_EVMAGIC_REF(evmagic),
+	  NEATAG_RELIABLE_REF(reliable),
+	  NEATAG_THROTTLE_REF(throttle),
+	  NEATAG_MINTHROTTLE_REF(min_throttle),
+	  TAG_NULL());
+  
+  ta_end(ta);
+
+  if (min_throttle < throttle)
+    min_throttle = throttle;
+
+  if (ct == NULL && cts == NULL)
+    return -1;
+
+  if (ct)
+    cts = ct->c_type;
+
+  evv = *evvp;
+
+  if (!evv) {
+    int i;
+
+    /* Check if the payload type already exists */
+    for (i = 0; (evv = ev->ev_views[i]); i++)
+      if (str0casecmp(cts, evv->evv_content_type->c_type) == 0)
+	break;
+    
+    if (private && evv == NULL) /* No private view without primary view. */
+      return -1;
+
+    if (i == NEA_VIEW_MAX)	/* Too many primary views. */
+      return -1;
+
+    primary_p = eevv = ev->ev_views + i;
+    
+    /* Search for fakeness/eventlist/private view */
+    if (evv && (private || evv->evv_private || evv->evv_fake != (unsigned)fake)) {
+      for (eevv = &evv->evv_next; (evv = *eevv); eevv = &evv->evv_next) {
+	if (private || evv->evv_private)
+	  continue;
+	if (evv->evv_fake == (unsigned)fake)
+	  break;
+      }
+    }
+  }
+   
+  /* New event view, allocate and link to chain */
+  if (!evv) {
+    sip_content_type_t *new_ct;
+
+    evv = su_zalloc(home, sizeof (*evv));
+    if (!evv)
+      return -1;
+    
+    new_pl = pl ? sip_payload_dup(home, pl)
+      : sip_payload_make(home, pls);
+    
+    new_ct = ct ? sip_content_type_dup(home, ct) 
+      : sip_content_type_make(home, cts);
+    
+    if ((!new_pl && pl) || !new_ct) {
+      su_free(home, evv); su_free(home, new_pl);
+      return -1;
+    }
+
+    *evvp = *eevv = evv;
+      
+    evv->evv_primary = *primary_p;
+    evv->evv_private = private != 0;
+    evv->evv_fake = fake != 0;
+    evv->evv_reliable = reliable != 0;
+    evv->evv_magic = evmagic;
+    evv->evv_content_type = new_ct;
+    evv->evv_payload = new_pl;
+    evv->evv_throttle = throttle;
+    evv->evv_min_throttle = min_throttle;
+
+    assert(evv->evv_content_type);
+  }
+  else {
+    if (pl && 
+	evv->evv_payload && 
+	evv->evv_payload->pl_len == pl->pl_len &&
+	memcmp(evv->evv_payload->pl_data, pl->pl_data, pl->pl_len) == 0)
+      return 0;
+    if (!pl && pls && evv->evv_payload && 
+	evv->evv_payload->pl_len == strlen(pls) && 
+	memcmp(evv->evv_payload->pl_data, pls, evv->evv_payload->pl_len) == 0)
+      return 0;
+    if (!pl && !pls && !evv->evv_payload)
+      return 0;
+
+    *evq = *evv->evv_head;
+
+    new_pl = pl ? sip_payload_dup(home, pl) : sip_payload_make(home, pls);
+
+    if (!new_pl && (pl || pls))
+      return -1;
+    
+    evv->evv_payload = new_pl;
+  }
+
+  if (version != UINT_MAX)
+    evv->evv_version = version;
+
+  if (!fake)
+    evv->evv_updated = ++ev->ev_updated;
+
+  if (evq->evq_content_type)
+    nea_view_queue(nes, evv, evq);
+
+  SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n", 
+	      nes, ev->ev_event->o_type, evv->evv_content_type->c_type));
+
+  return 1;
+}
+
+nea_event_view_t *nea_view_create(nea_server_t *nes,
+				  nea_event_t *ev,
+				  nea_evmagic_t *magic,
+				  tag_type_t tag,
+				  tag_value_t value,
+				  ...)
+{
+  nea_event_view_t *evv = NULL;
+  ta_list ta;
+
+  if (ev == NULL)
+    return NULL;
+
+  ta_start(ta, tag, value);
+
+  nea_view_update(nes, ev, &evv, 1, 0, ta_tags(ta));
+			 
+  ta_end(ta);
+
+  return evv;
+}
+
+void nea_view_destroy(nea_server_t *nes, nea_event_view_t *evv)
+{
+  nea_event_view_t **evvp;
+  nea_sub_t *s;
+
+  if (nes == NULL || evv == NULL || !evv->evv_private)
+    return;
+
+  assert(evv->evv_primary && evv != evv->evv_primary);
+
+  for (evvp = &evv->evv_primary->evv_next; *evvp; evvp = &(*evvp)->evv_next)
+    if (*evvp == evv) {
+      *evvp = evv->evv_next;
+      break;
+    }
+
+  for (s = nes->nes_subscribers; s; s = s->s_next)
+    if (s->s_view == evv)
+      nea_sub_assign_view(s, evv->evv_primary);
+
+  su_free(nes->nes_home, evv->evv_content_type);
+  su_free(nes->nes_home, evv->evv_payload);
+  su_free(nes->nes_home, evv);
+}
+
+nea_evmagic_t *nea_view_magic(nea_event_view_t const *evv)
+{
+  return evv ? evv->evv_magic : NULL;
+}
+
+void nea_view_set_magic(nea_event_view_t *evv, nea_evmagic_t *magic)
+{
+  if (evv)
+    evv->evv_magic = magic;
+}
+
+unsigned nea_view_version(nea_event_view_t const *evv)
+{
+  return evv ? evv->evv_version : 0;
+}
+
+/** Get primary, non-fake event view for given content type  */
+nea_event_view_t *nea_event_view(nea_event_t *ev, char const *content_type)
+{
+  int i;
+  nea_event_view_t *evv;
+
+  /* Check if the payload type already exists */
+  for (i = 0; ev->ev_views[i]; i++)
+    if (str0casecmp(content_type, ev->ev_views[i]->evv_content_type->c_type) == 0)
+      break;
+
+  for (evv = ev->ev_views[i]; evv; evv = evv->evv_next)
+    if (!evv->evv_fake)
+      return evv;
+
+  return ev->ev_views[i];
+}
+
+/** Get the content type for event view */
+sip_content_type_t const *nea_view_content_type(nea_event_view_t const *evv)
+{
+  return evv ? evv->evv_content_type : NULL;
+}
+
+
+/** Queue an old notification if needed. */
+static
+int nea_view_queue(nea_server_t *nes, 
+		   nea_event_view_t *evv, 
+		   nea_event_queue_t *evq)
+{
+  nea_sub_t *s = NULL;
+
+  assert(nes && evv && evq);
+
+  if (evv->evv_reliable)
+    for (s = nes->nes_subscribers; s; s = s->s_next) {
+      if (s->s_view != evv)
+	continue;
+      if (s->s_updated > evq->evq_updated)
+	continue;
+      if (s->s_updated == evq->evq_updated && s->s_oreq == NULL)
+	continue;
+      break;			/* This  */
+    }
+  
+  if (s) {
+    nea_event_queue_t *evq0 = su_alloc(nes->nes_home, sizeof *evq);
+
+    if (evq0 == NULL)
+      return -1;
+
+    *evq0 = *evq, evq = evq0;
+
+    /* evq should be copy of old head but with changed payload  */
+    assert(evq->evq_next == evv->evv_head->evq_next); 
+
+    evv->evv_head->evq_next = evq;     /* insert to the queue */
+
+    return 0;
+  }
+
+  su_free(nes->nes_home, (void *)evq->evq_payload);
+
+  return 0;
+}
+
+/** Remove old unneeded notifications. */
+static
+int nea_view_dequeue(nea_server_t *nes, 
+		     nea_event_t *ev)
+{
+  int i;
+  nea_event_view_t *evv;
+  nea_event_queue_t **prev, *evq;;
+
+  assert(nes && ev);
+
+  for (i = 0; ev->ev_views[i]; i++) {
+    for (evv = ev->ev_views[i]; evv; evv = evv->evv_next) {
+      if (!evv->evv_reliable)
+	continue;
+
+      for (prev = &evv->evv_head->evq_next; *prev; prev = &(*prev)->evq_next)
+	if (ev->ev_throttling >= (*prev)->evq_updated)
+	  break;
+
+      /* Free from evq onwards */
+      for (evq = *prev; evq; evq = *prev) {
+	*prev = evq->evq_next;
+	su_free(nes->nes_home, evq->evq_payload);
+	su_free(nes->nes_home, evq);
+      }
+    }
+  }
+
+  return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+/** Notify watchers.
+ *
+ * @return 
+ * The function nea_server_notify() returns number of subscribers that the
+ * notification could be sent, or -1 upon an error.
+ */
+int nea_server_notify(nea_server_t *nes, nea_event_t *ev)
+{
+  sip_time_t now = sip_now();
+  nea_sub_t *s;
+  int notified = 0, throttled = nes->nes_throttled;
+
+  SU_DEBUG_7(("nea_server_notify(%p): %s\n", nes, ev ? ev->ev_event->o_type: ""));
+
+  ++nes->nes_in_list;
+
+  nes->nes_throttled = 0;
+
+  if (ev == NULL)
+    for (ev = nes->nes_events; ev; ev = ev->ev_next)
+      ev->ev_throttling = UINT_MAX;
+  else
+    ev->ev_throttling = UINT_MAX;
+
+  for (s = nes->nes_subscribers; s; s = s->s_next) {
+    if ((ev == NULL || ev == s->s_event) && s->s_state != nea_terminated) {
+      notified += nea_sub_notify(nes, s, now, TAG_END());
+    }
+  }
+
+  if (throttled) {
+    /* Dequeue throttled updates */
+    if (ev == NULL)
+      for (ev = nes->nes_events; ev; ev = ev->ev_next) {
+	nea_view_dequeue(nes, ev);
+	SU_DEBUG_3(("nea_server(): notified %u, throttling at %u\n", 
+		    notified, ev->ev_throttling));
+      }
+    else {
+      SU_DEBUG_3(("nea_server(): notified %u, throttling at %u\n", 
+		  notified, ev->ev_throttling));
+      nea_view_dequeue(nes, ev);
+    }
+  }
+
+  if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+    nea_server_pending_flush(nes);
+
+  return notified;
+}
+
+
+/* ----------------------------------------------------------------- */
+void nea_server_flush(nea_server_t *nes, nea_event_t *event)
+{
+  nea_sub_t *s, **ss;
+  sip_time_t now;
+
+  if (nes == NULL)
+    return;
+
+  now = sip_now();
+
+  for (ss = &nes->nes_subscribers; (s = *ss);) {
+    if ((event == NULL || s->s_event == event) &&
+	(s->s_state == nea_terminated || s->s_expires < now)) {
+      /** On first flush, mark as garbage, remove on second flush */
+      if (!s->s_garbage)
+	s->s_garbage = 1;
+      else if (nes->nes_in_callback || nes->nes_in_list) {
+	nes->nes_pending_flush = 1;
+	(*ss)->s_pending_flush = 1;
+      }
+      else {
+	nea_sub_destroy(*ss);
+	continue;
+      }
+    } 
+    ss = &((*ss)->s_next);
+  }
+}
+
+
+/* ----------------------------------------------------------------- */
+static
+void nea_server_pending_flush(nea_server_t *nes)
+{
+  nea_sub_t **ss;
+
+  for (ss = &nes->nes_subscribers; *ss;) {
+    if ((*ss)->s_pending_flush && !(*ss)->s_processing) {
+      nea_sub_destroy(*ss);
+    } else {
+      ss = &((*ss)->s_next);
+    }
+  }
+
+  nes->nes_pending_flush = 0;
+}
+
+/* ----------------------------------------------------------------- */
+nea_sub_t *nea_sub_create(nea_server_t *nes)
+{
+  nea_sub_t *s;
+
+  assert(nes);
+
+  s = su_zalloc(nes->nes_home, sizeof (*s));
+
+  if (s) {
+    s->s_nes = nes;
+    if ((s->s_next = nes->nes_subscribers))
+      s->s_next->s_prev = &s->s_next;
+    s->s_prev = &nes->nes_subscribers;
+    nes->nes_subscribers = s;
+
+    /* Copy default values */
+    s->s_throttle = nes->nes_throttle;	
+  }
+
+  return s;
+}
+
+/* ----------------------------------------------------------------- */
+nta_incoming_t *nea_subnode_get_incoming(nea_subnode_t *sn)
+{
+  assert(sn);
+
+  if (sn->sn_subscriber) {
+    return sn->sn_subscriber->s_irq;
+  }
+  return NULL;
+}
+
+/* ----------------------------------------------------------------- */
+void nea_sub_remove(nea_sub_t *s)
+{
+  if (s) {
+    assert(s->s_prev);
+
+    if ((*s->s_prev = s->s_next))
+      s->s_next->s_prev = s->s_prev;
+
+    s->s_prev = NULL;
+    s->s_next = NULL;
+  }
+}
+
+/* ----------------------------------------------------------------- */
+/**Check if subscriber has been removed from list */
+static int nea_sub_is_removed(nea_sub_t const *s)
+{
+  return s->s_prev == NULL;
+}
+
+/* ----------------------------------------------------------------- */
+void nea_sub_destroy(nea_sub_t *s)
+{
+  if (s) {
+    nea_sub_t *del =  s;
+    su_home_t *home = del->s_nes->nes_home;
+
+    if (!nea_sub_is_removed(del))
+      nea_sub_remove(del);
+
+    del->s_event = NULL;
+
+    su_free(home, del->s_local), del->s_local = NULL;
+    su_free(home, del->s_remote), del->s_remote = NULL;
+
+    if (del->s_oreq) 
+      nta_outgoing_destroy(del->s_oreq), del->s_oreq = NULL;
+    if (del->s_leg) 
+      nta_leg_destroy(del->s_leg), del->s_leg = NULL;
+    if (del->s_from)
+      su_free(home, del->s_from), del->s_from = NULL;
+
+    su_free(home, del);
+  }
+}
+
+/** Create a new event.
+ *
+ * The function nea_event_create() creates a new event for the event server.
+ */
+nea_event_t *nea_event_create(nea_server_t *nes,
+			      nea_watcher_f *callback,
+			      nea_emagic_t *context,
+			      char const *name, 
+			      char const *subname,
+			      char const *default_content_type,
+			      char const *accept)
+{
+  return nea_event_tcreate(nes, callback, context, 
+			   name, subname, 
+			   SIPTAG_CONTENT_TYPE_STR(default_content_type), 
+			   SIPTAG_ACCEPT_STR(accept),
+			   TAG_END());
+}
+
+/** Create a new event (or subevent) with tags */
+nea_event_t *nea_event_tcreate(nea_server_t *nes,
+			       nea_watcher_f *callback,
+			       nea_emagic_t *context,
+			       char const *name, 
+			       char const *subname,
+			       tag_type_t tag, tag_value_t value, ...)
+{
+  nea_event_t *ev, **pev;
+  size_t len = strlen(name);
+  ta_list ta;
+
+  /* Find a matching event */
+  if (subname == NULL) {
+    for (pev = &nes->nes_events; (ev = *pev); pev = &(*pev)->ev_next) {
+      if (strcmp(ev->ev_event->o_type, name) != 0)
+	continue;
+      SU_DEBUG_5(("nea_event_create(): already event %s\n", name));
+      return NULL;
+    }
+  }
+  else {
+    for (pev = &nes->nes_events; (ev = *pev); pev = &(*pev)->ev_next) {
+      if (strncmp(ev->ev_event->o_type, name, len) != 0 ||
+	  ev->ev_event->o_type[len] != '.' ||
+	  strcmp(subname, ev->ev_event->o_type + len + 1) != 0)
+	continue;
+      SU_DEBUG_5(("nea_event_create(): already event %s.%s\n", name, subname));
+      return NULL;
+    }
+  }
+
+  ta_start(ta, tag, value);
+
+  ev = su_zalloc(nes->nes_home, sizeof (*ev));
+
+  if (ev) {
+    int reliable = 0;
+    sip_content_type_t const *ct = NULL;
+    sip_accept_t const *ac = NULL;
+    sip_supported_t const *k = NULL;
+    sip_require_t const *rq = NULL;
+    char const *ct_str = NULL, *ac_str = NULL, *k_str = NULL, *rq_str = NULL;
+    
+    unsigned throttle = nes->nes_throttle, min_throttle = nes->nes_min_throttle;
+    int eventlist = nes->nes_eventlist;
+
+    tl_gets(ta_args(ta),
+	    NEATAG_RELIABLE_REF(reliable),
+	    NEATAG_THROTTLE_REF(throttle),
+	    NEATAG_MINTHROTTLE_REF(min_throttle),
+	    NEATAG_EVENTLIST_REF(eventlist),
+	    SIPTAG_CONTENT_TYPE_REF(ct),
+	    SIPTAG_CONTENT_TYPE_STR_REF(ct_str),
+	    SIPTAG_ACCEPT_REF(ac),
+	    SIPTAG_ACCEPT_STR_REF(ac_str),
+	    SIPTAG_SUPPORTED_REF(k),
+	    SIPTAG_SUPPORTED_STR_REF(k_str),
+	    SIPTAG_REQUIRE_REF(rq),
+	    SIPTAG_REQUIRE_STR_REF(rq_str),
+	    TAG_END());
+
+    ev->ev_callback = callback;
+    ev->ev_magic = context;
+    ev->ev_event = sip_event_format(nes->nes_home, "%s%s%s", 
+				    name, 
+				    subname ? "." : "", 
+				    subname ? subname : "");
+ 
+    ev->ev_reliable = reliable != 0;
+    ev->ev_throttle = throttle;
+    ev->ev_min_throttle = min_throttle;
+    ev->ev_eventlist = eventlist;
+
+    if (eventlist && rq == NULL && rq_str == NULL)
+      rq_str = "eventlist";
+
+    if (rq)
+      ev->ev_require = sip_require_dup(nes->nes_home, rq);
+    else if (rq_str)
+      ev->ev_require = sip_require_make(nes->nes_home, rq_str);
+
+    if (ev->ev_event) {
+#define sip_allow_events_find(k, i) sip_params_find(k->k_items, i)
+      if (!sip_allow_events_find(nes->nes_allow_events, 
+				 ev->ev_event->o_type))
+	sip_allow_events_add(nes->nes_home, nes->nes_allow_events, 
+			     ev->ev_event->o_type);
+    }
+
+    if (ct)
+      ev->ev_default = sip_accept_make(nes->nes_home, ct->c_type);
+    else 
+      ev->ev_default = sip_accept_make(nes->nes_home, ct_str);
+
+    if (ac == NULL && ac_str == NULL)
+      ac_str = ct ? ct->c_type : ct_str;
+
+    if (ac)
+      ev->ev_accept = sip_accept_dup(nes->nes_home, ac);
+    else
+      ev->ev_accept = sip_accept_make(nes->nes_home, ac_str ? ac_str : "");
+
+    if (k)
+      ev->ev_supported = sip_supported_dup(nes->nes_home, k);
+    else if (k_str)
+      ev->ev_supported = sip_supported_make(nes->nes_home, k_str);
+
+    ev->ev_prev = pev;
+    *pev = ev; 
+  }
+
+  ta_end(ta);
+
+  return ev;
+}
+
+
+/* ----------------------------------------------------------------- */
+/** Return magic context bound to nea_event.
+ *
+ * The function returns the magic context bound to the event.
+ *
+ * @param ev pointer to event object
+ *
+ * @return
+ * The function nea_emagic_get() returns the magic context
+ * bound to the event.
+ */
+nea_emagic_t *nea_emagic_get(nea_event_t *ev)
+{
+  assert(ev);
+
+  return ev->ev_magic;
+}
+
+
+/* ----------------------------------------------------------------- */
+/** Get named event */
+nea_event_t *nea_event_get(nea_server_t const *nes, char const *e)
+{
+  nea_event_t *ev = NULL;
+
+  for (ev = nes->nes_events; ev; ev = ev->ev_next)
+    if (e == NULL || strcmp(ev->ev_event->o_type, e) == 0)
+      break;
+
+  return ev;
+}
+
+/* ----------------------------------------------------------------- */
+nta_incoming_t *nea_sub_get_request(nea_sub_t *sub)
+{
+  assert(sub);
+
+  return sub->s_irq;
+}
+
+/** Invoke the event callback.
+ *
+ * The function nes_watcher_callback() calls the callback provided by the 
+ * application using the notifier object. 
+ *
+ * @param nes pointer to notifier object
+ * @param ev  pointer to event view
+ * @param s   pointer to subscription object
+ * @param sip pointer to subscribe request
+ *
+ * @return
+ * The function nes_watcher_callback() returns -1 if the notifier object
+ * has been destroyed by the callback function, 0 otherwise.
+ */
+static
+int nes_watcher_callback(nea_server_t *nes, 
+			 nea_event_t *ev, 
+			 nea_sub_t *s, 
+			 sip_t const *sip)
+{
+  if (!nes->nes_in_callback) {
+    nes->nes_in_callback = 1;
+    if (ev->ev_callback) {
+      nea_subnode_t sn[1];
+
+      nea_subnode_init(sn, s, sip_now());
+
+      ev->ev_callback(nes, ev->ev_magic, ev, sn, sip);
+    }
+    nes->nes_in_callback = 0;
+
+    if (nes->nes_in_list)
+      return 0;
+    
+    if (nes->nes_pending_destroy) {
+      nea_server_destroy(nes);
+      return -2;
+    }
+    
+    if (sip == NULL && nes->nes_pending_flush) {
+      int flushed = s->s_pending_flush;
+      nea_server_pending_flush(nes);
+      if (flushed)
+	return -1;
+    }
+  }
+
+  return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+#if 0
+/** Process incoming SUBSCRIBE message.
+ *
+ * The function nea_server_add() is called when the notifier receives a
+ * SUBSCRIBE request without existing event dialog.
+ * 
+ * @param nes pointer to notifier
+ * @param local_target optional contact header 
+ * @param msg pointer to request message
+ * @param sip pointer to SIP view to request message
+ *
+ * @return 
+ * The function nea_server_add() returns 0 if successful, -1 upon an
+ * error.
+ *  
+ */
+int nea_server_add(nea_server_t *nes, 
+		   sip_contact_t const *local_target,
+		   msg_t *msg, sip_t *sip)
+{
+  su_home_t *home = nes->nes_home;
+  nea_sub_t *s = NULL;
+  url_t target[1];
+
+  s = nea_sub_create(nes);
+
+  s->s_from = sip_from_dup(home, sip->sip_from);
+
+  if (local_target == NULL)
+    local_target = nes->nes_eventity_uri;
+
+  s->s_local = sip_contact_dup(nes->nes_home, local_target);
+
+  *target = *local_target->m_url;
+
+  s->s_leg = nta_leg_tcreate(nes->nes_agent, nea_sub_process_incoming, s,
+			     SIPTAG_CALL_ID(sip->sip_call_id),
+			     SIPTAG_FROM(sip->sip_to), /* local address */
+			     SIPTAG_TO(sip->sip_from), /* remote address */
+			     URLTAG_URL(target),
+			     TAG_END());
+
+  if (s->s_local && s->s_leg) {
+    nta_leg_tag(s->s_leg, NULL);
+    return 0;
+  }
+  else {
+    nea_sub_destroy(s);
+    return -1;
+  }
+}
+#endif
+
+static
+int nea_server_callback(nea_sub_t *nes_as_sub,
+			nta_leg_t *leg,
+			nta_incoming_t *irq, 
+			sip_t const *sip)
+{
+  return nea_server_add_irq((nea_server_t *)nes_as_sub, leg, NULL, irq, sip);
+}
+
+/** Process incoming request */
+int nea_server_add_irq(nea_server_t *nes,
+		       nta_leg_t *leg,
+		       sip_contact_t const *local_target,
+		       nta_incoming_t *irq, 
+		       sip_t const *sip)
+{
+  nea_sub_t *s = NULL;
+  s = nea_sub_create(nes);
+
+  s->s_from = sip_from_dup(nes->nes_home, sip->sip_from);
+
+  if (local_target == NULL)
+    local_target = nes->nes_eventity_uri;
+
+  s->s_local = sip_contact_dup(nes->nes_home, local_target);
+
+  if (leg == NULL || leg == nes->nes_leg) {
+    url_t target[1];
+    
+    *target = *local_target->m_url;
+
+    s->s_leg = nta_leg_tcreate(nes->nes_agent, nea_sub_process_incoming, s, 
+			       SIPTAG_FROM(sip->sip_to),
+			       SIPTAG_TO(sip->sip_from),
+			       SIPTAG_CALL_ID(sip->sip_call_id),
+			       URLTAG_URL((url_string_t *)target),
+			       TAG_NULL());
+  }
+  else {
+    nta_leg_bind(s->s_leg = leg, nea_sub_process_incoming, s);
+  }
+  
+  if (s->s_leg) {
+    if (sip->sip_to->a_tag == NULL) {
+      nta_leg_tag(s->s_leg, NULL);
+      nta_incoming_tag(irq, nta_leg_get_tag(s->s_leg));
+    }
+    nta_leg_server_route(s->s_leg, sip->sip_record_route, sip->sip_contact);
+
+    return nea_sub_process_incoming(s, s->s_leg, irq, sip);
+  }
+  else {
+    nea_sub_destroy(s);
+    return 500;
+  }
+}
+
+
+/* ----------------------------------------------------------------- */
+
+/**Process incoming transactions for event dialog.
+ *
+ * The nea_sub_process_incoming() processes the transactions for event
+ * dialog. Currently, no other methods allowed beside SUBSCRIBE. The
+ * SUBSCRIBE is processed by nea_sub_process_subscribe().
+ *
+ * @param s   pointer to subscriber object
+ * @param leg pointer to NTA dialog object
+ * @param irq pointer to NTA server transaction
+ * @param sip pointer to structure containing SIP headers of the request
+ *
+ * The nea_sub_process_incoming() returns 0 if successful, SIP error code
+ * otherwise.
+ */
+int nea_sub_process_incoming(nea_sub_t *s,
+			     nta_leg_t *leg,
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  int retval;
+
+  s->s_processing = 1;
+  s->s_irq = irq;
+
+  switch(sip->sip_request->rq_method) {
+  case sip_method_subscribe:
+    retval = nea_sub_process_subscribe(s, leg, irq, sip);
+    break;
+
+  default:
+    nta_incoming_treply(irq, 
+			retval = SIP_405_METHOD_NOT_ALLOWED,
+			SIPTAG_ALLOW_STR("SUBSCRIBE"),
+			TAG_END());
+    retval = 405;
+  }
+
+  s->s_processing = 0;
+
+  if (s->s_irq)
+    nta_incoming_destroy(irq), s->s_irq = NULL;
+  
+  if (s->s_pending_flush || s->s_state == nea_embryonic)
+    nea_sub_destroy(s);
+
+  return retval;
+}
+
+
+/* ----------------------------------------------------------------- */
+
+/**Process incoming SUBSCRIBE transactions for event dialog.
+ *
+ * The function nea_sub_process_subscribe() processes the SUBSCRIBE
+ * transactions for (possible) event dialog.
+ *
+ * @param s   pointer to subscriber object
+ * @param leg pointer to NTA dialog object
+ * @param irq pointer to NTA server transaction
+ * @param sip pointer to structure containing SIP headers of the request
+ *
+ * @return
+ * The function nea_sub_process_subscribe() returns 0 if successful, and a
+ * SIP error code otherwise.
+ */
+int nea_sub_process_subscribe(nea_sub_t *s,
+			      nta_leg_t *leg,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  nea_server_t *nes = s->s_nes;
+  su_home_t *home = nes->nes_home;
+  nea_event_t *ev = NULL, *ev_maybe = NULL;
+  nea_event_view_t *evv = NULL, *evv_maybe = NULL;
+  sip_time_t delta = 0, now = sip_now();
+  sip_expires_t expires[1] = { SIP_EXPIRES_INIT() };
+  sip_unsupported_t *unsupported;
+  sip_event_t const *o;
+  sip_accept_t const *ac = NULL, *accept = NULL;
+  sip_accept_t *a0 = NULL, *a, *a_next, **aa;
+  sip_accept_t accept_default[1];
+  unsigned proposed_throttle;
+  char const *type, *throttle;
+  int once, what, supported_eventlist, require_eventlist;
+
+  if (sip->sip_payload && !sip->sip_content_type) {
+    nta_incoming_treply(irq, 400, "Missing Content-Type", 
+			SIPTAG_SERVER_STR(nes->nes_server),
+			SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			SIPTAG_ALLOW(nes->nes_allow_methods),
+			TAG_NULL());
+    return 0;
+  }
+
+  if (sip->sip_expires && 
+      sip->sip_expires->ex_delta > 0 && 
+      sip->sip_expires->ex_delta < nes->nes_min_expires) {
+    sip_min_expires_t me[1]; 
+
+    sip_min_expires_init(me);
+
+    me->me_delta = nes->nes_min_expires;
+
+    nta_incoming_treply(irq, 423, "Subscription Interval Too Small", 
+			SIPTAG_ACCEPT(accept),
+			SIPTAG_MIN_EXPIRES(me),
+			SIPTAG_SERVER_STR(nes->nes_server),
+			SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			SIPTAG_ALLOW(nes->nes_allow_methods),
+			TAG_NULL());
+    return 0;
+  }
+
+  /* Check features */
+  if (nes->nes_require) {
+    unsupported = sip_has_unsupported2(nes->nes_home, 
+				       sip->sip_supported,
+				       sip->sip_require,
+				       nes->nes_require);
+
+    if (unsupported) {
+      nta_incoming_treply(irq, SIP_421_EXTENSION_REQUIRED, 
+			  SIPTAG_REQUIRE(nes->nes_require),
+			  SIPTAG_UNSUPPORTED(unsupported),
+			  SIPTAG_SERVER_STR(nes->nes_server),
+			  SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			  SIPTAG_ALLOW(nes->nes_allow_methods),
+			  TAG_NULL());
+      su_free(nes->nes_home, unsupported);
+
+      return 0;
+    }
+  }
+
+  supported_eventlist = sip_has_feature(sip->sip_supported, "eventlist");
+  require_eventlist = sip_has_feature(sip->sip_require, "eventlist");
+  supported_eventlist = supported_eventlist || require_eventlist;
+
+  if (s->s_id && (!sip->sip_event || 
+		  str0cmp(s->s_id->o_type, sip->sip_event->o_type) != 0 ||
+		  str0cmp(s->s_id->o_id, sip->sip_event->o_id))) {
+    /* Multiple subscriptions per dialog are not supported. */
+    return nta_incoming_treply(irq, 501, 
+			       "Multiple subscriptions not implemented", 
+			       SIPTAG_SERVER_STR(nes->nes_server),
+			       TAG_NULL());
+  }
+
+  /* Check that subscriber asks for a supported event  */
+  for (once = 0; ev == NULL ;once++) {
+    o = sip->sip_event;
+
+    /* Check that we have a matching event */
+    if (o && o->o_type) {
+      for (ev = nes->nes_events; ev; ev = ev->ev_next) {
+	if (strcmp(o->o_type, ev->ev_event->o_type) == 0) {
+	  ev_maybe = ev;
+
+	  if (ev->ev_eventlist) {
+	    if (supported_eventlist)
+	      break;
+	  } else {
+	    if (!supported_eventlist)
+	      break;
+	  }
+	}
+      }
+    }
+
+    if (!ev && !require_eventlist)
+      ev = ev_maybe;
+          
+    if (ev || once)
+      break;
+
+    /* Ask the application either to
+       1) add a new event or assing us an event/payload (0), 
+       2) take care of transaction (positive), or 
+       3) drop request (negative).
+    */
+    if ((what = nes_new_event_callback(nes, &ev, &evv, irq, sip)) < 0)
+      break;
+    if (what > 0) {
+      s->s_irq = NULL;
+      return 0;
+    }
+  }
+
+  if (ev_maybe == NULL && ev == NULL) {
+    nta_incoming_treply(irq, SIP_489_BAD_EVENT, 
+			SIPTAG_SERVER_STR(nes->nes_server),
+			SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			SIPTAG_ALLOW(nes->nes_allow_methods),
+			NULL);
+    return 0;
+  } else if (ev == NULL) {
+    ev = ev_maybe;
+
+    unsupported = sip_has_unsupported(nes->nes_home, ev->ev_supported,
+				      sip->sip_require);
+
+    nta_incoming_treply(irq, SIP_420_BAD_EXTENSION, 
+			SIPTAG_UNSUPPORTED(unsupported),
+			SIPTAG_REQUIRE(ev->ev_require),
+			SIPTAG_SUPPORTED(ev->ev_supported),
+			SIPTAG_SERVER_STR(nes->nes_server),
+			SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			SIPTAG_ALLOW(nes->nes_allow_methods),
+			TAG_NULL());
+
+    su_free(nes->nes_home, unsupported);
+
+    return 0;
+  }
+
+  if (sip->sip_accept)
+    accept = sip->sip_accept;
+  else if (evv && evv->evv_content_type) {
+    /* Generate accept header from event view specified by application */
+    sip_accept_init(accept_default);
+    accept_default->ac_type = evv->evv_content_type->c_type;
+    accept_default->ac_subtype = evv->evv_content_type->c_subtype;
+
+    accept = a0;
+  }
+  else
+    accept = ev->ev_default;
+
+  for (once = 0; evv == NULL ;once++) {
+    /* If there are multiple accept values with different Q values,
+       insertion sort by Q value */
+    for (ac = accept->ac_next; ac; ac = ac->ac_next) {
+      if (ac->ac_q != accept->ac_q) {
+	if ((a0 = sip_accept_dup(home, accept))) {
+	  /* Sort the accept list by Q values */
+	  for (a = a0, accept = NULL; a; a = a_next) {
+	    a_next = a->ac_next;
+	    
+	    for (aa = (sip_accept_t **)&accept; 
+		 *aa && sip_q_value((*aa)->ac_q) >= sip_q_value(a->ac_q); 
+		 aa = &(*aa)->ac_next)
+	      ;
+	    
+	    a->ac_next = *aa; *aa = a; 	/* Insert */
+	  }
+	}
+
+	break;
+      }
+    }
+
+    /* Check that subscriber asks for a supported content type */
+    for (ac = accept; ac; ac = ac->ac_next) {
+      int i;
+
+      if (ac->ac_type == NULL || ac->ac_subtype == NULL)
+	continue;
+      
+      /* Check all supported content types v. accept */
+      for (i = 0; (evv = ev->ev_views[i]); i++) {
+	assert(evv->evv_content_type && evv->evv_content_type->c_type);
+	
+	if (strcmp(ac->ac_type, "*/*") == 0)
+	  break;
+
+	type = evv->evv_content_type->c_type;
+
+	if ((strcasecmp(ac->ac_type, type) == 0) ||
+	    (strcasecmp(ac->ac_subtype, "*") == 0 &&
+	     strncasecmp(ac->ac_type, type, 
+			 ac->ac_subtype - ac->ac_type) == 0)) {
+	  if (evv_maybe == NULL)
+	    evv_maybe = evv;
+	}
+      }
+
+      if (evv)			/* Found */
+	break;
+    }
+
+    /* Free the sorted Accept list */
+    for (a = a0; a; a = a_next)
+      a_next = a->ac_next, su_free(home, a); 
+
+    if (!evv)
+      evv = evv_maybe;
+  
+    if (evv || once)
+      break;
+
+    /* Ask the application either to
+       1) add a new event view or assign us an event view (0), 
+       2) take care of transaction (positive), or 
+       3) drop request (negative).
+    */
+    if ((what = nes_new_event_callback(nes, &ev, &evv, irq, sip)) < 0)
+      break;
+    if (what > 0) {
+      s->s_irq = NULL;
+      return 0;
+    }
+  }
+
+  if (evv == NULL) {
+    SU_DEBUG_3(("nea_server: event %s rejected %u %s\n",
+		ev->ev_event->o_type, SIP_406_NOT_ACCEPTABLE));
+
+    /* There is no media acceptable to watcher */
+    return nta_incoming_treply(irq, SIP_406_NOT_ACCEPTABLE, 
+			       SIPTAG_ACCEPT(ev->ev_accept),
+			       SIPTAG_SERVER_STR(nes->nes_server),
+			       SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			       SIPTAG_ALLOW(nes->nes_allow_methods),
+			       TAG_NULL());
+  }
+
+  /* Do not change private view */
+  if (s->s_view && s->s_view->evv_primary == evv)
+    evv = s->s_view;
+
+  /* Set throttle */
+  if (sip->sip_event && 
+      (throttle = sip_params_find(sip->sip_event->o_params, "throttle="))) {
+    proposed_throttle = strtoul(throttle, NULL, 10);
+
+    if (proposed_throttle < evv->evv_min_throttle)
+      proposed_throttle = evv->evv_min_throttle;
+  } else
+    proposed_throttle = evv->evv_throttle;
+
+  s->s_throttle = proposed_throttle;
+
+  /* Update route, store remote contact */
+  nta_leg_server_route(leg, sip->sip_record_route, sip->sip_contact);
+  su_free(home, s->s_remote);
+  s->s_remote = sip_contact_dup(home, sip->sip_contact);
+
+  /* Store content-type and body */
+  if (sip->sip_content_type) {
+    su_free(home, s->s_content_type);
+    s->s_content_type = sip_content_type_dup(home, sip->sip_content_type);
+    su_free(home, s->s_payload);
+    s->s_payload = sip_payload_dup(home, sip->sip_payload);
+  }
+
+  /* Calculate expiration time for subscription */
+  delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date,
+			      nes->nes_expires, now);
+  if (delta > nes->nes_max_expires)
+    delta = nes->nes_max_expires;
+  expires->ex_delta = delta;
+
+  if (s->s_subscribed == 0)
+    s->s_subscribed = now;
+  s->s_expires = now + delta;
+  /* s->s_accept = sip_accept_dup(home, accept); */
+  if (s->s_id == NULL)
+    s->s_id = sip_event_dup(home, sip->sip_event);
+  s->s_event = ev;
+  s->s_eventlist = supported_eventlist;
+  nea_sub_assign_view(s, evv);
+  s->s_updated = evv->evv_updated - 1;  /* Force notify */
+
+  if (nes->nes_202_before_notify) {
+    nta_incoming_treply(irq, SIP_202_ACCEPTED, 
+			SIPTAG_SERVER_STR(nes->nes_server),
+			SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			SIPTAG_ALLOW(nes->nes_allow_methods),
+			SIPTAG_REQUIRE(ev->ev_require),
+			SIPTAG_SUPPORTED(ev->ev_supported),
+			SIPTAG_EXPIRES(expires),
+			SIPTAG_CONTACT(s->s_local),
+			TAG_END());
+    nta_incoming_destroy(irq), s->s_irq = irq = NULL;
+  }
+
+  /* Callback for checking subscriber authorization */
+  if (nes_watcher_callback(nes, ev, s, sip) < 0) {
+    if (irq) {
+      nta_incoming_treply(irq, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
+      nta_incoming_destroy(irq);
+    }
+    return -1;
+  }
+  
+  evv = s->s_view;  /* Callback can change event view */
+
+  if (s->s_state == nea_embryonic)
+    nea_sub_auth(s, nea_pending, NEATAG_FAKE(1), TAG_END());
+
+  if (s->s_updated != evv->evv_updated && !(irq && s->s_rejected))
+    nea_sub_notify(nes, s, now, TAG_END());
+
+  if (irq) {
+    if (s->s_rejected)
+      nta_incoming_treply(irq, SIP_403_FORBIDDEN, 
+			  SIPTAG_SERVER_STR(nes->nes_server),
+			  TAG_END());
+    else if (s->s_state == nea_active)
+      nta_incoming_treply(irq, SIP_200_OK, 
+			  SIPTAG_REQUIRE(ev->ev_require),
+			  SIPTAG_SUPPORTED(ev->ev_supported),
+			  SIPTAG_EXPIRES(expires),
+			  SIPTAG_SERVER_STR(nes->nes_server),
+			  SIPTAG_CONTACT(s->s_local),
+			  SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			  SIPTAG_ALLOW(nes->nes_allow_methods),
+			  TAG_END());
+    else
+      nta_incoming_treply(irq, SIP_202_ACCEPTED, 
+			  SIPTAG_REQUIRE(ev->ev_require),
+			  SIPTAG_SUPPORTED(ev->ev_supported),
+			  SIPTAG_EXPIRES(expires),
+			  SIPTAG_SERVER_STR(nes->nes_server),
+			  SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+			  SIPTAG_ALLOW(nes->nes_allow_methods),
+			  SIPTAG_CONTACT(s->s_local),
+			  TAG_END());
+  }
+
+  return 0;
+}
+
+/* ----------------------------------------------------------------- */
+/**Notify subscriber 
+ *
+ * The function nea_sub_notify() sends a notification to the subscriber. The
+ * event type is specified by subscriber event, payload type and payload in
+ * the event view. The responses to the NOTIFY transaction are
+ * processed by response_to_notify().
+ *
+ * @param nes pointer to the notifier object
+ * @param s   pointer to the subscription object
+ * @param now current SIP time (if 0, no body is sent, 
+ *            but updated Subscription-State header only
+ * @param tag,value,... tag list
+ *
+ */
+int nea_sub_notify(nea_server_t *nes, nea_sub_t *s, 
+		   sip_time_t now,
+		   tag_type_t tag, tag_value_t value, ...)
+{
+  int notified = 0;
+  ta_list ta;
+  int subscription_state_change = now == 0;
+  nea_event_t *ev = s->s_event;
+  nea_state_t substate = s->s_state;
+
+  if (s->s_pending_flush || (s->s_oreq && substate != nea_terminated)) {
+    if (ev && ev->ev_throttling > s->s_updated)
+      ev->ev_throttling = s->s_updated;
+    return 0;
+  }
+
+  if (s->s_oreq)
+    nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+
+  assert(s->s_view); assert(ev);
+
+  if (!subscription_state_change && s->s_view->evv_updated == s->s_updated) 
+    return 0;
+
+  if (now == 0)
+    now = sip_now();
+
+  if (s->s_notified + s->s_throttle > now &&
+      /* Do not throttle state termination notification */
+      substate != nea_terminated && 
+      (long)(s->s_expires - now) > 0) {
+    if (ev->ev_throttling > s->s_updated && !s->s_fake)
+      ev->ev_throttling = s->s_updated;
+    nes->nes_throttled++;
+    return 0;
+  }
+
+  ta_start(ta, tag, value);
+  {
+    sip_subscription_state_t ss[1];
+    char expires[32];
+    sip_param_t params[] = { NULL, NULL, NULL };
+    char const *reason = NULL;
+    int fake = 0;
+    char reason_buf[64];
+    unsigned retry_after = (unsigned)-1;
+    char retry_after_buf[64];
+    int i = 0;
+    nta_response_f *callback;
+    nea_event_view_t *evv = s->s_view;
+    nea_event_queue_t *evq, *n_evq;
+
+    assert(ev);
+
+    sip_subscription_state_init(ss);
+
+    tl_gets(ta_args(ta), 
+	    NEATAG_REASON_REF(reason),
+	    NEATAG_FAKE_REF(fake), /* XXX - semantics??? */
+	    NEATAG_RETRY_AFTER_REF(retry_after),
+	    TAG_END());
+
+    if (substate == nea_terminated) {
+      if (reason)
+	snprintf(reason_buf, sizeof(reason_buf), 
+		 "reason=%s", reason), params[i++] = reason_buf;
+      if (retry_after != (unsigned)-1)
+	snprintf(retry_after_buf, sizeof(retry_after_buf), 
+		 "retry-after=%u", retry_after), params[i++] = retry_after_buf;
+    }
+    else if ((long)(s->s_expires - now) <= 0) {
+      substate = nea_terminated;
+      params[i++] = "reason=timeout";
+    }
+    else {
+      snprintf(expires, sizeof(expires),
+	       "expires=%lu", (unsigned long)(s->s_expires - now));
+      params[i++] = expires;
+    }
+
+    ss->ss_params = params;
+
+    switch (substate) {
+    case nea_extended: ss->ss_substate = s->s_extended; break;
+    case nea_pending:  ss->ss_substate = "pending"; break;
+    case nea_active:   ss->ss_substate = "active"; break;
+    case nea_terminated: ss->ss_substate = "terminated"; break;
+      /* Do not send notifys for embryonic subscriptions */      
+    case nea_embryonic:
+      ta_end(ta);
+      return 0; 
+    }
+
+    callback = substate != nea_terminated ? response_to_notify : NULL;
+
+    for (evq = evv->evv_head; evq->evq_next; evq = evq->evq_next) {
+      if (evq->evq_next->evq_updated <= s->s_updated)
+	break;
+    }
+
+    subscription_state_change = (s->s_view->evv_updated == s->s_updated);
+
+    n_evq = evq->evq_payload ? evq : evv->evv_primary->evv_head;
+
+    s->s_oreq = 
+      nta_outgoing_tcreate(s->s_leg, 
+			   callback, s, NULL, 
+			   SIP_METHOD_NOTIFY, NULL,
+			   SIPTAG_SUBSCRIPTION_STATE(ss),
+			   SIPTAG_REQUIRE(ev->ev_require),
+			   SIPTAG_SUPPORTED(ev->ev_supported),
+			   SIPTAG_USER_AGENT_STR(nes->nes_server),
+			   SIPTAG_CONTACT(s->s_local),
+			   SIPTAG_EVENT(s->s_id),
+			   TAG_IF(!subscription_state_change, 
+				  SIPTAG_CONTENT_TYPE(n_evq->evq_content_type)),
+			   TAG_IF(!subscription_state_change,
+				  SIPTAG_PAYLOAD(n_evq->evq_payload)),
+			   ta_tags(ta)); 
+
+
+    notified = s->s_oreq != 0;
+
+    if (notified) {
+      s->s_notified = now;
+      s->s_state = substate; /* XXX - we need state for "waiting" */
+      s->s_latest = evq->evq_version;  /* Application version */
+      s->s_updated = evq->evq_updated; /* Internal version */
+      if (ev->ev_throttling > s->s_updated)
+	ev->ev_throttling = s->s_updated;
+    }
+
+    if (callback == NULL) {
+      nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+      /* Inform the application of a subscriber leaving the subscription. */
+      nes_watcher_callback(nes, ev, s, NULL);
+    }
+  }
+  ta_end(ta);
+
+  return notified;
+}
+
+/* ----------------------------------------------------------------- */
+/**Process responses to the NOTIFY.
+ * 
+ * The response_to_notify() processes the responses to the NOTIFY request. 
+ * If there was an error with delivering the NOTIFY, the subscription is
+ * considered terminated.
+ *
+ * @param s   pointer to subscription object
+ */
+int response_to_notify(nea_sub_t *s,
+		       nta_outgoing_t *oreq,
+		       sip_t const *sip)
+{
+  nea_server_t *nes = s->s_nes;
+  int status = sip->sip_status->st_status;
+
+  if (status < 200)
+    return 0;
+
+  nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+
+  if (status < 300) {
+    if (s->s_view->evv_updated != s->s_updated) {
+      sip_time_t now = sip_now();
+
+      if (s->s_notified + s->s_throttle <= now)
+	nea_sub_notify(nes, s, now, TAG_END());
+      else
+	nes->nes_throttled++;
+    }
+  }
+
+  if (s->s_state == nea_terminated || status >= 300) {
+    SU_DEBUG_5(("nea_server: removing subscriber " URL_PRINT_FORMAT "\n",
+		URL_PRINT_ARGS(s->s_from->a_url)));
+    /* Inform the application of a subscriber leaving the subscription. */
+    nes_watcher_callback(nes, s->s_event, s, NULL);
+  }
+
+  return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+/** Get number of active subscribers.
+ *
+ * The function nea_server_active() counts the number of active subscribers
+ * watching the specified view. If the view is not specified (@a ev is @c
+ * NULL), it counts the number of all subscribers.
+ *
+ * @param nes notifier
+ * @param ev  event
+ * 
+ * The function nea_server_active() returns number of active subscribers.
+ */
+int nea_server_active(nea_server_t *nes, nea_event_t const *ev)
+{
+  int n = 0;
+  nea_sub_t *s = NULL;
+
+  /* Count the number of subscribers watching this event */
+  for (s = nes->nes_subscribers; s ; s = s->s_next)
+    if (!s->s_pending_flush && s->s_state == nea_active 
+	&& (ev == NULL || ev == s->s_event))
+      n++;
+
+  return n;
+}
+
+/** Get number of non-embryonic subscribers.
+ *
+ * The function nea_server_non_embryonic() counts the number of pending,
+ * active or terminated subscribers watching the specified view. If the view
+ * is not specified (@a ev is @c NULL), it counts the number of all
+ * subscribers.
+ *
+ * @param nes notifier
+ * @param ev  event view
+ * 
+ * The function nea_server_active() returns number of active subscribers.
+ */
+int nea_server_non_embryonic(nea_server_t *nes, nea_event_t const *ev)
+{
+  int n = 0;
+  nea_sub_t *s = NULL;
+
+  /* Count the number of subscribers watching this event */
+  for (s = nes->nes_subscribers; s ; s = s->s_next)
+    if (!s->s_pending_flush && s->s_state != nea_embryonic 
+	&& (ev == NULL || ev == s->s_event))
+      n++;
+
+  return n;
+}
+
+/** Set application version number */
+int nea_sub_version(nea_sub_t *s, unsigned version)
+{
+  if (s)
+    return s->s_version = version;
+  return 0;
+}
+
+/** Authorize a subscription.
+ *
+ * Application can modify the subscription state and authorize the user.
+ * The subscription state has following simple state diagram:
+ *
+ * @code
+ *               +---------------+ +------------------+
+ *               |	         | |       	      |
+ * +-----------+ |  +---------+  V |  +------------+  V  +------------+
+ * | embryonic |-+->| pending |--+-+->| authorized |--+->| terminated |
+ * +-----------+    +---------+       +------------+     +------------+
+ *
+ * @endcode
+ *
+ * @TAGS
+ * IF NEATAG_VIEW(view) is included in tagged arguments, @a view is assigned
+ * to the subscriber and the content from the view is delivered to the
+ * subscriber.
+ *
+ * If NEATAG_FAKE(1) is included in tags, content marked as 'fake' is
+ * delivered to the subscriber.
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int nea_sub_auth(nea_sub_t *s, 
+		 nea_state_t state,
+		 tag_type_t tag, tag_value_t value, ...)
+{
+
+  ta_list ta;
+  int retval, embryonic, rejected = 0;
+  int fake = 0;
+  char const *reason = NULL;
+  nea_event_view_t *evv = NULL;
+
+  if (s == NULL)
+    return -1;
+  if (state == nea_embryonic)
+    return -1;
+  if (state < s->s_state)
+    return -1;
+
+  ta_start(ta, tag, value);
+
+  embryonic = s->s_state == nea_embryonic;
+
+  s->s_state = state;
+
+  if (tl_gets(ta_args(ta), NEATAG_VIEW_REF(evv), TAG_END()) && evv) {
+    nea_sub_assign_view(s, evv);
+  }
+  else {
+    if (tl_gets(ta_args(ta), NEATAG_FAKE_REF(fake), TAG_END()))
+      s->s_fake = fake;
+
+    if (s->s_view && s->s_view->evv_fake != s->s_fake) {
+      for (evv = s->s_view->evv_primary; evv; evv = evv->evv_next)
+	if (!evv->evv_private && evv->evv_fake == s->s_fake) {
+	  nea_sub_assign_view(s, evv);
+	  break;
+	}
+    }
+  }
+
+  tl_gets(ta_args(ta), NEATAG_REASON_REF(reason), TAG_END());
+  
+  rejected = reason && strcasecmp(reason, "rejected") == 0;
+  
+  if (state == nea_terminated && embryonic && rejected && s->s_irq)
+    retval = 0, s->s_rejected = 1;
+  else
+    retval = nea_sub_notify(s->s_nes, s, 0, ta_tags(ta));
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/** Obtain a list of subscribers */
+nea_subnode_t const **nea_server_get_subscribers(nea_server_t *nes, 
+						 nea_event_t const *ev)
+{
+  nea_sub_t *s;
+  nea_subnode_t **sn_list, *sn;
+  int i, n;
+  sip_time_t now = sip_now();
+
+  n = nea_server_non_embryonic(nes, ev);
+  if (n == 0)
+    return NULL;
+
+  sn_list = su_zalloc(nes->nes_home, 
+		      (n + 1) * sizeof(sn) + n * sizeof(*sn));
+  if (sn_list) {
+    sn = (nea_subnode_t *)(sn_list + n + 1);
+
+    for (i = 0, s = nes->nes_subscribers; s; s = s->s_next) {
+      if (!s->s_pending_flush && s->s_state != nea_embryonic 
+	  && (ev == NULL || ev == s->s_event)) {
+	assert(i < n);
+	nea_subnode_init(sn, s, now);
+	sn_list[i++] = sn++;
+      }
+    }
+
+    nes->nes_in_list++;
+
+    sn_list[i] = NULL;
+  }
+
+  return (nea_subnode_t const **)sn_list;
+}
+
+/** Free a list of subscriptions. */
+void nea_server_free_subscribers(nea_server_t *nes, 
+				 nea_subnode_t const **sn_list)
+{
+  if (sn_list) {
+    su_free(nes->nes_home, (void *)sn_list);
+    if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+      nea_server_pending_flush(nes);
+  }
+}
+
+/* ----------------------------------------------------------------- */
+void nes_event_timer(nea_server_t *srvr,
+		     su_timer_t *timer,
+		     su_timer_arg_t *arg)
+{
+  nea_server_t *nes = (nea_server_t *) arg;
+  sip_time_t now = sip_now();
+  nea_sub_t *s = NULL, *s_next = NULL;
+  su_root_t *root = su_timer_root(timer);
+
+  su_timer_set(timer, nes_event_timer, nes);
+
+  nes->nes_in_list++;
+
+  /* Notify and terminate expired subscriptions */
+  for (s = nes->nes_subscribers; s; s = s_next) {
+    s_next = s->s_next;
+    if (s->s_state == nea_terminated)
+      continue;
+    if ((int)(now - s->s_expires) >= 0) {
+      nea_sub_notify(nes, s, now, TAG_END());
+      /* Yield so we can handle received packets */
+      su_root_yield(root);
+    }
+  }
+
+  if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+    nea_server_pending_flush(nes);
+
+  if (nes->nes_throttled)
+    nea_server_notify(nes, NULL);
+
+  return;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea_tag.c
+ * @brief Tags for Nokia SIP Transaction API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nea"
+
+#include "sofia-sip/nea.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+tag_typedef_t neatag_any = NSTAG_TYPEDEF(*);
+tag_typedef_t neatag_min_expires = UINTTAG_TYPEDEF(min_expires);
+tag_typedef_t neatag_expires = UINTTAG_TYPEDEF(expires);
+tag_typedef_t neatag_max_expires = UINTTAG_TYPEDEF(max_expires);
+tag_typedef_t neatag_throttle = UINTTAG_TYPEDEF(throttle);
+tag_typedef_t neatag_minthrottle = UINTTAG_TYPEDEF(minthrottle);
+tag_typedef_t neatag_dialog = PTRTAG_TYPEDEF(dialog);
+tag_typedef_t neatag_eventlist = BOOLTAG_TYPEDEF(eventlist);
+tag_typedef_t neatag_fake = BOOLTAG_TYPEDEF(fake);
+tag_typedef_t neatag_reason = STRTAG_TYPEDEF(reason);
+tag_typedef_t neatag_retry_after = UINTTAG_TYPEDEF(retry_after);
+tag_typedef_t neatag_exstate = STRTAG_TYPEDEF(exstate);
+tag_typedef_t neatag_version = INTTAG_TYPEDEF(version);
+tag_typedef_t neatag_view = PTRTAG_TYPEDEF(view);
+tag_typedef_t neatag_evmagic = PTRTAG_TYPEDEF(evmagic);
+tag_typedef_t neatag_reliable = BOOLTAG_TYPEDEF(reliable);
+tag_typedef_t neatag_sub = PTRTAG_TYPEDEF(sub);
+
+tag_typedef_t neatag_strict_3265 = BOOLTAG_TYPEDEF(strict_3265);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,378 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_H
+/** Defined when <sofia-sip/nea.h> has been included. */
+#define NEA_H
+/**@file sofia-sip/nea.h
+ * @brief Event API for SIP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Feb  7 13:23:44 EET 2003 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <sofia-sip/su_tag.h>
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+#ifndef NEA_TAG_H
+#include <sofia-sip/nea_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define NEA_VERSION      3.0
+#define NEA_VERSION_STR "3.0"
+
+#define NEA_DEFAULT_EXPIRES 3600
+
+/** Event notifier object. */
+typedef struct nea_server_s     nea_server_t;
+
+/** Subscription object. */
+typedef struct nea_sub_s        nea_sub_t;
+
+/** Event. */
+typedef struct nea_event_s      nea_event_t;
+
+/** Event view. */
+typedef struct nea_event_view_s nea_event_view_t;
+
+#ifndef NEA_SMAGIC_T 
+#define NEA_SMAGIC_T            struct nea_smagic_t
+#endif
+/** NEA server context */
+typedef NEA_SMAGIC_T nea_smagic_t;
+
+#ifndef NEA_EMAGIC_T 
+#define NEA_EMAGIC_T            struct nea_emagic_t
+#endif
+/** NEA server event context */
+typedef NEA_EMAGIC_T nea_emagic_t;
+
+#ifndef NEA_EVMAGIC_T 
+#define NEA_EVMAGIC_T           struct nea_evmagic_t
+#endif
+/** Event view context */
+typedef NEA_EVMAGIC_T nea_evmagic_t;
+
+/** Description of subscription */
+typedef struct nea_subnode_t {
+  nea_state_t          sn_state;       	/**< Subscription state */
+  unsigned             sn_fake;	       	/**< True if subscriber is given 
+				       	 *   fake contents.
+				       	 */
+  unsigned             sn_eventlist;    /**< Subscriber supports eventlist */
+  nea_sub_t           *sn_subscriber;  	/**< Pointer to subscriber object */
+  nea_event_t         *sn_event;       	/**< Event */
+  sip_from_t const    *sn_remote;      	/**< Identity of subscriber */
+  sip_contact_t const *sn_contact;     	/**< Contact of subscriber */
+
+  /** Content-Type of SUBSCRIBE body (filter). */
+  sip_content_type_t const *sn_content_type; 
+  sip_payload_t const *sn_payload;      /**< Body of subscribe*/
+
+  unsigned             sn_expires;     	/**< When subscription expires */
+  unsigned             sn_latest;      	/**< Latest notification version */
+  unsigned             sn_throttle;    	/**< Throttle value */
+  unsigned             sn_version;      /**< Latest notified version # by application */
+  sip_time_t           sn_notified;     /**< When latest notify was sent */
+  sip_time_t           sn_subscribed;   /**< When first SUBSCRIBE was recv */
+  nea_event_view_t    *sn_view;		/**< Event view for this subscriber */
+} nea_subnode_t;
+
+/** Multiple content types per event. */
+typedef struct nea_payloads_s   nea_payloads_t;
+
+/**Unknown event callback.
+ *
+ * The event server invokes this callback function when it has received a
+ * request for an unknown event or event with unknown content type.
+ *
+ * The callback may be called twice for one watcher, once for an unknown
+ * event, another time for an unknown content type.
+ *
+ * @retval 1 application takes care of responding to request
+ * @retval 0 application has added new event or payload format
+ * @retval -1 nea server rejects request 
+ */
+typedef int (nea_new_event_f)(nea_smagic_t *context,
+			      nea_server_t *nes,
+			      nea_event_t **event_p,
+			      nea_event_view_t **view_p,
+			      nta_incoming_t *irq,
+			      sip_t const *sip);
+
+/** Create a notifier server */
+SOFIAPUBFUN
+nea_server_t *nea_server_create(nta_agent_t *agent,
+				su_root_t *root,
+				url_t const *url,
+				int max_subs,
+				nea_new_event_f *callback,
+				nea_smagic_t *context,
+				tag_type_t tag, tag_value_t value,
+				...);
+
+
+/** Shutdown an event server */
+SOFIAPUBFUN int nea_server_shutdown(nea_server_t *nes, int retry_after);
+
+/** Destroy a server */
+SOFIAPUBFUN void nea_server_destroy(nea_server_t *nes);
+
+/** Zap terminated subscribtions. */
+SOFIAPUBFUN void nea_server_flush(nea_server_t *nes, nea_event_t *event);
+
+/** Update event information */
+SOFIAPUBFUN
+int nea_server_update(nea_server_t *nes,
+		      nea_event_t *ev,
+		      tag_type_t tag,
+		      tag_value_t value,
+		      ...);
+
+/** Add a new subscriber from subscribe transaction to an existing notifier. */
+SOFIAPUBFUN
+int nea_server_add_irq(nea_server_t *nes,
+		       nta_leg_t *leg,
+		       sip_contact_t const *local_target,
+		       nta_incoming_t *irq, 
+		       sip_t const *sip);
+
+/** QAUTH callback function type.
+ *
+ * The event server invokes this callback function upon each incoming
+ * SUBSCRIBE transaction when the subscription has expired.  The @a sip is
+ * NULL if the subscription has expired.
+ *
+ * The application determines if the subscription is authorized and relays
+ * the decision to event server via nea_server_auth() function.
+ */
+typedef void (nea_watcher_f)(nea_server_t *nes,
+			     nea_emagic_t *context,
+			     nea_event_t *event,
+			     nea_subnode_t *subnode,
+			     sip_t const *sip);
+
+/** Create a new event (or subevent) */
+SOFIAPUBFUN
+nea_event_t *nea_event_create(nea_server_t *nes,
+			      nea_watcher_f *callback,
+			      nea_emagic_t *context,
+			      char const *name, 
+			      char const *subname,
+			      char const *default_content_type,
+			      char const *accept);
+
+/** Create a new event (or subevent) with tags */
+SOFIAPUBFUN
+nea_event_t *nea_event_tcreate(nea_server_t *nes,
+			       nea_watcher_f *callback,
+			       nea_emagic_t *context,
+			       char const *name, 
+			       char const *subname,
+			       tag_type_t, tag_value_t, ...);
+
+/** Return magic context bind to nea_event */
+SOFIAPUBFUN nea_emagic_t *nea_emagic_get(nea_event_t *event);
+
+/** Find a nea event object with given event name */
+SOFIAPUBFUN nea_event_t *nea_event_get(nea_server_t const *, char const *name);
+
+/** Get number of active subscribers */
+SOFIAPUBFUN int nea_server_active(nea_server_t *nes, nea_event_t const *ev);
+
+/** Get number of (non-embryonic) subscribers. */
+int nea_server_non_embryonic(nea_server_t *nes, nea_event_t const *ev);
+
+/** Obtain a list of subscriptions. 
+ */
+SOFIAPUBFUN
+nea_subnode_t const **nea_server_get_subscribers(nea_server_t *nes, 
+						 nea_event_t const *ev);
+
+/** Free a list of subscriptions. */
+SOFIAPUBFUN
+void nea_server_free_subscribers(nea_server_t *nes, nea_subnode_t const **);
+
+/** Notify subscribers */
+SOFIAPUBFUN
+int nea_server_notify(nea_server_t *nes, 
+		      nea_event_t *ev);
+
+/** Notify a subscriber */
+SOFIAPUBFUN
+int nea_server_notify_one(nea_server_t *nes, 
+			  nea_event_t *ev,
+			  nea_sub_t *ns);
+
+#define nea_server_auth nea_sub_auth
+
+/** Get nta_incoming_t from nea_sub_t */
+SOFIAPUBFUN nta_incoming_t *nea_sub_get_request(nea_sub_t *sub);
+
+/** Authorize a subscription */
+SOFIAPUBFUN
+int nea_sub_auth(nea_sub_t *, nea_state_t state,
+		 tag_type_t, tag_value_t, ...);
+
+/** Get nta_incoming_t from sn->sn_subscriber */
+SOFIAPUBFUN nta_incoming_t *nea_subnode_get_incoming(nea_subnode_t *sn);
+/** Set subscriber version sequence */
+SOFIAPUBFUN int nea_sub_version(nea_sub_t *, unsigned);
+
+/** Return time until next notification can be sent */
+SOFIAPUBFUN unsigned nea_sub_pending(nea_sub_t const *);
+
+#if 0
+/** Do a remote qauth.
+ *
+ * The function nea_server_qauth() is given as q_callback pointer 
+ * to nea_server_create() if remote authentication from url is desired.
+ */
+void nea_server_qauth(nea_server_t *nes, 
+		      nea_emagic_t *context,
+		      nea_sub_t *subscriber, 
+		      sip_t const *sip);
+#endif
+
+/** Get primary event view for given content type  */
+SOFIAPUBFUN
+nea_event_view_t *nea_event_view(nea_event_t *, char const *content_type);
+
+/** Get a content type for event's payload */
+SOFIAPUBFUN
+sip_content_type_t const *nea_view_content_type(nea_event_view_t const *);
+
+/** Get actual payload for an event */
+SOFIAPUBFUN sip_payload_t const *nea_view_payload(nea_event_view_t *);
+
+/** Create a private event view */
+SOFIAPUBFUN nea_event_view_t *nea_view_create(nea_server_t *nes,
+					      nea_event_t *ev,
+					      nea_evmagic_t *magic,
+					      tag_type_t tag,
+					      tag_value_t value,
+					      ...);
+
+/** Destroy a private event view */
+SOFIAPUBFUN void nea_view_destroy(nea_server_t *nes, nea_event_view_t *ev);
+
+SOFIAPUBFUN nea_evmagic_t *nea_view_magic(nea_event_view_t const *);
+
+SOFIAPUBFUN void nea_view_set_magic(nea_event_view_t *, nea_evmagic_t *magic);
+
+SOFIAPUBFUN unsigned nea_view_version(nea_event_view_t const *);
+
+/** Reliable notify */
+#define NEATAG_RELIABLE(x)    neatag_reliable, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_reliable;
+
+#define NEATAG_RELIABLE_REF(x) neatag_reliable_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_reliable_ref;
+
+/** Event view handle */
+#define NEATAG_VIEW(x)     neatag_view, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_view;
+
+#define NEATAG_VIEW_REF(x) neatag_view_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_view_ref;
+
+/** Event view magic. */
+#define NEATAG_EVMAGIC(x)     neatag_evmagic, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_evmagic;
+
+#define NEATAG_EVMAGIC_REF(x) neatag_evmagic_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_evmagic_ref;
+
+/** tag for nea_sub_t */
+#define NEATAG_SUB(x)     neatag_sub, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_sub;
+
+#define NEATAG_SUB_REF(x) neatag_sub_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_sub_ref;
+
+
+/* ====================================================================== */
+/* Watcher side */
+
+/** NEA Event Watcher */
+typedef struct nea_s     nea_t;
+
+#ifndef NEA_MAGIC_T 
+#define NEA_MAGIC_T struct nea_magic_t
+#endif
+
+/** NEA Event Agent context */
+typedef NEA_MAGIC_T          nea_magic_t;
+
+/** Event notification callback type.
+ * 
+ * This callback is called also when initial or refresh subscribe transaction
+ * completes with the transaction result in @a sip.
+ */
+typedef int (*nea_notify_f)(nea_t *nea,
+			    nea_magic_t *context,
+			    sip_t const *sip);
+
+/* ====================================================================== */
+/* Client side */
+
+/** Create a subscription agent. */
+SOFIAPUBFUN
+nea_t *nea_create(nta_agent_t *agent,
+		  su_root_t *root,
+		  nea_notify_f no_callback,
+		  nea_magic_t *context,
+		  tag_type_t tag,
+		  tag_value_t value,
+		  ...);
+
+/** Update SUBSCRIBE payload (filter rules) */
+SOFIAPUBFUN
+int nea_update(nea_t *nea, 
+	       tag_type_t tag,
+	       tag_value_t value,
+	       ...);
+
+/** Unsubscribe agent. */
+SOFIAPUBFUN void nea_end(nea_t *agent);
+
+/** Destroy a subscription agent. */
+SOFIAPUBFUN void nea_destroy(nea_t *agent);
+
+SOFIAPUBFUN char const *nea_default_content_type(char const *event);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(NEA_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_TAG_H
+/** Defined when <sofia-sip/nea_tag.h> has been included. */
+#define NEA_TAG_H
+
+/**@file sofia-sip/nea_tag.h
+ * @brief Tags for Nokia User Agent Library
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Mon Nov 28 18:54:26 EET 2005 mela
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Event states */
+typedef enum {
+  nea_extended = -1,
+  nea_embryonic = 0,		/** Before first notify */
+  nea_pending,
+  nea_active,
+  nea_terminated
+} nea_state_t;
+
+/** Filter tag matching any nea tag. */
+#define NEATAG_ANY()         neatag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t neatag_any;
+
+/** Specify the minimum duration of a subscription (by default, 15 minutes) */
+#define NEATAG_MIN_EXPIRES(x) neatag_min_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_min_expires;
+
+#define NEATAG_MIN_EXPIRES_REF(x) neatag_min_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_min_expires_ref;
+
+#define NEATAG_MINSUB(x) neatag_min_expires, tag_uint_v((x))
+#define NEATAG_MINSUB_REF(x) neatag_min_expires_ref, tag_uint_vr((&x))
+
+/** Specify the default duration of a subscription (by default, 60 minutes) */
+#define NEATAG_EXPIRES(x) neatag_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_expires;
+
+#define NEATAG_EXPIRES_REF(x) neatag_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_expires_ref;
+
+/** Specify the maximum duration of a subscription (by default, 24 hours) */
+#define NEATAG_MAX_EXPIRES(x) neatag_max_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_max_expires;
+
+#define NEATAG_MAX_EXPIRES_REF(x) neatag_max_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_max_expires_ref;
+
+/** Indicate/require support for "eventlist" feature. */
+#define NEATAG_EVENTLIST(x)  neatag_eventlist, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_eventlist;
+
+#define NEATAG_EVENTLIST_REF(x) neatag_eventlist_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_eventlist_ref;
+
+/** Specify the default throttle value for subscription. */
+#define NEATAG_THROTTLE(x) neatag_throttle, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_throttle;
+
+#define NEATAG_THROTTLE_REF(x) neatag_throttle_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_throttle_ref;
+
+/** Specify the minimum throttle value for subscription. */
+#define NEATAG_MINTHROTTLE(x) neatag_minthrottle, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_minthrottle;
+
+#define NEATAG_MINTHROTTLE_REF(x) neatag_minthrottle_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_minthrottle_ref;
+
+/** Specify dialog handle */
+#define NEATAG_DIALOG(x)     neatag_dialog, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_dialog;
+
+#define NEATAG_DIALOG_REF(x) neatag_dialog_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_dialog_ref;
+
+/* Server-specific tags */
+
+/** Pass pointer to subscription */
+#define NEATAG_SUB(x)        neatag_sub, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_sub;
+
+#define NEATAG_SUB_REF(x)    neatag_sub_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_sub_ref;
+
+/** Use fake content. @sa nea_sub_auth() and nea_server_update(). */
+#define NEATAG_FAKE(x)    neatag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_fake;
+
+#define NEATAG_FAKE_REF(x) neatag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_fake_ref;
+
+/** Specify reason for termination */
+#define NEATAG_REASON(x)     neatag_reason, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_reason;
+
+#define NEATAG_REASON_REF(x) neatag_reason_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_reason_ref;
+
+/** Specify retry-after for termination */
+#define NEATAG_RETRY_AFTER(x)    neatag_retry_after, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_retry_after;
+
+#define NEATAG_RETRY_AFTER_REF(x) neatag_retry_after_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_retry_after_ref;
+
+/** Specify extended state for subscription-state */
+#define NEATAG_EXSTATE(x)    neatag_exstate, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_exstate;
+
+#define NEATAG_EXSTATE_REF(x) neatag_exstate_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_exstate_ref;
+
+/** Do not try to conform pre-3265 notifiers/watchers */
+#define NEATAG_STRICT_3265(x)    neatag_strict_3265, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_strict_3265;
+
+#define NEATAG_STRICT_3265_REF(x) neatag_strict_3265_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_strict_3265_ref;
+
+/** Version number of content */
+#define NEATAG_VERSION(x) neatag_version, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_version;
+
+#define NEATAG_VERSION_REF(x) neatag_version_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_version_ref;
+
+/** List of all NEA tags. */
+/* extern tag_type_t nea_tag_list[]; */
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Renamed nta_test.c as test_nta.c.
+
+2005-10-21  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed server-rport feature in nta.c.
+
+    M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+  * Fixed agent_init_contact() in nta/nta.c.
+  The logic for selecting transport parameter for primary contact was flawed.
+  Added some tests, too.
+
+    M ./libsofia-sip-ua/nta/nta.c -9 +20
+    M ./libsofia-sip-ua/nta/nta_test.c +54
+
+2005-10-15  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fix callerpref bug #1326727.
+
+  Copying Accept-Contact, Reject-Contact, and Request-Disposition from
+  original request to ACK/CANCEL.
+
+    M ./libsofia-sip-ua/nta/nta.c -1 +5
+
+  * Fixed socket() if AF_INET6 is used.
+
+    M ./libsofia-sip-ua/nta/nta_test.c -3 +3
+
+  * Removed Last modified.
+
+    M ./libsofia-sip-ua/nta/nta.c -1
+    M ./libsofia-sip-ua/nta/nta.h -1
+    M ./libsofia-sip-ua/nta/nta_compat.c -1
+    M ./libsofia-sip-ua/nta/nta_compat.h -1
+    M ./libsofia-sip-ua/nta/nta_dll.h -1
+    M ./libsofia-sip-ua/nta/nta_internal.h -1
+    M ./libsofia-sip-ua/nta/nta_stateless.h -1
+    M ./libsofia-sip-ua/nta/nta_tag.c -1
+    M ./libsofia-sip-ua/nta/nta_tag.h -1
+    M ./libsofia-sip-ua/nta/nta_test.c -1
+    M ./libsofia-sip-ua/nta/nta_tport.h -1
+    M ./libsofia-sip-ua/nta/portbind.c -1
+    M ./libsofia-sip-ua/nta/sl_read_payload.c -1
+    M ./libsofia-sip-ua/nta/sl_utils.h -1
+    M ./libsofia-sip-ua/nta/sl_utils_log.c -1
+    M ./libsofia-sip-ua/nta/sl_utils_print.c -1
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Contact generated by nta now contains URL transport parameter.
+  The transport=UDP was left out from contact URL always. Now it is left out
+  only if both UDP and TCP are supported.
+  Added utility function sip_contact_create_from_via_with_transport().
+
+    M ./libsofia-sip-ua/nta/nta.c -2 +14
+    M ./libsofia-sip-ua/sip/sip_util.c -10 +28
+    M ./libsofia-sip-ua/sip/sip_util.h +6
+
+2005-10-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed memory leak in nta_agent_create()/nta_agent_destroy().
+
+    M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+2005-10-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added agent.pem and cafile.pem for TLS testing.
+
+2005-08-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* nta.c (nta_agent_set_params()): Returning -1 upon an error.
+
+2005-08-26  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* nta.c, nta_test.c: Fixed alias usage.
+
+2005-08-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Now we can start agent without any transport interfaces.
+
+	Added flag for disabling server-side rport.
+
+2005-08-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Fixed running tests on IPv6. Added portbind.
+
+2005-07-14  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* nta_internal.h, nta_tag.h, nta_tag.c, nta.c: Added bitmasks for
+	detecting parsing errors.
+
+	* nta.c: Accept CANCELs for non-INVITEs, too.
+
+2005-07-20  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* run_nta_test: Fixed portbind/bind test.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+PROJECT_NAME         = "nta"
+OUTPUT_DIRECTORY     = ../docs/html/nta
+
+INPUT 		     = nta.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES           += ../docs/su.doxytags=../su
+TAGFILES           += ../docs/ipt.doxytags=../ipt
+TAGFILES           += ../docs/bnf.doxytags=../bnf
+TAGFILES           += ../docs/url.doxytags=../url
+TAGFILES           += ../docs/msg.doxytags=../msg
+TAGFILES           += ../docs/sip.doxytags=../sip
+TAGFILES           += ../docs/sresolv.doxytags=../sresolv
+TAGFILES           += ../docs/tport.doxytags=../tport
+
+GENERATE_TAGFILE    = ../docs/nta.doxytags
+
+EXCLUDE_PATTERNS   += sl_*.h sl_*.c nta_compat.*
+
+ALIASES            +=
+
+ at INCLUDE = ../sip/sip.doxyaliases
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,79 @@
+#
+# Makefile.am for nta module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../sresolv -I../sresolv \
+			-I$(srcdir)/../tport -I../tport \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../features -I../features \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libnta.la
+
+check_PROGRAMS = 	test_nta_api test_nta portbind
+dist_noinst_SCRIPTS =	run_test_nta_api run_test_nta
+
+TESTS =			run_test_nta_api run_test_nta
+TESTS_ENVIRONMENT =	$(SHELL) 
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		nta_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nta.h sofia-sip/nta_stateless.h \
+			sofia-sip/nta_tport.h sofia-sip/nta_tag.h \
+			sofia-sip/sl_utils.h 
+
+libnta_la_SOURCES = 	nta.c nta_check.c nta_tag.c nta_tag_ref.c \
+			nta_internal.h \
+			sl_utils_print.c sl_utils_log.c \
+			sl_read_payload.c
+
+COVERAGE_INPUT = 	$(libnta_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libnta.la \
+			../ipt/libipt.la \
+			../sip/libsip.la \
+			../features/libfeatures.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../http/libhttp.la \
+			../stun/libstun.la \
+			../url/liburl.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nta_LDFLAGS = 	-static
+
+MOSTLYCLEANFILES +=	.test[0-9]*
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile nta.docs sl_utils.docs \
+			agent.pem cafile.pem \
+			invite.msc $(BUILT_SOURCES) 
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+# Generate list of nta tags
+TAG_DLL_FLAGS = 	LIST=nta_tag_list
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,763 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nta module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libnta_la_SOURCES) portbind.c test_nta.c test_nta_api.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_nta_api$(EXEEXT) test_nta$(EXEEXT) \
+	portbind$(EXEEXT)
+DIST_COMMON = $(dist_noinst_SCRIPTS) $(nobase_include_sofia_HEADERS) \
+	$(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nta
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnta_la_LIBADD =
+am_libnta_la_OBJECTS = nta.lo nta_check.lo nta_tag.lo nta_tag_ref.lo \
+	sl_utils_print.lo sl_utils_log.lo sl_read_payload.lo
+libnta_la_OBJECTS = $(am_libnta_la_OBJECTS)
+portbind_SOURCES = portbind.c
+portbind_OBJECTS = portbind.$(OBJEXT)
+portbind_LDADD = $(LDADD)
+portbind_DEPENDENCIES = libnta.la ../ipt/libipt.la ../sip/libsip.la \
+	../features/libfeatures.la ../sresolv/libsresolv.la \
+	../tport/libtport.la ../http/libhttp.la ../stun/libstun.la \
+	../url/liburl.la ../msg/libmsg.la ../bnf/libbnf.la \
+	../su/libsu.la
+test_nta_SOURCES = test_nta.c
+test_nta_OBJECTS = test_nta.$(OBJEXT)
+test_nta_LDADD = $(LDADD)
+test_nta_DEPENDENCIES = libnta.la ../ipt/libipt.la ../sip/libsip.la \
+	../features/libfeatures.la ../sresolv/libsresolv.la \
+	../tport/libtport.la ../http/libhttp.la ../stun/libstun.la \
+	../url/liburl.la ../msg/libmsg.la ../bnf/libbnf.la \
+	../su/libsu.la
+test_nta_api_SOURCES = test_nta_api.c
+test_nta_api_OBJECTS = test_nta_api.$(OBJEXT)
+test_nta_api_LDADD = $(LDADD)
+test_nta_api_DEPENDENCIES = libnta.la ../ipt/libipt.la \
+	../sip/libsip.la ../features/libfeatures.la \
+	../sresolv/libsresolv.la ../tport/libtport.la \
+	../http/libhttp.la ../stun/libstun.la ../url/liburl.la \
+	../msg/libmsg.la ../bnf/libbnf.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libnta_la_SOURCES) portbind.c test_nta.c test_nta_api.c
+DIST_SOURCES = $(libnta_la_SOURCES) portbind.c test_nta.c \
+	test_nta_api.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@ .test[0-9]*
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = $(SHELL) 
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../sresolv -I../sresolv \
+			-I$(srcdir)/../tport -I../tport \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../features -I../features \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnta.la
+dist_noinst_SCRIPTS = run_test_nta_api run_test_nta
+TESTS = run_test_nta_api run_test_nta
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nta_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nta.h sofia-sip/nta_stateless.h \
+			sofia-sip/nta_tport.h sofia-sip/nta_tag.h \
+			sofia-sip/sl_utils.h 
+
+libnta_la_SOURCES = nta.c nta_check.c nta_tag.c nta_tag_ref.c \
+			nta_internal.h \
+			sl_utils_print.c sl_utils_log.c \
+			sl_read_payload.c
+
+COVERAGE_INPUT = $(libnta_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnta.la \
+			../ipt/libipt.la \
+			../sip/libsip.la \
+			../features/libfeatures.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../http/libhttp.la \
+			../stun/libstun.la \
+			../url/liburl.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nta_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nta.docs sl_utils.docs \
+			agent.pem cafile.pem \
+			invite.msc $(BUILT_SOURCES) 
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+# Generate list of nta tags
+TAG_DLL_FLAGS = LIST=nta_tag_list
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/nta/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/nta/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnta.la: $(libnta_la_OBJECTS) $(libnta_la_DEPENDENCIES) 
+	$(LINK)  $(libnta_la_LDFLAGS) $(libnta_la_OBJECTS) $(libnta_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+portbind$(EXEEXT): $(portbind_OBJECTS) $(portbind_DEPENDENCIES) 
+	@rm -f portbind$(EXEEXT)
+	$(LINK) $(portbind_LDFLAGS) $(portbind_OBJECTS) $(portbind_LDADD) $(LIBS)
+test_nta$(EXEEXT): $(test_nta_OBJECTS) $(test_nta_DEPENDENCIES) 
+	@rm -f test_nta$(EXEEXT)
+	$(LINK) $(test_nta_LDFLAGS) $(test_nta_OBJECTS) $(test_nta_LDADD) $(LIBS)
+test_nta_api$(EXEEXT): $(test_nta_api_OBJECTS) $(test_nta_api_DEPENDENCIES) 
+	@rm -f test_nta_api$(EXEEXT)
+	$(LINK) $(test_nta_api_LDFLAGS) $(test_nta_api_OBJECTS) $(test_nta_api_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_check.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/portbind.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_read_payload.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_utils_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_utils_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nta.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nta_api.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,159 @@
+#
+# MSCs Illustrating NTA Usage
+#
+
+User Agent Client Initiating a Call
+-----------------------------------
+
+                    APP ¦ NTA
+User                    ¦
+Agent                   ¦
+ |                      ¦
+ | nta = nta_agent_create
+ |- - - - - - - - - - - - - - - - -> NTA
+ | (msg_cb, contact)    ¦           agent
+ |                      ¦             |
+ |                      ¦             |
+ |- - ->Call            ¦             |
+ |        |             ¦             |
+ |        | leg = nta_leg_create      |
+ |        |- - - - - - -¦- - - - - - -|- - - -> leg
+ |        |(nta, leg_cb, ..., To, From, ... )    |
+ |        |             ¦             |          |
+ |        |             ¦             |          |
+ |        | oreq = nta_outgoing_create|          |
+ |        |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ |        |       (leg, response_cb, INVITE, url, headers...) |
+ |        |             ¦             |          |            |
+ |        |             ¦             |          |	      | INVITE
+ |        |             ¦             |          |	      |---->
+ |        |             ¦             |          |            |
+ |        |             ¦             |          |            | 100 Trying
+ |        |             ¦             |          |            |<----
+ |        |             ¦             |          |            |
+ |        |             ¦             |          |            | 180 Ringing
+ |        |             ¦             |      response_cb(180) |<----
+ |  ALERT |<--------------------------|----------|------------|
+ |<-------|             ¦             |          |            | 200 OK
+ |        |             ¦             |      response_cb(200) |<----
+ |OFFHOOK |<--------------------------|----------|------------|
+ |<-------|             ¦             |          |            |
+ |        | nta_outgoing_destroy      |          |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            X
+ |        | nta_leg_destroy           |          |
+ |        |---------------------------|--------->|
+ |        |             ¦             |          X
+ |        | leg = nta_leg_create      |
+ |        |- - - - - - -¦- - - - - - -|- - - -> leg
+ |        |(nta, leg_cb, ..., To+tag, From, ...) |
+ |        |             ¦             |          |
+ |        | oreq = nta_outgoing_create|          |
+ |        |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ |        | (leg, ..., ACK, url, headers)        |            |
+ |        |             ¦             |          |            | ACK
+ |        |             ¦             |          |            |---->
+ |        | nta_outgoing_destroy      |          |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            X
+
+
+User Agent Client Releasing a Call
+-----------------------------------
+
+                    APP ¦ NTA
+User    Call            ¦            NTA        leg
+Agent     |             ¦           agent        |
+ |        |             ¦             |          |
+ |ONHOOK  |             ¦             |          |
+ |------->|             ¦             |          |
+ |        |oreq = nta_outgoing_create |          |
+ |        |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ |        | (leg, ..., BYE, url, headers)        |            |
+ |        |             ¦             |          |            | BYE
+ |        |             ¦             |          |            |---->
+ |        |             ¦             |          |            |
+ |        |             ¦             |          |            | 180 Ringing
+ |        |             ¦             |      response_cb(180) |<----
+ |        |<--------------------------|----------|------------|
+ |        |             ¦             |          |            | 200 OK
+ |        |             ¦             |      response_cb(200) |<----
+ |        |<--------------------------|----------|------------|
+ |        |             ¦             |          |            |
+ |        |nta_outgoing_destroy       |          |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            X
+ |        |nta_leg_destroy            |          |
+ |        |---------------------------|--------->|
+ |        |             ¦             |          X
+ |        X             ¦             |          
+
+
+User Agent Server Accepting a Call
+----------------------------------
+
+                    APP ¦ NTA
+User                  	¦	     NTA 
+Agent                 	¦	    agent
+ |                      ¦             |                INVITE
+ |			¦             |<----------------------
+ |                      ¦             |
+ |                   msg_cb(leg, msg) |
+ |<-----------------------------------|
+ |                      ¦             |
+ |- - -> Call           ¦             |
+ |        | nta_msg_leg ¦             |
+ |        |-------------------------->|- - - -> leg
+ |        | (msg, request_cb)         |          |
+ |        |             ¦             |          |- - - -> incoming
+ |        | nta_leg_tag ¦             |          |            |
+ |        |---------------------------|--------->|            |
+ |        | (tag)       ¦             |          |            |
+ |        |             ¦             |     request_cb(reply) |
+ |        |<--------------------------|----------|------------|
+ |        |             ¦             |          |            |
+ |        | nta_incoming_bind(ireq, ack_cb)      |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            |
+ |        | nta_incoming_reply(180)   |          |            |
+ | ALERT  |---------------------------|----------|----------->| 180 Ringing
+ |<-------|             ¦             |          |            |---->
+ |        |             ¦             |          |            |
+ |OFFHOOK |             ¦             |          |            |
+ |------->| nta_incoming_reply        |          |            |
+ |        |---------------------------|----------|----------->| 200 Ok
+ |        | (200, sdp)  ¦             |          |            |---->
+ |        |             ¦             |          |            |
+ |        |             ¦             |          |            | ACK
+ |        |             ¦             |          |ack_cb(ACK) |<----
+ |        |<--------------------------|----------|------------|
+ |        |             ¦             |          |            |
+ |        | nta_incoming_destroy(ireq)|          |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            X
+
+
+User Agent Server Receiving a Call Release
+------------------------------------------
+
+                    APP ¦ NTA
+User    Call            ¦            NTA        leg
+Agent     |             ¦           agent        |
+ |        |             ¦             |          |              BYE
+ |        |             ¦             |          |<------------------
+ |        |             ¦             |          |
+ |        |             ¦             |          |- - - -> Incoming
+ |        |             ¦             |          |            |
+ |        |             ¦             |     request_cb(reply) |
+ | ONHOOK |<--------------------------|----------|------------|
+ |<-------|             ¦             |          |            |
+ |        | nta_incoming_reply(200)   |          |            |
+ |        |---------------------------|----------|----------->| 200 Ok
+ |        | (200, sdp)  ¦             |          |            |---->
+ |        |             ¦             |          |            |
+ |        | nta_incoming_destroy(ireq)|          |            |
+ |        |---------------------------|----------|----------->|
+ |        |             ¦             |          |            X
+ |        |nta_leg_destroy            |          |
+ |        |---------------------------|--------->|
+ |        X             ¦             |          X

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10182 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta.c
+ * @brief Sofia SIP Transaction API implementation
+ * 
+ * This source file has been divided into sections as follows:
+ * 1) agent
+ * 2) tport handling
+ * 3) dispatching messages received from network
+ * 4) message creation, message utility
+ * 5) stateless operation
+ * 6) dialogs (legs)
+ * 7) server transactions (incoming)
+ * 8) client transactions (outgoing)
+ * 9) resolving URLs for client transactions
+ * 10) 100rel reliable responses (reliable)
+ * 11) SigComp handling and public transport interface
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+
+/** @internal SU message argument structure type */
+#define SU_MSG_ARG_T   union sm_arg_u
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T struct nta_agent_s
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_time.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/msg_parser.h>
+
+#include "nta_internal.h"
+#include "sofia-sip/nta_stateless.h"
+#include "sofia-sip/url_tag.h"
+
+#if !defined(random) && defined(_WIN32)
+#define random rand
+#endif
+
+#if !defined(EMSGSIZE) && defined(_WIN32)
+#define EMSGSIZE WSAEMSGSIZE
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <limits.h>
+#include <errno.h>
+
+/* From AM_INIT/AC_INIT in our "config.h" */
+char const nta_version[] = PACKAGE_VERSION;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nta";
+#endif
+
+#define NONE ((void *)-1)
+
+/* Internal tags */
+
+/* Delay sending of request */
+#define NTATAG_DELAY_SENDING(x) ntatag_delay_sending, tag_bool_v((x))
+#define NTATAG_DELAY_SENDING_REF(x) \
+ntatag_delay_sending_ref, tag_bool_vr(&(x))
+
+extern tag_typedef_t ntatag_delay_sending;
+extern tag_typedef_t ntatag_delay_sending_ref;
+
+/* Allow sending incomplete responses */
+#define NTATAG_INCOMPLETE(x) ntatag_incomplete, tag_bool_v((x))
+#define NTATAG_INCOMPLETE_REF(x) \
+ntatag_incomplete_ref, tag_bool_vr(&(x))
+
+extern tag_typedef_t ntatag_incomplete;
+extern tag_typedef_t ntatag_incomplete_ref;
+
+nta_compressor_vtable_t *nta_compressor_vtable = NULL;
+
+/* Agent */
+static int agent_tag_init(nta_agent_t *self);
+static int agent_timer_init(nta_agent_t *agent);
+static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
+static int agent_launch_terminator(nta_agent_t *agent);
+static void agent_kill_terminator(nta_agent_t *agent);
+static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
+static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
+static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
+
+/* Transport interface */
+static sip_via_t const *agent_tport_via(tport_t *tport);
+static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
+static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
+
+static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
+					   char const data[], usize_t dlen,
+					   tport_t const *tport,
+					   tp_client_t *via);
+
+static int complete_response(msg_t *response, 
+			     int status, char const *phrase, 
+			     msg_t const *request);
+
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)     TAG_IF(cc, TPTAG_COMPARTMENT(cc)),
+#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc) TPTAG_COMPARTMENT_REF(cc),
+
+struct sigcomp_compartment;
+
+struct sigcomp_compartment *
+nta_compartment_ref(struct sigcomp_compartment *cc);
+
+static
+struct sigcomp_compartment *
+agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
+			      int new_if_needed);
+
+static
+int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
+			    struct sigcomp_compartment *cc);
+
+static int agent_close_compressor(nta_agent_t *sa,
+				  struct sigcomp_compartment *cc);
+
+static int agent_zap_compressor(nta_agent_t *sa,
+				struct sigcomp_compartment *cc);
+
+
+static char const * stateful_branch(su_home_t *home, nta_agent_t *);
+static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
+				    tp_name_t const *tp);
+
+#define NTA_BRANCH_PRIME SU_U64_C(0xB9591D1C361C6521)
+#define NTA_TAG_PRIME    SU_U64_C(0xB9591D1C361C6521)
+
+HTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
+static nta_leg_t *leg_find(nta_agent_t const *sa,
+			   char const *method_name,
+			   url_t const *request_uri,
+			   sip_call_id_t const *i,
+			   char const *from_tag,
+			   url_t const *from_uri,
+			   char const *to_tag,
+			   url_t const *to_uri);
+static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
+			   char const *method);
+static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
+static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
+
+#define NTA_HASH(i, cs) ((i)->i_hash + 26839U * (uint32_t)(cs))
+
+HTABLE_PROTOS_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
+static nta_incoming_t *incoming_create(nta_agent_t *agent,
+				       msg_t *request,
+				       sip_t *sip,
+				       tport_t *tport,
+				       char const *tag);
+static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
+static void incoming_free(nta_incoming_t *irq);
+static inline void incoming_cut_off(nta_incoming_t *irq);
+static inline void incoming_reclaim(nta_incoming_t *irq);
+static void incoming_queue_init(incoming_queue_t *, 
+				unsigned timeout);
+static void incoming_queue_adjust(nta_agent_t *sa, 
+				  incoming_queue_t *queue, 
+				  unsigned timeout);
+
+static inline
+nta_incoming_t *incoming_find(nta_agent_t const *agent, sip_t const *sip,
+			      sip_via_t const *v,
+			      nta_incoming_t **merge,
+			      nta_incoming_t **ack);
+static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
+static inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+				tport_t *tport);
+static inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+			       tport_t *tport);
+static inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+				  tport_t *tport);
+static inline int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+				 tport_t *tport);
+static inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
+static inline int incoming_timer(nta_agent_t *, su_duration_t);
+
+static nta_reliable_t *reliable_mreply(nta_incoming_t *,
+				       nta_prack_f *, nta_reliable_magic_t *,
+				       msg_t *, sip_t *);
+static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
+static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
+static msg_t *reliable_response(nta_incoming_t *irq);
+static int reliable_recv(nta_incoming_t *, msg_t *, sip_t *, tport_t *);
+static void reliable_flush(nta_incoming_t *irq);
+static void reliable_timeout(nta_incoming_t *irq, int timeout);
+
+HTABLE_PROTOS_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
+static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+				       nta_response_f *callback,
+				       nta_outgoing_magic_t *magic,
+				       url_string_t const *route_url,
+				       tp_name_t const *tpn,
+				       msg_t *msg,
+				       tag_type_t tag, tag_value_t value, ...);
+static void outgoing_queue_init(outgoing_queue_t *, 
+				unsigned timeout);
+static void outgoing_queue_adjust(nta_agent_t *sa, 
+				  outgoing_queue_t *queue, 
+				  unsigned timeout);
+static void outgoing_free(nta_outgoing_t *orq);
+static inline void outgoing_cut_off(nta_outgoing_t *orq);
+static inline void outgoing_reclaim(nta_outgoing_t *orq);
+static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
+				     msg_t const *msg,
+				     sip_t const *sip,
+				     sip_via_t const *v);
+static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
+static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
+static inline int outgoing_timer(nta_agent_t *, su_duration_t);
+static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
+
+/* Internal message passing */
+union sm_arg_u {
+  struct leg_recv_s {
+    nta_leg_t    *leg;
+    msg_t        *msg;
+    tport_t      *tport;
+  } a_leg_recv[1];
+
+  struct outgoing_recv_s {
+    nta_outgoing_t *orq;
+    msg_t          *msg;
+    sip_t          *sip;
+    int             status;
+  } a_outgoing_recv[1];
+
+  incoming_queue_t a_incoming_queue[1];
+  outgoing_queue_t a_outgoing_queue[1];
+};
+
+/* Global module data */
+
+/**@var char const NTA_DEBUG[];
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The NTA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ * 
+ * @sa <su_debug.h>, #su_log_global, #SOFIA_DEBUG
+ */
+extern char const NTA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b nta module. 
+ * 
+ * The nta_log is the log object used by @b nta module. The level of
+ * nta_log is set using #NTA_DEBUG environment variable.
+ */
+su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };
+
+/* ====================================================================== */
+/* 1) Agent */
+
+/**
+ * Create an NTA agent object.
+ *
+ * The function nta_agent_create() creates an NTA agent object.  The agent
+ * object creates and binds a server socket with address specified in @e url.
+ * If the @e host portion of the @e url is @c "*", the agent listens to all
+ * addresses available on the host.
+ *
+ * When a message is received, the agent object parses it.  If the result is
+ * a valid SIP message, the agent object passes the message to the
+ * application by invoking the nta_message_f @e callback function.
+ *
+ * @note
+ * The @e url can be either parsed url (of type url_t ()), or a valid
+ * SIP URL as a string.
+ *
+ * @note
+ * If @e url is @c NULL, the default @e url @c "sip:*" is used.
+ * @par
+ * If @p transport parameters are specified in @a url, agent uses only
+ * specified transport type.
+ *
+ * @par
+ * If an @p maddr parameter is specified in @e url, agent binds to the
+ * specified address, but uses @e host part of @e url when it generates
+ * @Contact and @Via headers. The @p maddr parameter is also included,
+ * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
+ *
+ * @param root          pointer to a su_root_t used for synchronization
+ * @param contact_url   URL that agent uses to bind the server sockets
+ * @param callback      pointer to callback function
+ * @param magic         pointer to user data
+ * @param tag,value,... other arguments
+ *
+ * @note It is possible to provide -1 as @a contact_url.
+ * 
+ * @retval handle to the agent when successful,
+ * @retval NULL upon an error.
+ *
+ */
+nta_agent_t *nta_agent_create(su_root_t *root,
+			      url_string_t const *contact_url,
+			      nta_message_f *callback,
+			      nta_agent_magic_t *magic,
+			      tag_type_t tag, tag_value_t value, ...)
+{
+  nta_agent_t *agent;
+  ta_list ta;
+
+  if (root == NULL)
+    return su_seterrno(EINVAL), NULL;
+
+  ta_start(ta, tag, value);
+
+  if ((agent = su_home_new(sizeof(*agent)))) {
+    agent->sa_root = root;
+    agent->sa_callback = callback;
+    agent->sa_magic = magic;
+    agent->sa_flags = MSG_DO_CANONIC;
+
+    agent->sa_maxsize         = 2 * 1024 * 1024; /* 2 MB */
+    agent->sa_bad_req_mask    = ~(sip_mask_response | sip_mask_proxy);
+    agent->sa_bad_resp_mask   = ~(sip_mask_request | sip_mask_proxy);
+    agent->sa_t1 	      = NTA_SIP_T1;
+    agent->sa_t2 	      = NTA_SIP_T2;
+    agent->sa_t4              = NTA_SIP_T4;
+    agent->sa_t1x64 	      = 64 * NTA_SIP_T1;
+    agent->sa_drop_prob       = 0;
+    agent->sa_is_a_uas        = 0;
+    agent->sa_progress        = 60 * 1000;
+    agent->sa_user_via        = 0;
+    agent->sa_extra_100       = 0;
+    agent->sa_pass_100        = 0;
+    agent->sa_timeout_408     = 1;
+    agent->sa_pass_408        = 0;
+    agent->sa_merge_482       = 0;
+    agent->sa_cancel_2543     = 0;
+    agent->sa_cancel_487      = 1;
+    agent->sa_invite_100rel   = 0;
+    agent->sa_timestamp       = 0;
+    agent->sa_use_naptr       = 1;
+    agent->sa_use_srv         = 1;
+    agent->sa_auto_comp       = 0;
+    agent->sa_server_rport    = 1;
+
+    /* RFC 3261 section 8.1.1.6 */
+    sip_max_forwards_init(agent->sa_max_forwards);
+
+    if (getenv("SIPCOMPACT"))
+      agent->sa_flags |= MSG_DO_COMPACT;
+
+    agent_set_params(agent, ta_args(ta));
+
+    if (agent->sa_mclass == NULL)
+      agent->sa_mclass = sip_default_mclass();
+
+    agent->sa_in.re_t1 = &agent->sa_in.re_list;
+    
+    incoming_queue_init(agent->sa_in.proceeding, 0);
+    incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
+    incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
+    incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
+    incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
+    incoming_queue_init(agent->sa_in.terminated, 0);
+    incoming_queue_init(agent->sa_in.final_failed, 0); 
+
+    agent->sa_out.re_t1 = &agent->sa_out.re_list;
+
+    outgoing_queue_init(agent->sa_out.delayed, 0);
+    outgoing_queue_init(agent->sa_out.resolving, 0);
+    outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
+    outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
+    outgoing_queue_init(agent->sa_out.terminated, 0); 
+    /* Special queues (states) for outgoing INVITE transactions */
+    outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
+    outgoing_queue_init(agent->sa_out.inv_proceeding, 0); 
+    outgoing_queue_init(agent->sa_out.inv_completed, 32000); /* Timer D */
+
+    if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
+	leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
+	outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
+	incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
+      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"));
+      goto deinit;
+    }
+    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"));
+
+    if (contact_url != (url_string_t *)-1 &&
+	nta_agent_add_tport(agent, contact_url, ta_tags(ta)) < 0) {
+      SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"));
+      goto deinit;
+    }
+    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"));
+
+    if (agent_tag_init(agent) < 0) {
+      SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"));
+      goto deinit;
+    }
+    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"));
+
+    if (agent_timer_init(agent) < 0) {
+      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"));
+      goto deinit;
+    }
+    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"));
+
+    if (agent_launch_terminator(agent) == 0)
+      SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"));
+
+#if HAVE_SOFIA_SRESOLV
+    agent->sa_resolver = sres_resolver_create(root, NULL, ta_tags(ta));
+    if (!agent->sa_resolver) {
+      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"));
+    }
+    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"));
+#endif
+
+    ta_end(ta);
+
+    return agent;
+
+  deinit:
+    nta_agent_destroy(agent);
+  }
+
+  ta_end(ta);
+
+  return NULL;
+}
+
+/**
+ * Destroy an NTA agent object.
+ *
+ * @param agent the NTA agent object to be destroyed.
+ *
+ */
+void nta_agent_destroy(nta_agent_t *agent)
+{
+  if (agent) {
+    size_t i;
+    outgoing_htable_t *oht = agent->sa_outgoing;
+    incoming_htable_t *iht = agent->sa_incoming;
+    /* Currently, this is pretty pointless, as legs don't keep any resources */
+    leg_htable_t *lht;
+    nta_leg_t *leg;
+
+    for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
+      if ((leg = lht->lht_table[i])) {
+	SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"
+		    URL_PRINT_FORMAT ">\n",
+		    URL_PRINT_ARGS(leg->leg_remote->a_url)));
+	leg_free(agent, leg);
+      }
+    }
+
+    for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
+      if ((leg = lht->lht_table[i])) {
+	SU_DEBUG_3(("%s: destroying leg for <" 
+		    URL_PRINT_FORMAT ">\n",
+		    __func__, URL_PRINT_ARGS(leg->leg_url)));
+	leg_free(agent, leg);
+      }
+    }
+
+    if (agent->sa_default_leg)
+      leg_free(agent, agent->sa_default_leg);
+
+    for (i = iht->iht_size; i-- > 0; )
+      while (iht->iht_table[i]) {
+	nta_incoming_t *irq = iht->iht_table[i];
+
+	if (!irq->irq_destroyed)
+	  SU_DEBUG_3(("%s: destroying %s server transaction from <"
+		      URL_PRINT_FORMAT ">\n",
+		      __func__, irq->irq_rq->rq_method_name,
+		      URL_PRINT_ARGS(irq->irq_from->a_url)));
+
+	incoming_free(irq);
+      }
+
+    for (i = oht->oht_size; i-- > 0;)
+      while (oht->oht_table[i]) {
+	nta_outgoing_t *orq = oht->oht_table[i];
+
+	if (!orq->orq_destroyed)
+	  SU_DEBUG_3(("%s: destroying %s client transaction to <"
+		      URL_PRINT_FORMAT ">\n",
+		      __func__, orq->orq_method_name,
+		      URL_PRINT_ARGS(orq->orq_to->a_url)));
+
+	outgoing_free(orq);
+      }
+
+    su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL;
+
+#   if HAVE_SOFIA_SRESOLV
+    sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL;
+#   endif
+
+    tport_destroy(agent->sa_tports), agent->sa_tports = NULL;
+
+    agent_kill_terminator(agent);
+
+    su_home_unref(agent->sa_home);
+  }
+}
+
+/** Return agent context. */
+nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
+{
+  return agent ? agent->sa_magic : NULL;
+}
+
+/** Return @Contact header.
+ *
+ * The function nta_agent_contact() returns a @Contact header, which can be
+ * used to reach @a agent.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_contact() returns a sip_contact_t object
+ * corresponding to the @a agent.
+ *
+ * User agents can insert the @Contact header in the outgoing REGISTER,
+ * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
+ * transactions.
+ *
+ * Proxies can use the @Contact header to create appropriate @RecordRoute
+ * headers:
+ * @code
+ * r_r = sip_record_route_create(msg_home(msg),
+ *	 			 sip->sip_request->rq_url,
+ *				 contact->m_url);
+ * @endcode
+ */
+sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
+{
+  return agent ? agent->sa_contact : NULL;
+}
+
+/** Return a list of @Via headers.
+ *
+ * The function nta_agent_via() returns @Via headers for all activated
+ * transport.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_via() returns a list of sip_via_t objects
+ * used by the @a agent.
+ */
+sip_via_t *nta_agent_via(nta_agent_t const *agent)
+{
+  return agent ? agent->sa_vias : NULL;
+}
+
+
+/** Return a list of public (UPnP, STUN) @Via headers.
+ *
+ * The function nta_agent_public_via() returns public @Via headers for all activated
+ * transports.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_public_via() returns a list of sip_via_t objects
+ * used by the @a agent.
+ */
+sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
+{
+  return agent ? agent->sa_public_vias : NULL;
+}
+
+/** Return @UserAgent header.
+ *
+ * The function nta_agent_name() returns a @UserAgent information with
+ * NTA version.
+ *
+ * @param agent NTA agent object (may be NULL)
+ *
+ * @return The function nta_agent_contact() returns a string containing the
+ * @a agent version.
+ */
+char const *nta_agent_version(nta_agent_t const *agent)
+{
+  return "nta" "/" VERSION;
+}
+
+/** Initialize default tag */
+static int agent_tag_init(nta_agent_t *self)
+{
+  sip_contact_t *m = self->sa_contact;
+  uint32_t hash = 1;
+
+  if (m) {
+
+    if (m->m_url->url_user)
+      hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
+    if (m->m_url->url_host)
+      hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
+    if (m->m_url->url_port)
+      hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
+    if (m->m_url->url_params)
+      hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
+  }
+
+  if (hash == 0)
+    hash = 914715421U;
+
+  self->sa_branch = NTA_BRANCH_PRIME * su_ntp_now();
+  self->sa_branch *= hash;
+
+  self->sa_tags = NTA_TAG_PRIME * self->sa_branch;
+
+  return 0;
+}
+
+/** Initialize agent timer. */
+static
+int agent_timer_init(nta_agent_t *agent)
+{
+  return su_timer_set(agent->sa_timer =
+		      su_timer_create(su_root_task(agent->sa_root),
+				      NTA_SIP_T1 / 8),
+		      agent_timer,
+		      agent);
+}
+
+/**
+ * Agent timer routine.
+ */
+static
+void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
+{
+  su_duration_t now = su_time_ms(agent->sa_now = su_now());
+  int again;
+
+  now += now == 0;
+
+  agent->sa_millisec = now;
+
+  again = outgoing_timer(agent, now);
+  again = incoming_timer(agent, now) || again;
+
+  agent->sa_millisec = 0;
+
+  if (again)
+    su_timer_set_at(timer, agent_timer, agent, su_time_add(su_now(), 1));
+  else
+    su_timer_set(timer, agent_timer, agent);
+}
+
+/** Calculate nonzero value for timer */
+static inline
+su_duration_t set_timeout(nta_agent_t const *agent, su_duration_t offset)
+{
+  su_duration_t now;
+
+#if 0
+  if (agent->sa_millisec)
+    now = agent->sa_millisec;
+  else
+#endif
+    now = (su_duration_t)su_time_ms(su_now());
+
+  now += offset;
+
+  return now ? now : 1;
+}
+
+
+/** Return current timeval. */
+static
+su_time_t agent_now(nta_agent_t const *agent)
+{
+  return agent->sa_millisec ? agent->sa_now : su_now();
+}
+
+
+/** Launch transaction terminator task */
+static
+int agent_launch_terminator(nta_agent_t *agent)
+{
+#ifdef TPTAG_THRPSIZE
+  if (agent->sa_tport_threadpool) {
+    su_home_threadsafe(agent->sa_home);
+    return su_clone_start(agent->sa_root, 
+			  agent->sa_terminator,
+			  NULL,
+			  NULL,
+			  NULL);
+  }
+#endif
+  return -1;
+}
+
+/** Kill transaction terminator task */
+static
+void agent_kill_terminator(nta_agent_t *agent)
+{
+  su_clone_wait(agent->sa_root, agent->sa_terminator);
+}
+
+
+/**Set NTA Parameters.
+ *
+ * The nta_agent_set_params() function sets the stack parameters. The
+ * parameters determine the way NTA handles the retransmissions, how long
+ * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
+ * INVITE transactions, or how the @Via headers are generated.
+ *
+ * @note 
+ * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(),
+ * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
+ * 0 selects the default value.
+ *
+ * @TAGS
+ * NTATAG_ALIASES(), NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(),
+ * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_DEBUG_DROP_PROB(),
+ * NTATAG_DEFAULT_PROXY(), NTATAG_EXTRA_100(), NTATAG_MAXSIZE(),
+ * NTATAG_MAX_FORWARDS(),
+ * NTATAG_UDP_MTU(), NTATAG_MERGE_482(), NTATAG_PASS_100(),
+ * NTATAG_PRELOAD(), NTATAG_REL100(), NTATAG_RPORT(), NTATAG_SERVER_RPORT(),
+ * NTATAG_TCP_RPORT(),
+ * NTATAG_SIPFLAGS(), NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(),
+ * NTATAG_SIP_T4(), NTATAG_SMIME(), NTATAG_STATELESS(), NTATAG_TAG_3261(),
+ * NTATAG_TIMEOUT_408(), NTATAG_PASS_408(), NTATAG_UA(), NTATAG_USER_VIA(),
+ * and NTATAG_USE_TIMESTAMP().
+ */
+int nta_agent_set_params(nta_agent_t *agent,
+			 tag_type_t tag, tag_value_t value, ...)
+{
+  int retval;
+
+  if (agent) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    retval = agent_set_params(agent, ta_args(ta));
+    ta_end(ta);
+  } else {
+    su_seterrno(EINVAL);
+    retval = -1;
+  }
+
+  return retval;
+}
+
+/** Internal function for setting tags */
+static
+int agent_set_params(nta_agent_t *agent, tagi_t *tags)
+{
+  int n, m;
+  unsigned bad_req_mask = agent->sa_bad_req_mask;
+  unsigned bad_resp_mask = agent->sa_bad_resp_mask;
+  usize_t  maxsize    = agent->sa_maxsize;
+  unsigned max_forwards = agent->sa_max_forwards->mf_count;
+  usize_t  udp_mtu    = agent->sa_udp_mtu;
+  unsigned sip_t1     = agent->sa_t1;
+  unsigned sip_t2     = agent->sa_t2;
+  unsigned sip_t4     = agent->sa_t4;
+  unsigned sip_t1x64  = agent->sa_t1x64;
+  unsigned blacklist  = agent->sa_blacklist;
+  int ua              = agent->sa_is_a_uas;
+  unsigned progress   = agent->sa_progress;
+  int stateless       = agent->sa_is_stateless;
+  unsigned drop_prob  = agent->sa_drop_prob;
+  int user_via        = agent->sa_user_via;
+  int extra_100       = agent->sa_extra_100;
+  int pass_100        = agent->sa_pass_100;
+  int timeout_408     = agent->sa_timeout_408;
+  int pass_408        = agent->sa_pass_408;
+  int merge_482       = agent->sa_merge_482;
+  int cancel_2543     = agent->sa_cancel_2543;
+  int cancel_487      = agent->sa_cancel_487;
+  int invite_100rel   = agent->sa_invite_100rel;
+  int use_timestamp   = agent->sa_timestamp;
+  int use_naptr       = agent->sa_use_naptr;
+  int use_srv         = agent->sa_use_srv;
+  void *smime         = agent->sa_smime;
+  uint32_t flags      = agent->sa_flags;
+  int rport           = agent->sa_rport;
+  int server_rport    = agent->sa_server_rport;
+  int tcp_rport       = agent->sa_tcp_rport;
+  unsigned preload         = agent->sa_preload;
+  unsigned threadpool      = agent->sa_tport_threadpool;
+  char const *sigcomp = agent->sa_sigcomp_options;
+  char const *algorithm = NONE;
+  msg_mclass_t *mclass = NONE;
+  sip_contact_t const *aliases = NONE;
+  url_string_t const *proxy = NONE;
+  tport_t *tport;
+
+  su_home_t *home = agent->sa_home;
+
+  n = tl_gets(tags,
+	      NTATAG_MCLASS_REF(mclass),
+	      NTATAG_BAD_REQ_MASK_REF(bad_req_mask),
+	      NTATAG_BAD_RESP_MASK_REF(bad_resp_mask),
+	      NTATAG_ALIASES_REF(aliases),
+	      NTATAG_UA_REF(ua),
+	      NTATAG_STATELESS_REF(stateless),
+	      NTATAG_MAXSIZE_REF(maxsize),
+	      NTATAG_MAX_FORWARDS_REF(max_forwards),
+	      NTATAG_UDP_MTU_REF(udp_mtu),
+	      NTATAG_SIP_T1_REF(sip_t1),
+	      NTATAG_SIP_T2_REF(sip_t2),
+	      NTATAG_SIP_T4_REF(sip_t4),
+	      NTATAG_SIP_T1X64_REF(sip_t1x64),
+	      NTATAG_PROGRESS_REF(progress),
+	      NTATAG_BLACKLIST_REF(blacklist),
+	      NTATAG_DEBUG_DROP_PROB_REF(drop_prob),
+	      NTATAG_USER_VIA_REF(user_via),
+	      NTATAG_EXTRA_100_REF(extra_100),
+	      NTATAG_PASS_100_REF(pass_100),
+	      NTATAG_TIMEOUT_408_REF(timeout_408),
+	      NTATAG_PASS_408_REF(pass_408),
+	      NTATAG_MERGE_482_REF(merge_482),
+	      NTATAG_DEFAULT_PROXY_REF(proxy),
+	      NTATAG_CANCEL_2543_REF(cancel_2543),
+	      NTATAG_CANCEL_487_REF(cancel_487),
+	      NTATAG_REL100_REF(invite_100rel),
+	      NTATAG_USE_TIMESTAMP_REF(use_timestamp),
+	      NTATAG_USE_NAPTR_REF(use_naptr),
+	      NTATAG_USE_SRV_REF(use_srv),
+#if HAVE_SOFIA_SMIME
+	      NTATAG_SMIME_REF(smime),
+#endif
+	      NTATAG_SIPFLAGS_REF(flags),
+	      NTATAG_RPORT_REF(rport),
+	      NTATAG_SERVER_RPORT_REF(server_rport),
+	      NTATAG_TCP_RPORT_REF(tcp_rport),
+	      NTATAG_PRELOAD_REF(preload),
+#ifdef TPTAG_THRPSIZE
+	      /* If threadpool is enabled, start a separate "reaper thread" */
+	      TPTAG_THRPSIZE_REF(threadpool),
+#endif
+	      NTATAG_SIGCOMP_OPTIONS_REF(sigcomp),
+	      NTATAG_SIGCOMP_ALGORITHM_REF(algorithm),
+	      TAG_END());
+
+  if (mclass != NONE)
+    agent->sa_mclass = mclass ? mclass : sip_default_mclass();
+
+  m = 0;
+  for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
+    m = tport_set_params(tport, TAG_NEXT(tags));
+  }
+
+  if (n == 0 || m == -1)
+    return m;
+
+  n += m;
+
+  if (aliases != NONE) {
+    sip_contact_t const *m, *m_next;
+
+    m = agent->sa_aliases;
+    agent->sa_aliases = sip_contact_dup(home, aliases);
+
+    for (; m; m = m_next) {	/* Free old aliases */
+      m_next = m->m_next;
+      su_free(home, (void *)m);
+    }
+  }
+
+  if (proxy != NONE) {
+    url_t *dp = url_hdup(home, proxy->us_url);
+
+    url_sanitize(dp);
+
+    if (dp == NULL || dp->url_type == url_sip || dp->url_type == url_sips) {
+      if (agent->sa_default_proxy)
+	su_free(home, agent->sa_default_proxy);
+      agent->sa_default_proxy = dp;
+    }
+    else
+      n = -1;
+  }
+
+  if (algorithm != NONE)
+    agent->sa_algorithm = su_strdup(home, algorithm);
+
+  if (str0cmp(sigcomp, agent->sa_sigcomp_options)) {
+    char const * const *l = NULL;
+    char *s = su_strdup(home, sigcomp);
+    char *s1 = su_strdup(home, s), *s2 = s1;
+
+    if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
+      su_free(home, (void *)agent->sa_sigcomp_options);
+      su_free(home, (void *)agent->sa_sigcomp_option_list);
+      agent->sa_sigcomp_options = s;
+      agent->sa_sigcomp_option_free = s1;
+      agent->sa_sigcomp_option_list = l;
+    } else {
+      su_free(home, s);
+      su_free(home, s1);
+      su_free(home, (void *)l);
+      n = -1;
+    }
+  }
+
+  if (maxsize == 0) maxsize = 2 * 1024 * 1024;
+  if (maxsize > NTA_TIME_MAX) maxsize = NTA_TIME_MAX;
+  agent->sa_maxsize = maxsize;
+
+  if (max_forwards == 0) max_forwards = 70; /* Default value */
+  agent->sa_max_forwards->mf_count = max_forwards;
+
+  if (udp_mtu == 0) udp_mtu = 1300;
+  if (udp_mtu > 65535) udp_mtu = 65535;
+  if (agent->sa_udp_mtu != udp_mtu) {
+    agent->sa_udp_mtu = udp_mtu;
+    agent_set_udp_params(agent, udp_mtu);
+  }
+
+  if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
+  if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
+  agent->sa_t1 = sip_t1;
+
+  if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
+  if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
+  agent->sa_t2 = sip_t2;
+
+  if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
+  if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
+  if (agent->sa_t4 != sip_t4) {
+    incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
+    outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
+  }
+  agent->sa_t4 = sip_t4;
+
+  if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
+  if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
+  if (agent->sa_t1x64 != sip_t1x64) {
+    incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
+    incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
+    incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
+    outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
+    outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
+  }
+  agent->sa_t1x64 = sip_t1x64;
+  agent->sa_blacklist = blacklist;
+
+  if (progress == 0)
+    progress = 60 * 1000;
+  agent->sa_progress = progress;
+
+  agent->sa_bad_req_mask = bad_req_mask;
+  agent->sa_bad_resp_mask = bad_resp_mask;
+
+  agent->sa_is_a_uas = ua != 0;
+  agent->sa_is_stateless = stateless != 0;
+  agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
+  agent->sa_user_via = user_via != 0;
+  agent->sa_extra_100 = extra_100 != 0;
+  agent->sa_pass_100 = pass_100 != 0;
+  agent->sa_timeout_408 = timeout_408 != 0;
+  agent->sa_pass_408 = pass_408 != 0;
+  agent->sa_merge_482 = merge_482 != 0;
+  agent->sa_cancel_2543 = cancel_2543 != 0;
+  agent->sa_cancel_487 = cancel_487 != 0;
+  agent->sa_invite_100rel = invite_100rel != 0;
+  agent->sa_timestamp = use_timestamp != 0;
+  agent->sa_use_naptr = use_naptr != 0;
+  agent->sa_use_srv = use_srv != 0;
+  agent->sa_smime = smime;
+  agent->sa_flags = flags & MSG_FLG_USERMASK;
+  agent->sa_rport = rport != 0;
+  agent->sa_server_rport = server_rport != 0;
+  agent->sa_tcp_rport = tcp_rport != 0;
+  agent->sa_preload = preload;
+  agent->sa_tport_threadpool = threadpool;
+
+  return n;
+}
+
+static 
+void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
+{
+  tport_t *tp;
+
+  /* Set via fields for the tports */
+  for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
+    if (tport_is_udp(tp))
+      tport_set_params(tp,
+		       TPTAG_TIMEOUT(2 * self->sa_t1x64),
+		       TPTAG_MTU(udp_mtu),
+		       TAG_END());
+  }
+}
+
+/**Get NTA Parameters.
+ *
+ * The nta_agent_get_params() function retrieves the stack parameters. The
+ * parameters determine the way NTA handles the retransmissions, how long
+ * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
+ * INVITE transactions, or how the @Via headers are generated.
+ *
+ * @TAGS
+ * NTATAG_ALIASES_REF(), NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
+ * NTATAG_CONTACT_REF(), NTATAG_DEBUG_DROP_PROB_REF(),
+ * NTATAG_DEFAULT_PROXY_REF(), NTATAG_EXTRA_100_REF(), NTATAG_MAXSIZE_REF(),
+ * NTATAG_MAX_FORWARDS_REF(),
+ * NTATAG_MERGE_482_REF(), NTATAG_PASS_100_REF(), NTATAG_PRELOAD_REF(),
+ * NTATAG_REL100_REF(), NTATAG_RPORT_REF(), NTATAG_SIPFLAGS_REF(),
+ * NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T1_REF(), NTATAG_SIP_T2_REF(),
+ * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
+ * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_PASS_408_REF(),
+ * NTATAG_UA_REF(), NTATAG_USER_VIA_REF(), and NTATAG_USE_TIMESTAMP_REF().
+ *
+ */
+int nta_agent_get_params(nta_agent_t *agent,
+			 tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+
+  if (agent) {
+    ta_start(ta, tag, value);
+    n = agent_get_params(agent, ta_args(ta));
+    ta_end(ta);
+  } else {
+    su_seterrno(EINVAL);
+    n = -1;
+  }
+
+  return n;
+}
+
+/** Get NTA parameters */
+static
+int agent_get_params(nta_agent_t *agent, tagi_t *tags)
+{
+  return
+    tl_tgets(tags,
+	     NTATAG_MCLASS(agent->sa_mclass),
+	     NTATAG_CONTACT(agent->sa_contact),
+	     NTATAG_ALIASES(agent->sa_aliases),
+	     NTATAG_UA(agent->sa_is_a_uas),
+	     NTATAG_STATELESS(agent->sa_is_stateless),
+	     NTATAG_MAXSIZE(agent->sa_maxsize),
+	     NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count),
+	     NTATAG_UDP_MTU(agent->sa_udp_mtu),
+	     NTATAG_SIP_T1(agent->sa_t1),
+	     NTATAG_SIP_T2(agent->sa_t2),
+	     NTATAG_SIP_T4(agent->sa_t4),
+	     NTATAG_SIP_T1X64(agent->sa_t1x64),
+	     NTATAG_BLACKLIST(agent->sa_blacklist),
+	     NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob),
+	     NTATAG_USER_VIA(agent->sa_user_via),
+	     NTATAG_EXTRA_100(agent->sa_extra_100),
+	     NTATAG_PASS_100(agent->sa_pass_100),
+	     NTATAG_TIMEOUT_408(agent->sa_timeout_408),
+	     NTATAG_PASS_408(agent->sa_pass_408),
+	     NTATAG_MERGE_482(agent->sa_merge_482),
+	     NTATAG_DEFAULT_PROXY(agent->sa_default_proxy),
+	     NTATAG_CANCEL_2543(agent->sa_cancel_2543),
+	     NTATAG_CANCEL_487(agent->sa_cancel_487),
+	     NTATAG_TAG_3261(1),
+	     NTATAG_REL100(agent->sa_invite_100rel),
+	     NTATAG_USE_TIMESTAMP(agent->sa_timestamp),
+	     NTATAG_USE_NAPTR(agent->sa_use_naptr),
+	     NTATAG_USE_SRV(agent->sa_use_srv),
+#if HAVE_SOFIA_SMIME
+	     NTATAG_SMIME(agent->sa_smime),
+#else
+	     NTATAG_SMIME(NULL),
+#endif
+	     NTATAG_SIPFLAGS(agent->sa_flags),
+	     NTATAG_RPORT(agent->sa_rport),
+	     NTATAG_PRELOAD(agent->sa_preload),
+	     NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm),
+	     NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?
+				    agent->sa_sigcomp_options :
+				    "sip"),
+	     TAG_END());
+}
+
+/**Get NTA statistics.
+ *
+ * The nta_agent_get_stats() function retrieves the stack statistics.
+ *
+ * @TAGS
+ * @TAG NTATAG_S_*
+ *
+ */
+int nta_agent_get_stats(nta_agent_t *agent,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+
+  if (!agent)
+    return su_seterrno(EINVAL), -1;
+
+  ta_start(ta, tag, value);
+
+  n = tl_tgets(ta_args(ta),
+	       NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size),
+	       NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size),
+	       NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size),
+	       NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used),
+	       NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used),
+	       NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used),
+	       NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg),
+	       NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request),
+	       NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response),
+	       NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message),
+	       NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request),
+	       NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response),
+	       NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request),
+	       NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response),
+	       NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr),
+	       NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr),
+	       NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr),
+	       NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr),
+	       NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr),
+	       NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request),
+	       NTATAG_S_TRLESS_TO_TR(agent->sa_stats->as_trless_to_tr),
+	       NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response),
+	       NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200),
+	       NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request),
+	       NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg),
+	       NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request),
+	       NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response),
+	       NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request),
+	       NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response),
+	       NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry),
+	       NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request),
+	       NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response),
+	       TAG_END());
+
+  ta_end(ta);
+
+  return n;
+}
+
+/**Calculate a new unique tag.
+ *
+ * This function generates a series of 2**64 unique tags for @From or @To
+ * headers. The start of the tag series is derived from the NTP time the NTA
+ * agent was initialized.
+ *
+ */
+char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa)
+{
+  char tag[(8 * 8 + 4)/ 5 + 1];
+
+  if (sa == NULL)
+    return su_seterrno(EINVAL), NULL;
+
+  /* XXX - use a cryptographically safe func here? */
+  sa->sa_tags += NTA_TAG_PRIME;
+
+  msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags));
+
+  if (fmt && fmt[0])
+    return su_sprintf(home, fmt, tag);
+  else
+    return su_strdup(home, tag);
+}
+
+/**
+ * Calculate branch value.
+ */
+static char const *stateful_branch(su_home_t *home, nta_agent_t *sa)
+{
+  char branch[(8 * 8 + 4)/ 5 + 1];
+
+  /* XXX - use a cryptographically safe func here? */
+  sa->sa_branch += NTA_BRANCH_PRIME;
+
+  msg_random_token(branch, sizeof(branch) - 1, 
+		   &sa->sa_branch, sizeof(sa->sa_branch));
+
+  return su_sprintf(home, "branch=z9hG4bK%s", branch);
+}
+
+#include <sofia-sip/su_md5.h>
+
+/**
+ * Calculate branch value for stateless operation.
+ * 
+ * XXX - should include HMAC of previous @Via line.
+ */
+static
+char const *stateless_branch(nta_agent_t *sa, 
+			     msg_t *msg,
+			     sip_t const *sip, 
+			     tp_name_t const *tpn)
+{
+  su_md5_t md5[1];
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+  char branch[(SU_MD5_DIGEST_SIZE * 8 + 4)/ 5 + 1];
+  sip_route_t const *r;
+
+  assert(sip->sip_request);
+
+  if (!sip->sip_via)
+    return stateful_branch(msg_home(msg), sa);
+
+  su_md5_init(md5);
+
+  su_md5_str0update(md5, tpn->tpn_host);
+  su_md5_str0update(md5, tpn->tpn_port);
+
+  url_update(md5, sip->sip_request->rq_url);
+  if (sip->sip_call_id) {
+    su_md5_str0update(md5, sip->sip_call_id->i_id);
+  }
+  if (sip->sip_from) {
+    url_update(md5, sip->sip_from->a_url);
+    su_md5_stri0update(md5, sip->sip_from->a_tag);
+  }
+  if (sip->sip_to) {
+    url_update(md5, sip->sip_to->a_url);
+    /* XXX - some broken implementations include To tag in CANCEL */
+    /* su_md5_str0update(md5, sip->sip_to->a_tag); */
+  }
+  if (sip->sip_cseq) {
+    uint32_t cseq = htonl(sip->sip_cseq->cs_seq);
+    su_md5_update(md5, &cseq, sizeof(cseq));
+  }
+
+  for (r = sip->sip_route; r; r = r->r_next)
+    url_update(md5, r->r_url);
+
+  su_md5_digest(md5, digest);
+
+  msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest));
+
+  return su_sprintf(msg_home(msg), "branch=z9hG4bK.%s", branch);
+}
+
+/* ====================================================================== */
+/* 2) Transport interface */
+
+/* Local prototypes */
+static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags);
+static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr);
+static int agent_init_contact(nta_agent_t *self);
+static void agent_recv_message(nta_agent_t *agent,
+			       tport_t *tport,
+			       msg_t *msg,
+			       sip_via_t *tport_via,
+			       su_time_t now);
+static void agent_tp_error(nta_agent_t *agent,
+			   tport_t *tport,
+			   int errcode,
+			   char const *remote);
+static void agent_update_tport(nta_agent_t *agent, tport_t *);
+
+/**For each transport, we have name used by tport module, SRV prefixes used
+ * for resolving, and NAPTR service/conversion.
+ */
+static 
+struct sipdns_tport {
+  char name[6];			/**< Named used by tport module */
+  char port[6];			/**< Default port number */
+  char prefix[14];		/**< Prefix for SRV domains */
+  char service[10];		/**< NAPTR service */
+}
+#define SIPDNS_TRANSPORTS (4)
+const sipdns_tports[SIPDNS_TRANSPORTS] = {
+  { "udp",  "5060", "_sip._udp.",  "SIP+D2U"  },
+  { "tcp",  "5060", "_sip._tcp.",  "SIP+D2T"  },
+  { "sctp", "5060", "_sip._sctp.", "SIP+D2S" },
+  { "tls",  "5061", "_sips._tcp.", "SIPS+D2T"  },
+};
+
+static char const * const tports_sip[] =
+  {
+    "udp", "tcp", "sctp", NULL
+  };
+
+static char const * const tports_sips[] =
+  {
+    "tls", NULL
+  };
+
+static tport_stack_class_t nta_agent_class[1] =
+  {{
+    sizeof(nta_agent_class),
+    agent_recv_message,
+    agent_tp_error,
+    nta_msg_create_for_transport,
+    agent_update_tport,
+  }};
+
+
+/** Add a transport to the agent.
+ *
+ * The function nta_agent_add_tport() creates a new transport and binds it
+ * to the port specified by the @a uri. The @a uri must have sip: or sips:
+ * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as
+ * follows:
+ *
+ * @code url <scheme>:<host>[:<port>]<url-params> @endcode
+ * where <url-params> may be
+ * @code
+ * ;transport=<xxx>
+ * ;maddr=<actual addr>
+ * ;comp=sigcomp
+ * @endcode
+ *
+ * The scheme part determines which transports are used. "sip" implies UDP
+ * and TCP, "sips" TLS over TCP. In the future, more transports can be
+ * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS
+ * over SCTP.
+ *
+ * The "host" part determines what address/domain name is used in @Contact.
+ * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0
+ * means that the only the IPv4 addresses are used. [::] means that only
+ * the IPv6 addresses are used. If a domain name or a specific IP address
+ * is given as "host" part, an additional "maddr" parameter can be used to
+ * control which addresses are used by the stack when binding listen
+ * sockets for incoming requests.
+ *
+ * The "port" determines what port is used in contact, and to which port the
+ * stack binds in order to listen for incoming requests. Empty or missing
+ * port means that default port should be used (5060 for sip, 5061 for
+ * sips). An "*" in "port" part means any port, i.e., the stack binds to an
+ * ephemeral port.
+ *
+ * The "transport" parameter determines the transport protocol that is used
+ * and how they are preferred. If no protocol is specified, both UDP and TCP
+ * are used for SIP URL and TLS for SIPS URL. The preference can be
+ * indicated with a comma-separated list of transports, for instance,
+ * parameter @code transport=tcp,udp @endocde indicates that TCP is
+ * preferred to UDP.
+ *
+ * The "maddr" parameter determines to which address the stack binds in
+ * order to listen for incoming requests. An "*" in "maddr" parameter is
+ * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets
+ * are created. [::] means that only IPv6 sockets are created.
+ *
+ * The "comp" parameter determines the supported compression protocol.
+ * Currently only sigcomp is supported (with suitable library.
+ *
+ * @par Examples:
+ * @code sip:172.21.40.24;maddr=* @endcode \n
+ * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n
+ * @code sips:* @endcode
+ *
+ * @return
+ * On success, zero is returned. On error, -1 is returned, and @a errno is
+ * set appropriately.
+ */
+int nta_agent_add_tport(nta_agent_t *self,
+			url_string_t const *uri,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  url_t *url;
+  char tp[32];
+  char maddr[256];
+  char comp[32];
+  tp_name_t tpn[1] = {{ NULL }};
+  char const * const * tports = tports_sip;
+  int error;
+  ta_list ta;
+
+  if (self == NULL) {
+    su_seterrno(EINVAL);
+    return -1;
+  }
+
+  if (uri == NULL)
+    uri = (url_string_t *)"sip:*";
+  else if (url_string_p(uri) ?
+	   strcmp(uri->us_str, "*") == 0 :
+	   uri->us_url->url_type == url_any) {
+    uri = (url_string_t *)"sip:*:*";
+  }
+
+  if (!(url = url_hdup(self->sa_home, uri->us_url)) ||
+      (url->url_type != url_sip && url->url_type != url_sips)) {
+    if (url_string_p(uri))
+      SU_DEBUG_1(("nta: %s: invalid bind URL\n", uri->us_str));
+    else
+      SU_DEBUG_1(("nta: invalid bind URL\n"));
+    su_seterrno(EINVAL);
+    return -1;
+  }
+
+  tpn->tpn_canon = url->url_host;
+  tpn->tpn_host = url->url_host;
+  tpn->tpn_port = url_port(url);
+
+  if (url->url_type == url_sip) {
+    tpn->tpn_proto = "*";
+    tports = tports_sip;
+    if (!tpn->tpn_port || !tpn->tpn_port[0]) 
+      tpn->tpn_port = SIP_DEFAULT_SERV;
+  }
+  else {
+    assert(url->url_type == url_sips);
+    tpn->tpn_proto = "*";
+    tports = tports_sips;
+    if (!tpn->tpn_port || !tpn->tpn_port[0]) 
+      tpn->tpn_port = SIPS_DEFAULT_SERV;
+  }
+
+  if (url->url_params) {
+    if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) {
+      if (strchr(tp, ',')) {
+	int i; char *t, *tps[9];
+
+	/* Split tp into transports */
+	for (i = 0, t = tp; t && i < 8; i++) {
+	  tps[i] = t;
+	  if ((t = strchr(t, ',')))
+	    *t++ = '\0';
+	}
+
+	tps[i] = NULL;
+	tports = (char const * const *)tps;
+      } else {
+	tpn->tpn_proto = tp;
+      }
+    }
+    if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0)
+      tpn->tpn_host = maddr;
+    if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0)
+      tpn->tpn_comp = comp;
+
+    if (tpn->tpn_comp && 
+	(nta_compressor_vtable == NULL || 
+	 strcasecmp(tpn->tpn_comp, nta_compressor_vtable->ncv_name) != 0)) {
+      SU_DEBUG_1(("nta(%p): comp=%s not supported for " URL_PRINT_FORMAT "\n",
+		  self, tpn->tpn_comp, URL_PRINT_ARGS(url)));
+    }
+  }
+
+  ta_start(ta, tag, value);
+
+  if (self->sa_tports == NULL) {
+    if (agent_create_master_transport(self, ta_args(ta)) < 0) {
+      error = su_errno();
+      SU_DEBUG_1(("nta: cannot create master transport: %s\n",
+		  su_strerror(error)));
+      goto error;
+    }
+  }
+
+  if (tport_tbind(self->sa_tports, tpn, tports, ta_tags(ta)) < 0) {
+    error = su_errno();
+    SU_DEBUG_1(("nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n",
+		tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,
+		tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",
+		tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",
+		tpn->tpn_comp ? ";comp=" : "",
+		tpn->tpn_comp ? tpn->tpn_comp : "",
+		su_strerror(error)));
+    goto error;
+  }
+  else
+    SU_DEBUG_5(("nta: bound to (%s:%s;transport=%s%s%s%s%s)\n",
+		tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,
+		tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",
+		tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",
+		tpn->tpn_comp ? ";comp=" : "",
+		tpn->tpn_comp ? tpn->tpn_comp : ""));
+
+  /* XXX - when to use maddr? */
+  if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) {
+    error = su_errno();
+    SU_DEBUG_1(("nta: cannot create Via headers\n"));
+    goto error;
+  }
+  else
+    SU_DEBUG_9(("nta: Via fields initialized\n"));
+
+  if ((agent_init_contact(self)) < 0) {
+    error = su_errno();
+    SU_DEBUG_1(("nta: cannot create Contact header\n"));
+    goto error;
+  }
+  else
+    SU_DEBUG_9(("nta: Contact header created\n"));
+
+  su_free(self->sa_home, url);
+  ta_end(ta);
+
+  return 0;
+
+ error:
+  ta_end(ta);
+  su_seterrno(error);
+  return -1;
+}
+
+static
+int agent_create_master_transport(nta_agent_t *self, tagi_t *tags)
+{
+  self->sa_tports = 
+    tport_tcreate(self, nta_agent_class, self->sa_root,
+		  TPTAG_SDWN_ERROR(0),
+		  TPTAG_IDLE(1800000),
+		  TPTAG_DEBUG_DROP(self->sa_drop_prob),
+		  TAG_NEXT(tags));
+
+  if (!self->sa_tports)
+    return -1;
+
+  SU_DEBUG_9(("nta: master transport created\n"));
+
+  return 0;
+}
+
+
+/** Initialize @Via headers. */
+static
+int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr)
+{
+  sip_via_t *via = NULL, *new_via, *dup_via, *v, **vv = &via;
+  sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public;
+  tport_t *tp;
+  su_addrinfo_t const *ai;
+
+  su_home_t autohome[SU_HOME_AUTO_SIZE(2048)];
+
+  su_home_auto(autohome, sizeof autohome);
+
+  self->sa_tport_ip4 = 0;
+  self->sa_tport_ip6 = 0;
+  self->sa_tport_udp = 0;
+  self->sa_tport_tcp = 0;
+  self->sa_tport_sctp = 0;
+  self->sa_tport_tls = 0;
+
+  /* Set via fields for the tports */
+  for (tp = primaries; tp; tp = tport_next(tp)) {
+    int maddr, first_via;
+    tp_name_t tpn[1];
+    char const *comp = NULL;
+
+    *tpn = *tport_name(tp);
+
+    assert(tpn->tpn_proto);
+    assert(tpn->tpn_canon);
+    assert(tpn->tpn_host);
+    assert(tpn->tpn_port);
+
+#if 0
+    if (getenv("SIP_UDP_CONNECT")
+	&& strcmp(tpn->tpn_proto, "udp") == 0)
+      tport_set_params(tp, TPTAG_CONNECT(1), TAG_END());
+#endif
+
+    if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1;
+
+#if SU_HAVE_IN6
+    if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1;
+#endif
+
+    if (strcasecmp(tpn->tpn_proto, "udp") == 0)
+      self->sa_tport_udp = 1;
+    else if (strcasecmp(tpn->tpn_proto, "tcp") == 0)
+      self->sa_tport_tcp = 1;
+    else if (strcasecmp(tpn->tpn_proto, "sctp") == 0)
+      self->sa_tport_sctp = 1;
+
+    if (tport_has_tls(tp)) self->sa_tport_tls = 1;
+
+    first_via = 1;
+
+    ai = tport_get_address(tp);
+
+    for (; ai; ai = ai->ai_next) {
+      char host[TPORT_HOSTPORTSIZE] = "";
+      char sport[8];
+      char const *canon = ai->ai_canonname;
+      su_sockaddr_t *su = (void *)ai->ai_addr;
+      int port;
+
+      if (su) {
+	inet_ntop(su->su_family, SU_ADDR(su), host, sizeof host);
+	maddr = use_maddr && strcasecmp(canon, host) != 0;
+	port = ntohs(su->su_port);
+      }
+      else {
+	msg_random_token(host, 16, NULL, 0);
+	canon = strcat(host, ".is.invalid");
+	maddr = 0;
+	port = 0;
+      }
+	
+      if (strncasecmp(tpn->tpn_proto, "tls", 3)
+	  ? port == SIP_DEFAULT_PORT
+	  : port == SIPS_DEFAULT_PORT)
+	port = 0;
+
+      snprintf(sport, sizeof sport, ":%u", port);
+      
+      comp = tpn->tpn_comp;
+
+      SU_DEBUG_9(("nta: agent_init_via: "
+		  "%s/%s %s%s%s%s%s%s (%s)\n",
+		  SIP_VERSION_CURRENT, tpn->tpn_proto,
+		  canon, port ? sport : "",
+		  maddr ? ";maddr=" : "", maddr ? host : "",
+		  comp ? ";comp=" : "", comp ? comp : "",
+		  tpn->tpn_ident ? tpn->tpn_ident : "*"));
+
+      v = sip_via_format(autohome,
+			 "%s/%s %s%s%s%s%s%s",
+			 SIP_VERSION_CURRENT, tpn->tpn_proto,
+			 canon, port ? sport : "",
+			 maddr ? ";maddr=" : "", maddr ? host : "",
+			 comp ? ";comp=" : "", comp ? comp : "");
+      if (v == NULL)
+	goto error;
+
+      v->v_comment = tpn->tpn_ident;
+      v->v_common->h_data = tp;	/* Nasty trick */
+      *vv = v; vv = &(*vv)->v_next;
+    }
+  }
+
+  /* Duplicate the list bind to the transports */
+  new_via = sip_via_dup(self->sa_home, via);
+  /* Duplicate the complete list shown to the application */
+  dup_via = sip_via_dup(self->sa_home, via);
+
+  if (via && (!new_via || !dup_via)) {
+    msg_header_free(self->sa_home, (void *)new_via);
+    msg_header_free(self->sa_home, (void *)dup_via);
+    goto error;
+  }
+
+  new_vias = NULL, next_new_via = &new_vias;
+  new_publics = NULL, next_new_public = &new_publics;
+
+  /* Set via field magic for the tports */
+  for (tp = primaries; tp; tp = tport_next(tp)) {
+    assert(via->v_common->h_data == tp);
+    v = tport_magic(tp);
+    tport_set_magic(tp, new_via);
+    msg_header_free(self->sa_home, (void *)v);
+
+    if (tport_is_public(tp))
+      *next_new_public = dup_via;
+    else
+      *next_new_via = dup_via;
+
+    while (via->v_next && via->v_next->v_common->h_data == tp)
+      via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next;
+    
+    via = via->v_next;
+    /* Break the link in via list between transports */
+    vv = &new_via->v_next, new_via = *vv, *vv = NULL;
+    vv = &dup_via->v_next, dup_via = *vv, *vv = NULL;
+
+    if (tport_is_public(tp))
+      while (*next_new_public) next_new_public = &(*next_new_public)->v_next;
+    else
+      while (*next_new_via) next_new_via = &(*next_new_via)->v_next;
+  }
+
+  assert(dup_via == NULL);
+  assert(new_via == NULL);
+
+  if (self->sa_tport_udp)
+    agent_set_udp_params(self, self->sa_udp_mtu);
+
+  v = self->sa_vias;
+  self->sa_vias = new_vias; 
+  msg_header_free(self->sa_home, (void *)v);
+
+  v = self->sa_public_vias;
+  self->sa_public_vias = new_publics;
+  msg_header_free(self->sa_home, (void *)v);
+
+  su_home_deinit(autohome);
+
+  return 0;
+
+ error:
+  su_home_deinit(autohome);
+  return -1;
+}
+
+
+/** Initialize main contact header. */
+static
+int agent_init_contact(nta_agent_t *self)
+{
+  sip_via_t const *v1, *v2;
+  char const *tp;
+
+  if (self->sa_contact)
+    return 0;
+
+  if (self->sa_vias)
+    v1 = self->sa_vias;
+  else
+    v1 = self->sa_public_vias;
+
+  if (!v1)
+    return -1;
+
+  tp = strrchr(v1->v_protocol, '/');
+  if (!tp++)
+    return -1;
+
+  v2 = v1->v_next;
+
+  if (v2 && 
+      strcasecmp(v1->v_host, v2->v_host) == 0 &&
+      str0casecmp(v1->v_port, v2->v_port) == 0) {
+    char const *p1 = v1->v_protocol, *p2 = v2->v_protocol;
+
+    if (strcasecmp(p1, sip_transport_udp))
+      p1 = v2->v_protocol, p2 = v1->v_protocol;
+
+    if (strcasecmp(p1, sip_transport_udp) == 0 &&
+	strcasecmp(p2, sip_transport_tcp) == 0)
+      /* Do not include transport if we have both UDP and TCP */
+      tp = NULL;
+  }
+
+  self->sa_contact = 
+    sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL, tp);
+
+  if (!self->sa_contact)
+    return -1;
+
+  return 0;
+}
+
+/** Return @Via line corresponging to tport. */
+static
+sip_via_t const *agent_tport_via(tport_t *tport)
+{
+  sip_via_t *v = tport_magic(tport);
+  while (v && v->v_next)
+    v = v->v_next;
+  return v;
+}
+
+/** Insert @Via to a request message */
+static
+int outgoing_insert_via(nta_outgoing_t *orq, 
+			sip_via_t const *via)
+{
+  nta_agent_t *self = orq->orq_agent;
+  msg_t *msg = orq->orq_request;
+  sip_t *sip = sip_object(msg);
+  char const *branch = orq->orq_via_branch;
+  int user_via = orq->orq_user_via;
+  sip_via_t *v;
+  int clear = 0;
+
+  assert(sip); assert(via);
+
+  if (user_via && sip->sip_via) {
+    /* Use existing @Via provided by application */
+    v = sip->sip_via;
+  }
+  else if (msg && via && sip->sip_request &&
+	   (v = sip_via_copy(msg_home(msg), via))) {
+    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+  }
+  else
+    return -1;
+
+  if (!v->v_rport && 
+      ((self->sa_rport && v->v_protocol == sip_transport_udp) ||
+       (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp)))
+    msg_header_add_param(msg_home(msg), v->v_common, "rport");
+
+  if (!orq->orq_tpn->tpn_comp)
+    msg_header_remove_param(v->v_common, "comp");
+
+  if (branch && branch != v->v_branch) {
+    char const *bvalue = branch + strcspn(branch, "=");
+    if (*bvalue) bvalue++;
+    if (!v->v_branch || strcasecmp(bvalue, v->v_branch))
+      msg_header_replace_param(msg_home(msg), v->v_common, branch);
+  }
+
+  if (via->v_protocol != v->v_protocol &&
+      strcasecmp(via->v_protocol, v->v_protocol))
+    clear = 1, v->v_protocol = via->v_protocol;
+
+  /* XXX - should we do this? */
+  if (via->v_host != v->v_host &&
+      str0cmp(via->v_host, v->v_host))
+    clear = 1, v->v_host = via->v_host;
+
+  if (via->v_port != v->v_port &&
+      str0cmp(via->v_port, v->v_port))
+    clear = 1, v->v_port = via->v_port;
+
+  if (clear)
+    msg_fragment_clear(v->v_common);
+
+  return 0;
+}
+
+/** Get destination name from @Via. 
+ *
+ * If @a using_rport is non-null, try rport.
+ * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
+ * If <protocol> is UDP, set *using_rport to zero.
+ */
+static
+int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport)
+{
+  if (!v)
+    return -1;
+
+  tpn->tpn_proto = sip_via_transport(v);
+  tpn->tpn_canon = v->v_host;
+
+  if (v->v_maddr)
+    tpn->tpn_host = v->v_maddr;
+  else if (v->v_received)
+    tpn->tpn_host = v->v_received;
+  else
+    tpn->tpn_host = v->v_host;
+
+  tpn->tpn_port = sip_via_port(v, using_rport);
+  tpn->tpn_comp = v->v_comp;
+  tpn->tpn_ident = NULL;
+
+  return 0;
+}
+
+/** Get transport name from URL. */
+int nta_tpn_by_url(su_home_t *home,
+		   tp_name_t *tpn,
+		   char const **scheme,
+		   char const **port,
+		   url_string_t const *us)
+{
+  url_t url[1];
+  isize_t n;
+  char *b;
+
+  n = url_xtra(us->us_url);
+  b = su_alloc(home, n);
+
+  if (b == NULL || url_dup(b, n, url, us->us_url) < 0) {
+    su_free(home, b);
+    return -1;
+  }
+
+  if (url->url_type != url_sip && 
+      url->url_type != url_sips &&
+      url->url_type != url_im &&
+      url->url_type != url_pres) {
+    su_free(home, b);
+    return -1;
+  }
+
+  SU_DEBUG_7(("nta: selecting scheme %s\n", url->url_scheme));
+
+  *scheme = url->url_scheme;
+  if (strcasecmp(url->url_scheme, "sips") == 0)
+    tpn->tpn_proto = "tls";
+  else
+    tpn->tpn_proto = "*";
+  tpn->tpn_canon = url->url_host;
+  tpn->tpn_host = url->url_host;
+
+  if (url->url_params) {
+    for (b = (char *)url->url_params; b[0]; b += n) {
+      n = strcspn(b, ";");
+
+      if (n > 10 && strncasecmp(b, "transport=", 10) == 0)
+	tpn->tpn_proto = b + 10;
+      else if (n > 5 && strncasecmp(b, "comp=", 5) == 0)
+	tpn->tpn_comp = b + 5;
+      else if (n > 6 && strncasecmp(b, "maddr=", 6) == 0)
+	tpn->tpn_host = b + 6;
+
+      if (b[n])
+	b[n++] = '\0';
+    }
+  }
+
+  if ((*port = url->url_port))
+    tpn->tpn_port = url->url_port;
+
+  tpn->tpn_ident = NULL;
+
+  return 0;
+}
+
+/** Handle transport errors. */
+static
+void agent_tp_error(nta_agent_t *agent,
+		    tport_t *tport,
+		    int errcode,
+		    char const *remote)
+{
+  su_llog(nta_log, 1,
+	  "nta_agent: tport: %s%s%s\n",
+	  remote ? remote : "", remote ? ": " : "",
+	  su_strerror(errcode));
+}
+
+/** Handle updated transport addresses */
+static void agent_update_tport(nta_agent_t *self, tport_t *tport)
+{
+  /* Initialize local Vias first */
+  agent_init_via(self, tport_primaries(self->sa_tports), 0);
+
+  if (self->sa_update_tport) {
+    self->sa_update_tport(self->sa_update_magic, self);
+  }
+  else {
+    /* XXX - we should do something else? */
+    SU_DEBUG_3(("nta(%p): transport address updated\n", self));
+  }
+}
+
+/* ====================================================================== */
+/* 3) Message dispatch */
+
+static void agent_recv_request(nta_agent_t *agent,
+			       msg_t *msg,
+			       sip_t *sip,
+			       tport_t *tport);
+static int agent_check_request_via(nta_agent_t *agent,
+				   msg_t *msg,
+				   sip_t *sip,
+				   sip_via_t *v,
+				   tport_t *tport);
+static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);
+static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *,
+				sip_via_t *, tport_t*);
+static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);
+
+
+/** Handle incoming message. */
+static
+void agent_recv_message(nta_agent_t *agent,
+			tport_t *tport,
+			msg_t *msg,
+			sip_via_t *tport_via,
+			su_time_t now)
+{
+  sip_t *sip = sip_object(msg);
+
+  agent->sa_millisec = su_time_ms(agent->sa_now = now);
+
+  if (sip && sip->sip_request) {
+    agent_recv_request(agent, msg, sip, tport);
+  }
+  else if (sip && sip->sip_status) {
+    agent_recv_response(agent, msg, sip, tport_via, tport);
+  }
+  else {
+    agent_recv_garbage(agent, msg, tport);
+  }
+
+  agent->sa_millisec = 0;
+}
+
+/** @internal Handle incoming requests. */
+static
+void agent_recv_request(nta_agent_t *agent,
+			msg_t *msg,
+			sip_t *sip,
+			tport_t *tport)
+{
+  nta_leg_t *leg;
+  nta_incoming_t *irq, *merge = NULL, *ack = NULL;
+  sip_method_t method = sip->sip_request->rq_method;
+  char const *method_name = sip->sip_request->rq_method_name;
+  url_t url[1];
+  unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
+  int insane, errors, stream;
+
+  agent->sa_stats->as_recv_msg++;
+  agent->sa_stats->as_recv_request++;
+
+  SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n",
+	      method_name,
+	      URL_PRINT_ARGS(sip->sip_request->rq_url),
+	      sip->sip_request->rq_version, cseq));
+
+  stream = tport_is_stream(tport);
+
+  /* Try to use compression on reverse direction if @Via has comp=sigcomp  */
+  if (stream && 
+      sip->sip_via && sip->sip_via->v_comp &&
+      tport_can_send_sigcomp(tport) &&
+      tport_name(tport)->tpn_comp == NULL && 
+      tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) {
+    tport_set_compression(tport, sip->sip_via->v_comp);
+  }
+
+  if (sip->sip_flags & MSG_FLG_TOOLARGE) {
+    SU_DEBUG_5(("nta: %s (%u) is %s\n", 
+		method_name, cseq, sip_413_Request_too_large));
+    agent->sa_stats->as_bad_request++;
+    nta_msg_treply(agent, msg, SIP_413_REQUEST_TOO_LARGE,
+		   NTATAG_TPORT(tport),
+		   NTATAG_INCOMPLETE(1),		   
+		   TPTAG_SDWN_AFTER(stream),
+		   TAG_END());
+    return;
+  }
+
+  insane = 0;
+
+  if (agent->sa_bad_req_mask != ~0U)
+    errors = msg_extract_errors(msg) & agent->sa_bad_req_mask;
+  else
+    errors = sip->sip_error != NULL;
+
+  if (errors ||
+      (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ || 
+      (insane = (sip_sanity_check(sip) < 0))) {
+    sip_header_t const *h;
+    char const *badname = NULL, *phrase;
+    
+    agent->sa_stats->as_bad_message++;
+    agent->sa_stats->as_bad_request++;
+
+    if (insane)
+      SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq,
+		  "failed sanity check"));
+
+    for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_next) {
+      char const *bad;
+
+      if (h->sh_class == sip_error_class)
+	bad = h->sh_error->er_name;
+      else 
+	bad = h->sh_class->hc_name;
+
+      if (bad)
+	SU_DEBUG_5(("nta: %s has bad %s header\n", method_name, bad));
+      
+      if (!badname)
+	badname = bad;
+    }
+
+    if (sip->sip_via && method != sip_method_ack) {
+      msg_t *reply = nta_msg_create(agent, 0);
+      
+      if (reply) {
+	agent_check_request_via(agent, msg, sip, sip->sip_via, tport);
+
+	if (badname)
+	  phrase = su_sprintf(msg_home(reply), "Bad %s Header", badname);
+	else
+	  phrase = sip_400_Bad_request;
+
+	SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, phrase));
+	
+	nta_msg_mreply(agent, reply, sip_object(reply),
+		       400, phrase,
+		       msg,
+		       NTATAG_TPORT(tport), 
+		       NTATAG_INCOMPLETE(1), 
+		       TPTAG_SDWN_AFTER(stream),
+		       TAG_END());
+      }
+    } else {
+      msg_destroy(msg);
+      if (stream)		/* Send FIN */
+	tport_shutdown(tport, 1);
+    }
+
+    return;
+  }
+
+  if (str0casecmp(sip->sip_request->rq_version, sip_version_2_0) != 0) {
+    agent->sa_stats->as_bad_request++;
+    agent->sa_stats->as_bad_message++;
+
+    SU_DEBUG_5(("nta: bad version %s for %s (%u)\n",
+		sip->sip_request->rq_version, method_name, cseq));
+
+    nta_msg_treply(agent, msg, SIP_505_VERSION_NOT_SUPPORTED,
+		   NTATAG_TPORT(tport), 
+		   TPTAG_SDWN_AFTER(stream),
+		   TAG_END());
+
+    return;
+  }
+
+  if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) {
+    agent->sa_stats->as_bad_message++;
+    agent->sa_stats->as_bad_request++;
+    SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"));
+    msg_destroy(msg);
+    return;
+  }
+
+  /* First, try existing incoming requests */
+  irq = incoming_find(agent, sip, sip->sip_via, &merge, &ack);
+  if (irq) {
+    /* Match - this is a retransmission */
+    SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n",
+		method_name, cseq, irq->irq_rq->rq_method_name));
+    if (incoming_recv(irq, msg, sip, tport) >= 0)
+      return;
+  }
+  else if (ack) {
+    /* Match - this is an ACK or CANCEL or PRACK */
+    SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",
+		method_name, cseq,
+		ack->irq_rq->rq_method_name, ack->irq_cseq->cs_seq));
+    if (method == sip_method_ack) {
+      if (incoming_ack(ack, msg, sip, tport) >= 0)
+	return;
+    }
+    else if (method == sip_method_cancel) {
+      if (incoming_cancel(ack, msg, sip, tport) >= 0)
+	return;
+    }
+    else if (method == sip_method_prack) {
+      if (reliable_recv(ack, msg, sip, tport) >= 0)
+	return;
+    }
+    else {
+      assert(!method);
+    }
+  }
+  else if (merge) {
+    SU_DEBUG_5(("nta: %s (%u) %s\n",
+		method_name, cseq, "is a merged request"));
+    if (incoming_merge(merge, msg, sip, tport) >= 0)
+      return;
+  }
+
+  *url = *sip->sip_request->rq_url;
+  url->url_params = NULL;
+  agent_aliases(agent, url, tport); /* canonize urls */
+
+  if ((leg = leg_find(agent, 
+		      method_name, url, 
+		      sip->sip_call_id,
+		      sip->sip_from->a_tag, sip->sip_from->a_url, 
+		      sip->sip_to->a_tag, sip->sip_to->a_url))) {
+    /* Try existing dialog */
+    SU_DEBUG_5(("nta: %s (%u) %s\n",
+		method_name, cseq, "going to existing leg"));
+    leg_recv(leg, msg, sip, tport);
+    return;
+  }
+  else if (!agent->sa_is_stateless &&
+	   (leg = dst_find(agent, url, method_name))) {
+    /* Dialogless legs - let application process transactions statefully */
+    SU_DEBUG_5(("nta: %s (%u) %s\n",
+		method_name, cseq, "going to a dialogless leg"));
+    leg_recv(leg, msg, sip, tport);
+  }
+  else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
+    SU_DEBUG_5(("nta: %s (%u) %s\n",
+		method_name, cseq, "going to a default leg"));
+    leg_recv(leg, msg, sip, tport);
+  }
+  else if (agent->sa_callback) {
+    /* Stateless processing for request */
+    agent->sa_stats->as_trless_request++;
+    SU_DEBUG_5(("nta: %s (%u) %s\n", 
+		method_name, cseq, "to message callback"));
+    (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
+  }
+  else {
+    agent->sa_stats->as_trless_request++;
+    SU_DEBUG_5(("nta: %s (%u) no place to go: %d %s\n",
+		method_name, cseq, SIP_501_NOT_IMPLEMENTED));
+    if (method != sip_method_ack)
+      nta_msg_treply(agent, msg, SIP_501_NOT_IMPLEMENTED,
+		     NTATAG_TPORT(tport),
+		     TAG_END());
+    else
+      msg_destroy(msg);
+  }
+}
+
+/** Check @Via header.
+ *
+ */
+static
+int agent_check_request_via(nta_agent_t *agent,
+			    msg_t *msg,
+			    sip_t *sip,
+			    sip_via_t *v,
+			    tport_t *tport)
+{
+  enum { receivedlen = sizeof("received=") - 1 };
+  char received[receivedlen + TPORT_HOSTPORTSIZE];
+  char *hostport = received + receivedlen;
+  char const *rport;
+  su_sockaddr_t const *from;
+  sip_via_t const *tpv = agent_tport_via(tport);
+
+  assert(tport); assert(msg); assert(sip);
+  assert(sip->sip_request); assert(tpv);
+
+  from = msg_addr(msg);
+
+  if (v == NULL) {
+    /* Make up a via line */
+    v = sip_via_format(msg_home(msg), "SIP/2.0/%s %s",
+		       tport_name(tport)->tpn_proto,
+		       tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1));
+    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+
+    return v ? 0 : -1;
+  }
+
+  if (str0casecmp(v->v_protocol, tpv->v_protocol)) {
+    tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1);
+    SU_DEBUG_1(("nta: Via check: invalid transport \"%s\" from %s\n",
+		v->v_protocol, hostport));
+    return -1;
+  }
+
+  if (v->v_received) {
+    /* Nasty, nasty */
+    tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1);
+    SU_DEBUG_1(("nta: Via check: extra received=%s from %s\n",
+		v->v_received, hostport));
+    msg_header_remove_param(v->v_common, "received");
+  }
+
+  if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 0))
+    return -1;
+
+  if (strcasecmp(hostport, v->v_host)) {
+    size_t rlen;
+    /* Add the "received" field */
+    memcpy(received, "received=", receivedlen);
+
+    if (hostport[0] == '[') {
+      rlen = strlen(hostport + 1) - 1;
+      memmove(hostport, hostport + 1, rlen);
+      hostport[rlen] = '\0';
+    }
+
+    msg_header_replace_param(msg_home(msg), v->v_common, 
+			     su_strdup(msg_home(msg), received));
+    SU_DEBUG_5(("nta: Via check: %s\n", received));
+  }
+
+  if (!agent->sa_server_rport) {
+    /*Xyzzy*/;
+  }
+  else if (v->v_rport) {
+    rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port));
+    msg_header_replace_param(msg_home(msg), v->v_common, rport);
+  } 
+  else if (tport_is_tcp(tport)) {
+    rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port));
+    msg_header_replace_param(msg_home(msg), v->v_common, rport);
+  }
+
+  return 0;
+}
+
+/** @internal Handle aliases of local node. 
+ *
+ * Return true if @a url is modified.
+ */
+static
+int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport)
+{
+  sip_contact_t *m;
+  sip_via_t const *lv;
+  char const *tport_port = "";
+
+  if (!url->url_host)
+    return 0;
+
+  if (tport)
+    tport_port = tport_name(tport)->tpn_port;
+
+  assert(tport_port);
+
+  for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact;
+       m;
+       m = m->m_next) {
+    if (url->url_type != m->m_url->url_type)
+      continue;
+
+    if (host_cmp(url->url_host, m->m_url->url_host))
+      continue;
+
+    if (url->url_port == NULL)
+      break;
+
+    if (m->m_url->url_port) {
+      if (strcmp(url->url_port, m->m_url->url_port))
+	continue;
+    } else {
+      if (strcmp(url->url_port, tport_port))
+	continue;
+    }
+
+    break;
+  }
+
+  if (!m)
+    return 0;
+
+  SU_DEBUG_7(("nta: canonizing " URL_PRINT_FORMAT " with %s\n",
+	      URL_PRINT_ARGS(url),
+	      agent->sa_aliases ? "aliases" : "contact"));
+
+  url->url_host = "%";
+
+  if (agent->sa_aliases) {
+    url->url_type = agent->sa_aliases->m_url->url_type;
+    url->url_scheme = agent->sa_aliases->m_url->url_scheme;
+    url->url_port = agent->sa_aliases->m_url->url_port;
+    return 1;
+  }
+  else {
+    /* Canonize the request URL port */
+    if (tport) {
+      lv = agent_tport_via(tport_parent(tport)); assert(lv);
+      if (lv->v_port)
+	/* Add non-default port */
+	url->url_port = lv->v_port;
+      return 1;
+    }
+    if (url->url_port &&
+	strcmp(url->url_port, url_port_default(url->url_type)) == 0)
+      /* Remove default port */
+      url->url_port = NULL;
+
+    return 0;
+  }
+}
+
+/** @internal Handle incoming responses. */
+static
+void agent_recv_response(nta_agent_t *agent,
+                         msg_t *msg,
+                         sip_t *sip,
+                         sip_via_t *tport_via,
+                         tport_t *tport)
+{
+  int status = sip->sip_status->st_status;
+  int errors;
+  char const *phrase = sip->sip_status->st_phrase;
+  char const *method =
+    sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>";
+  uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
+  nta_outgoing_t *orq;
+
+  agent->sa_stats->as_recv_msg++;
+  agent->sa_stats->as_recv_response++;
+
+  SU_DEBUG_5(("nta: received %03d %s for %s (%u)\n", 
+	      status, phrase, method, cseq));
+
+  if (agent->sa_bad_resp_mask)
+    errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask;
+  else
+    errors = sip->sip_error != NULL;
+
+  if (errors || 
+      sip_sanity_check(sip) < 0) {
+    sip_header_t const *h;
+
+    agent->sa_stats->as_bad_response++;
+    agent->sa_stats->as_bad_message++;
+
+    SU_DEBUG_5(("nta: %03d %s failed sanity check\n", status, phrase));
+
+    for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_next) {
+      if (h->sh_class->hc_name) {
+	SU_DEBUG_5(("nta: %03d has bad %s header\n", status,
+		    h->sh_class->hc_name));
+      }
+    }
+
+    msg_destroy(msg);
+    return;
+  }
+
+  if (str0casecmp(sip->sip_status->st_version, sip_version_2_0) != 0) {
+    agent->sa_stats->as_bad_response++;
+    agent->sa_stats->as_bad_message++;
+
+    SU_DEBUG_5(("nta: bad version %s %03d %s\n",
+		sip->sip_status->st_version, status, phrase));
+    msg_destroy(msg);
+    return;
+  }
+
+  if (sip->sip_cseq->cs_method == sip_method_ack) {
+    /* Drop response messages to ACK */
+    agent->sa_stats->as_bad_response++;
+    agent->sa_stats->as_bad_message++;
+    SU_DEBUG_5(("nta: %03d %s is response to ACK\n", status, phrase));
+    msg_destroy(msg);
+    return;
+  }
+
+  /* XXX - should check if msg should be discarded based on via? */
+
+  if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
+    SU_DEBUG_5(("nta: %03d %s going to a transaction\n", status, phrase));
+    if (outgoing_recv(orq, status, msg, sip) == 0)
+      return;
+  }
+
+  agent->sa_stats->as_trless_response++;
+
+  if ((orq = agent->sa_default_outgoing)) {
+    SU_DEBUG_5(("nta: %03d %s to the default transaction\n", status, phrase));
+    outgoing_default_recv(orq, status, msg, sip);
+    return;
+  }
+  else if (agent->sa_callback) {
+    SU_DEBUG_5(("nta: %03d %s to message callback\n", status, phrase));
+    /*
+     * Store message and transport to hook for the duration of the callback
+     * so that the transport can be obtained by nta_transport().
+     */
+    (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
+    return;
+  }
+
+  if (sip->sip_cseq->cs_method == sip_method_invite
+      && 200 <= sip->sip_status->st_status
+      && sip->sip_status->st_status < 300) {
+    agent->sa_stats->as_trless_200++;
+    /* Orphan 200 Ok to INVITE. ACK and BYE it */
+    SU_DEBUG_5(("nta: %03d %s must be ACK&BYE\n", status, phrase));
+    if (nta_msg_ackbye(agent, msg) != -1)
+      return;
+  }
+
+  SU_DEBUG_5(("nta: %03d %s was discarded\n", status, phrase));
+  msg_destroy(msg);
+}
+/** @internal Agent receives garbage */
+static
+void agent_recv_garbage(nta_agent_t *agent,
+			msg_t *msg,
+			tport_t *tport)
+{
+  agent->sa_stats->as_recv_msg++;
+  agent->sa_stats->as_bad_message++;
+
+#if SU_DEBUG >= 3
+  if (nta_log->log_level >= 3) {
+    tp_name_t tpn[1];
+
+    tport_delivered_from(tport, msg, tpn);
+
+    SU_DEBUG_3(("nta_agent: received garbage from " TPN_FORMAT "\n",
+		TPN_ARGS(tpn)));
+  }
+#endif
+
+  msg_destroy(msg);
+}
+
+/* ====================================================================== */
+/* 4) Message handling - create, complete, destroy */
+
+/** Create a new message belonging to the agent */
+msg_t *nta_msg_create(nta_agent_t *agent, int flags)
+{
+  msg_t *msg;
+
+  if (agent == NULL)
+    return su_seterrno(EINVAL), NULL;
+
+  msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
+
+  if (agent->sa_preload)
+    su_home_preload(msg_home(msg), 1, agent->sa_preload);
+
+  return msg;
+}
+
+/** Create a new message for transport */
+msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
+				    char const data[], usize_t dlen,
+				    tport_t const *tport, tp_client_t *via)
+{
+  msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
+
+  msg_maxsize(msg, agent->sa_maxsize);
+
+  if (agent->sa_preload)
+    su_home_preload(msg_home(msg), 1, dlen + agent->sa_preload);
+
+  return msg;
+}
+
+/** Complete a message. */
+int nta_msg_complete(msg_t *msg)
+{
+  return sip_complete_message(msg);
+}
+
+/** Discard a message */
+void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
+{
+  msg_destroy(msg);
+}
+
+/** Check if the message is internally generated by NTA. */
+int  nta_is_internal_msg(msg_t const *msg)
+{
+  return msg_get_flags(msg, NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG;
+}
+
+/* ====================================================================== */
+/* 5) Stateless operation */
+
+/**Forward a request or response message. 
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+		  tag_type_t tag, tag_value_t value, ...)
+{
+  int retval = -1;
+  ta_list ta;
+  sip_t *sip = sip_object(msg);
+  tp_name_t tpn[1] = {{ NULL }};
+  char const *what;
+
+  if (!sip) {
+    msg_destroy(msg);
+    return -1;
+  }
+
+  what = 
+    sip->sip_status ? "nta_msg_tsend(response)" : 
+    sip->sip_request ? "nta_msg_tsend(request)" :
+    "nta_msg_tsend()";
+
+  ta_start(ta, tag, value);
+
+  if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+    SU_DEBUG_3(("%s: cannot add headers\n", what));
+  else if (sip->sip_status) {
+    tport_t *tport = NULL;
+    int *use_rport = NULL;
+    int retry_without_rport = 0;
+
+    struct sigcomp_compartment *cc; cc = NONE;
+
+    if (agent->sa_server_rport)
+      use_rport = &retry_without_rport, retry_without_rport = 1;
+
+    tl_gets(ta_args(ta),
+	    NTATAG_TPORT_REF(tport),
+	    IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)
+	    /* NTATAG_INCOMPLETE_REF(incomplete), */
+	    TAG_END());
+
+    if (!sip->sip_separator && 
+	!(sip->sip_separator = sip_separator_create(msg_home(msg))))
+      SU_DEBUG_3(("%s: cannot create sip_separator\n", what));
+    else if (msg_serialize(msg, (msg_pub_t *)sip) != 0)
+      SU_DEBUG_3(("%s: sip_serialize() failed\n", what));
+    else if (!sip_via_remove(msg, sip))
+      SU_DEBUG_3(("%s: cannot remove Via\n", what));
+    else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
+      SU_DEBUG_3(("%s: bad via\n", what));
+    else {
+      if (!tport)
+	tport = tport_by_name(agent->sa_tports, tpn);
+      if (!tport)
+	tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
+
+      if (retry_without_rport)
+	tpn->tpn_port = sip_via_port(sip->sip_via, NULL);
+
+      if (tport && tpn->tpn_comp && cc == NONE)
+	cc = agent_compression_compartment(agent, tport, tpn, -1);
+
+      if (tport_tsend(tport, msg, tpn,
+		      IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+		      TPTAG_MTU(INT_MAX), ta_tags(ta), TAG_END())) {
+	agent->sa_stats->as_sent_msg++;
+	agent->sa_stats->as_sent_response++;
+	retval = 0;
+      }
+      else {
+	SU_DEBUG_3(("%s: send fails\n", what));
+      }
+    }
+  }
+  else {
+    /* Send request */
+    if (outgoing_create(agent, NULL, NULL, u, NULL, msg_ref_create(msg), 
+			NTATAG_STATELESS(1),
+			ta_tags(ta)))
+      retval = 0;
+  }
+
+  if (retval == 0)
+    SU_DEBUG_5(("%s\n", what));
+
+  ta_end(ta);
+
+  msg_destroy(msg);
+
+  return retval;
+}
+
+/** Reply to a request message.
+ *
+ * @param agent    nta agent object
+ * @param req_msg  request message
+ * @param status   status code
+ * @param phrase   status phrase (may be NULL if status code is well-known)
+ * @param tag, value, ... optional additional headers terminated by TAG_END()
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_treply(nta_agent_t *agent,
+		   msg_t *req_msg,
+		   int status, char const *phrase,
+		   tag_type_t tag, tag_value_t value, ...)
+{
+  int retval;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  retval = nta_msg_mreply(agent, NULL, NULL, status, phrase, req_msg, 
+			  ta_tags(ta));
+  ta_end(ta);
+
+  return retval;
+}
+
+/**Reply to the request message.
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_mreply(nta_agent_t *agent,
+		   msg_t *reply, sip_t *sip,
+		   int status, char const *phrase,
+		   msg_t *req_msg,
+		   tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  tp_name_t tpn[1];
+  int retval = -1;
+  tport_t *tport = NULL;
+  struct sigcomp_compartment *cc = NONE;
+  int *use_rport = NULL;
+  int retry_without_rport = 0, incomplete = 0;
+
+  if (!agent)
+    return -1;
+
+  if (agent->sa_server_rport)
+    use_rport = &retry_without_rport, retry_without_rport = 1;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  NTATAG_TPORT_REF(tport),
+	  NTATAG_INCOMPLETE_REF(incomplete),
+	  TPTAG_COMPARTMENT_REF(cc),
+	  TAG_END());
+
+  if (reply == NULL) {
+    reply = nta_msg_create(agent, 0);
+    sip = sip_object(reply);
+  }
+
+  if (!sip) {
+    SU_DEBUG_3(("%s: no msg\n", __func__));
+  }
+  else if (sip_add_tl(reply, sip, ta_tags(ta)) < 0) {
+    SU_DEBUG_3(("%s: cannot add user headers\n", __func__));
+  }
+  else if (complete_response(reply, status, phrase, req_msg) < 0 &&
+	   !incomplete) {
+    SU_DEBUG_3(("%s: cannot complete message\n", __func__));
+  }
+  else if (sip->sip_status && sip->sip_status->st_status > 100 &&
+	   sip->sip_to && !sip->sip_to->a_tag &&
+	   sip->sip_cseq && sip->sip_cseq->cs_method != sip_method_cancel &&
+	   sip_to_tag(msg_home(reply), sip->sip_to,
+		      nta_agent_newtag(msg_home(reply), "tag=%s", agent)) < 0) {
+    SU_DEBUG_3(("%s: cannot add To tag\n", __func__));
+  }
+  else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) {
+    SU_DEBUG_3(("%s: no Via\n", __func__));
+  }
+  else {
+    if (tport == NULL)
+      tport = tport_delivered_by(agent->sa_tports, req_msg);
+
+    if (!tport) {
+      tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
+
+      tport = tport_by_name(primary, tpn);
+
+      if (!tport)
+	tport = primary;
+    }
+
+    if (retry_without_rport)
+      tpn->tpn_port = sip_via_port(sip->sip_via, NULL);
+
+    if (tport && tpn->tpn_comp) {
+      if (cc == NONE)
+	cc = agent_compression_compartment(agent, tport, tpn, -1);
+
+      if (cc != NULL && cc != NONE &&
+	  tport_delivered_with_comp(tport, req_msg, NULL) != -1) {
+	agent_accept_compressed(agent, req_msg, cc);
+      }
+    }
+
+    if (tport_tsend(tport, reply, tpn, 
+		    IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+		    TPTAG_MTU(INT_MAX), ta_tags(ta))) {
+      agent->sa_stats->as_sent_msg++;
+      agent->sa_stats->as_sent_response++;
+      retval = 0;			/* Success! */
+    }
+    else {
+      SU_DEBUG_3(("%s: send fails\n", __func__));
+    }
+  }
+
+  msg_destroy(reply);
+  msg_destroy(req_msg);
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/** Add headers from the request to the response message. */
+static
+int complete_response(msg_t *response, 
+		      int status, char const *phrase, 
+		      msg_t const *request)
+{
+  su_home_t *home = msg_home(response);
+  sip_t *response_sip = sip_object(response);
+  sip_t const *request_sip = sip_object(request);
+
+  int incomplete = 0;
+
+  if (!response_sip || !request_sip || !request_sip->sip_request)
+    return -1;
+
+  if (!response_sip->sip_status)
+    response_sip->sip_status = sip_status_create(home, status, phrase, NULL);
+  if (!response_sip->sip_via)
+    response_sip->sip_via = sip_via_dup(home, request_sip->sip_via);
+  if (!response_sip->sip_from)
+    response_sip->sip_from = sip_from_dup(home, request_sip->sip_from);
+  if (!response_sip->sip_to)
+    response_sip->sip_to = sip_to_dup(home, request_sip->sip_to);
+  if (!response_sip->sip_call_id)
+    response_sip->sip_call_id = 
+      sip_call_id_dup(home, request_sip->sip_call_id);
+  if (!response_sip->sip_cseq)
+    response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq);
+
+  if (!response_sip->sip_record_route && request_sip->sip_record_route)
+    sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route);
+
+  incomplete = sip_complete_message(response) < 0;
+
+  msg_serialize(response, (msg_pub_t *)response_sip);
+
+  if (incomplete ||
+      !response_sip->sip_status ||
+      !response_sip->sip_via ||
+      !response_sip->sip_from ||
+      !response_sip->sip_to ||
+      !response_sip->sip_call_id ||
+      !response_sip->sip_cseq ||
+      !response_sip->sip_content_length ||
+      !response_sip->sip_separator ||
+      (request_sip->sip_record_route && !response_sip->sip_record_route))
+    return -1;
+
+  return 0;
+}
+
+/** ACK and BYE an unknown 200 OK response to INVITE.
+ *
+ * A UAS may still return a 2XX series response to an INVITE request after
+ * the client transaction has been terminated. In that case, the UAC can not
+ * really accept the call, but it may send a ACK request to UAS followed
+ * immediately by BYE using nta_msg_ackbye(). The function does not create a
+ * transaction objects, but just sends the ACK and BYE request messages
+ * according to the @RecordRoute and @Contact headers in the @a msg.
+ */
+int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg)
+{
+  sip_t *sip = sip_object(msg);
+  msg_t *amsg = nta_msg_create(agent, 0);
+  sip_t *asip = sip_object(amsg);
+  msg_t *bmsg = NULL;
+  sip_t *bsip;
+  url_string_t const *ruri;
+  nta_outgoing_t *ack = NULL, *bye = NULL;
+  sip_cseq_t *cseq;
+  sip_request_t *rq;
+  sip_route_t *route = NULL, *r, r0[1];
+  su_home_t *home = msg_home(amsg);
+
+  if (asip == NULL)
+    return -1;
+
+  sip_add_tl(amsg, asip,
+	     SIPTAG_TO(sip->sip_to),
+	     SIPTAG_FROM(sip->sip_from),
+	     SIPTAG_CALL_ID(sip->sip_call_id),
+	     TAG_END());
+
+  if (sip->sip_contact) {
+    ruri = (url_string_t const *)sip->sip_contact->m_url;
+  } else {
+    ruri = (url_string_t const *)sip->sip_to->a_url;
+  }
+
+  /* Reverse (and fix) record route */
+  route = sip_route_reverse(home, sip->sip_record_route);
+
+  if (route && !url_has_param(route->r_url, "lr")) {
+    for (r = route; r->r_next; r = r->r_next)
+      ;
+
+    /* Append r-uri */
+    *sip_route_init(r0)->r_url = *ruri->us_url;
+    r->r_next = sip_route_dup(home, r0);
+    
+    /* Use topmost route as request-uri */
+    ruri = (url_string_t const *)route->r_url;
+    route = route->r_next;
+  }
+
+  msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route);
+
+  bmsg = msg_copy(amsg); bsip = sip_object(bmsg);
+
+  if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACK)))
+    goto err;
+  else
+    msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq);
+
+  if (!(rq = sip_request_create(home, SIP_METHOD_ACK, ruri, NULL)))
+    goto err;
+  else
+    msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq);
+
+  if (!(ack = nta_outgoing_mcreate(agent, NULL, NULL, NULL, amsg,
+				   NTATAG_ACK_BRANCH(sip->sip_via->v_branch),
+				   NTATAG_STATELESS(1),
+				   TAG_END())))
+    goto err;
+  else
+    nta_outgoing_destroy(ack);
+
+  home = msg_home(bmsg);
+
+  if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYE)))
+    goto err;
+  else
+    msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq);
+
+  if (!(rq = sip_request_create(home, SIP_METHOD_BYE, ruri, NULL)))
+    goto err;
+  else
+    msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq);
+
+  if (!(bye = nta_outgoing_mcreate(agent, NULL, NULL, NULL, bmsg, 
+				   NTATAG_STATELESS(1),
+				   TAG_END())))
+    goto err;
+
+  msg_destroy(msg);
+  return 0;
+
+ err:
+  msg_destroy(amsg);
+  msg_destroy(bmsg);
+  return -1;
+}
+
+/**Complete a request with values from dialog.
+ *
+ * The function nta_msg_request_complete() completes a request message @a
+ * msg belonging to a dialog associated with @a leg. It increments the local
+ * @CSeq value, adds @CallID, @To, @From and @Route headers (if
+ * there is such headers present in @a leg), and creates a new request line
+ * object from @a method, @a method_name and @a request_uri.
+ *
+ * @param msg          pointer to a request message object
+ * @param leg          pointer to a #nta_leg_t object
+ * @param method       request method number or #sip_method_unknown
+ * @param method_name  method name (if @a method == #sip_method_unknown)
+ * @param request_uri  request URI
+ *
+ * If @a request_uri contains query part, the query part is converted as SIP
+ * headers and added to the request.
+ *
+ * @retval 0  when successful
+ * @retval -1 upon an error
+ *
+ * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate()
+ */
+int nta_msg_request_complete(msg_t *msg,
+			     nta_leg_t *leg,
+			     sip_method_t method,
+			     char const *method_name,
+			     url_string_t const *request_uri)
+{
+  su_home_t *home = msg_home(msg);
+  sip_t *sip = sip_object(msg);
+  sip_to_t const *to;
+  sip_cseq_t *cseq;
+  uint32_t seq;
+  url_t reg_url[1];
+  url_string_t const *original = request_uri;
+
+  if (!leg || !msg)
+    return -1;
+
+  if (!sip->sip_route && leg->leg_route) {
+    if (leg->leg_loose_route) {
+      if (leg->leg_target) {
+	request_uri = (url_string_t *)leg->leg_target->m_url;
+      }
+      sip->sip_route = sip_route_dup(home, leg->leg_route);
+    }
+    else {
+      sip_route_t **rr;
+
+      request_uri = (url_string_t *)leg->leg_route->r_url;
+      sip->sip_route = sip_route_dup(home, leg->leg_route->r_next);
+
+      for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next)
+	;
+
+      if (leg->leg_target)
+	*rr = sip_route_dup(home, (sip_route_t *)leg->leg_target);
+    }
+  }
+  else if (leg->leg_target)
+    request_uri = (url_string_t *)leg->leg_target->m_url;
+
+  if (!request_uri && sip->sip_request)
+    request_uri = (url_string_t *)sip->sip_request->rq_url;
+
+  to = sip->sip_to ? sip->sip_to : leg->leg_remote;
+  
+  if (!request_uri && to) {
+    if (method != sip_method_register)
+      request_uri = (url_string_t *)to->a_url;
+    else {
+      /* Remove user part from REGISTER requests */
+      *reg_url = *to->a_url;
+      reg_url->url_user = reg_url->url_password = NULL;
+      request_uri = (url_string_t *)reg_url;
+    }
+  }
+
+  if (!request_uri)
+    return -1;
+
+  if (method || method_name) {
+    sip_request_t *rq = sip->sip_request;
+    int use_headers = 
+      request_uri == original || (url_t *)request_uri == rq->rq_url;
+
+    if (!rq
+	|| request_uri != (url_string_t *)rq->rq_url
+	|| method != rq->rq_method
+	|| str0cmp(method_name, rq->rq_method_name))
+      rq = NULL;
+
+    if (rq == NULL) {
+      rq = sip_request_create(home, method, method_name, request_uri, NULL);
+      if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0)
+	return -1;
+    }
+
+    /* @RFC3261 table 1 (page 152): 
+     * Req-URI cannot contain method parameter or headers 
+     */
+    if (rq->rq_url->url_params) {
+      rq->rq_url->url_params = 
+	url_strip_param_string((char *)rq->rq_url->url_params, "method");
+      sip_fragment_clear(rq->rq_common);
+    }
+
+    if (rq->rq_url->url_headers) {
+      if (use_headers) {
+	char *s = url_query_as_header_string(msg_home(msg),
+					     rq->rq_url->url_headers);
+	if (!s)
+	  return -1;
+	msg_header_parse_str(msg, (msg_pub_t*)sip, s);
+      }
+      rq->rq_url->url_headers = NULL, sip_fragment_clear(rq->rq_common);
+    }
+  }
+
+  if (!sip->sip_request)
+    return -1;
+
+  if (!sip->sip_max_forwards)
+    sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards);
+
+  if (!sip->sip_call_id) {
+    if (leg->leg_id)
+      sip->sip_call_id = sip_call_id_dup(home, leg->leg_id);
+    else
+      sip->sip_call_id = sip_call_id_create(home, NULL);
+  }
+
+  if (!sip->sip_from)
+    sip->sip_from = sip_from_dup(home, leg->leg_local);
+  else if (leg->leg_local && leg->leg_local->a_tag &&
+	   (!sip->sip_from->a_tag ||
+	    strcasecmp(sip->sip_from->a_tag, leg->leg_local->a_tag)))
+    sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag);
+
+  if (sip->sip_from && !sip->sip_from->a_tag) {
+    sip_fragment_clear(sip->sip_from->a_common);
+    sip_from_add_param(home, sip->sip_from,
+		       nta_agent_newtag(home, "tag=%s", leg->leg_agent));
+  }
+
+  if (sip->sip_to) {
+    if (leg->leg_remote && leg->leg_remote->a_tag)
+      sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag);
+  }
+  else if (leg->leg_remote) {
+    sip->sip_to = sip_to_dup(home, leg->leg_remote);
+  }
+  else {
+    sip_to_t *to = sip_to_create(home, request_uri);
+    if (to) sip_aor_strip(to->a_url);
+    sip->sip_to = to;
+  }
+
+  if (!sip->sip_from || !sip->sip_from || !sip->sip_to)
+    return -1;
+
+  method = sip->sip_request->rq_method;
+  method_name = sip->sip_request->rq_method_name;
+
+  if (method == sip_method_ack || method == sip_method_cancel)
+    seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq; 
+  else if (leg->leg_seq)
+    seq = ++leg->leg_seq;
+  else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */
+    seq = leg->leg_seq = sip->sip_cseq->cs_seq;
+  else
+    seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff;
+
+  if ((!sip->sip_cseq || 
+       seq != sip->sip_cseq->cs_seq ||
+       method != sip->sip_cseq->cs_method ||
+       (method == sip_method_unknown && 
+	strcmp(method_name, sip->sip_cseq->cs_method_name) != 0)) &&
+      (!(cseq = sip_cseq_create(home, seq, method, method_name)) ||
+       msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0))
+    return -1;
+
+  return 0;
+}
+
+/* ====================================================================== */
+/* 6) Dialogs (legs) */
+
+static void leg_insert(nta_agent_t *agent, nta_leg_t *leg);
+static int leg_route(nta_leg_t *leg,
+		     sip_record_route_t const *route,
+		     sip_record_route_t const *reverse,
+		     sip_contact_t const *contact);
+static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*,
+				nta_incoming_t*, sip_t const *);
+#define HTABLE_HASH_LEG(leg) ((leg)->leg_hash)
+HTABLE_BODIES_WITH(leg_htable, lht, nta_leg_t, HTABLE_HASH_LEG, size_t, hash_value_t);
+static inline
+hash_value_t hash_istring(char const *, char const *, hash_value_t);
+
+/**@typedef nta_request_f
+ *
+ * Callback for incoming requests
+ *
+ * This is a callback function invoked by NTA for each incoming SIP request.
+ *
+ * @param lmagic call leg context
+ * @param leg    call leg handle
+ * @param ireq   incoming request
+ * @param sip    incoming request contents
+ *
+ * @retval 100..699
+ * NTA constructs a reply message with given error code and corresponding
+ * standard phrase, then sends the reply.
+ *
+ * @retval 0
+ * The application takes care of sending (or not sending) the reply.
+ *
+ * @retval other
+ * All other return values will be interpreted as
+ * @e 500 @e Internal @e server @e error.
+ */
+
+
+/**
+ * Create a new leg object.
+ *
+ * The function nta_leg_tcreate() creates a leg object. A leg object is used
+ * to represent dialogs, partial dialogs (for example, in case of REGISTER),
+ * and destinations within a particular NTA object.
+ *
+ * When a leg is created, a callback pointer and a application context is
+ * provided. All other parameters are optional.
+ *
+ * @param agent    agent object
+ * @param callback function which is called for each
+ *                 incoming request belonging to this leg
+ * @param magic    call leg context
+ * @param tag,value,... optional extra headers in taglist
+ *
+ * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(),
+ * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used
+ * to establish dialog context. The SIPTAG_FROM() is used to pass local
+ * address (@From header when making a call, @To header when answering
+ * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is
+ * used to pass remote address (@To header when making a call, @From
+ * header when answering to a call).
+ *
+ * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE()
+ * and NTATAG_TARGET() can be used. A client or server can also set the
+ * route using @RecordRoute and @Contact headers from a response or
+ * request message with the functions nta_leg_client_route() and
+ * nta_leg_server_route(), respectively.
+ *
+ * When a leg representing a local destination is created, the tags
+ * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a
+ * request with matching request-URI (URLTAG_URL()) and method
+ * (NTATAG_METHOD()) is received, it is passed to the callback function
+ * provided with the leg.
+ *
+ * @sa nta_leg_stateful(), nta_leg_bind(),
+ *     nta_leg_tag(), nta_leg_rtag(),
+ *     nta_leg_client_route(), nta_leg_server_route(),
+ *     nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f().
+ *
+ * @TAGS 
+ * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(),
+ * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(),
+ * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(),
+ * NTATAG_TARGET() and SIPTAG_CSEQ().
+ *
+ */
+nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
+			   nta_request_f *callback,
+			   nta_leg_magic_t *magic,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  sip_route_t const *route = NULL;
+  sip_contact_t const *contact = NULL;
+  sip_cseq_t const *cs = NULL;
+  sip_call_id_t const *i = NULL;
+  sip_from_t const *from = NULL;
+  sip_to_t const *to = NULL;
+  char const *method = NULL;
+  char const *i_str = NULL, *to_str = NULL, *from_str = NULL, *cs_str = NULL;
+  url_string_t const *url_string = NULL;
+  int no_dialog = 0;
+  unsigned rseq = 0;
+  /* RFC 3261 section 12.2.1.1 */
+  uint32_t seq = 0;
+  ta_list ta;
+  nta_leg_t *leg;
+  su_home_t *home;
+  url_t *url;
+
+  if (agent == NULL)
+    return su_seterrno(EINVAL), NULL;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  NTATAG_NO_DIALOG_REF(no_dialog),
+	  NTATAG_METHOD_REF(method),
+	  URLTAG_URL_REF(url_string),
+	  SIPTAG_CALL_ID_REF(i),
+	  SIPTAG_CALL_ID_STR_REF(i_str),
+	  SIPTAG_FROM_REF(from),
+	  SIPTAG_FROM_STR_REF(from_str),
+	  SIPTAG_TO_REF(to),
+	  SIPTAG_TO_STR_REF(to_str),
+	  SIPTAG_ROUTE_REF(route),
+	  NTATAG_TARGET_REF(contact),
+	  NTATAG_REMOTE_CSEQ_REF(rseq),
+	  SIPTAG_CSEQ_REF(cs),
+	  SIPTAG_CSEQ_STR_REF(cs_str),
+	  TAG_END());
+
+  ta_end(ta);
+
+  if (cs)
+    seq = cs->cs_seq;
+  else if (cs_str)
+    seq = strtoul(cs_str, (char **)&cs_str, 10);
+
+  if (i == NONE) /* Magic value, used for compatibility */
+    no_dialog = 1;
+
+  if (!(leg = su_home_clone(agent->sa_home, sizeof(*leg))))
+    return NULL;
+  home = leg->leg_home;
+
+  leg->leg_agent = agent;
+  nta_leg_bind(leg, callback, magic);
+
+  if (from) {
+    /* Now this is kludge */
+    leg->leg_local_is_to = sip_is_to((sip_header_t*)from); 
+    leg->leg_local = sip_to_dup(home, from);
+  }
+  else if (from_str)
+    leg->leg_local = sip_to_make(home, from_str);
+
+  if (to && no_dialog) {
+    /* Remove tag, if any */
+    sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL;
+    leg->leg_remote = sip_from_dup(home, to0);
+  }
+  else if (to)
+    leg->leg_remote = sip_from_dup(home, to);
+  else if (to_str)
+    leg->leg_remote = sip_from_make(home, to_str);
+
+  if (route && route != NONE)
+    leg->leg_route = sip_route_dup(home, route);
+
+  if (contact && contact != NONE) {
+    sip_contact_t m[1];
+    sip_contact_init(m);
+    *m->m_url = *contact->m_url;
+    m->m_url->url_headers = NULL;
+    leg->leg_target = sip_contact_dup(home, m);
+  }
+
+  url = url_hdup(home, url_string->us_url);
+
+  /* Match to local hosts */
+  if (url && agent_aliases(agent, url, NULL)) {
+    url_t *changed = url_hdup(home, url);
+    su_free(home, url);
+    url = changed;
+  }	
+
+  leg->leg_rseq = rseq;
+  leg->leg_seq = seq;
+  leg->leg_url = url;
+
+  if (from && from != NONE && leg->leg_local == NULL) {
+    SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate local address\n"));
+    goto err;
+  }
+  else if (to && to != NONE && leg->leg_remote == NULL) {
+    SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate remote address\n"));
+    goto err;
+  }
+  else if (route && route != NONE && leg->leg_route == NULL) {
+    SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate route\n"));
+    goto err;
+  }
+  else if (contact && contact != NONE && leg->leg_target == NULL) {
+    SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate target\n"));
+    goto err;
+  }
+  else if (url_string && leg->leg_url == NULL) {
+    SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate local destination\n"));
+    goto err;
+  }
+
+  if (!no_dialog) {
+    if (!leg->leg_local || !leg->leg_remote) {
+      /* To and/or From header missing */
+      SU_DEBUG_3(("nta_leg_tcreate(): missing%s%s header\n",
+		  !leg->leg_remote ? " To" : "",
+		  !leg->leg_local ? " From" : ""));
+      goto err;
+    }
+
+    leg->leg_dialog = 1;
+
+    if (i != NULL)
+      leg->leg_id = sip_call_id_dup(home, i);
+    else if (i_str != NULL)
+      leg->leg_id = sip_call_id_make(home, i_str);
+    else
+      leg->leg_id = sip_call_id_create(home, NULL);
+
+    if (!leg->leg_id) {
+      SU_DEBUG_3(("nta_leg_tcreate(): cannot create Call-ID\n"));
+      goto err;
+    }
+
+    leg->leg_hash = leg->leg_id->i_hash;
+  }
+  else if (url) {
+    /* This is "default leg" with a destination URL. */
+    hash_value_t hash = 0;
+
+    if (method) {
+      leg->leg_method = su_strdup(home, method);
+    }
+#if 0
+    else if (url->url_params) {
+      int len = url_param(url->url_params, "method", NULL, 0);
+      if (len) {
+	char *tmp = su_alloc(home, len);
+	leg->leg_method = tmp;
+	url_param(url->url_params, "method", tmp, len);
+      }
+    }
+#endif
+
+    if (url->url_user && strcmp(url->url_user, "") == 0)
+      url->url_user = "%";	/* Match to any user */
+
+    hash = hash_istring(url->url_scheme, ":", 0);
+    hash = hash_istring(url->url_host, "", hash);
+    hash = hash_istring(url->url_user, "@", hash);
+
+    leg->leg_hash = hash;
+  }
+  else {
+    /* This is "default leg" without a destination URL. */
+    if (agent->sa_default_leg) {
+      SU_DEBUG_1(("leg_create(): tried to create second default leg\n"));
+      su_seterrno(EEXIST);
+      goto err;
+    }
+    else {
+      agent->sa_default_leg = leg;
+    }
+    return leg;
+  }
+
+  if (url) {
+    /* Parameters are ignored when comparing incoming URLs */
+    url->url_params = NULL;
+  }
+
+  leg_insert(agent, leg);
+
+  SU_DEBUG_9(("nta_leg_create(%p)\n", leg));
+
+  return leg;
+
+ err:
+  su_home_zap(leg->leg_home);
+
+  return NULL;
+}
+
+/** Return the default leg, if any */
+nta_leg_t *nta_default_leg(nta_agent_t const *agent)
+{
+  return agent ? agent->sa_default_leg : NULL;
+}
+
+
+/**
+ * Insert a call leg to agent.
+ */
+static
+void leg_insert(nta_agent_t *sa, nta_leg_t *leg)
+{
+  leg_htable_t *leg_hash;
+  assert(leg);
+  assert(sa);
+
+  if (leg->leg_dialog)
+    leg_hash = sa->sa_dialogs;
+  else
+    leg_hash = sa->sa_defaults;
+
+  if (leg_htable_is_full(leg_hash)) {
+    leg_htable_resize(sa->sa_home, leg_hash, 0);
+    assert(leg_hash->lht_table);
+    SU_DEBUG_7(("nta: resized%s leg hash to "MOD_ZU"\n",
+		leg->leg_dialog ? "" : " default", leg_hash->lht_size));
+  }
+
+  /* Insert entry into hash table (before other legs with same hash) */
+  leg_htable_insert(leg_hash, leg);
+}
+
+/**
+ * Destroy a leg.
+ *
+ * @param leg leg to be destroyed
+ */
+void nta_leg_destroy(nta_leg_t *leg)
+{
+  SU_DEBUG_9(("nta_leg_destroy(%p)\n", leg));
+
+  if (leg) {
+    leg_htable_t *leg_hash;
+    nta_agent_t *sa = leg->leg_agent;
+
+    assert(sa);
+
+    if (leg->leg_dialog) {
+      assert(sa->sa_dialogs);
+      leg_hash = sa->sa_dialogs;
+    }
+    else if (leg != sa->sa_default_leg) {
+      assert(sa->sa_defaults);
+      leg_hash = sa->sa_defaults;
+    }
+    else {
+      sa->sa_default_leg = NULL;
+      leg_hash = NULL;
+    }
+
+    if (leg_hash)
+      leg_htable_remove(leg_hash, leg);
+
+    leg_free(sa, leg);
+  }
+}
+
+static
+void leg_free(nta_agent_t *sa, nta_leg_t *leg)
+{
+  su_free(sa->sa_home, leg);
+}
+
+/** Return application context for the leg */
+nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
+			       nta_request_f *callback)
+{
+  if (leg)
+    if (!callback || leg->leg_callback == callback)
+      return leg->leg_magic;
+
+  return NULL;
+}
+
+/**Bind a callback function and context to a leg object.
+ *
+ * The function nta_leg_bind() is used to change the callback
+ * and context pointer attached to a leg object.
+ *
+ * @param leg      leg object to be bound
+ * @param callback new callback function (or NULL if no callback is desired)
+ * @param magic    new context pointer
+ */
+void nta_leg_bind(nta_leg_t *leg,
+		  nta_request_f *callback,
+		  nta_leg_magic_t *magic)
+{
+  if (leg) {
+    if (callback)
+      leg->leg_callback = callback;
+    else
+      leg->leg_callback = leg_callback_default;
+    leg->leg_magic = magic;
+  }
+}
+
+/** Add a local tag to the leg.
+ *
+ * @param leg leg to be tagged
+ * @param tag tag to be added (if NULL, a tag generated by @b NTA is added)
+ *
+ * @return 
+ * Pointer to tag if successful, NULL otherwise.
+ */
+char const *nta_leg_tag(nta_leg_t *leg, char const *tag)
+{
+  if (!leg || !leg->leg_local)
+    return su_seterrno(EINVAL), NULL;
+
+  if (tag && strchr(tag, '='))
+    tag = strchr(tag, '=') + 1;
+
+  /* If there already is a tag, 
+     return NULL if it does not match with new one */
+  if (leg->leg_local->a_tag) {
+    if (!tag && str0casecmp(tag, leg->leg_local->a_tag))
+      return NULL;
+    else
+      return leg->leg_local->a_tag;
+  }
+  
+  if (tag) {
+    if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0)
+      return NULL;
+    return leg->leg_local->a_tag;
+  }
+
+  tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent);
+
+  if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0)
+    return NULL;
+
+  return leg->leg_local->a_tag;
+}
+
+/** Get local tag. */
+char const *nta_leg_get_tag(nta_leg_t const *leg)
+{
+  if (leg && leg->leg_local)
+    return leg->leg_local->a_tag;
+  else
+    return NULL;
+}
+
+/** Add a remote tag to the leg.
+ *
+ * @note No remote tag is ever generated. 
+ *
+ * @param leg leg to be tagged
+ * @param tag tag to be added (@b must be non-NULL)
+ *
+ * @return 
+ * Pointer to tag if successful, NULL otherwise.
+ */
+char const *nta_leg_rtag(nta_leg_t *leg, char const *tag)
+{
+  /* Add a tag parameter, unless there already is a tag */
+  if (leg && leg->leg_remote && tag) {
+    if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0)
+      return NULL;
+  }
+
+  if (leg && leg->leg_remote)
+    return leg->leg_remote->a_tag;
+  else 
+    return NULL;
+}
+
+/** Get remote tag. */
+char const *nta_leg_get_rtag(nta_leg_t const *leg)
+{
+  if (leg && leg->leg_remote)
+    return leg->leg_remote->a_tag;
+  else
+    return NULL;
+}
+
+/** Save target and route set at UAC side.
+ *
+ * @sa nta_leg_server_route(), @RFC3261 section 12.1.2
+ */
+int nta_leg_client_route(nta_leg_t *leg,
+			 sip_record_route_t const *route,
+			 sip_contact_t const *contact)
+{
+  return leg_route(leg, NULL, route, contact);
+}
+
+/** Save target and route set at UAS side.
+ *
+ * @sa nta_leg_client_route(), @RFC3261 section 12.1.1
+ */
+int nta_leg_server_route(nta_leg_t *leg,
+			 sip_record_route_t const *route,
+			 sip_contact_t const *contact)
+{
+  return leg_route(leg, route, NULL, contact);
+}
+
+/** Return route components. */
+int nta_leg_get_route(nta_leg_t *leg, 
+		      sip_route_t const **return_route, 
+		      sip_contact_t const **return_target)
+{
+  if (!leg)
+    return -1;
+
+  if (return_route)
+    *return_route = leg->leg_route;
+
+  if (return_target)
+    *return_target = leg->leg_target;
+
+  return 0;
+}
+
+/** Generate @Replaces header.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN
+sip_replaces_t *nta_leg_make_replaces(nta_leg_t *leg,
+				      su_home_t *home,
+				      int early_only)
+{
+  char const *from_tag, *to_tag;
+
+  if (!leg)
+    return NULL;
+  if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id)
+    return NULL;
+  
+  from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0";
+  to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0";
+
+  return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s",
+			     leg->leg_id->i_id, from_tag, to_tag, 
+			     early_only ? ";early-only" : "");
+}
+
+/** Get dialog leg by @Replaces header.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
+{
+  nta_leg_t *leg = NULL;
+
+  if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) {
+    char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag;
+    sip_call_id_t id[1];
+    sip_call_id_init(id);
+
+    id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
+
+    leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, to_tag, NULL);
+
+    if (leg == NULL && strcmp(from_tag, "0") == 0)
+      leg = leg_find(sa, NULL, NULL, id, NULL, NULL, to_tag, NULL);
+    if (leg == NULL && strcmp(to_tag, "0") == 0)
+      leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, NULL, NULL);
+  }
+
+  return leg;
+}
+
+/** Calculate a simple case-insensitive hash over a string */
+static inline
+hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash)
+{
+  if (s) {
+    for (; *s; s++) {
+      unsigned char c = *s;
+      if ('A' <= c && c <= 'Z')
+	c += 'a' - 'A';
+      hash = 38501U * (hash + c);
+    }
+    for (s = term; *s; s++) {
+      unsigned char c = *s;
+      hash = 38501U * (hash + c);
+    }
+  }
+
+  return hash;
+}
+
+/** @internal Handle requests intended for this leg. */
+static
+void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+  nta_agent_t *agent = leg->leg_agent;
+  nta_incoming_t *irq;
+  sip_method_t method = sip->sip_request->rq_method;
+  char const *method_name = sip->sip_request->rq_method_name;
+  char const *tag = NULL;
+  int status;
+
+  if (leg->leg_local)
+    tag = leg->leg_local->a_tag;
+
+  if (leg->leg_dialog)
+    agent->sa_stats->as_dialog_tr++;
+
+  /* RFC-3262 section 3 (page 4) */
+  if (agent->sa_is_a_uas && method == sip_method_prack) {
+    nta_msg_treply(agent, msg,
+		   481, "No such response", 
+		   NTATAG_TPORT(tport),
+		   TAG_END());
+    return;
+  }
+
+  if (!(irq = incoming_create(agent, msg, sip, tport, tag))) {
+    SU_DEBUG_3(("nta: leg_recv(%p): cannot create transaction for %s\n",
+		leg, method_name));
+    nta_msg_treply(agent, msg,
+		   SIP_500_INTERNAL_SERVER_ERROR,
+		   NTATAG_TPORT(tport),
+		   TAG_END());
+    return;
+  }
+
+  irq->irq_in_callback = 1;
+  status = incoming_callback(leg, irq, sip);
+  irq->irq_in_callback = 0;
+
+  if (irq->irq_destroyed) {
+    if (irq->irq_terminated) {
+      incoming_free(irq);
+      return;
+    }
+    if (status < 200)
+      status = 500;
+  }
+
+  if (status == 0)
+    return;
+
+  if (status < 100 || status > 699) {
+    SU_DEBUG_3(("nta_leg(%p): invalid status %03d from callback\n",
+		leg, status));
+    status = 500;
+  }
+  else if (method == sip_method_invite && status >= 200 && status < 300) {
+    SU_DEBUG_3(("nta_leg(%p): invalid INVITE status %03d from callback\n",
+		leg, status));
+    status = 500;
+  }
+
+  if (status >= 100 && irq->irq_status < 200)
+    nta_incoming_treply(irq, status, NULL, TAG_END());
+
+  if (status >= 200)
+    nta_incoming_destroy(irq);
+}
+
+/**Compare two SIP from/to fields.
+ *
+ * @retval nonzero if matching.
+ * @retval zero if not matching.
+ */
+static inline
+int addr_cmp(url_t const *a, url_t const *b)
+{
+  if (b == NULL)
+    return 0;
+  else
+    return
+      host_cmp(a->url_host, b->url_host)
+      || str0cmp(a->url_port, b->url_port)
+      || str0cmp(a->url_user, b->url_user);
+}
+
+/** Get a leg by dialog.
+ *
+ * The function nta_leg_by_dialog() searches for a dialog leg from agent's
+ * hash table. The matching rules based on parameters  are as follows:
+ *
+ * @param agent        pointer to agent object
+ * @param request_uri  if non-NULL, and there is destination URI
+ *                     associated with the dialog, these URIs must match
+ * @param call_id      if non-NULL, must match with @CallID header contents
+ * @param remote_tag   if there is remote tag 
+ *                     associated with dialog, @a remote_tag must match 
+ * @param remote_uri   if there is no remote tag, the remote URI must match
+ * @param local_tag    if non-NULL and there is local tag associated with leg,
+ *                     it must math
+ * @param local_uri    if there is no local tag, the local URI must match
+ *
+ */
+nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
+			     url_t const *request_uri,
+			     sip_call_id_t const *call_id,
+			     char const *remote_tag,
+			     url_t const *remote_uri,
+			     char const *local_tag,
+			     url_t const *local_uri)
+{
+  void *to_be_freed = NULL, *tbf2 = NULL, *tbf3 = NULL;
+  url_t *url;
+  url_t url0[1];
+  nta_leg_t *leg;
+
+  if (!agent || !call_id)
+    return su_seterrno(EINVAL), NULL;
+
+  if (request_uri == NULL) {
+    url = NULL;
+  }
+  else if (URL_IS_STRING(request_uri)) {
+    /* accept a string as URL */
+    to_be_freed = url = url_hdup(NULL, request_uri);
+  } 
+  else {
+    *url0 = *request_uri, url = url0;
+  }
+
+  if (url) {
+    url->url_params = NULL;
+    agent_aliases(agent, url, NULL); /* canonize url */
+  }
+
+  if (remote_uri && URL_IS_STRING(remote_uri))
+    request_uri = tbf2 = url_hdup(NULL, remote_uri);
+
+  if (local_uri && URL_IS_STRING(local_uri))
+    local_uri = tbf3 = url_hdup(NULL, local_uri);
+  
+  leg = leg_find(agent, 
+		 NULL, url, 
+		 call_id, 
+		 remote_tag, remote_uri,
+		 local_tag, local_uri);
+
+  if (to_be_freed) su_free(NULL, to_be_freed);
+  if (tbf2) su_free(NULL, tbf2);
+  if (tbf3) su_free(NULL, tbf3);
+
+  return leg;
+}
+
+/**@internal
+ * Find a leg corresponding to the request message.
+ *
+ * A leg matches to message if leg_match_request() returns true ("Call-ID",
+ * "To", and "From" match).
+ */
+static
+nta_leg_t *leg_find(nta_agent_t const *sa,
+		    char const *method_name,
+		    url_t const *request_uri,
+		    sip_call_id_t const *i,
+		    char const *from_tag,
+		    url_t const *from_uri,
+		    char const *to_tag,
+		    url_t const *to_uri)
+{
+  hash_value_t hash = i->i_hash;
+  leg_htable_t const *lht = sa->sa_dialogs;
+  nta_leg_t  **ll, *leg, *loose_match = NULL;
+
+  for (ll = leg_htable_hash(lht, hash);
+       (leg = *ll);
+       ll = leg_htable_next(lht, ll)) {
+    sip_call_id_t const *leg_i = leg->leg_id;
+    url_t const *remote_uri = leg->leg_remote->a_url;
+    char const *remote_tag = leg->leg_remote->a_tag;
+    url_t const *local_uri = leg->leg_local->a_url;
+    char const *local_tag = leg->leg_local->a_tag;
+    url_t const *leg_url = leg->leg_url;
+    char const *leg_method = leg->leg_method;
+
+    if (leg->leg_hash != hash)
+      continue;
+    if (strcmp(leg_i->i_id, i->i_id) != 0)
+      continue;
+    /* Do not match if the incoming To has tag, but the local does not */
+    if (!local_tag && to_tag)
+      continue;
+    /* Do not match if incoming From has no tag but remote has a tag */
+    if (remote_tag && !from_tag)
+      continue;
+    /* Avoid matching with itself */
+    if (!remote_tag != !from_tag && !local_tag != !to_tag)
+      continue;
+
+    if (local_tag && to_tag ? 
+	strcasecmp(local_tag, to_tag) : addr_cmp(local_uri, to_uri))
+      continue;
+    if (remote_tag && from_tag ? 
+	strcasecmp(remote_tag, from_tag) : addr_cmp(remote_uri, from_uri))
+      continue;
+
+    if (leg_url && request_uri && url_cmp(leg_url, request_uri))
+      continue;
+    if (leg_method && method_name && strcasecmp(method_name, leg_method))
+      continue;
+
+    /* Perfect match if both local and To have tag
+     * or local does not have tag.
+     */
+    if ((!local_tag || to_tag))
+      return leg;
+
+    if (loose_match == NULL)
+      loose_match = leg;
+  }
+
+  return loose_match;
+}
+
+/** Get leg by destination */
+nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us)
+{
+  url_t *url;
+  nta_leg_t *leg;
+
+  if (!agent)
+    return NULL;
+
+  if (!us)
+    return agent->sa_default_leg;
+
+  url = url_hdup(NULL, us->us_url);
+
+  agent_aliases(agent, url, NULL);
+
+  leg = url ? dst_find(agent, url, NULL) : NULL;
+
+  su_free(NULL, url);
+
+  return leg;
+}
+
+/** Find a non-dialog leg corresponding to the request uri u0 */
+static
+nta_leg_t *dst_find(nta_agent_t const *sa,
+		    url_t const *u0,
+		    char const *method_name)
+{
+  hash_value_t hash, hash2;
+  leg_htable_t const *lht = sa->sa_defaults;
+  nta_leg_t **ll, *leg, *loose_match = NULL;
+   int again;
+  url_t url[1];
+
+  *url = *u0;
+  hash = hash_istring(url->url_scheme, ":", 0);
+  hash = hash_istring(url->url_host, "", hash);
+  hash2 = hash_istring("%", "@", hash);
+  hash = hash_istring(url->url_user, "@", hash);
+
+  /* First round, search with user name */
+  /* Second round, search without user name */
+  do {
+    for (ll = leg_htable_hash(lht, hash);
+	 (leg = *ll);
+	 ll = leg_htable_next(lht, ll)) {
+      if (leg->leg_hash != hash)
+	continue;
+      if (url_cmp(url, leg->leg_url))
+	continue;
+      if (!method_name) {
+	if (leg->leg_method)
+	  continue;
+	return leg;
+      }
+      else if (leg->leg_method) {
+	if (strcasecmp(method_name, leg->leg_method))
+	  continue;
+	return leg;
+      }
+      loose_match = leg;
+    }
+    if (loose_match)
+      return loose_match;
+
+    again = 0;
+
+    if (url->url_user && strcmp(url->url_user, "%")) {
+      url->url_user = "%";
+      hash = hash2;
+      again = 1;
+    }
+  } while (again);
+
+  return NULL;
+}
+
+/** Set leg route and target URL.
+ *
+ * The function leg_route() sets the leg route and contact using the
+ * @RecordRoute and @Contact headers.
+ */
+static
+int leg_route(nta_leg_t *leg,
+	      sip_record_route_t const *route,
+	      sip_record_route_t const *reverse,
+	      sip_contact_t const *contact)
+{
+  su_home_t *home = leg->leg_home;
+  sip_route_t *r, r0[1];
+
+  if (!leg)
+    return -1;
+
+  if (route == NULL && reverse == NULL && contact == NULL)
+    return 0;
+
+  sip_route_init(r0);
+
+  if (leg->leg_route) {
+    r = leg->leg_route;
+  }
+  else if (route) {
+    r = sip_route_fixdup(home, route); if (!r) return -1;
+  }
+  else if (reverse) {
+    r = sip_route_reverse(home, reverse); if (!r) return -1;
+  }
+  else
+    r = NULL;
+
+#ifdef NTA_STRICT_ROUTING
+  /*
+   * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4.
+   */
+  if (contact) {
+    *r0->r_url = *contact->m_url;
+
+    if (!(m_r = sip_route_dup(leg->leg_home, r0)))
+      return -1;
+
+    /* Append, but replace last entry if it was generated from contact */
+    for (rr = &r; *rr; rr = &(*rr)->r_next)
+      if (leg->leg_contact_set && (*rr)->r_next == NULL)
+	break;
+  }
+  else
+    rr = NULL;
+
+  if (rr) {
+    if (*rr)
+      su_free(leg->leg_home, *rr);
+    *rr = m_r;
+  }
+  if (m_r != NULL)
+    leg->leg_contact_set = 1;
+
+#else
+  if (r && r->r_url->url_params)
+    leg->leg_loose_route = url_has_param(r->r_url, "lr");
+
+  if (contact) {
+    sip_contact_t *target, m[1], *m0;
+
+    sip_contact_init(m);
+    *m->m_url = *contact->m_url;
+    m->m_url->url_headers = NULL;
+    target = sip_contact_dup(leg->leg_home, m);
+
+    if (target && target->m_url->url_params) {
+      /* Remove ttl, method. @RFC3261 table 1, page 152 */
+      char *p = (char *)target->m_url->url_params;
+      p = url_strip_param_string(p, "method");
+      p = url_strip_param_string(p, "ttl");
+      target->m_url->url_params = p;
+    }
+
+    m0 = leg->leg_target, leg->leg_target = target;
+
+    if (m0)
+      su_free(leg->leg_home, m0);
+  }
+#endif
+
+  leg->leg_route = r;
+
+  return 0;
+}
+
+/** @internal Default leg callback. */
+static int
+leg_callback_default(nta_leg_magic_t *magic,
+		     nta_leg_t  *leg,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  nta_incoming_treply(irq,
+		      SIP_501_NOT_IMPLEMENTED,
+		      TAG_END());
+  return 501;
+}
+
+/* ====================================================================== */
+/* 7) Server-side (incoming) transactions */
+
+#define HTABLE_HASH_IRQ(irq) ((irq)->irq_hash)
+HTABLE_BODIES_WITH(incoming_htable, iht, nta_incoming_t, HTABLE_HASH_IRQ,
+		   size_t, hash_value_t);
+
+static void incoming_insert(nta_agent_t *agent, 
+			    incoming_queue_t *queue, 
+			    nta_incoming_t *irq);
+
+static inline int incoming_is_queued(nta_incoming_t const *irq);
+static inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *);
+static inline void incoming_remove(nta_incoming_t *irq);
+static inline void incoming_set_timer(nta_incoming_t *, unsigned interval);
+static inline void incoming_reset_timer(nta_incoming_t *);
+static inline int incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q);
+
+static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags);
+static inline
+int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
+			     int create_if_needed);
+
+static inline nta_incoming_t
+  *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *);
+static inline int incoming_final_failed(nta_incoming_t *irq, msg_t *);
+static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport);
+
+/** Create a default server transaction. 
+ *
+ * The default server transaction is used by a proxy to forward responses
+ * statelessly.
+ *
+ * @param agent pointer to agent object
+ *
+ * @retval pointer to default server transaction object 
+ * @retval NULL if failed
+ */
+nta_incoming_t *nta_incoming_default(nta_agent_t *agent)
+{
+  msg_t *msg;
+  su_home_t *home;
+  nta_incoming_t *irq;
+
+  if (agent == NULL)
+    return su_seterrno(EFAULT), NULL;
+  if (agent->sa_default_incoming)
+    return su_seterrno(EEXIST), NULL;
+
+  msg = nta_msg_create(agent, 0);
+  if (!msg)
+    return NULL;
+
+  irq = su_zalloc(home = msg_home(msg), sizeof(*irq));
+  if (!irq)
+    return (void)msg_destroy(msg), NULL;
+
+  irq->irq_home = home;
+  irq->irq_request = NULL;
+  irq->irq_agent = agent;
+  irq->irq_received = agent_now(agent);
+  irq->irq_method = sip_method_invalid;
+
+  irq->irq_default = 1;
+  agent->sa_default_incoming = irq;
+    
+  return irq;
+}
+
+/** Create a server transaction. 
+ *
+ * The function nta_incoming_create() creates a server transaction for a
+ * request message. This function is used when an element processing
+ * requests statelessly wants to process a particular request statefully.
+ *
+ * @param agent pointer to agent object
+ * @param leg  pointer to leg object (either @a agent or @a leg may be NULL)
+ * @param msg  pointer to message object
+ * @param sip  pointer to SIP structure (may be NULL)
+ * @param tag,value,... optional tagged parameters
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ *
+ * @TAGS
+ * @TAG NTATAG_TPORT() specifies the transport used to receive the request 
+ *      and also default transport for sending the response.
+ *
+ * @retval nta_incoming_t pointer to the newly created server transaction 
+ * @retval NULL if failed
+ */
+nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
+				    nta_leg_t *leg,
+				    msg_t *msg,
+				    sip_t *sip,
+				    tag_type_t tag, tag_value_t value, ...)
+{
+  char const *to_tag = NULL;
+  tport_t *tport = NULL;
+  ta_list ta;
+  nta_incoming_t *irq;
+
+  if (msg == NULL)
+    return NULL;
+
+  if (agent == NULL && leg != NULL)
+    agent = leg->leg_agent;
+
+  if (sip == NULL)
+    sip = sip_object(msg);
+
+  if (agent == NULL || sip == NULL || !sip->sip_request || !sip->sip_cseq)
+    return msg_destroy(msg), NULL;
+
+  ta_start(ta, tag, value);
+  
+  tl_gets(ta_args(ta), 
+	  NTATAG_TPORT_REF(tport), 
+	  TAG_END());
+  ta_end(ta);
+
+  if (leg && leg->leg_local)
+    to_tag = leg->leg_local->a_tag;
+
+  if (tport == NULL)
+    tport = tport_delivered_by(agent->sa_tports, msg);
+
+  irq = incoming_create(agent, msg, sip, tport, to_tag);
+
+  if (!irq)
+    msg_destroy(msg);
+
+  return irq;
+}
+
+/** @internal Create a new incoming transaction object. */
+static
+nta_incoming_t *incoming_create(nta_agent_t *agent,
+				msg_t *msg,
+				sip_t *sip,
+				tport_t *tport,
+				char const *tag)
+{
+  nta_incoming_t *irq = su_zalloc(msg_home(msg), sizeof(*irq));
+
+  agent->sa_stats->as_server_tr++;
+
+  if (irq) {
+    su_home_t *home;
+    incoming_queue_t *queue;
+    sip_method_t method = sip->sip_request->rq_method;
+
+    irq->irq_request = msg; 
+    irq->irq_home = home = msg_home(msg_ref_create(msg));
+    irq->irq_agent = agent;
+
+    irq->irq_received = agent_now(agent);
+
+    irq->irq_method = method;
+    irq->irq_rq = sip_request_copy(home, sip->sip_request);
+    irq->irq_from = sip_from_copy(home, sip->sip_from);
+    irq->irq_to = sip_to_copy(home, sip->sip_to);
+    irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id);
+    irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq);
+    irq->irq_via = sip_via_copy(home, sip->sip_via);
+    switch (method) {
+    case sip_method_ack:
+    case sip_method_cancel:
+    case sip_method_bye:
+    case sip_method_options:
+    case sip_method_register:	/* Handling Path is up to application */
+    case sip_method_info:
+    case sip_method_prack:
+    case sip_method_publish:
+      break;
+    default:
+      irq->irq_record_route = 
+	sip_record_route_copy(home, sip->sip_record_route);
+    }
+    irq->irq_branch  = irq->irq_via->v_branch;
+    irq->irq_reliable_tp = tport_is_reliable(tport);
+
+    if (sip->sip_timestamp)
+      irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp);
+
+    /* Tag transaction */
+    if (tag)
+      sip_to_tag(home, irq->irq_to, tag);
+
+    if (method != sip_method_ack) {
+      int *use_rport = NULL;
+      int retry_without_rport = 0;
+
+      if (agent->sa_server_rport)
+	use_rport = &retry_without_rport, retry_without_rport = 1;
+
+      if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0)
+	SU_DEBUG_1(("%s: bad via\n", __func__));
+    }
+
+    incoming_set_compartment(irq, tport, msg, 0);
+
+    if (method == sip_method_invite) {
+      irq->irq_must_100rel =
+	sip->sip_require && sip_has_feature(sip->sip_require, "100rel");
+
+      if (irq->irq_must_100rel ||
+	  (sip->sip_supported &&
+	   sip_has_feature(sip->sip_supported, "100rel"))) {
+	irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */
+      }
+
+      queue = agent->sa_in.proceeding;
+
+      if (irq->irq_reliable_tp)
+	incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */
+      else
+	incoming_set_timer(irq, 200); /* N1 = 200 ms */
+
+      irq->irq_tport = tport_ref(tport);
+    }
+    else if (method == sip_method_ack) {
+      irq->irq_status = 700;	/* Never send reply to ACK */
+      irq->irq_completed = 1;
+      if (irq->irq_reliable_tp || !agent->sa_is_a_uas) {
+	queue = agent->sa_in.terminated;
+	irq->irq_terminated = 1;
+      }
+      else {
+	queue = agent->sa_in.completed;	/* Timer J */
+      }
+    } 
+    else {
+      queue = agent->sa_in.proceeding;
+	/* draft-sparks-sip-nit-actions-03:
+
+   Blacklisting on a late response occurs even over reliable transports.
+   Thus, if an element processing a request received over a reliable
+   transport is delaying its final response at all, sending a 100 Trying
+   well in advance of the timeout will prevent blacklisting.  Sending a
+   100 Trying immediately will not harm the transaction as it would over
+   UDP, but a policy of always sending such a message results in
+   unneccessary traffic.  A policy of sending a 100 Trying after the
+   period of time in which Timer E reaches T2 had this been a UDP hop is
+   one reasonable compromise.
+
+	 */	
+      if (agent->sa_extra_100 && irq->irq_reliable_tp)
+	incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */
+
+      irq->irq_tport = tport_ref(tport);
+    }
+
+    irq->irq_hash = NTA_HASH(irq->irq_call_id, irq->irq_cseq->cs_seq);
+
+    incoming_insert(agent, queue, irq);
+  }
+
+  return irq;
+}
+
+/** @internal
+ * Insert incoming transaction to hash table.
+ */
+static void
+incoming_insert(nta_agent_t *agent, 
+		incoming_queue_t *queue,
+		nta_incoming_t *irq)
+{
+  incoming_queue(queue, irq);
+
+  if (incoming_htable_is_full(agent->sa_incoming))
+    incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0);
+
+  if (irq->irq_method != sip_method_ack)
+    incoming_htable_insert(agent->sa_incoming, irq);
+  else
+    /* ACK is appended - final response with tags match with it,
+     * not with the original INVITE transaction */
+    /* XXX - what about rfc2543 servers, which do not add tag? */
+    incoming_htable_append(agent->sa_incoming, irq);
+}
+
+/** Call callback for incoming request */
+static
+int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip)
+{
+  sip_method_t method = sip->sip_request->rq_method;
+  char const *method_name = sip->sip_request->rq_method_name;
+
+  /* RFC-3261 section 12.2.2 (page 76) */
+  if (leg->leg_dialog && 
+      irq->irq_agent->sa_is_a_uas && 
+      method != sip_method_ack) {
+    uint32_t seq = sip->sip_cseq->cs_seq;
+
+    if (leg->leg_rseq > sip->sip_cseq->cs_seq) {
+      SU_DEBUG_3(("nta_leg(%p): out-of-order %s (%u < %u)\n",
+		  leg, method_name, seq, leg->leg_rseq));
+      return 500;
+    }
+
+    leg->leg_rseq = seq;
+  }
+
+  return leg->leg_callback(leg->leg_magic, leg, irq, sip);
+}
+
+/**
+ * Destroy an incoming transaction.
+ *
+ * This function does not actually free transaction object, but marks it as
+ * disposable. The object is freed after a timeout.
+ *
+ * @param irq incoming request object to be destroyed
+ */
+void nta_incoming_destroy(nta_incoming_t *irq)
+{
+  if (irq) {
+    irq->irq_callback = NULL;
+    irq->irq_magic = NULL;
+    irq->irq_destroyed = 1;
+    if (!irq->irq_in_callback) {
+      if (irq->irq_terminated || irq->irq_default)
+	incoming_free(irq);
+      else if (irq->irq_status < 200)
+	nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+    }
+  }
+}
+
+/** @internal
+ * Initialize a queue for incoming transactions.
+ */
+static void
+incoming_queue_init(incoming_queue_t *queue, unsigned timeout)
+{
+  memset(queue, 0, sizeof *queue);
+  queue->q_tail = &queue->q_head;
+  queue->q_timeout = timeout;
+}
+
+/** Change the timeout value of a queue */
+static void
+incoming_queue_adjust(nta_agent_t *sa, 
+		      incoming_queue_t *queue, 
+		      unsigned timeout)
+{
+  nta_incoming_t *irq;
+  su_duration_t latest;
+
+  if (timeout >= queue->q_timeout || !queue->q_head) {
+    queue->q_timeout = timeout;
+    return;
+  }
+
+  latest = set_timeout(sa, queue->q_timeout = timeout);
+
+  for (irq = queue->q_head; irq; irq = irq->irq_next) {
+    if (irq->irq_timeout - latest > 0)
+      irq->irq_timeout = latest;
+  }
+}
+
+/** @internal
+ * Test if an incoming transaction is in a queue.
+ */
+static inline
+int incoming_is_queued(nta_incoming_t const *irq)
+{
+  return irq && irq->irq_queue;
+}
+
+/** @internal
+ * Insert an incoming transaction into a queue. 
+ *
+ * The function incoming_queue() inserts a server transaction into a queue,
+ * and sets the corresponding timeout at the same time.
+ */
+static inline
+void incoming_queue(incoming_queue_t *queue, 
+		    nta_incoming_t *irq)
+{
+  if (irq->irq_queue == queue) {
+    assert(queue->q_timeout == 0);
+    return;
+  }
+
+  if (incoming_is_queued(irq))
+    incoming_remove(irq);
+
+  assert(*queue->q_tail == NULL);
+
+  if (queue->q_timeout)
+    irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout);
+  else
+    irq->irq_timeout = 0;
+
+  irq->irq_queue = queue;
+  irq->irq_prev = queue->q_tail; 
+  *queue->q_tail = irq;
+  queue->q_tail = &irq->irq_next;
+  queue->q_length++;
+}
+
+/** @internal
+ * Remove an incoming transaction from a queue.
+ */
+static inline
+void incoming_remove(nta_incoming_t *irq)
+{
+  assert(incoming_is_queued(irq));
+  assert(irq->irq_queue->q_length > 0);
+
+  if ((*irq->irq_prev = irq->irq_next))
+    irq->irq_next->irq_prev = irq->irq_prev;
+  else
+    irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail);
+
+  irq->irq_queue->q_length--;
+  irq->irq_next = NULL;
+  irq->irq_prev = NULL;
+  irq->irq_queue = NULL;
+  irq->irq_timeout = 0;
+}
+
+static inline
+void incoming_set_timer(nta_incoming_t *irq, unsigned interval)
+{
+  nta_incoming_t **rq;
+  
+  assert(irq);
+
+  if (interval == 0) {
+    incoming_reset_timer(irq);
+    return;
+  }
+
+  if (irq->irq_rprev) {
+    if ((*irq->irq_rprev = irq->irq_rnext)) 
+      irq->irq_rnext->irq_rprev = irq->irq_rprev;
+    if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
+      irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
+  } else {
+    irq->irq_agent->sa_in.re_length++;
+  }
+
+  irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval);
+
+  rq = irq->irq_agent->sa_in.re_t1;
+
+  if (!(*rq) || (*rq)->irq_retry - irq->irq_retry > 0)
+    rq = &irq->irq_agent->sa_in.re_list;
+
+  while (*rq && (*rq)->irq_retry - irq->irq_retry <= 0)
+    rq = &(*rq)->irq_rnext;
+
+  if ((irq->irq_rnext = *rq))
+    irq->irq_rnext->irq_rprev = &irq->irq_rnext;
+  *rq = irq;
+  irq->irq_rprev = rq;
+
+  /* Optimization: keep special place for transactions with T1 interval */
+  if (interval == irq->irq_agent->sa_t1)
+    irq->irq_agent->sa_in.re_t1 = rq;
+}
+
+static inline
+void incoming_reset_timer(nta_incoming_t *irq)
+{
+  if (irq->irq_rprev) {
+    if ((*irq->irq_rprev = irq->irq_rnext)) 
+      irq->irq_rnext->irq_rprev = irq->irq_rprev;
+    if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
+      irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
+    irq->irq_agent->sa_in.re_length--;
+  } 
+
+  irq->irq_interval = 0, irq->irq_retry = 0;
+  irq->irq_rnext = NULL, irq->irq_rprev = NULL;
+}
+
+/** @internal
+ * Free an incoming transaction.
+ */
+static
+void incoming_free(nta_incoming_t *irq)
+{
+  SU_DEBUG_9(("nta: incoming_free(%p)\n", irq));
+
+  incoming_cut_off(irq);
+  incoming_reclaim(irq);
+}
+
+/** Remove references to the irq */
+static inline
+void incoming_cut_off(nta_incoming_t *irq)
+{
+  nta_agent_t *agent = irq->irq_agent;
+
+  assert(agent);
+
+  if (irq->irq_default) {
+    if (irq == agent->sa_default_incoming)
+      agent->sa_default_incoming = NULL;
+    irq->irq_default = 0;
+    return;
+  }
+
+  if (incoming_is_queued(irq))
+    incoming_remove(irq);
+
+  incoming_reset_timer(irq);
+
+  incoming_htable_remove(agent->sa_incoming, irq);
+
+  if (irq->irq_cc)
+    nta_compartment_decref(&irq->irq_cc);
+
+  if (irq->irq_tport)
+    tport_decref(&irq->irq_tport);
+}
+
+/** Reclaim the memory used by irq */
+static inline
+void incoming_reclaim(nta_incoming_t *irq)
+{
+  su_home_t *home = irq->irq_home;
+  nta_reliable_t *rel, *rel_next;
+
+  if (irq->irq_request)
+    msg_destroy(irq->irq_request), irq->irq_request = NULL;
+  if (irq->irq_request2)
+    msg_destroy(irq->irq_request2), irq->irq_request2 = NULL;
+  if (irq->irq_response)
+    msg_destroy(irq->irq_response), irq->irq_response = NULL;
+
+  for (rel = irq->irq_reliable; rel; rel = rel_next) {
+    rel_next = rel->rel_next;
+    if (rel->rel_unsent)
+      msg_destroy(rel->rel_unsent);
+    su_free(irq->irq_agent->sa_home, rel);
+  }
+
+  irq->irq_home = NULL;
+
+  su_free(home, irq);
+
+  msg_destroy((msg_t *)home); 
+}
+
+/** Queue request to be freed */
+static inline 
+void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq)
+{
+  incoming_cut_off(irq);
+  incoming_queue(q, irq);
+}
+
+/** Reclaim memory used by queue of requests */
+static 
+void incoming_reclaim_queued(su_root_magic_t *rm,
+			     su_msg_r msg,
+			     union sm_arg_u *u)
+{
+  incoming_queue_t *q = u->a_incoming_queue;
+  nta_incoming_t *irq, *irq_next;
+
+  SU_DEBUG_9(("incoming_reclaim_all(%p, %p, %p)\n", rm, msg, u));
+
+  for (irq = q->q_head; irq; irq = irq_next) {
+    irq_next = irq->irq_next;
+    incoming_reclaim(irq);
+  }
+}
+
+/**Bind a callback and context to an incoming transaction object
+ *
+ * The function nta_incoming_bind() is used to set the callback and
+ * context pointer attached to an incoming request object.  The callback
+ * function will be invoked if the incoming request is cancelled, or if the
+ * final response to an incoming @b INVITE request has been acknowledged.
+ *
+ * If the callback is NULL, or no callback has been bound, NTA invokes the
+ * request callback of the call leg.
+ *
+ * @param irq      incoming transaction
+ * @param callback callback function
+ * @param magic    application context
+ */
+void nta_incoming_bind(nta_incoming_t *irq,
+		       nta_ack_cancel_f *callback,
+		       nta_incoming_magic_t *magic)
+{
+  if (irq) {
+    irq->irq_callback = callback;
+    irq->irq_magic = magic;
+  }
+}
+
+/** Add a @To tag to incoming request if needed.
+ *
+ * If @a tag is NULL, a new tag is generated.
+ */
+char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag)
+{
+  if (!irq)
+    return su_seterrno(EFAULT), NULL;
+
+  if (irq->irq_default)
+    return su_seterrno(EINVAL), NULL;
+
+  if (tag && strchr(tag, '='))
+    tag = strchr(tag, '=') + 1;
+
+  if (tag && irq->irq_tag && strcasecmp(tag, irq->irq_tag))
+    return NULL;
+
+  if (!irq->irq_tag) {
+    if (tag)
+      tag = su_strdup(irq->irq_home, tag);
+    else
+      tag = nta_agent_newtag(irq->irq_home, NULL, irq->irq_agent);
+
+    if (!tag)
+      return tag;
+
+    irq->irq_tag = tag;
+    irq->irq_tag_set = 1;
+  }
+
+  return irq->irq_tag;
+}
+
+
+/**Get request message.
+ *
+ * Retrieve the incoming request message of the incoming transaction. Note
+ * that the message is not copied, but a new reference to it is created.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval
+ * A pointer to request message is returned.
+ */
+msg_t *nta_incoming_getrequest(nta_incoming_t *irq)
+{
+  msg_t *msg = NULL;
+
+  if (irq && !irq->irq_default)
+    msg = msg_ref_create(irq->irq_request);
+
+  return msg;
+}
+
+/**Get ACK or CANCEL message.
+ *
+ * Retrieve the incoming ACK or CANCEL request message of the incoming
+ * transaction. Note that the ACK or CANCEL message is not copied, but a new
+ * reference to it is created.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval A pointer to request message is returned, or NULL if there is no
+ * CANCEL or ACK received.
+ */
+msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq)
+{
+  msg_t *msg = NULL;
+
+  if (irq && irq->irq_request2)
+    msg = msg_ref_create(irq->irq_request2);
+
+  return msg;
+}
+
+/**Get response message.
+ *
+ * Retrieve the response message latest sent by the server transaction. Note
+ * that the message is not copied, but a new reference to it is created. Use
+ * msg_dup() or msg_copy() to make a copy of it.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval
+ * A pointer to a response message is returned.
+ */
+msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
+{
+  msg_t *msg = NULL;
+
+  if (irq && irq->irq_response)
+    msg = msg_ref_create(irq->irq_response);
+
+  return msg;
+}
+
+/** Get method of a server transaction. */
+sip_method_t nta_incoming_method(nta_incoming_t const *irq)
+{
+  return irq ? irq->irq_method : sip_method_invalid;
+}
+
+/** Get method name of a server transaction. */
+char const *nta_incoming_method_name(nta_incoming_t const *irq)
+{
+  if (irq == NULL)
+    return NULL;
+  else if (irq->irq_rq)
+    return irq->irq_rq->rq_method_name;
+  else
+    return "*";
+}
+
+/** Get Request-URI of a server transaction */
+url_t const *nta_incoming_url(nta_incoming_t const *irq)
+{
+  return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL;
+}
+
+/** Get sequence number of a server transaction.
+ */
+uint32_t nta_incoming_cseq(nta_incoming_t const *irq)
+{
+  return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0;
+}
+
+/** Get local tag for incoming request */
+char const *nta_incoming_gettag(nta_incoming_t const *irq)
+{
+  return irq ? irq->irq_tag : 0;
+}
+
+/**
+ * Get status code of a server transaction.
+ */
+int nta_incoming_status(nta_incoming_t const *irq)
+{
+  return irq ? irq->irq_status : 400;
+}
+
+/** Get context pointer for an incoming transaction */
+nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
+					 nta_ack_cancel_f *callback)
+{
+  return irq && irq->irq_callback == callback ? irq->irq_magic : NULL;
+}
+
+/** Find incoming transaction. */
+nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
+				  sip_t const *sip,
+				  sip_via_t const *v)
+{
+  if (agent && sip && v)
+    return incoming_find(agent, sip, v, NULL, NULL);
+  else
+    return NULL;
+}
+
+static inline
+int addr_match(sip_addr_t const *a, sip_addr_t const *b)
+{
+  if (a->a_tag && b->a_tag)
+    return strcasecmp(a->a_tag, b->a_tag) == 0;
+  else
+    return
+      str0casecmp(a->a_host, b->a_host) == 0 &&
+      str0cmp(a->a_user, b->a_user) == 0;
+}
+
+/** Find a matching server transaction object.
+ *
+ *
+ */
+static inline
+nta_incoming_t *incoming_find(nta_agent_t const *agent,
+			      sip_t const *sip,
+			      sip_via_t const *v,
+			      nta_incoming_t **merge,
+			      nta_incoming_t **ack)
+{
+  sip_cseq_t const *cseq = sip->sip_cseq;
+  sip_call_id_t const *i = sip->sip_call_id;
+  sip_to_t const *to = sip->sip_to;
+  sip_from_t const *from = sip->sip_from;
+  sip_request_t *rq = sip->sip_request;
+  int is_uas_ack = ack && agent->sa_is_a_uas && rq->rq_method == sip_method_ack;
+  incoming_htable_t const *iht = agent->sa_incoming;
+  hash_value_t hash = NTA_HASH(i, cseq->cs_seq);
+
+  nta_incoming_t **ii, *irq, *maybe;
+
+  for (ii = incoming_htable_hash(iht, hash), maybe = NULL;
+       (irq = *ii);
+       ii = incoming_htable_next(iht, ii)) {
+    if (hash != irq->irq_hash ||
+	irq->irq_call_id->i_hash != i->i_hash ||
+	strcmp(irq->irq_call_id->i_id, i->i_id))
+      continue;
+    if (irq->irq_cseq->cs_seq != cseq->cs_seq)
+      continue;
+    if (str0casecmp(irq->irq_from->a_tag, from->a_tag))
+      continue;
+    if (is_uas_ack) {
+      if (!addr_match(irq->irq_to, to))
+	continue;
+    }
+    else if (irq->irq_tag_set || !irq->irq_tag) {
+      if (str0casecmp(irq->irq_to->a_host, to->a_host) != 0 ||
+	  str0cmp(irq->irq_to->a_user, to->a_user) != 0)
+	continue;
+    }
+    else if (str0casecmp(irq->irq_to->a_tag, to->a_tag))
+      continue;
+
+    if (str0casecmp(irq->irq_via->v_branch, v->v_branch) != 0) {
+      if (!agent->sa_is_a_uas)
+	continue;
+      if (is_uas_ack && irq->irq_status >= 200 && irq->irq_status < 300)
+	*ack = irq;
+      /* RFC3261 - section 8.2.2.2 Merged Requests */
+      else if (merge && !to->a_tag && agent->sa_merge_482)
+	*merge = irq;
+      continue;
+    }
+    if (!is_uas_ack && url_cmp(irq->irq_rq->rq_url, rq->rq_url))
+      continue;
+
+#if 0
+    if (irq->irq_terminated)
+      continue;
+#endif
+
+    if (irq->irq_method == rq->rq_method)
+      break;		/* found */
+
+    if (ack && rq->rq_method == sip_method_cancel)
+      *ack = irq;
+    else if (ack && rq->rq_method == sip_method_ack && 
+	     irq->irq_method == sip_method_invite)
+      *ack = irq;
+  }
+
+  if (irq)
+    return irq;
+
+  /* Check PRACKed requests */
+  if (ack && rq->rq_method == sip_method_prack && sip->sip_rack) {
+    sip_rack_t const *rack = sip->sip_rack;
+    hash = NTA_HASH(i, rack->ra_cseq);
+
+    for (ii = incoming_htable_hash(iht, hash);
+	 (irq = *ii);
+	 ii = incoming_htable_next(iht, ii)) {
+      if (hash != irq->irq_hash)
+	continue;
+      if (irq->irq_call_id->i_hash != i->i_hash)
+	continue;
+      if (strcmp(irq->irq_call_id->i_id, i->i_id))
+	continue;
+      if (irq->irq_cseq->cs_seq != rack->ra_cseq)
+	continue;
+      if (!addr_match(irq->irq_to, to) ||
+	  !addr_match(irq->irq_from, from))
+	continue;
+      if (!irq->irq_from->a_tag != !from->a_tag)
+	continue;
+      *ack = irq;
+
+      return NULL;
+    }
+  }
+
+  return irq;
+}
+
+/** Process retransmitted requests. */
+static inline
+int 
+incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+  nta_agent_t *agent = irq->irq_agent;
+
+  agent->sa_stats->as_recv_retry++;
+
+  if (irq->irq_status >= 100) {
+    SU_DEBUG_5(("nta: re-received %s request, retransmitting %u reply\n",
+		sip->sip_request->rq_method_name, irq->irq_status));
+    incoming_retransmit_reply(irq, tport);
+  }
+  else if (irq->irq_agent->sa_extra_100) {
+    /* Answer automatically with 100 Trying */
+    if (irq->irq_method == sip_method_invite ||
+	/*
+	 * Send 100 trying to non-invite if at least half of T2 has expired
+	 * since the transaction was created.
+	 */
+	su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U >
+	irq->irq_agent->sa_t2) {
+      SU_DEBUG_5(("nta: re-received %s request, sending 100 Trying\n",
+		  sip->sip_request->rq_method_name));
+      nta_incoming_treply(irq, SIP_100_TRYING, NTATAG_TPORT(tport), TAG_END());
+    }
+  }
+
+  msg_destroy(msg);
+
+  return 0;
+}
+
+static inline
+int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+  nta_agent_t *agent = irq->irq_agent;
+
+  /* Process ACK separately? */
+  if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas)
+    return -1;
+
+  if (irq->irq_queue == agent->sa_in.inv_completed) {
+    if (!irq->irq_confirmed)
+      agent->sa_stats->as_acked_tr++;
+
+    irq->irq_confirmed = 1;
+    incoming_reset_timer(irq); /* Reset timer G */
+
+    if (!irq->irq_reliable_tp) {
+      incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */
+    }
+    else {
+      irq->irq_terminated = 1;
+      incoming_queue(agent->sa_in.terminated, irq);
+    }
+
+    if (!irq->irq_destroyed) {
+      if (!irq->irq_callback)	/* Process ACK normally */
+	return -1;
+
+      incoming_call_callback(irq, msg, sip); /* ACK callback */
+    }
+  } else if (irq->irq_queue == agent->sa_in.proceeding ||
+	     irq->irq_queue == agent->sa_in.preliminary)
+    return -1;
+  else 
+    assert(irq->irq_queue == agent->sa_in.inv_confirmed ||
+	   irq->irq_queue == agent->sa_in.terminated);
+
+  msg_destroy(msg);
+
+  return 0;
+}
+
+static inline
+int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+		    tport_t *tport)
+{
+  nta_agent_t *agent = irq->irq_agent;
+
+  /* Respond to the CANCEL */
+  nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK, 
+		 NTATAG_TPORT(tport),
+		 TAG_END());
+
+  if (irq->irq_completed || irq->irq_method != sip_method_invite) {
+    msg_destroy(msg);
+    return 0;
+  }
+
+  if (!irq->irq_canceled) {
+    irq->irq_canceled = 1;
+    agent->sa_stats->as_canceled_tr++;
+    irq = incoming_call_callback(irq, msg, sip);
+  }
+
+  if (irq && !irq->irq_completed && agent->sa_cancel_487)
+    /* Respond to the cancelled request */
+    nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END());
+
+  msg_destroy(msg);
+
+  return 0;
+}
+
+/** Process merged requests */
+static inline
+int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+  nta_agent_t *agent = irq->irq_agent;
+
+  agent->sa_stats->as_merged_request++;
+
+  irq = incoming_create(irq->irq_agent, msg, sip, tport, irq->irq_tag);
+
+  if (!irq) {
+    SU_DEBUG_3(("nta: incoming_merge(): cannot create transaction for %s\n",
+		sip->sip_request->rq_method_name));
+    nta_msg_treply(agent, msg, 482, "Request merged", 
+		   NTATAG_TPORT(tport),
+		   TAG_END());
+    return 0;
+  }
+
+  nta_incoming_treply(irq, 482, "Request merged", TAG_END());
+  nta_incoming_destroy(irq);
+
+  return 0;
+}
+
+/**@typedef nta_ack_cancel_f
+ *
+ * Callback function prototype for CANCELed/ACKed requests
+ *
+ * This is a callback function is invoked by NTA when an incoming request
+ * has been cancelled or an response to an incoming INVITE request has been
+ * acknowledged.
+ *
+ * @param magic   incoming request context
+ * @param ireq    incoming request
+ * @param sip     ACK/CANCEL message
+ *
+ * @retval 0
+ * This callback function should return always 0.
+ */
+
+/** Call callback of incoming transaction */
+static inline
+nta_incoming_t *
+incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+  if (irq->irq_callback) {
+    irq->irq_in_callback = 1;
+    irq->irq_request2 = msg;
+    irq->irq_callback(irq->irq_magic, irq, sip);
+    irq->irq_request2 = NULL;
+    irq->irq_in_callback = 0;
+
+    if (irq->irq_terminated && irq->irq_destroyed)
+      incoming_free(irq), irq = NULL;
+  }
+  return irq;
+}
+
+/**Set server transaction parameters.
+ *
+ * Sets the server transaction parameters. The parameters determine the way
+ * the SigComp compression is handled.
+ *
+ * @TAGS
+ * NTATAG_COMP(), and NTATAG_SIGCOMP_CLOSE().
+ *
+ * @retval number of set parameters when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_set_params(nta_incoming_t *irq,
+			    tag_type_t tag, tag_value_t value, ...)
+{
+  int retval = -1;
+  
+  if (irq) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    retval = incoming_set_params(irq, ta_args(ta));
+    ta_end(ta);
+  }
+  else {
+    su_seterrno(EINVAL);
+  }
+
+  return retval;
+}
+
+static
+int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags)
+{
+  int retval = 0;
+
+  tagi_t const *t;
+  char const *comp = NONE;
+  struct sigcomp_compartment *cc = NONE;
+
+  if (irq->irq_default)
+    return retval;
+
+  for (t = tags; t; t = tl_next(t)) {
+    tag_type_t tt = t->t_tag; 
+
+    if (ntatag_comp == tt) 
+      comp = (char const *)t->t_value, retval++;
+
+    else if (ntatag_sigcomp_close == tt)
+      irq->irq_sigcomp_zap = t->t_value != 0, retval++;
+
+    else if (tptag_compartment == tt) 
+      cc = (void *)t->t_value, retval++;
+  }
+
+  if (cc != NONE) {
+    if (cc)
+      agent_accept_compressed(irq->irq_agent, irq->irq_request, cc);
+    if (irq->irq_cc)
+      nta_compartment_decref(&irq->irq_cc);
+    irq->irq_cc = nta_compartment_ref(cc);
+  }
+  else if (comp != NULL && comp != NONE && irq->irq_cc == NULL) {
+    incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1);
+  }
+
+  else if (comp == NULL) {
+    irq->irq_tpn->tpn_comp = NULL;
+  }
+
+  return retval; 
+}
+
+static inline
+int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
+			     int create_if_needed)
+{
+  if (!nta_compressor_vtable)
+    return 0;
+
+  if (irq->irq_cc == NULL 
+      || irq->irq_tpn->tpn_comp
+      || tport_delivered_with_comp(tport, msg, NULL) != -1) {
+    struct sigcomp_compartment *cc;
+
+    cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn,
+				       create_if_needed);
+    
+    if (cc)
+      agent_accept_compressed(irq->irq_agent, msg, cc);
+    
+    irq->irq_cc = cc;
+  }
+
+  return 0;
+}
+
+/** Complete a response message.
+ *
+ * @param irq     server transaction object
+ * @param msg     response message to be completed
+ * @param status  status code (in range 100 - 699)
+ * @param phrase  status phrase (may be NULL)
+ * @param tag,value,... taged argument list
+ *
+ * Generate status structure based on @a status and @a phrase.
+ * Add essential headers to the response message: 
+ * @From, @To, @CallID, @CSeq, @Via, and optionally 
+ * @RecordRoute.
+ */
+int nta_incoming_complete_response(nta_incoming_t *irq,
+				   msg_t *msg,
+				   int status, 
+				   char const *phrase,
+				   tag_type_t tag, tag_value_t value, ...)
+{
+  su_home_t *home = msg_home(msg);
+  sip_t *sip = sip_object(msg);
+  int clone = 0;
+  int retval;
+  ta_list ta;
+
+  if (irq == NULL || sip == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  if (status != 0 && (status < 100 || status > 699))
+    return su_seterrno(EINVAL), -1;
+
+  if (!sip->sip_status)
+    sip->sip_status = sip_status_create(home, status, phrase, NULL);
+
+  ta_start(ta, tag, value);
+  retval = sip_add_tl(msg, sip, ta_tags(ta));
+  ta_end(ta);
+
+  if (retval < 0)
+    return -1;
+
+  if (irq->irq_default)
+    return sip_complete_message(msg);
+
+  if (!sip->sip_from)
+    clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from);
+  if (status > 100 && !irq->irq_tag) {
+    if (sip->sip_to)
+      nta_incoming_tag(irq, sip->sip_to->a_tag);
+    else
+      nta_incoming_tag(irq, NULL);
+  }
+  if (!sip->sip_to)
+    clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to);
+  if (sip->sip_status && sip->sip_status->st_status > 100 &&
+      irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag)
+    sip_to_tag(home, sip->sip_to, irq->irq_tag);
+  if (!sip->sip_call_id)
+    clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
+  if (!sip->sip_cseq)
+    clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
+  if (!sip->sip_via)
+    clone = 1, sip->sip_via = sip_via_copy(home, irq->irq_via);
+  if (status < 300 && 
+      !sip->sip_record_route && irq->irq_record_route)
+    sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route);
+
+  if (clone)
+    msg_set_parent(msg, (msg_t *)irq->irq_home);
+
+  if (retval < 0 || !sip->sip_from || !sip->sip_to || !sip->sip_call_id
+      || !sip->sip_cseq || !sip->sip_via
+      || (status < 300 && irq->irq_record_route && !sip->sip_record_route &&
+	  sip->sip_cseq && sip->sip_cseq->cs_method != sip_method_register))
+    return -1;
+
+  return sip_complete_message(msg);
+}
+
+
+/**Reply to an incoming transaction request.
+ *
+ * This function creates a response message to an incoming request and sends
+ * it to the client.
+ *
+ * @note
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ *
+ * @param irq    incoming request
+ * @param status status code
+ * @param phrase status phrase (may be NULL if status code is well-known)
+ * @param tag,value,... optional additional headers terminated by TAG_END()
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_treply(nta_incoming_t *irq,
+			int status,
+			char const *phrase,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  int retval = -1;
+
+  if (irq &&
+      (irq->irq_status < 200 || status < 200 ||
+       (irq->irq_method == sip_method_invite && status < 300))) {
+    ta_list ta;
+    msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+
+    ta_start(ta, tag, value);
+
+    if (!msg)
+      ;
+    else if (nta_incoming_complete_response(irq, msg, status, phrase,
+					    ta_tags(ta)) < 0)
+      msg_destroy(msg);
+    else if (incoming_set_params(irq, ta_args(ta)) < 0)
+      msg_destroy(msg);
+    else
+      retval = nta_incoming_mreply(irq, msg);
+
+    ta_end(ta);
+
+    if (retval < 0 && status >= 200)
+      incoming_final_failed(irq, NULL);
+  }
+
+  return retval;
+}
+
+/**
+ * Return a response message to client.
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg) 
+{
+  sip_t *sip = sip_object(msg);
+
+  int status;
+
+  if (irq == NULL) {
+    msg_destroy(msg);
+    return -1;
+  }
+
+  if (msg == NULL)
+    return -1;
+
+  if (msg == irq->irq_response)
+    return 0;
+
+  if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq)
+    return incoming_final_failed(irq, msg);
+
+  assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default);
+
+  status = sip->sip_status->st_status;
+
+  if (!irq->irq_tag && status > 100 && !irq->irq_default)
+    nta_incoming_tag(irq, NULL);
+
+  if (/* (irq->irq_confirmed && status >= 200) || */
+      (irq->irq_completed && status >= 300)) {
+    SU_DEBUG_3(("%s: already %s transaction\n", __func__,
+		irq->irq_confirmed ? "confirmed" : "completed"));
+    msg_destroy(msg);
+    return -1;
+  }
+
+  if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
+    /* This nta_reliable_t object will be destroyed by PRACK or timeout */
+    if (nta_reliable_mreply(irq, NULL, NULL, msg))
+      return 0;
+
+    return -1;
+  }
+
+  if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) {
+    if (reliable_final(irq, msg, sip) == 0)
+      return 0;
+  }
+
+  return incoming_reply(irq, msg, sip);
+}
+
+
+
+/** Send the response message.
+ *
+ * @note The ownership of msg is handled to incoming_reply().
+ */
+int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+  nta_agent_t *agent = irq->irq_agent;
+  int status = sip->sip_status->st_status;
+  int sending = 1;
+  int *use_rport = NULL;
+  int retry_without_rport = 0;
+  tp_name_t *tpn, default_tpn[1];
+
+  if (status == 408 && 
+      irq->irq_method != sip_method_invite && 
+      !agent->sa_pass_408 &&
+      !irq->irq_default) {
+    /* draft-sparks-sip-nit-actions-03 Action 2:
+       
+   A transaction-stateful SIP element MUST NOT send a response with
+   Status-Code of 408 to a non-INVITE request.  As a consequence, an
+   element that can not respond before the transaction expires will not
+   send a final response at all.
+    */
+    sending = 0;
+  }
+
+  if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp)
+    incoming_timestamp(irq, msg, sip);
+
+  if (irq->irq_default) {
+    if (agent->sa_server_rport)
+      use_rport = &retry_without_rport, retry_without_rport = 1;
+    tpn = default_tpn;
+    if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
+      tpn = NULL;
+  }
+  else {
+    tpn = irq->irq_tpn;
+  }
+
+  if (sip_complete_message(msg) < 0)
+    SU_DEBUG_1(("%s: sip_complete_message() failed\n", __func__));
+  else if (msg_serialize(msg, (msg_pub_t *)sip) < 0)
+    SU_DEBUG_1(("%s: sip_serialize() failed\n", __func__));
+  else if (!(irq->irq_tport) &&
+	   !(tport_decref(&irq->irq_tport),
+	     irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0))
+    SU_DEBUG_1(("%s: no tport\n", __func__));
+  else {
+    int i, err = 0;
+    tport_t *tp = NULL;
+    incoming_queue_t *queue;
+
+    char const *method_name;
+    uint32_t cseq;
+
+    if (irq->irq_default) {
+      assert(sip->sip_cseq);
+      method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq;
+    }
+    else {
+      method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq;
+    }
+
+    if (sending) {
+      for (i = 0; i < 3; i++) {
+	tp = tport_tsend(irq->irq_tport, msg, tpn,
+			 IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)
+			 TPTAG_MTU(INT_MAX),
+			 TAG_END());
+	if (tp)
+	  break;
+
+	err = msg_errno(msg);
+	SU_DEBUG_5(("%s: tport_tsend: %s%s\n",
+		    __func__, su_strerror(err),
+		    err == EPIPE ? "(retrying)" : ""));
+	
+	if (err != EPIPE && err != ECONNREFUSED)
+	  break;
+	tport_decref(&irq->irq_tport);
+	irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn));
+      }
+
+      if (!tp) {
+	SU_DEBUG_3(("%s: tport_tsend: "
+		    "error (%s) while sending %u %s for %s (%u)\n",
+		    __func__, su_strerror(err),
+		    status, sip->sip_status->st_phrase, method_name, cseq));
+	if (status < 200)
+	  msg_destroy(msg);
+	else
+	  incoming_final_failed(irq, msg);
+	return 0;
+      }
+
+      agent->sa_stats->as_sent_msg++;
+      agent->sa_stats->as_sent_response++;
+    }
+
+    SU_DEBUG_5(("nta: %s %u %s for %s (%u)\n",
+		sending ? "sent" : "not sending",
+		status, sip->sip_status->st_phrase, method_name, cseq));
+
+    if (irq->irq_default) {
+      msg_destroy(msg);
+      return 0;
+    }
+
+    incoming_reset_timer(irq);
+
+    if (status < 200) {
+      queue = agent->sa_in.proceeding;
+      
+      if (irq->irq_method == sip_method_invite && status > 100 && 
+	  agent->sa_progress != UINT_MAX && agent->sa_is_a_uas) {
+	/* Retransmit preliminary responses in regular intervals */
+	incoming_set_timer(irq, agent->sa_progress); /* N2 */
+      }
+    } 
+    else {
+      irq->irq_completed = 1;
+
+      /* XXX - we should do this only after message has actually been sent! */
+      if (irq->irq_sigcomp_zap && irq->irq_cc)
+	agent_close_compressor(irq->irq_agent, irq->irq_cc);
+
+      if (irq->irq_method != sip_method_invite) {
+	irq->irq_confirmed = 1;
+
+	if (irq->irq_reliable_tp) {
+	  irq->irq_terminated = 1;
+	  queue = agent->sa_in.terminated ; /* J - set for 0 seconds */
+	} else {
+	  queue = agent->sa_in.completed; /* J */
+	}
+
+	tport_decref(&irq->irq_tport);
+      }
+      else if (status >= 300 || agent->sa_is_a_uas) {
+	if (status < 300 || !irq->irq_reliable_tp) 
+	  incoming_set_timer(irq, agent->sa_t1); /* G */
+	queue = agent->sa_in.inv_completed; /* H */
+      }
+      else {
+#if 1
+	/* Avoid bug in @RFC3261:
+	  Keep INVITE transaction around in order to catch
+	  retransmitted INVITEs
+	*/
+	irq->irq_confirmed = 1;
+	queue = agent->sa_in.inv_confirmed; /* H */
+#else
+	irq->irq_terminated = 1;
+	queue = agent->sa_in.terminated;
+#endif
+      }
+    }
+
+    if (irq->irq_queue != queue)
+      incoming_queue(queue, irq);
+
+    if (status >= 200 || irq->irq_status < 200) {
+      if (irq->irq_response)
+	msg_destroy(irq->irq_response);
+      assert(msg_home(msg) != irq->irq_home);
+      irq->irq_response = msg;
+    }
+    else {
+      msg_destroy(msg);
+    }
+
+    if (sip->sip_cseq->cs_method == irq->irq_method &&
+	irq->irq_status < 200 && status > irq->irq_status)
+      irq->irq_status = status;
+
+    return 0;
+  }
+
+  /*
+   *  XXX - handling error is very problematic.
+   * Nobody checks return code from nta_incoming_*reply()
+   */
+  if (status < 200) {
+    msg_destroy(msg);
+    return -1;
+  }
+
+  /* We could not send final response. */
+  return incoming_final_failed(irq, msg); 
+}
+
+
+/** @internal Sending final response has failed.
+ *
+ * Put transaction into its own queue, try later to send the response.
+ */
+static inline
+int incoming_final_failed(nta_incoming_t *irq, msg_t *msg)
+{
+  msg_destroy(msg);
+
+  if (!irq->irq_default) {
+    irq->irq_final_failed = 1;
+    incoming_queue(irq->irq_agent->sa_in.final_failed, irq);
+  }
+
+  return -1;
+}
+
+/** @internal Retransmit the reply */
+static
+void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport)
+{
+  msg_t *msg = NULL;
+
+  if (irq->irq_final_failed)
+    return;
+
+  if (tport == NULL)
+    tport = irq->irq_tport;
+
+  /* Answer with existing reply */
+  if (irq->irq_reliable && !irq->irq_reliable->rel_pracked)
+    msg = reliable_response(irq);
+  else
+    msg = irq->irq_response;
+  
+  if (msg && tport) {
+    irq->irq_retries++;
+
+    if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) {
+      irq->irq_tpn->tpn_comp = NULL;
+      
+      if (irq->irq_cc) {
+	agent_close_compressor(irq->irq_agent, irq->irq_cc);
+	nta_compartment_decref(&irq->irq_cc);
+      }
+    }
+
+    tport = tport_tsend(tport, msg, irq->irq_tpn, 
+			IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)
+			TPTAG_MTU(INT_MAX), TAG_END());
+    irq->irq_agent->sa_stats->as_sent_msg++;
+    irq->irq_agent->sa_stats->as_sent_response++;
+  }
+}
+
+/** @internal Create timestamp header for response */
+static
+int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+  sip_timestamp_t ts[1];
+  su_time_t now = su_now();
+  char delay[32];
+  double diff = su_time_diff(now, irq->irq_received);
+
+  snprintf(delay, sizeof delay, "%.06f", diff);
+
+  *ts = *irq->irq_timestamp;
+  ts->ts_delay = delay;
+
+  return sip_add_dup(msg, sip, (sip_header_t *)ts);
+}
+
+enum {
+  timer_max_retransmit = 30,
+  timer_max_terminate = 100000,
+  timer_max_timeout = 100
+};
+
+/** @internal Timer routine for the incoming request. */
+static inline
+int incoming_timer(nta_agent_t *sa, su_duration_t now)
+{
+  nta_incoming_t *irq, *irq_next;
+  size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0;
+  size_t unconfirmed = 
+    sa->sa_in.inv_completed->q_length + 
+    sa->sa_in.preliminary->q_length;
+  size_t unterminated = 
+    sa->sa_in.inv_confirmed->q_length + 
+    sa->sa_in.completed->q_length;
+  size_t total = sa->sa_incoming->iht_used;
+
+  incoming_queue_t rq[1];
+
+  incoming_queue_init(rq, 0);
+
+  /* Handle retry queue */
+  while ((irq = sa->sa_in.re_list)) {
+    if ((irq->irq_retry && irq->irq_retry - now > 0) ||
+	retransmitted >= timer_max_retransmit) 
+      break;
+
+    if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) {
+      /* Timer G */
+      assert(irq->irq_queue == sa->sa_in.inv_completed);
+
+      retransmitted++;
+
+      SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+		  "G", irq->irq_status));
+
+      incoming_retransmit_reply(irq, irq->irq_tport);
+
+      if (2U * irq->irq_interval < sa->sa_t2)
+	incoming_set_timer(irq, 2U * irq->irq_interval); /* G */
+      else
+	incoming_set_timer(irq, sa->sa_t2); /* G */
+    } 
+    else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) {
+      if (irq->irq_queue == sa->sa_in.preliminary) {
+	/* Timer P1 - PRACK timer */
+	retransmitted++;
+	SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+		    "P1", irq->irq_status));
+
+	incoming_retransmit_reply(irq, irq->irq_tport);
+
+	incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */
+      }
+      else {
+	/* Retransmitting provisional responses */
+	SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+		    "N2", irq->irq_status));
+	incoming_set_timer(irq, sa->sa_progress);
+	retransmitted++;
+	incoming_retransmit_reply(irq, irq->irq_tport);
+      }
+    } else {
+      /* Timer N1 */
+      SU_DEBUG_5(("nta: timer N1 fired, sending %u %s\n", SIP_100_TRYING));
+      incoming_reset_timer(irq);
+      nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+    }
+  }
+
+  while ((irq = sa->sa_in.final_failed->q_head)) {
+    incoming_remove(irq);
+    irq->irq_final_failed = 0;
+
+    /* Report error to application */
+    SU_DEBUG_5(("nta: sending final response failed, timeout %u response\n",
+		irq->irq_status));
+    reliable_timeout(irq, 0);
+
+    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+
+    if (!irq->irq_final_failed)	/* We have taken care of the error... */
+      continue;
+
+    if (irq->irq_destroyed) {
+      incoming_free_queue(rq, irq);
+      continue;
+    }
+
+    incoming_reset_timer(irq);
+    irq->irq_confirmed = 1;
+    irq->irq_terminated = 1;
+    incoming_queue(sa->sa_in.terminated, irq);
+  }
+
+  /* Timeouts.
+   * For each state the request is in, there is always a queue of its own 
+   */
+  while ((irq = sa->sa_in.preliminary->q_head)) {
+    assert(irq->irq_status < 200);
+    assert(irq->irq_timeout);
+
+    if (irq->irq_timeout - now > 0 
+	|| timeout >= timer_max_timeout)
+      break;
+
+    timeout++;
+
+    /* Timer P2 - PRACK timer */
+    SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+		"P2", "timeout", irq->irq_status));
+    incoming_reset_timer(irq);
+    irq->irq_timeout = 0;
+    reliable_timeout(irq, 1);
+  }
+
+  while ((irq = sa->sa_in.inv_completed->q_head)) {
+    assert(irq->irq_status >= 200);
+    assert(irq->irq_timeout);
+    assert(irq->irq_method == sip_method_invite);
+
+    if (irq->irq_timeout - now > 0 || 
+	timeout >= timer_max_timeout || 
+	terminated >= timer_max_terminate)
+      break;
+
+    /* Timer H */
+    SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+		"H", "timeout and terminate", irq->irq_status));
+    irq->irq_confirmed = 1;
+    irq->irq_terminated = 1;
+    incoming_reset_timer(irq);
+    if (!irq->irq_destroyed) {
+      timeout++; 
+      incoming_queue(sa->sa_in.terminated, irq);
+      /* report timeout error to user */
+      incoming_call_callback(irq, NULL, NULL);
+    } else {
+      timeout++;
+      terminated++;
+      incoming_free_queue(rq, irq);
+    }
+  } 
+
+  while ((irq = sa->sa_in.inv_confirmed->q_head)) {
+    assert(irq->irq_timeout);
+    assert(irq->irq_status >= 200);
+    assert(irq->irq_method == sip_method_invite);
+
+    if (irq->irq_timeout - now > 0 || 
+	terminated >= timer_max_terminate)
+      break;
+    
+    /* Timer I */
+    SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+		"I", "terminate", irq->irq_status));
+
+    terminated++;
+    irq->irq_terminated = 1;
+
+    if (!irq->irq_destroyed)
+      incoming_queue(sa->sa_in.terminated, irq);
+    else
+      incoming_free_queue(rq, irq);
+  }
+
+  while ((irq = sa->sa_in.completed->q_head)) {
+    assert(irq->irq_status >= 200);
+    assert(irq->irq_timeout);
+    assert(irq->irq_method != sip_method_invite);
+
+    if (irq->irq_timeout - now > 0 || 
+	terminated >= timer_max_terminate)
+      break;
+
+    /* Timer J */
+
+    SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+		"J", "terminate", irq->irq_status));
+
+    terminated++;
+    irq->irq_terminated = 1;
+
+    if (!irq->irq_destroyed)
+      incoming_queue(sa->sa_in.terminated, irq);
+    else
+      incoming_free_queue(rq, irq);
+  }
+
+  for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) {
+    irq_next = irq->irq_next;
+    if (irq->irq_destroyed)
+      incoming_free_queue(rq, irq);
+  }
+
+  destroyed = incoming_mass_destroy(sa, rq);
+
+  if (retransmitted || timeout || terminated || destroyed)
+    SU_DEBUG_5(("nta_incoming_timer: "
+		MOD_ZU"/"MOD_ZU" resent, "
+		MOD_ZU"/"MOD_ZU" tout, "
+		MOD_ZU"/"MOD_ZU" term, "
+		MOD_ZU"/"MOD_ZU" free\n",
+		retransmitted, unconfirmed, 
+		timeout, unconfirmed,
+		terminated, unterminated, 
+		destroyed, total));
+
+  return 
+    retransmitted >= timer_max_retransmit
+    || timeout >= timer_max_timeout
+    || terminated >= timer_max_terminate;
+}
+
+/** Mass destroy server transactions */
+static inline
+int incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
+{
+  size_t destroyed = q->q_length;
+
+  if (destroyed > 2 && *sa->sa_terminator) {
+    su_msg_r m = SU_MSG_R_INIT;
+
+    if (su_msg_create(m,
+		      su_clone_task(sa->sa_terminator),
+		      su_root_task(sa->sa_root),
+		      incoming_reclaim_queued,
+		      sizeof(incoming_queue_t)) == SU_SUCCESS) {
+      incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue;
+
+      *mq = *q;
+
+      if (su_msg_send(m) == SU_SUCCESS)
+	q->q_length = 0;
+    }    
+  } 
+
+  if (q->q_length > 0)
+    incoming_reclaim_queued(NULL, NULL, (void *)q);
+
+  return destroyed;
+}
+
+/* ====================================================================== */
+/* 8) Client-side (outgoing) transactions */
+
+#define HTABLE_HASH_ORQ(orq) ((orq)->orq_hash)
+
+HTABLE_BODIES_WITH(outgoing_htable, oht, nta_outgoing_t, HTABLE_HASH_ORQ,
+		   size_t, hash_value_t);
+
+static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+				       nta_response_f *callback,
+				       nta_outgoing_magic_t *magic,
+				       url_string_t const *route_url,
+				       tp_name_t const *tpn,
+				       msg_t *msg,
+				       tag_type_t tag, tag_value_t value, ...);
+static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
+			      msg_t *msg, sip_t *sip,
+			      tagi_t *tags);
+static void outgoing_prepare_send(nta_outgoing_t *orq);
+static void outgoing_send(nta_outgoing_t *orq, int retransmit);
+static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
+static void outgoing_try_udp_instead(nta_outgoing_t *orq);
+static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
+				 tport_t *tp, msg_t *msg, int error);
+static void outgoing_print_tport_error(nta_outgoing_t *orq, 
+				       int level, char *todo,
+				       tp_name_t const *, msg_t *, int error);
+static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq);
+static void outgoing_destroy(nta_outgoing_t *orq);
+static inline int outgoing_is_queued(nta_outgoing_t const *orq);
+static inline void outgoing_queue(outgoing_queue_t *queue, 
+				  nta_outgoing_t *orq);
+static inline void outgoing_remove(nta_outgoing_t *orq);
+static inline void outgoing_set_timer(nta_outgoing_t *orq, unsigned interval);
+static inline void outgoing_reset_timer(nta_outgoing_t *orq);
+static size_t outgoing_timer_dk(outgoing_queue_t *q, 
+			     char const *timer, 
+			     su_duration_t now);
+static size_t outgoing_timer_bf(outgoing_queue_t *q, 
+			     char const *timer, 
+			     su_duration_t now);
+
+static void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
+static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
+			      tagi_t const *tags);
+static void outgoing_retransmit(nta_outgoing_t *orq);
+static void outgoing_trying(nta_outgoing_t *orq);
+static void outgoing_timeout(nta_outgoing_t *orq, su_duration_t now);
+static int outgoing_complete(nta_outgoing_t *orq);
+static int outgoing_terminate(nta_outgoing_t *orq);
+static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q);
+static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip);
+static int outgoing_duplicate(nta_outgoing_t *orq,
+			      msg_t *msg,
+			      sip_t *sip);
+static int outgoing_reply(nta_outgoing_t *orq,
+			  int status, char const *phrase,
+			  int delayed);
+
+static int outgoing_default_cb(nta_outgoing_magic_t *magic,
+			       nta_outgoing_t *request,
+			       sip_t const *sip);
+
+#if HAVE_SOFIA_SRESOLV
+static void outgoing_resolve(nta_outgoing_t *orq);
+static inline void outgoing_cancel_resolver(nta_outgoing_t *orq);
+static inline void outgoing_destroy_resolver(nta_outgoing_t *orq);
+static int outgoing_other_destinations(nta_outgoing_t const *orq);
+static int outgoing_try_another(nta_outgoing_t *orq);
+#else
+#define outgoing_other_destinations(orq) (0)
+#define outgoing_try_another(orq) (0) 
+#endif
+
+/** Create a default outgoing transaction.
+ *
+ * The default outgoing transaction is used when agent receives responses
+ * not belonging to any transaction. 
+ *
+ * @sa nta_leg_default(), nta_incoming_default().
+ */
+nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic)
+{
+  nta_outgoing_t *orq;
+
+  if (agent == NULL)
+    return NULL;
+
+  if (agent->sa_default_outgoing)
+    return NULL;
+
+  orq = su_zalloc(agent->sa_home, sizeof *orq);
+  if (!orq)
+    return NULL;
+    
+  orq->orq_agent     = agent;
+  orq->orq_callback  = callback;
+  orq->orq_magic     = magic;
+  orq->orq_method    = sip_method_invalid;
+  orq->orq_method_name = "*";
+  orq->orq_default   = 1;
+  orq->orq_stateless = 1;
+  orq->orq_delay     = UINT_MAX;
+
+  return agent->sa_default_outgoing = orq;
+}
+
+/**Create an outgoing request and client transaction belonging to the leg.
+ *
+ * The function nta_outgoing_tcreate() creates a request message and passes
+ * the request message to an outgoing client transaction object. The request
+ * is sent to the @a route_url (if non-NULL), default proxy (if defined by
+ * NTATAG_DEFAULT_PROXY()), or to the address specified by @a request_uri.
+ * If no @a request_uri is specified, it is taken from route-set target or
+ * from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param leg         call leg object
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param route_url   optional URL used to route transaction requests
+ * @param method      method type
+ * @param name        method name
+ * @param request_uri Request-URI
+ * @param tag, value, ... list of tagged arguments
+ *
+ * @return
+ * A pointer to a newly created outgoing transaction object if successful,
+ * and NULL otherwise.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @sa
+ * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ *
+ * @TAGS
+ * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
+ * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
+ * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
+ * SIP tags from <sip_tag.h> can be used to manipulate the request message. 
+ * SIP tags after SIPTAG_END() are ignored, however.
+ */
+nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     sip_method_t method,
+				     char const *name,
+				     url_string_t const *request_uri,
+				     tag_type_t tag, tag_value_t value, ...)
+{
+  nta_agent_t *agent;
+  msg_t *msg;
+  sip_t *sip;
+  nta_outgoing_t *orq = NULL;
+  ta_list ta;
+
+  if (leg == NULL)
+    return NULL;
+
+  agent = leg->leg_agent;
+  msg = nta_msg_create(agent, 0);
+  sip = sip_object(msg);
+
+  if (route_url == NULL)
+    route_url = (url_string_t *)agent->sa_default_proxy;
+
+  ta_start(ta, tag, value);
+
+  if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+    ;
+  else if (route_url == NULL && leg->leg_route &&
+	   leg->leg_loose_route &&
+	   !(route_url = (url_string_t *)leg->leg_route->r_url))
+    ;
+  else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
+    ;
+  else
+    orq = outgoing_create(agent, callback, magic, route_url, NULL, msg,
+			  ta_tags(ta));
+
+  ta_end(ta);
+
+  if (!orq)
+    msg_destroy(msg);
+
+  return orq;
+}
+
+/**Create an outgoing client transaction.
+ *
+ * Create an outgoing transaction object. The request message is passed to
+ * the transaction object, which sends the request to the network. The
+ * request is sent to the @a route_url (if non-NULL), default proxy (if
+ * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a
+ * request_uri. If no @a request_uri is specified, it is taken from
+ * route-set target or from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param agent       NTA agent object
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param route_url   optional URL used to route transaction requests
+ * @param msg         request message
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return
+ * Returns a pointer to newly created outgoing transaction object if
+ * successful, and NULL otherwise.
+ *
+ * @note The caller is responsible for destroying the request message @a msg 
+ * upon failure.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nnta_outgoing_tcancel(), nta_outgoing_destroy().
+ *
+ * @TAGS
+ * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
+ * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
+ * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
+ * SIP tags from <sip_tag.h> can be used to manipulate the request message. 
+ * SIP tags after SIPTAG_END() are ignored, however.
+ */
+nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     msg_t *msg,
+				     tag_type_t tag, tag_value_t value, ...)
+{
+  nta_outgoing_t *orq = NULL;
+  int cleanup = 0;
+
+  if (msg == NONE)
+    msg = nta_msg_create(agent, 0), cleanup = 1;
+
+  if (msg && agent) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) >= 0)
+      orq = outgoing_create(agent, callback, magic, route_url, NULL, msg,
+			    ta_tags(ta));
+    ta_end(ta);
+  }
+
+  if (!orq && cleanup)
+    msg_destroy(msg);
+
+  return orq;
+}
+
+/** Cancel the request. */
+int nta_outgoing_cancel(nta_outgoing_t *orq)
+{
+  nta_outgoing_t *cancel =
+    nta_outgoing_tcancel(orq, NULL, NULL, TAG_NULL());
+
+  return (cancel != NULL) - 1;
+}
+
+/** Cancel the request.
+ *
+ * Initiate a cancel transaction for client transaction @a orq.
+ *
+ * @param orq      client transaction to cancel
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param tag, value, ... list of extra arguments
+ *
+ * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE)
+ * if callback is NULL.
+ *
+ * @TAGS
+ * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are
+ * accepted by nta_outgoing_tcreate().
+ *
+ * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack
+ * generates a 487 response to the request internally. If
+ * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent.
+ *
+ * @note
+ * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE
+ * requests.
+ */
+nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     tag_type_t tag, tag_value_t value, ...)
+{
+  msg_t *msg;
+  int cancel_2543, cancel_408;
+  ta_list ta;
+  int delay_sending;
+
+  if (orq == NULL || orq == NONE)
+    return NULL;
+
+  if (orq->orq_destroyed) {
+    SU_DEBUG_3(("%s: trying to cancel destroyed request\n", __func__));
+    return NULL;
+  }
+  if (orq->orq_method != sip_method_invite) {
+    SU_DEBUG_3(("%s: trying to cancel non-INVITE request\n", __func__));
+    return NULL;
+  }
+  if (orq->orq_status >= 200
+      /* && orq->orq_method != sip_method_invite ... !multicast */) {
+    SU_DEBUG_3(("%s: trying to cancel completed request\n", __func__));
+    return NULL;
+  }
+  if (orq->orq_canceled) {
+    SU_DEBUG_3(("%s: trying to cancel cancelled request\n", __func__));
+    return NULL;
+  }
+  orq->orq_canceled = 1;
+
+#if HAVE_SOFIA_SRESOLV
+  if (!orq->orq_resolved) {
+    if (orq->orq_resolver)
+      outgoing_cancel_resolver(orq);
+    outgoing_reply(orq, SIP_487_REQUEST_CANCELLED, 1);
+    return NULL;		/* XXX - Does anyone care about reply? */
+  }
+#endif
+
+  cancel_408 = 0;		/* Don't really CANCEL, this is timeout. */
+  cancel_2543 = orq->orq_agent->sa_cancel_2543;
+  /* CANCEL may be sent only after a provisional response has been received. */
+  delay_sending = orq->orq_status < 100;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta), 
+	  NTATAG_CANCEL_408_REF(cancel_408), 
+	  NTATAG_CANCEL_2543_REF(cancel_2543),
+	  TAG_END());
+
+  if (!cancel_408)
+    msg = outgoing_ackmsg(orq, SIP_METHOD_CANCEL, ta_args(ta));
+  else
+    msg = NULL;
+
+  ta_end(ta);
+
+  if ((cancel_2543 || cancel_408) && 
+      !orq->orq_stateless && !orq->orq_destroyed)
+    outgoing_reply(orq, SIP_487_REQUEST_CANCELLED, 1);
+
+  if (msg) {
+    nta_outgoing_t *cancel;
+    if (cancel_2543)		/* Follow RFC 2543 semantics for CANCEL */
+      delay_sending = 0;
+
+    cancel = outgoing_create(orq->orq_agent, callback, magic,
+			     NULL, orq->orq_tpn, msg,
+			     NTATAG_BRANCH_KEY(orq->orq_branch),
+			     NTATAG_DELAY_SENDING(delay_sending),
+			     NTATAG_USER_VIA(1),
+			     TAG_END());
+
+    if (delay_sending)
+      orq->orq_cancel = cancel;
+
+    if (cancel)
+      return cancel;
+
+    msg_destroy(msg);
+  }
+
+  return NULL;
+}
+
+/**
+ * Destroy a request object.
+ *
+ * @note
+ * This function does not actually free the object, but marks it as
+ * disposable. The object is freed after a timeout.
+ */
+void nta_outgoing_destroy(nta_outgoing_t *orq)
+{
+  if (orq == NULL || orq == NONE)
+    return;
+
+  if (orq->orq_destroyed) {
+    SU_DEBUG_1(("nta_outgoing_destroy(%p): already destroyed\n", orq));
+    return;
+  }
+
+  outgoing_destroy(orq);
+}
+
+/** Return the request URI */
+url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE ? orq->orq_url : NULL;
+}
+
+/** Return the URI used to route the request */
+url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE ? orq->orq_route : NULL;
+}
+
+/** Return method of the client transaction */
+sip_method_t nta_outgoing_method(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE ? orq->orq_method : sip_method_invalid;
+}
+
+/** Return method name of the client transaction */
+char const *nta_outgoing_method_name(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE ? orq->orq_method_name : NULL;
+}
+
+/** Get sequence number of a client transaction.
+ */
+uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE && orq->orq_cseq 
+    ? orq->orq_cseq->cs_seq : 0;
+}
+
+/**
+ * Get the status code of a client transaction.
+ */
+int nta_outgoing_status(nta_outgoing_t const *orq)
+{
+  /* Return 500 Internal server error for invalid handles. */
+  return orq != NULL && orq != NONE ? orq->orq_status : 500; 
+}
+
+/** Get the RTT delay measured using @Timestamp header. */
+unsigned nta_outgoing_delay(nta_outgoing_t const *orq)
+{
+  return orq != NULL && orq != NONE ? orq->orq_delay : UINT_MAX;
+}
+
+/**Get reference to response message.
+ *
+ * Retrieve the latest incoming response message to the outgoing
+ * transaction. Note that the message is not copied, but a new reference to
+ * it is created instead.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to response message is returned, or NULL if no response message
+ * has been received.
+ */
+msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
+{
+  if (orq != NULL && orq != NONE)
+    return msg_ref_create(orq->orq_response);
+  else
+    return NULL;
+}
+
+/**Get request message.
+ *
+ * Retrieves the request message sent to the network. Note that the request
+ * message is @b not copied, but a new reference to it is created.
+ *
+ * @retval
+ * A pointer to the request message is returned, or NULL if an error
+ * occurred.
+ */
+msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
+{
+  if (orq != NULL && orq != NONE)
+    return msg_ref_create(orq->orq_request);
+  else
+    return NULL;
+}
+
+/**Create an outgoing request.
+ *
+ * The function outgoing_create() creates an outgoing transaction object and
+ * sends the request to the network. The request is sent to the @a route_url
+ * (if non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or
+ * to the address specified by @a sip->sip_request->rq_url.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param agent       nta agent object
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param route_url   optional URL used to route transaction requests
+ * @param msg         request message
+ * @param tpn         (optional) transport name
+ * @param msg         request message to 
+ * @param tag, value, ... tagged arguments
+ *
+ * @return
+ * Returns a pointer to newly created outgoing transaction object if
+ * successful, and NULL otherwise.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @TAG NTATAG_TPORT must point to an existing transport object for
+ *      'agent' (the passed tport is otherwise ignored).
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ */
+nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+				nta_response_f *callback,
+				nta_outgoing_magic_t *magic,
+				url_string_t const *route_url,
+				tp_name_t const *tpn,
+				msg_t *msg,
+				tag_type_t tag, tag_value_t value, ...)
+{
+  nta_outgoing_t *orq;
+  sip_t *sip;
+  su_home_t *home;
+  char const *comp = NONE;
+  char const *branch = NONE;
+  char const *ack_branch = NONE;
+  char const *tp_ident;
+  int delay_sending = 0, sigcomp_zap = 0;
+  int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp;
+  enum nta_res_order_e res_order = agent->sa_res_order;
+  struct sigcomp_compartment *cc = NULL;
+  ta_list ta;
+  char const *scheme = NULL;
+  char const *port = NULL;
+  int invalid, resolved, stateless = 0, user_via = agent->sa_user_via;
+  tagi_t const *t;
+  tport_t const *override_tport = NULL;
+
+  if (!agent->sa_tport_ip6)
+    res_order = nta_res_ip4_only;
+  else if (!agent->sa_tport_ip4)
+    res_order = nta_res_ip6_only;
+
+  if (!callback)
+    callback = outgoing_default_cb;
+  if (!route_url)
+    route_url = (url_string_t *)agent->sa_default_proxy;
+
+  sip = sip_object(msg);
+  home = msg_home(msg);
+
+  if (!sip->sip_request || sip_complete_message(msg) < 0) {
+    SU_DEBUG_3(("nta: outgoing_create: incomplete request\n"));
+    return NULL;
+  }
+
+  if (!route_url && !tpn && sip->sip_route &&
+      sip->sip_route->r_url->url_params &&
+      url_param(sip->sip_route->r_url->url_params, "lr", NULL, 0))
+    route_url = (url_string_t *)sip->sip_route->r_url;
+
+  if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq))))
+    return NULL;
+
+  tp_ident = tpn ? tpn->tpn_ident : NULL;
+
+  ta_start(ta, tag, value);
+
+  /* tl_gets() is a bit too slow here... */
+  for (t = ta_args(ta); t; t = tl_next(t)) {
+    tag_type_t tt = t->t_tag; 
+
+    if (ntatag_stateless == tt) 
+      stateless = t->t_value != 0; 
+    else if (ntatag_delay_sending == tt) 
+      delay_sending = t->t_value != 0; 
+    else if (ntatag_branch_key == tt) 
+      branch = (void *)t->t_value; 
+    else if (ntatag_pass_100 == tt) 
+      pass_100 = t->t_value != 0; 
+    else if (ntatag_use_timestamp == tt) 
+      use_timestamp = t->t_value != 0; 
+    else if (ntatag_user_via == tt) 
+      user_via = t->t_value != 0; 
+    else if (ntatag_ack_branch == tt) 
+      ack_branch = (void *)t->t_value; 
+    else if (ntatag_default_proxy == tt) 
+      route_url = (void *)t->t_value; 
+    else if (tptag_ident == tt)
+      tp_ident = (void *)t->t_value;
+    else if (ntatag_comp == tt)
+      comp = (char const *)t->t_value;
+    else if (ntatag_sigcomp_close == tt)
+      sigcomp_zap = t->t_value != 0;
+    else if (tptag_compartment == tt)
+      cc = (void *)t->t_value;
+    else if (ntatag_tport == tt) {
+      override_tport = (tport_t *)t->t_value;
+    }
+  }
+
+  orq->orq_agent    = agent;
+  orq->orq_callback = callback;
+  orq->orq_magic    = magic;
+  orq->orq_method   = sip->sip_request->rq_method;
+  orq->orq_method_name = sip->sip_request->rq_method_name;
+  orq->orq_cseq     = sip->sip_cseq;
+  orq->orq_to       = sip->sip_to;
+  orq->orq_from     = sip->sip_from;
+  orq->orq_call_id  = sip->sip_call_id;
+  orq->orq_tags     = tl_afilter(home, tport_tags, ta_args(ta));
+  orq->orq_delayed  = delay_sending != 0;
+  orq->orq_pass_100 = pass_100 != 0;
+  orq->orq_sigcomp_zap = sigcomp_zap;
+  orq->orq_sigcomp_new = comp != NONE && comp != NULL;
+  orq->orq_res_order = res_order;
+  orq->orq_timestamp = use_timestamp;
+  orq->orq_delay     = UINT_MAX;
+  orq->orq_stateless = stateless != 0;
+  orq->orq_user_via  = user_via != 0 && sip->sip_via;
+  if (cc)
+    orq->orq_cc = nta_compartment_ref(cc);
+
+  /* Add supported features */
+  outgoing_features(agent, orq, msg, sip, ta_args(ta));
+
+  ta_end(ta);
+
+  /* select the tport to use for the outgoing message  */
+  if (override_tport) {
+    /* note: no ref taken to the tport as its only used once here */
+    tpn = tport_name(override_tport);
+  }
+
+  if (route_url) {
+    invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
+    resolved = tport_name_is_resolved(orq->orq_tpn);
+    orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+    if (route_url != (url_string_t *)agent->sa_default_proxy)
+      orq->orq_route = url_hdup(home, route_url->us_url);
+  }
+  else if (tpn) {
+    invalid = tport_name_dup(home, orq->orq_tpn, tpn);
+#if HAVE_SOFIA_SRESOLV
+    assert(tport_name_is_resolved(orq->orq_tpn));
+#endif
+    resolved = tport_name_is_resolved(orq->orq_tpn);
+    orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+    scheme = "sip";		/* XXX */
+  }
+  else {
+    invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port,
+			     (url_string_t *)sip->sip_request->rq_url);
+    resolved = tport_name_is_resolved(orq->orq_tpn);
+    orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+    sip_fragment_clear(sip->sip_request->rq_common);
+  }
+
+  orq->orq_tpn->tpn_ident = tp_ident;
+  if (comp == NULL)
+    orq->orq_tpn->tpn_comp = comp;
+
+  if (orq->orq_user_via && str0cmp(orq->orq_tpn->tpn_proto, "*") == 0) {
+    char const *proto = sip_via_transport(sip->sip_via);
+    if (proto) orq->orq_tpn->tpn_proto = proto;
+  }
+
+  if (branch && branch != NONE) {
+    if (strchr(branch, '='))
+      branch = su_strdup(home, branch);
+    else
+      branch = su_sprintf(home, "branch=%s", branch);
+  }
+  else if (orq->orq_user_via && sip->sip_via->v_branch)
+    branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch);
+  else if (stateless)
+    branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
+  else
+    branch = stateful_branch(home, agent);
+
+  orq->orq_branch = branch;
+  orq->orq_via_branch = branch;
+
+  if (orq->orq_method == sip_method_ack) {
+    if (ack_branch != NULL && ack_branch != NONE) {
+      orq->orq_branch = su_strdup(home, ack_branch);
+    } 
+    else if (!stateless && agent->sa_is_a_uas) {
+      /*
+       * ACK redirect further 2XX messages to it.
+       *
+       * Use orq_branch from INVITE, but put a different branch in topmost Via.
+       */
+      nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL);
+      
+      if (invite) {
+	sip_t const *inv = sip_object(invite->orq_request);
+
+	orq->orq_branch = su_strdup(home, invite->orq_branch);
+
+	/* @RFC3261 section 13.2.2.4 -
+	 * The ACK MUST contain the same credentials as the INVITE. 
+	 */
+	if (!sip->sip_proxy_authorization && !sip->sip_authorization) {
+	  if (inv->sip_proxy_authorization)
+	    sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization);
+	  if (inv->sip_authorization)
+	    sip_add_dup(msg, sip, (void *)inv->sip_authorization);
+	}
+      }
+      else {
+	SU_DEBUG_1(("outgoing_create: ACK without INVITE\n"));
+	assert(!"INVITE found for ACK");
+      }
+    }
+  }
+
+#if HAVE_SOFIA_SRESOLV
+  if (!resolved)
+    orq->orq_tpn->tpn_port = port;
+  orq->orq_resolved = resolved;
+#else
+  orq->orq_resolved = resolved = 1;
+#endif
+  orq->orq_scheme = scheme;
+
+  if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) {
+    SU_DEBUG_3(("nta outgoing create: %s\n",
+		invalid < 0 ? "invalid URI" :
+		!orq->orq_branch ? "no branch" : "invalid message"));
+    outgoing_free(orq);
+    return NULL;
+  }
+
+  /* Now we are committed in sending the transaction */
+  orq->orq_request = msg;
+  agent->sa_stats->as_client_tr++;
+  orq->orq_hash = NTA_HASH(sip->sip_call_id, sip->sip_cseq->cs_seq);
+
+  if (resolved)
+    outgoing_prepare_send(orq);
+#if HAVE_SOFIA_SRESOLV
+  else
+    outgoing_resolve(orq);
+#endif
+
+  if (stateless && 
+      orq->orq_status >= 200 && 
+      callback == outgoing_default_cb) {
+    void *retval;
+
+    if (orq->orq_status < 300) 
+      retval = (void *)-1;	/* NONE */
+    else 
+      retval = NULL, orq->orq_request = NULL;
+
+    outgoing_free(orq);
+
+    return retval;
+  }
+
+  assert(orq->orq_queue);
+
+  outgoing_insert(agent, orq);
+
+  return orq;
+}
+
+/** Prepare sending a request */
+static void
+outgoing_prepare_send(nta_outgoing_t *orq)
+{
+  nta_agent_t *sa = orq->orq_agent;
+  tport_t *tp;
+  tp_name_t *tpn = orq->orq_tpn;
+  int sips = strcasecmp(orq->orq_scheme, "sips") == 0;
+
+  /* Select transport by scheme */
+  if (sips && strcmp(tpn->tpn_proto, "*") == 0)
+    tpn->tpn_proto = "tls";
+
+  if (!tpn->tpn_port)
+    tpn->tpn_port = "";
+
+  tp = tport_by_name(sa->sa_tports, tpn);
+  orq->orq_tport = tport_ref(tp);
+
+  if (tpn->tpn_port[0] == '\0') {
+    if (sips || tport_has_tls(tp))
+      tpn->tpn_port = "5061";
+    else
+      tpn->tpn_port = "5060";
+  }
+
+  if (!orq->orq_tport) {
+    if (sips) {
+      SU_DEBUG_3(("nta outgoing create: no secure transport\n"));
+      outgoing_reply(orq, SIP_416_UNSUPPORTED_URI, 1);
+    }
+    else {
+      SU_DEBUG_3(("nta outgoing create: no transport protocol\n"));
+      outgoing_reply(orq, 503, "No transport", 1);
+    }
+    return;
+  }
+
+  if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
+    SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n"));
+    outgoing_reply(orq, 503, "Cannot insert Via", 1);
+    return;
+  }
+
+  orq->orq_user_via = 1;
+
+#if HAVE_SOFIA_SMIME
+  {
+    sm_object_t *smime = sa->sa_smime;
+    sip_t *sip = sip_object(orq->orq_request);
+
+    if (sa->sa_smime &&
+	(sip->sip_request->rq_method == sip_method_invite ||
+	 sip->sip_request->rq_method == sip_method_message)) {
+      msg_prepare(orq->orq_request);
+      if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) {
+	outgoing_tport_error(sa, orq, NULL,
+			     orq->orq_request, su_errno());
+	return;
+      }
+    }
+  }
+#endif
+
+  orq->orq_prepared = 1;
+
+  if (orq->orq_delayed) {
+    SU_DEBUG_5(("nta: delayed sending %s (%u)\n",
+		orq->orq_method_name, orq->orq_cseq->cs_seq));
+    outgoing_queue(sa->sa_out.delayed, orq);
+    return;
+  }
+
+  outgoing_send(orq, 0);
+}
+
+/** Send a request */
+static void
+outgoing_send(nta_outgoing_t *orq, int retransmit)
+{
+  int err;
+  tp_name_t const *tpn = orq->orq_tpn;
+  msg_t *msg = orq->orq_request;
+  nta_agent_t *agent = orq->orq_agent;
+  tport_t *tp;
+  int once = 0;
+  su_time_t now = su_now();
+  tag_type_t tag = tag_skip;
+  tag_value_t value = 0;
+  struct sigcomp_compartment *cc; cc = NULL;
+
+  /* tport can be NULL if we are just switching network */
+  if (orq->orq_tport == NULL) {
+    outgoing_tport_error(agent, orq, NULL, orq->orq_request, ENETRESET);
+    return;
+  }
+
+  if (!retransmit)
+    orq->orq_sent = now;
+
+  if (orq->orq_timestamp) {
+    sip_t *sip = sip_object(msg);
+    sip_timestamp_t *ts =
+      sip_timestamp_format(msg_home(msg), "%lu.%06lu",
+			   now.tv_sec, now.tv_usec);
+
+    if (ts) {
+      if (sip->sip_timestamp)
+	msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp);
+      msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts);
+    }
+  }
+
+  for (;;) {
+    if (tpn->tpn_comp == NULL) {
+      /* xyzzy */
+    }
+    else if (orq->orq_cc) {
+      cc = orq->orq_cc, orq->orq_cc = NULL;
+    }
+    else {
+      cc = agent_compression_compartment(agent, orq->orq_tport, tpn, 
+					 orq->orq_sigcomp_new);
+    }
+
+    if (orq->orq_try_udp_instead)
+      tag = tptag_mtu, value = 65535;
+
+    tp = tport_tsend(orq->orq_tport, msg, tpn, 
+		     tag, value,
+		     IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+		     TAG_NEXT(orq->orq_tags));
+    if (tp)
+      break;
+
+    err = msg_errno(orq->orq_request);
+
+    if (cc)
+      nta_compartment_decref(&cc);
+
+    /* RFC3261, 18.1.1 */
+    if (err == EMSGSIZE && !orq->orq_try_tcp_instead) {
+      if (strcasecmp(tpn->tpn_proto, "udp") == 0 ||
+	  strcasecmp(tpn->tpn_proto, "*") == 0) {
+	outgoing_try_tcp_instead(orq);
+	continue;
+      }
+    }
+    else if (err == ECONNREFUSED && orq->orq_try_tcp_instead) {
+      if (strcasecmp(tpn->tpn_proto, "tcp") == 0 && msg_size(msg) <= 65535) {
+	outgoing_try_udp_instead(orq);
+	continue;
+      }
+    }
+    else if (err == EPIPE) {
+      /* Connection was closed */
+      if (!once++) {
+	orq->orq_retries++;
+	continue;
+      }
+    }
+
+    if (orq->orq_pending && orq->orq_tport)
+      tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, 
+		    NULL, orq, 0);
+
+    orq->orq_pending = 0;
+
+    outgoing_tport_error(agent, orq, NULL, orq->orq_request, err);
+
+    return;
+  }
+
+  agent->sa_stats->as_sent_msg++;
+  agent->sa_stats->as_sent_request++;
+  if (retransmit)
+    agent->sa_stats->as_retry_request++;
+
+  SU_DEBUG_5(("nta: %ssent %s (%u) to " TPN_FORMAT "\n",
+	      retransmit ? "re" : "",
+	      orq->orq_method_name, orq->orq_cseq->cs_seq,
+	      TPN_ARGS(tpn)));
+
+  if (cc) {
+    if (orq->orq_cc)
+      nta_compartment_decref(&orq->orq_cc);
+  }
+
+  if (orq->orq_pending) {
+    assert(orq->orq_tport);
+    tport_release(orq->orq_tport, orq->orq_pending, 
+		  orq->orq_request, NULL, orq, 0);
+    orq->orq_pending = 0;
+  }
+
+  if (orq->orq_stateless) {
+    outgoing_reply(orq, 202, NULL, 202);
+    return;
+  }
+
+  if (orq->orq_method != sip_method_ack) {
+    orq->orq_pending = tport_pend(tp, orq->orq_request, 
+				  outgoing_tport_error, orq);
+    if (orq->orq_pending < 0)
+      orq->orq_pending = 0;
+  }
+
+  if (tp != orq->orq_tport) {
+    tport_decref(&orq->orq_tport);
+    orq->orq_tport = tport_ref(tp);
+  }
+
+  orq->orq_reliable = tport_is_reliable(tp);
+
+  if (retransmit)
+    return;
+
+  /* Set timers */
+  if (orq->orq_method == sip_method_ack) {
+    /* ACK */
+    outgoing_complete(orq); /* Timer K */
+    return;
+  }
+
+  outgoing_trying(orq);		/* Timer B / F */
+
+  if (!orq->orq_reliable)
+    outgoing_set_timer(orq, agent->sa_t1); /* Timer A/E */
+  else if (orq->orq_try_tcp_instead && !tport_is_connected(tp))
+    outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */
+}
+
+static void
+outgoing_try_tcp_instead(nta_outgoing_t *orq)
+{
+  tport_t *tp;
+  tp_name_t tpn[1];
+
+  *tpn = *orq->orq_tpn;
+  tpn->tpn_proto = "tcp";
+  orq->orq_try_tcp_instead = 1;
+
+  tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+  if (tp && tp != orq->orq_tport) {
+    sip_t *sip = sip_object(orq->orq_request);
+    sip_fragment_clear(sip->sip_via->v_common);
+    sip->sip_via->v_protocol = sip_transport_tcp;
+
+    SU_DEBUG_5(("nta: %s (%u) too large for UDP, trying TCP\n",
+		orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    orq->orq_tpn->tpn_proto = "tcp";
+    tport_decref(&orq->orq_tport);
+    orq->orq_tport = tport_ref(tp);
+
+    return;
+  }
+
+  tpn->tpn_proto = "udp";
+  orq->orq_try_udp_instead = 1;	/* Try again without SIP MTU limit */
+
+  tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+  if (tp && tp != orq->orq_tport) {
+    SU_DEBUG_5(("nta: %s (%u) exceed normal UDP size limit\n",
+		orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    tport_decref(&orq->orq_tport);
+    orq->orq_tport = tport_ref(tp);
+  }
+}
+
+static void
+outgoing_try_udp_instead(nta_outgoing_t *orq)
+{
+  tport_t *tp;
+  tp_name_t tpn[1];
+
+  *tpn = *orq->orq_tpn;
+  tpn->tpn_proto = "udp";
+  orq->orq_try_udp_instead = 1;
+  
+  tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+  if (tp && tp != orq->orq_tport) {
+    sip_t *sip = sip_object(orq->orq_request);
+
+    sip_fragment_clear(sip->sip_via->v_common);
+    sip->sip_via->v_protocol = sip_transport_udp;
+
+    SU_DEBUG_5(("nta: %s (%u) TCP refused, trying UDP\n",
+		orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    orq->orq_tpn->tpn_proto = "udp";
+    tport_decref(&orq->orq_tport);
+    orq->orq_tport = tport_ref(tp);
+  }
+}
+
+
+/** @internal Report transport errors. */
+void
+outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
+		     tport_t *tp, msg_t *msg, int error)
+{
+  tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn;
+
+  if (orq->orq_pending) {
+    assert(orq->orq_tport);
+    tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, 
+		  NULL, orq, 0);
+    orq->orq_pending = 0;
+  }
+
+  if (error == EPIPE && orq->orq_retries++ == 0) {
+    /* XXX - we should retry only if the transport is not newly created */
+    outgoing_print_tport_error(orq, 5, "retrying once after ", 
+			       tpn, msg, error);
+    outgoing_send(orq, 1);
+    return;
+  }
+  else if (error == ECONNREFUSED && orq->orq_try_tcp_instead) {
+    /* RFC3261, 18.1.1 */
+    if (strcasecmp(tpn->tpn_proto, "tcp") == 0 && msg_size(msg) <= 65535) {
+      outgoing_print_tport_error(orq, 5, "retrying with UDP after ", 
+				 tpn, msg, error);
+      outgoing_try_udp_instead(orq);
+      outgoing_remove(orq);	/* Reset state - this is no resend! */
+      outgoing_send(orq, 0);	/* Send */
+      return;
+    }
+  }
+
+  if (outgoing_other_destinations(orq)) {
+    outgoing_print_tport_error(orq, 5, "trying alternative server after ", 
+			       tpn, msg, error);
+    outgoing_try_another(orq);
+    return;
+  }
+
+  outgoing_print_tport_error(orq, 3, "", tpn, msg, error);
+
+  outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE, 0);
+}
+
+static
+void
+outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo,
+			   tp_name_t const *tpn, msg_t *msg, int error)
+{
+  su_sockaddr_t const *su = msg_addr(msg);
+  char addr[SU_ADDRSIZE];
+
+  su_llog(nta_log, level, 
+	  "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",
+	  orq->orq_method_name, orq->orq_cseq->cs_seq,
+	  todo, su_strerror(error), error, 
+	  tpn->tpn_proto, 
+	  inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+	  htons(su->su_port));
+}
+
+/**@internal
+ * Add features supported.
+ */
+static
+int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
+		      msg_t *msg, sip_t *sip,
+		      tagi_t *tags)
+{
+  char const *supported[8];
+  int i;
+
+  if (orq->orq_method != sip_method_invite) /* fast path for now */
+    return 0;
+
+  supported[i = 0] = NULL;
+
+  if (orq->orq_method == sip_method_invite) {
+    int add_100rel = agent->sa_invite_100rel;
+    int require_100rel = sip_has_feature(sip->sip_require, "100rel");
+
+    tl_gets(tags,
+	    NTATAG_REL100_REF(add_100rel),
+	    TAG_END());
+    if (add_100rel && !require_100rel &&
+	!sip_has_feature(sip->sip_supported, "100rel"))
+      supported[i++] = "100rel";
+
+    orq->orq_must_100rel = require_100rel;
+  }
+
+  if (i) {
+    supported[i] = NULL;
+
+    if (sip->sip_supported) {
+      su_home_t *home = msg_home(msg);
+      return msg_list_append_items(home, sip->sip_supported, supported);
+    }
+    else {
+      sip_supported_t s[1];
+      sip_supported_init(s);
+      s->k_items = supported;
+      return sip_add_dup(msg, sip, (sip_header_t *)s);
+    }
+  }
+
+  return 0;
+}
+
+
+/**@internal
+ * Insert outgoing request to agent hash table
+ */
+static
+void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq)
+{
+  if (outgoing_htable_is_full(agent->sa_outgoing))
+    outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0);
+  outgoing_htable_insert(agent->sa_outgoing, orq);
+  orq->orq_inserted = 1;
+}
+
+/** @internal
+ * Initialize a queue for outgoing transactions.
+ */
+static void
+outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout)
+{
+  memset(queue, 0, sizeof *queue);
+  queue->q_tail = &queue->q_head;
+  queue->q_timeout = timeout;
+}
+
+/** Change the timeout value of a queue */
+static void
+outgoing_queue_adjust(nta_agent_t *sa, 
+		      outgoing_queue_t *queue, 
+		      unsigned timeout)
+{
+  nta_outgoing_t *orq;
+  su_duration_t latest;
+
+  if (timeout >= queue->q_timeout || !queue->q_head) {
+    queue->q_timeout = timeout;
+    return;
+  }
+
+  latest = set_timeout(sa, queue->q_timeout = timeout);
+
+  for (orq = queue->q_head; orq; orq = orq->orq_next) {
+    if (orq->orq_timeout - latest > 0)
+      orq->orq_timeout = latest;
+  }
+}
+
+/** @internal
+ * Test if an outgoing transaction is in a queue.
+ */
+static inline
+int outgoing_is_queued(nta_outgoing_t const *orq)
+{
+  return orq && orq->orq_queue;
+}
+
+/** @internal
+ * Insert an outgoing transaction into a queue. 
+ *
+ * The function outgoing_queue() inserts a client transaction into a queue,
+ * and sets the corresponding timeout at the same time.
+ */
+static inline
+void outgoing_queue(outgoing_queue_t *queue, 
+		    nta_outgoing_t *orq)
+{
+  if (orq->orq_queue == queue) {
+    assert(queue->q_timeout == 0);
+    return;
+  }
+
+  if (outgoing_is_queued(orq))
+    outgoing_remove(orq);
+
+  assert(*queue->q_tail == NULL);
+
+  orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
+    
+  orq->orq_queue = queue;
+  orq->orq_prev = queue->q_tail; 
+  *queue->q_tail = orq;
+  queue->q_tail = &orq->orq_next;
+  queue->q_length++;
+}
+
+/** @internal
+ * Remove an outgoing transaction from a queue.
+ */
+static inline
+void outgoing_remove(nta_outgoing_t *orq)
+{
+  assert(outgoing_is_queued(orq));
+  assert(orq->orq_queue->q_length > 0);
+
+  if ((*orq->orq_prev = orq->orq_next))
+    orq->orq_next->orq_prev = orq->orq_prev;
+  else
+    orq->orq_queue->q_tail = orq->orq_prev, assert(!*orq->orq_queue->q_tail);
+
+  orq->orq_queue->q_length--;
+  orq->orq_next = NULL;
+  orq->orq_prev = NULL;
+  orq->orq_queue = NULL;
+  orq->orq_timeout = 0;
+}
+
+/** Set retransmit timer (orq_retry).
+ *
+ * The function outgoing_set_timer() will set the retry timer (B/D) on
+ * the outgoing request (client transaction). 
+ */
+static inline
+void outgoing_set_timer(nta_outgoing_t *orq, unsigned interval)
+{
+  nta_outgoing_t **rq;
+  
+  assert(orq);
+
+  if (interval == 0) {
+    outgoing_reset_timer(orq);
+    return;
+  }
+
+  if (orq->orq_rprev) {
+    /* Remove transaction from retry dequeue, re-insert it later. */
+    if ((*orq->orq_rprev = orq->orq_rnext)) 
+      orq->orq_rnext->orq_rprev = orq->orq_rprev;
+    if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
+      orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
+  }
+  else {
+    orq->orq_agent->sa_out.re_length++;
+  }
+
+  orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval);
+
+  rq = orq->orq_agent->sa_out.re_t1;
+
+  if (!(*rq) || (*rq)->orq_retry - orq->orq_retry > 0)
+    rq = &orq->orq_agent->sa_out.re_list;
+
+  while (*rq && (*rq)->orq_retry - orq->orq_retry <= 0)
+    rq = &(*rq)->orq_rnext;
+
+  if ((orq->orq_rnext = *rq))
+    orq->orq_rnext->orq_rprev = &orq->orq_rnext;
+  *rq = orq;
+  orq->orq_rprev = rq;
+
+  if (interval == orq->orq_agent->sa_t1)
+    orq->orq_agent->sa_out.re_t1 = rq;
+}
+
+static inline
+void outgoing_reset_timer(nta_outgoing_t *orq)
+{
+  if (orq->orq_rprev) {
+    if ((*orq->orq_rprev = orq->orq_rnext)) 
+      orq->orq_rnext->orq_rprev = orq->orq_rprev;
+    if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
+      orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
+    orq->orq_agent->sa_out.re_length--;
+  } 
+
+  orq->orq_interval = 0, orq->orq_retry = 0;
+  orq->orq_rnext = NULL, orq->orq_rprev = NULL;
+}
+
+/** @internal
+ * Free resources associated with the request.
+ */
+static
+void outgoing_free(nta_outgoing_t *orq)
+{
+  SU_DEBUG_9(("nta: outgoing_free(%p)\n", orq));
+  outgoing_cut_off(orq);
+  outgoing_reclaim(orq);
+}
+
+/** Remove outgoing request from hash tables */
+static inline
+void outgoing_cut_off(nta_outgoing_t *orq)
+{
+  nta_agent_t *agent = orq->orq_agent;
+
+  if (orq->orq_default)
+    agent->sa_default_outgoing = NULL;
+
+  if (orq->orq_inserted)
+    outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0;
+
+  if (outgoing_is_queued(orq))
+    outgoing_remove(orq);
+
+  outgoing_reset_timer(orq);
+
+  if (orq->orq_pending) {
+    tport_release(orq->orq_tport, orq->orq_pending, 
+		  orq->orq_request, NULL, orq, 0);
+  }
+  orq->orq_pending = 0;
+
+  if (orq->orq_cc)
+    nta_compartment_decref(&orq->orq_cc);
+
+  if (orq->orq_tport)
+    tport_decref(&orq->orq_tport);
+}
+
+/** Reclaim outgoing request */
+static inline
+void outgoing_reclaim(nta_outgoing_t *orq)
+{
+  if (orq->orq_request)
+    msg_destroy(orq->orq_request), orq->orq_request = NULL;
+  if (orq->orq_response)
+    msg_destroy(orq->orq_response), orq->orq_response = NULL;
+#if HAVE_SOFIA_SRESOLV
+  if (orq->orq_resolver)
+    outgoing_destroy_resolver(orq);
+#endif  
+  su_free(orq->orq_agent->sa_home, orq);
+}
+
+/** Queue request to be freed */
+static inline 
+void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq)
+{
+  outgoing_cut_off(orq);
+  outgoing_queue(q, orq);
+}
+
+/** Reclaim memory used by queue of requests */
+static 
+void outgoing_reclaim_queued(su_root_magic_t *rm,
+			     su_msg_r msg,
+			     union sm_arg_u *u)
+{
+  outgoing_queue_t *q = u->a_outgoing_queue;
+  nta_outgoing_t *orq, *orq_next;
+
+  SU_DEBUG_9(("outgoing_reclaim_all(%p, %p, %p)\n", rm, msg, u));
+
+  for (orq = q->q_head; orq; orq = orq_next) {
+    orq_next = orq->orq_next;
+    outgoing_reclaim(orq);
+  }
+}
+
+/** @internal Default callback for request */
+int outgoing_default_cb(nta_outgoing_magic_t *magic,
+			nta_outgoing_t *orq,
+			sip_t const *sip)
+{
+  if (sip == NULL || sip->sip_status->st_status >= 200)
+    outgoing_destroy(orq);
+  return 0;
+}
+
+/** @internal Destroy an outgoing transaction */
+void outgoing_destroy(nta_outgoing_t *orq)
+{
+  if (orq->orq_terminated || orq->orq_default) {
+    outgoing_free(orq);
+  }
+  else {
+    orq->orq_destroyed = 1;
+    orq->orq_callback = outgoing_default_cb;
+    orq->orq_magic = NULL;
+  }
+}
+
+/** @internal Outgoing transaction timer routine. */
+static
+int outgoing_timer(nta_agent_t *sa, su_duration_t now)
+{
+  nta_outgoing_t *orq;
+  outgoing_queue_t rq[1];
+  size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed;
+  size_t total = sa->sa_outgoing->oht_used;
+  size_t trying = sa->sa_out.re_length;
+  size_t pending = sa->sa_out.trying->q_length + sa->sa_out.inv_calling->q_length;
+  size_t completed = sa->sa_out.completed->q_length + 
+    sa->sa_out.inv_completed->q_length;
+
+  outgoing_queue_init(sa->sa_out.free = rq, 0);
+
+  while ((orq = sa->sa_out.re_list)) {
+    if ((orq->orq_retry && orq->orq_retry - now > 0)
+	|| retransmitted >= timer_max_retransmit)
+      break;
+
+    if (orq->orq_reliable) {
+      outgoing_reset_timer(orq);
+
+      if (!tport_is_connected(orq->orq_tport)) {
+	/*
+	 * Timer N3: try to use UDP if trying to send via TCP
+	 * but no connection is established within SIP T4
+	 */
+	SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", "N3", 
+		    "try UDP instead", orq->orq_method_name, orq->orq_cseq->cs_seq));
+	outgoing_try_udp_instead(orq);
+      }
+      continue;
+    }
+
+    assert(!orq->orq_reliable && orq->orq_interval != 0);
+
+    SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",
+		orq->orq_method == sip_method_invite ? "A" : "E",
+		"retransmit", orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    outgoing_retransmit(orq);
+
+    if (orq->orq_method == sip_method_invite ||
+	2U * orq->orq_interval < sa->sa_t2)
+      outgoing_set_timer(orq, 2U * orq->orq_interval);
+    else
+      outgoing_set_timer(orq, sa->sa_t2);
+
+    if (++retransmitted % 5 == 0)
+      su_root_yield(sa->sa_root);	/* Handle received packets */
+  }
+
+  terminated
+    = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now)
+    + outgoing_timer_dk(sa->sa_out.completed, "K", now);
+
+  timeout
+    = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now)
+    + outgoing_timer_bf(sa->sa_out.trying, "F", now);
+
+  destroyed = outgoing_mass_destroy(sa, rq);
+
+  sa->sa_out.free = NULL;
+
+  if (retransmitted || timeout || terminated || destroyed) {
+    SU_DEBUG_5(("nta_outgoing_timer: "
+		MOD_ZU"/"MOD_ZU" resent, "
+		MOD_ZU"/"MOD_ZU" tout, "
+		MOD_ZU"/"MOD_ZU" term, "
+		MOD_ZU"/"MOD_ZU" free\n",
+		retransmitted, trying,
+		timeout, pending,
+		terminated, completed, 
+		destroyed, total));
+  }
+
+  return 
+    retransmitted >= timer_max_retransmit || 
+    terminated >= timer_max_terminate || 
+    timeout >= timer_max_timeout;
+}
+
+/** @internal Retransmit the outgoing request. */
+void outgoing_retransmit(nta_outgoing_t *orq)
+{
+  if (orq->orq_prepared && !orq->orq_delayed) {
+    orq->orq_retries++;
+
+    if (orq->orq_retries >= 4 && orq->orq_cc) {
+      orq->orq_tpn->tpn_comp = NULL;
+      if (orq->orq_retries == 4) {
+	agent_close_compressor(orq->orq_agent, orq->orq_cc);
+	nta_compartment_decref(&orq->orq_cc);
+      }
+    }
+
+    outgoing_send(orq, 1);
+  }
+}
+
+/** Trying a client transaction. */
+static
+void outgoing_trying(nta_outgoing_t *orq)
+{
+  if (orq->orq_method == sip_method_invite)
+    outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq);
+  else
+    outgoing_queue(orq->orq_agent->sa_out.trying, orq);
+}
+
+/** Handle timers B and F */
+static
+size_t outgoing_timer_bf(outgoing_queue_t *q, 
+			 char const *timer, 
+			 su_duration_t now)
+{
+  size_t timeout = 0;
+
+  for (;;) {
+    nta_outgoing_t *orq = q->q_head;
+
+    if (!orq 
+	|| !orq->orq_timeout
+	|| orq->orq_timeout - now > 0 
+	|| timeout >= timer_max_timeout)
+      return timeout;
+
+    timeout++;
+    
+    SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",
+		timer, "timeout", 
+		orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    outgoing_timeout(orq, now);
+
+    assert(q->q_head != orq || orq->orq_timeout - now > 0);
+  }
+}
+
+/** @internal Signal transaction timeout to the application. */
+void outgoing_timeout(nta_outgoing_t *orq, su_duration_t now)
+{
+  nta_outgoing_t *cancel;
+
+  if (outgoing_other_destinations(orq)) {
+    SU_DEBUG_5(("nta(%p): try next after timeout\n", orq));
+    outgoing_try_another(orq);
+    return;
+  }
+
+  cancel = orq->orq_cancel; orq->orq_cancel = NULL;
+  orq->orq_agent->sa_stats->as_tout_request++;
+
+  outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT, 0);
+
+  if (cancel)
+    outgoing_timeout(cancel, now);
+}
+
+/** Complete a client transaction. 
+ *
+ * @return True if transaction was free()d.
+ */
+static
+int outgoing_complete(nta_outgoing_t *orq)
+{
+  orq->orq_completed = 1;
+
+  outgoing_reset_timer(orq); /* Timer A/E */
+
+  if (orq->orq_stateless)
+    return outgoing_terminate(orq);
+
+  if (orq->orq_reliable && orq->orq_method != sip_method_ack)
+    return outgoing_terminate(orq);
+
+  if (orq->orq_method == sip_method_invite) {
+    outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
+  }
+  else {
+    outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */
+  }
+
+  return 0;
+}
+
+/** Handle timers D and K */
+static
+size_t outgoing_timer_dk(outgoing_queue_t *q, 
+			 char const *timer, 
+			 su_duration_t now)
+{
+  size_t terminated = 0;
+
+  for (;;) {
+    nta_outgoing_t *orq = q->q_head;
+
+    if (!orq 
+	|| !orq->orq_timeout 
+	|| orq->orq_timeout - now > 0 
+	|| terminated >= timer_max_terminate)
+      return terminated;
+
+    terminated++;
+
+    SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", timer,
+		"terminate", orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+    outgoing_terminate(orq);
+  }
+}
+
+/** Terminate a client transaction. */
+static
+int outgoing_terminate(nta_outgoing_t *orq)
+{
+  orq->orq_terminated = 1;
+
+  if (!orq->orq_destroyed) {
+    outgoing_queue(orq->orq_agent->sa_out.terminated, orq);
+    return 0;
+  }
+  else if (orq->orq_agent->sa_out.free) {
+    outgoing_free_queue(orq->orq_agent->sa_out.free, orq);
+    return 1;
+  }
+  else {
+    outgoing_free(orq);
+    return 1;
+  }
+}
+
+/** Mass destroy client transactions */
+static
+size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q)
+{
+  size_t destroyed = q->q_length;
+
+  if (destroyed > 2 && *sa->sa_terminator) {
+    su_msg_r m = SU_MSG_R_INIT;
+
+    if (su_msg_create(m,
+		      su_clone_task(sa->sa_terminator),
+		      su_root_task(sa->sa_root),
+		      outgoing_reclaim_queued,
+		      sizeof(outgoing_queue_t)) == SU_SUCCESS) {
+      outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue;
+
+      *mq = *q;
+
+      if (su_msg_send(m) == SU_SUCCESS)
+	q->q_length = 0;
+    }    
+  }
+  
+  if (q->q_length) 
+    outgoing_reclaim_queued(NULL, NULL, (void*)q);
+
+  return destroyed;
+}
+
+/** Find an outgoing request corresponging to a message and @Via line.
+ *
+ * Return an outgoing request object based on a message and the @Via line
+ * given as argument. This function is used when doing loop checking: if we
+ * have sent the request and it has been routed back to us. 
+ *
+ * @param agent
+ * @param msg
+ * @param sip
+ * @param v
+ */
+nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent,
+				  msg_t const *msg,
+				  sip_t const *sip,
+				  sip_via_t const *v)
+{
+  if (agent == NULL || msg == NULL || sip == NULL || v == NULL) {
+    su_seterrno(EFAULT);
+    return NULL;
+  }
+
+  return outgoing_find(agent, msg, sip, v);
+}
+
+/**@internal
+ *
+ * Find an outgoing request corresponging to a message and @Via line.
+ *
+ */
+nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
+			      msg_t const *msg,
+			      sip_t const *sip,
+			      sip_via_t const *v)
+{
+  nta_outgoing_t **oo, *orq;
+  outgoing_htable_t const *oht = sa->sa_outgoing;
+  sip_cseq_t const *cseq = sip->sip_cseq;
+  sip_call_id_t const *i = sip->sip_call_id;
+  hash_value_t hash;
+  sip_method_t method, method2;
+  unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0;
+
+  if (cseq == NULL)
+    return NULL;
+
+  hash = NTA_HASH(i, cseq->cs_seq);
+
+  method = cseq->cs_method;
+
+  /* Get original invite when ACKing */
+  if (sip->sip_request && method == sip_method_ack && v == NULL)
+    method = sip_method_invite, method2 = sip_method_invalid;
+  else if (sa->sa_is_a_uas && status >= 200 && method == sip_method_invite)
+    method2 = sip_method_ack;
+  else
+    method2 = method;
+
+  for (oo = outgoing_htable_hash(oht, hash);
+       (orq = *oo);
+       oo = outgoing_htable_next(oht, oo)) {
+    if (orq->orq_stateless)
+      continue;
+    /* Accept terminated transactions when looking for original INVITE */
+    if (orq->orq_terminated && method2 != sip_method_invalid)
+      continue;
+    if (hash != orq->orq_hash)
+      continue;
+    if (orq->orq_call_id->i_hash != i->i_hash ||
+	strcmp(orq->orq_call_id->i_id, i->i_id))
+      continue;
+    if (orq->orq_cseq->cs_seq != cseq->cs_seq)
+      continue;
+    if (method == sip_method_unknown &&
+	strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name))
+      continue;
+    if (orq->orq_method != method && orq->orq_method != method2)
+      continue;
+    if (str0casecmp(orq->orq_from->a_tag, sip->sip_from->a_tag))
+      continue;
+    if (orq->orq_to->a_tag && sip->sip_to->a_tag
+	? strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)
+	: !addr_match(orq->orq_to, sip->sip_to))
+      continue;
+    if (orq->orq_method == method ?
+	/* Don't match if request To has a tag and response has no To tag */
+	orq->orq_to->a_tag && !sip->sip_to->a_tag :
+	/* Don't (with ACK) if request/response tag mismatch */
+	!orq->orq_to->a_tag != !sip->sip_to->a_tag)
+      continue;
+
+    if (orq->orq_method == sip_method_ack) {
+      if (orq->orq_ack_error ? status < 300 : status >= 300)
+	continue;
+    }
+
+    if (v && str0casecmp(orq->orq_branch + strlen("branch="), v->v_branch))
+      continue;
+
+    break;			/* match */
+  }
+
+  return orq;
+}
+
+/** Process a response message. */
+int outgoing_recv(nta_outgoing_t *orq,
+		  int status,
+		  msg_t *msg,
+		  sip_t *sip)
+{
+  nta_agent_t *sa = orq->orq_agent;
+  short orq_status = orq->orq_status;
+
+  if (status < 100) status = 100;
+
+  if (sip && orq->orq_delay == UINT_MAX)
+    outgoing_estimate_delay(orq, sip);
+
+  if (orq->orq_cc)
+    agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc);
+
+  if (orq->orq_cancel) {
+    nta_outgoing_t *cancel;
+
+    cancel = orq->orq_cancel; orq->orq_cancel = NULL;
+
+    cancel->orq_delayed = 0;
+
+    if (status < 200)
+      outgoing_send(cancel, 0);
+    else
+      outgoing_reply(cancel, SIP_481_NO_TRANSACTION, 0);
+  }
+
+  if (orq->orq_pending) {
+    tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, 
+		  msg, orq, status < 200);
+    if (status >= 200)
+      orq->orq_pending = 0;
+  }
+
+  /* The state machines */
+  if (orq->orq_method == sip_method_invite) {
+    if (orq->orq_destroyed && status > 100 && status < 300)
+      return -1;  /* Proxy statelessly (RFC3261 section 16.11) */
+
+    outgoing_reset_timer(orq);
+
+    if (status < 200) {
+      if (orq->orq_queue == sa->sa_out.inv_calling) {
+	orq->orq_status = status;
+	outgoing_queue(sa->sa_out.inv_proceeding, orq);
+      }
+
+      /* Handle 100rel */
+      if (sip && sip->sip_rseq)
+	if (outgoing_recv_reliable(orq, msg, sip) < 0) {
+	  msg_destroy(msg);
+	  return 0;
+	}
+    }
+    else {
+      /* Final response */
+      if (status >= 300)
+	outgoing_ack(orq, msg, sip);
+
+      if (!orq->orq_completed) {
+	if (outgoing_complete(orq))
+	  return 0;
+
+	if (sip && sa->sa_is_a_uas) {
+	  su_home_t *home = msg_home(orq->orq_request);
+	  orq->orq_tag = su_strdup(home, sip->sip_to->a_tag);
+	}
+      }
+      /* Retransmission or response from another fork */
+      else {
+	/* Once 2xx has been received, non-2xx will not be forwarded */
+	if (status >= 300)
+	  return outgoing_duplicate(orq, msg, sip);
+
+	if (sa->sa_is_a_uas) {
+	  if (str0cmp(sip->sip_to->a_tag, orq->orq_tag) == 0)
+	    /* Catch retransmission */
+	    return outgoing_duplicate(orq, msg, sip);
+	}
+      }
+
+      orq->orq_status = status;
+    }
+  }
+  else if (orq->orq_method != sip_method_ack) {
+    /* Non-INVITE */
+    if (orq->orq_queue == sa->sa_out.trying) {
+      assert(orq_status < 200); (void)orq_status;
+
+      if (status < 200) {
+	if (!orq->orq_reliable)
+	  outgoing_set_timer(orq, sa->sa_t2);
+      } 
+      else if (!outgoing_complete(orq)) {
+	if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc)
+	  agent_zap_compressor(orq->orq_agent, orq->orq_cc);
+      } 
+      else /* outgoing_complete */ {
+	msg_destroy(msg);
+	return 0;
+      }
+    } else {
+      /* Already completed or terminated */
+      assert(orq->orq_queue == sa->sa_out.completed ||
+	     orq->orq_queue == sa->sa_out.terminated);
+      assert(orq->orq_status >= 200);
+      return outgoing_duplicate(orq, msg, sip);
+    }
+
+    orq->orq_status = status;
+  }
+  else {
+    /* ACK */
+    if (sip && (sip->sip_flags & NTA_INTERNAL_MSG) == 0)
+      /* Received re-transmitted final reply to INVITE, retransmit ACK */
+      outgoing_retransmit(orq);
+    msg_destroy(msg);
+    return 0;
+  }
+
+  if (status + orq->orq_pass_100 > 100 && !orq->orq_destroyed) {
+    if (orq->orq_response)
+      msg_destroy(orq->orq_response);
+    orq->orq_response = msg;
+    /* Call callback */
+    orq->orq_callback(orq->orq_magic, orq, sip);
+  }
+  else
+    msg_destroy(msg);
+
+  return 0;
+}
+
+static void outgoing_default_recv(nta_outgoing_t *orq,
+				 int status,
+				 msg_t *msg,
+				 sip_t *sip)
+{
+  assert(sip->sip_cseq);
+
+  orq->orq_status = status;
+  orq->orq_response = msg;
+  orq->orq_callback(orq->orq_magic, orq, sip);
+  orq->orq_response = NULL;
+  orq->orq_status = 0;
+  msg_destroy(msg);
+}
+
+static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip)
+{
+  su_time_t now = su_now();
+  double diff = 1000 * su_time_diff(now, orq->orq_sent);
+
+  if (orq->orq_timestamp && sip->sip_timestamp) {
+    double diff2, delay = 0.0;
+    su_time_t timestamp = { 0, 0 };
+    char const *bad;
+
+    sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu",
+	   &timestamp.tv_sec, &timestamp.tv_usec);
+
+    diff2 = 1000 * su_time_diff(now, timestamp);
+
+    if (diff2 < 0)
+      bad = "negative";
+    else if (diff2 > diff + 1e-3)
+      bad = "too large";
+    else {
+      if (sip->sip_timestamp->ts_delay)
+	sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay);
+
+      if (1000 * delay <= diff2) {
+	diff = diff2 - 1000 * delay;
+	orq->orq_delay = (unsigned)diff;
+	SU_DEBUG_7(("nta_outgoing: RTT is %g ms, now is %lu.%06lu, "
+		    "Timestamp was %s %s\n",
+		    diff, now.tv_sec, now.tv_usec,
+		    sip->sip_timestamp->ts_stamp,
+		    sip->sip_timestamp->ts_delay ?
+		    sip->sip_timestamp->ts_delay : ""));
+	return;
+      }
+      bad = "delay";
+    }
+
+    SU_DEBUG_3(("nta_outgoing: %s Timestamp %lu.%06lu %g "
+		"(sent %lu.%06lu, now is %lu.%06lu)\n",
+		bad,
+		timestamp.tv_sec, timestamp.tv_usec,
+		delay,
+		orq->orq_sent.tv_sec, orq->orq_sent.tv_usec,
+		now.tv_sec, now.tv_usec));
+  }
+
+  if (diff >= 0 && diff < (double)UINT_MAX) {
+    orq->orq_delay = (unsigned)diff;
+    SU_DEBUG_7(("nta_outgoing: RTT is %g ms\n", diff));
+  }
+}
+
+/**@typedef nta_response_f
+ *
+ * Callback for replies to outgoing requests.
+ *
+ * This is a callback function invoked by NTA when it has received a new
+ * reply to an outgoing request.
+ *
+ * @param magic   request context
+ * @param request request handle
+ * @param sip     received status message
+ *
+ * @return
+ * This callback function should return always 0.
+ *
+ */
+
+/** Process duplicate responses */
+static int outgoing_duplicate(nta_outgoing_t *orq,
+			      msg_t *msg,
+			      sip_t *sip)
+{
+  sip_via_t *v;
+
+  if (sip && (sip->sip_flags & NTA_INTERNAL_MSG) == 0) {
+    v = sip->sip_via;
+
+    SU_DEBUG_5(("nta: %u %s is duplicate response to %d %s\n",
+		sip->sip_status->st_status, sip->sip_status->st_phrase,
+		orq->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name));
+    if (v)
+      SU_DEBUG_5(("\tVia: %s %s%s%s%s%s%s%s%s%s\n",
+		  v->v_protocol, v->v_host,
+		  SIP_STRLOG(":", v->v_port),
+		  SIP_STRLOG(" ;received=", v->v_received),
+		  SIP_STRLOG(" ;maddr=", v->v_maddr),
+		  SIP_STRLOG(" ;branch=", v->v_branch)));
+  }
+
+  msg_destroy(msg);
+  return 0;
+}
+
+/** @internal ACK to a final response (300..699).
+ * These messages are ACK'ed via the original URL (and tport)
+ */
+void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip)
+{
+  nta_outgoing_t *ack;
+  msg_t *ackmsg;
+  sip_t *acksip;
+
+  assert(orq);
+
+  /* Do not ack internally generated messages... */
+  if (sip == NULL || sip->sip_flags & NTA_INTERNAL_MSG)
+    return;
+
+  assert(sip); assert(sip->sip_status);
+  assert(sip->sip_status->st_status >= 300);
+  assert(orq->orq_tport);
+
+  ackmsg = outgoing_ackmsg(orq, SIP_METHOD_ACK, NULL);
+  acksip = sip_object(ackmsg);
+
+  if (acksip) {
+    if (sip->sip_to->a_tag && !acksip->sip_to->a_tag)
+      sip_to_tag(msg_home(ackmsg), acksip->sip_to, sip->sip_to->a_tag);
+
+    if ((ack = outgoing_create(orq->orq_agent, NULL, NULL,
+			       NULL, orq->orq_tpn, ackmsg,
+			       NTATAG_BRANCH_KEY(sip->sip_via->v_branch),
+			       NTATAG_USER_VIA(1),
+			       NTATAG_STATELESS(1),
+			       TAG_END())))
+      ;
+    else
+      msg_destroy(msg);
+  }
+}
+
+/** Generate messages for hop-by-hop ACK or CANCEL.
+ */
+msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname,
+		       tagi_t const *tags)
+{
+  msg_t *msg = nta_msg_create(orq->orq_agent, 0);
+  su_home_t *home = msg_home(msg);
+  sip_t *sip = sip_object(msg);
+  sip_t *old = sip_object(orq->orq_request);
+  sip_via_t via[1];
+
+  if (!sip)
+    return NULL;
+
+  sip->sip_request =
+    sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL);
+
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_to);
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_from);
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id);
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_route);
+  /* @RFC3841. Bug #1326727. */
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact);
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact);
+  sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition);
+
+  if (old->sip_via) {
+    /* Add only the topmost Via header */
+    *via = *old->sip_via; via->v_next = NULL;
+    sip_add_dup(msg, sip, (sip_header_t *)via);
+  }
+
+  sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname);
+
+  if (tags)
+    sip_add_tl(msg, sip, TAG_NEXT(tags));
+
+  if (!sip->sip_max_forwards)
+    sip_add_dup(msg, sip, (sip_header_t *)orq->orq_agent->sa_max_forwards);
+
+  if (sip->sip_request &&
+      sip->sip_to &&
+      sip->sip_from &&
+      sip->sip_call_id &&
+      (!old->sip_route || sip->sip_route) &&
+      sip->sip_cseq)
+    return msg;
+
+  msg_destroy(msg);
+
+  return NULL;
+}
+
+static
+void outgoing_delayed_recv(su_root_magic_t *rm,
+			   su_msg_r msg,
+			   union sm_arg_u *u);
+
+/** Respond internally to a transaction. */
+int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase,
+		   int delayed)
+{
+  nta_agent_t *agent = orq->orq_agent;
+  msg_t *msg = NULL;
+  sip_t *sip = NULL;
+
+  assert(status == 202 || status >= 400);
+
+  if (orq->orq_pending)
+    tport_release(orq->orq_tport, orq->orq_pending, 
+		  orq->orq_request, NULL, orq, 0);
+  orq->orq_pending = 0;
+
+  orq->orq_delayed = 0;
+
+  if (orq->orq_method == sip_method_ack) {
+    if (status != delayed)
+      SU_DEBUG_3(("nta(%p): responding %u %s to ACK!\n", orq, status, phrase));
+    orq->orq_status = status;
+    if (orq->orq_queue == NULL)
+      outgoing_complete(orq);	/* Timer D/K */
+    return 0;
+  }
+    
+  if (orq->orq_destroyed) {
+    if (orq->orq_status < 200)
+      orq->orq_status = status;
+    outgoing_complete(orq);	/* Timer D/K */
+    return 0;
+  }
+
+  if (orq->orq_stateless)
+    ;
+  else if (orq->orq_queue == NULL ||
+	   orq->orq_queue == orq->orq_agent->sa_out.resolving ||
+	   orq->orq_queue == orq->orq_agent->sa_out.delayed) 
+    outgoing_trying(orq);
+
+  /** Insert a dummy Via header */
+  if (!orq->orq_prepared) {
+    tport_t *tp = tport_primaries(orq->orq_agent->sa_tports);
+    outgoing_insert_via(orq, agent_tport_via(tp));
+  }
+
+  /* Create response message, if needed */
+  if (!orq->orq_stateless &&
+      !(orq->orq_callback == outgoing_default_cb) &&
+      !(status == 408 && !orq->orq_agent->sa_timeout_408)) {
+    char const *to_tag;
+
+    msg = nta_msg_create(agent, NTA_INTERNAL_MSG);
+
+    if (complete_response(msg, status, phrase, orq->orq_request) < 0) {
+      assert(!"complete message");
+      return -1;
+    } 
+
+    sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG);
+    to_tag = nta_agent_newtag(msg_home(msg), "tag=%s", agent);
+
+    if (status > 100 &&
+	sip->sip_to && !sip->sip_to->a_tag &&
+	sip->sip_cseq->cs_method != sip_method_cancel &&
+	sip_to_tag(msg_home(msg), sip->sip_to, to_tag) < 0) {
+      assert(!"adding tag");
+      return -1;
+    }
+
+    if (status > 400 && agent->sa_blacklist) {
+      sip_retry_after_t af[1];
+      sip_retry_after_init(af)->af_delta = agent->sa_blacklist;
+
+      sip_add_dup(msg, sip, (sip_header_t *)af);
+    }
+  }
+
+  if (orq->orq_inserted && !delayed) {
+    outgoing_recv(orq, status, msg, sip);
+    return 0;
+  }
+  else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) {
+    /* Xyzzy */
+    orq->orq_status = status;
+    outgoing_complete(orq);
+  }
+  else {
+    /*
+     * The thread creating outgoing transaction must return to application
+     * before transaction callback can be invoked. Therefore processing an
+     * internally generated response message must be delayed until
+     * transaction creation is completed.
+     *
+     * The internally generated message is transmitted using su_msg_send()
+     * and it is delivered back to NTA when the application next time
+     * executes the su_root_t event loop.
+     */
+    nta_agent_t *agent = orq->orq_agent;
+    su_root_t *root = agent->sa_root;
+    su_msg_r su_msg = SU_MSG_R_INIT;
+
+    if (su_msg_create(su_msg,
+		      su_root_task(root),
+		      su_root_task(root),
+		      outgoing_delayed_recv,
+		      sizeof(struct outgoing_recv_s)) == SU_SUCCESS) {
+      struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv;
+
+      a->orq = orq;
+      a->msg = msg;
+      a->sip = sip;
+      a->status = status;
+
+      if (su_msg_send(su_msg) == SU_SUCCESS) {
+	return 0;
+      }
+    }
+  }
+
+  if (msg)
+    msg_destroy(msg);
+
+  return -1;
+}
+
+static
+void outgoing_delayed_recv(su_root_magic_t *rm,
+			   su_msg_r msg,
+			   union sm_arg_u *u)
+{
+  struct outgoing_recv_s *a = u->a_outgoing_recv;
+  if (outgoing_recv(a->orq, a->status, a->msg, a->sip) < 0 && a->msg)
+    msg_destroy(a->msg);
+}
+
+
+/* ====================================================================== */
+/* 9) Resolving (SIP) URL */
+
+#if HAVE_SOFIA_SRESOLV
+
+struct sipdns_query;
+
+/** DNS resolving for (SIP) URLs */
+struct sipdns_resolver
+{
+  tp_name_t             sr_tpn[1];     	/**< Copy of original transport name */
+  sres_query_t         *sr_query;      	/**< Current DNS Query */
+  char const           *sr_target;     	/**< Target for current query */
+
+  struct sipdns_query  *sr_current;    	/**< Current query (with results) */
+  char                **sr_results;    	/**< A/AAAA results to be used */
+
+  struct sipdns_query  *sr_head;       	/**< List of intermediate results */
+  struct sipdns_query **sr_tail;       	/**< End of intermediate result list */
+
+  struct sipdns_query  *sr_done;       	/**< Completed intermediate results */
+
+  /** Transports to consider for this request */
+  struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS + 1];
+
+  uint16_t sr_a_aaaa1, sr_a_aaaa2;     /**< Order of A and/or AAAA queries. */
+
+  unsigned 
+    sr_use_naptr:1, 
+    sr_use_srv:1,
+    sr_use_a_aaaa:1;
+};
+
+/** Intermediate queries */
+struct sipdns_query
+{
+  struct sipdns_query *sq_next;
+
+  char const *sq_proto;
+  char const *sq_domain;
+  char     sq_port[6];		/* port number */
+
+  uint16_t sq_type;
+  uint16_t sq_priority;		/* priority or preference  */
+  uint16_t sq_weight;		/* preference or weight */
+};
+
+static int outgoing_resolve_next(nta_outgoing_t *orq);
+static int outgoing_resolving(nta_outgoing_t *orq);
+static int outgoing_resolving_error(nta_outgoing_t *, 
+				    int status, char const *phrase);
+static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain);
+static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q,
+				  sres_record_t *answers[]);
+
+static int outgoing_make_srv_query(nta_outgoing_t *orq);
+static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq);
+
+static void outgoing_query_all(nta_outgoing_t *orq);
+
+static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
+				sres_record_t *answers[]);
+
+#if SU_HAVE_IN6
+static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
+				 sres_record_t *answers[]);
+#endif
+
+static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
+			      sres_record_t *answers[]);
+
+static void outgoing_query_results(nta_outgoing_t *orq,
+				   struct sipdns_query *sq,
+				   char *results[],
+				   size_t rlen);
+
+
+#define SIPDNS_503_ERROR 503, "DNS Error"
+
+/** Resolve a request destination */
+static void
+outgoing_resolve(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = NULL;
+  char const *tpname = orq->orq_tpn->tpn_proto;
+
+  if (orq->orq_agent->sa_resolver)
+    orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr));
+
+  if (!sr) {
+    outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+    return;
+  } 
+
+  *sr->sr_tpn = *orq->orq_tpn;
+  sr->sr_use_srv = orq->orq_agent->sa_use_srv;
+  sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv;
+  sr->sr_use_a_aaaa = 1;
+  sr->sr_tail = &sr->sr_head;
+
+  /* RFC 3263:
+     If the TARGET was not a numeric IP address, but a port is present in
+     the URI, the client performs an A or AAAA record lookup of the domain
+     name.  The result will be a list of IP addresses, each of which can
+     be contacted at the specific port from the URI and transport protocol
+     determined previously.  The client SHOULD try the first record.  If
+     an attempt should fail, based on the definition of failure in Section
+     4.3, the next SHOULD be tried, and if that should fail, the next
+     SHOULD be tried, and so on.
+     
+     This is a change from RFC 2543.  Previously, if the port was
+     explicit, but with a value of 5060, SRV records were used.  Now, A
+     or AAAA records will be used.
+  */
+  if (sr->sr_tpn->tpn_port)
+    sr->sr_use_naptr = 0, sr->sr_use_srv = 0;
+  /* RFC3263:
+     If [...] a transport was specified explicitly, the client performs an
+     SRV query for that specific transport,
+  */
+  else if (strcmp(tpname, "*") != 0)
+    sr->sr_use_naptr = 0;
+
+  if (sr->sr_use_srv || sr->sr_use_naptr) {
+    /* Initialize sr_tports */
+    tport_t *tport;
+    char const *ident = sr->sr_tpn->tpn_ident;
+    int i, j;
+
+    for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn);
+	 tport;
+	 tport = tport_next(tport)) {
+      tp_name_t const *tpn = tport_name(tport);
+      if (strcmp(tpname, "*") && strcasecmp(tpn->tpn_proto, tpname))
+	continue;
+      if (ident && (tpn->tpn_ident == NULL || strcmp(ident, tpn->tpn_ident)))
+	continue;
+
+      for (j = 0; j < SIPDNS_TRANSPORTS; j++)
+	if (strcasecmp(tpn->tpn_proto, sipdns_tports[j].name) == 0)
+	  break;
+
+      assert(j < SIPDNS_TRANSPORTS); 
+      if (j == SIPDNS_TRANSPORTS)
+	/* Someone added transport but did not update sipdns_tports */
+	continue;
+
+      for (i = 0; i < SIPDNS_TRANSPORTS; i++) {
+	if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL)
+	  break;
+      }
+      sr->sr_tports[i] = sipdns_tports + j;
+
+      if (strcmp(tpname, "*")) /* Looking for only one transport */
+	break;	
+    }
+
+    /* Nothing found */
+    if (!sr->sr_tports[0]) {
+      SU_DEBUG_3(("nta(%p): transport %s is not supported%s%s\n", orq, tpname,
+		  ident ? " by interface " : "", ident ? ident : ""));
+      outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+      return;
+    }
+  }
+
+  switch (orq->orq_res_order) {
+  default:
+  case nta_res_ip6_ip4:
+    sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a;
+    break;
+  case nta_res_ip4_ip6:
+    sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa;
+    break;
+  case nta_res_ip6_only:
+    sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa;
+    break;
+  case nta_res_ip4_only:
+    sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a;
+    break;
+  }    
+
+  outgoing_resolve_next(orq);
+}
+
+/** Resolve next destination. */
+static int
+outgoing_resolve_next(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  if (sr == NULL) {
+    outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+    return 0;
+  }
+
+  if (sr->sr_results) {
+    /* Use existing A/AAAA results */
+    su_free(msg_home(orq->orq_request), sr->sr_results[0]);
+    sr->sr_results++;
+    if (sr->sr_results[0]) {
+      struct sipdns_query *sq = sr->sr_current; assert(sq);
+
+      if (sq->sq_proto)
+	orq->orq_tpn->tpn_proto = sq->sq_proto;
+      if (sq->sq_port[0])
+	  orq->orq_tpn->tpn_port = sq->sq_port;
+
+      orq->orq_tpn->tpn_host = sr->sr_results[0];
+
+      outgoing_reset_timer(orq);
+      outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+      outgoing_prepare_send(orq);
+      return 1;
+    }
+    else {
+      sr->sr_current = NULL;
+      sr->sr_results = NULL;
+    }
+  }
+
+  if (sr->sr_head)
+    outgoing_query_all(orq);
+  else if (sr->sr_use_naptr)
+    outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */
+  else if (sr->sr_use_srv)
+    outgoing_make_srv_query(orq);	/* SRV */
+  else if (sr->sr_use_a_aaaa)
+    outgoing_make_a_aaaa_query(orq);	/* A/AAAA */
+  else
+    return outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+  
+  return 1;
+}
+
+/** Check if can we retry other destinations? */
+static int
+outgoing_other_destinations(nta_outgoing_t const *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  if (!sr)
+    return 0;
+
+  if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr) 
+    return 1;
+
+  if (sr->sr_results && sr->sr_results[1])
+    return 1;
+
+  if (sr->sr_head)
+    return 1;
+
+  return 0;
+}
+
+/** Resolve a request destination */
+static int
+outgoing_try_another(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  if (sr == NULL)
+    return 0;
+
+  *orq->orq_tpn = *sr->sr_tpn;
+  orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0;
+  outgoing_reset_timer(orq);
+  outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+
+  return outgoing_resolve_next(orq);
+}
+
+/** Cancel resolver query */
+static inline void outgoing_cancel_resolver(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  
+  assert(orq->orq_resolver);
+
+  if (sr->sr_query)    /* Cancel resolver query */
+      sres_query_bind(sr->sr_query, NULL, NULL), sr->sr_query = NULL;
+}
+
+/** Destroy resolver */
+static inline void outgoing_destroy_resolver(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  assert(orq->orq_resolver);
+
+  if (sr->sr_query)    /* Cancel resolver query */
+    sres_query_bind(sr->sr_query, NULL, NULL), sr->sr_query = NULL;
+
+  su_free(orq->orq_agent->sa_home, sr);
+
+  orq->orq_resolver = NULL;
+}
+
+/** Check if we are resolving. If not, return 503 response. */
+static
+int outgoing_resolving(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  
+  assert(orq->orq_resolver);
+
+  if (!sr->sr_query) {
+    return outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+  } 
+  else {
+    outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+    return 0;
+  }
+}
+
+/** Return 503 response */
+static 
+int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase) 
+{
+  orq->orq_resolved = 1;
+  outgoing_reply(orq, status, phrase, 0);
+  return -1;
+}
+
+/* Query SRV records (with the given tport). */
+static
+int outgoing_make_srv_query(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  su_home_t *home = msg_home(orq->orq_request);
+  struct sipdns_query *sq;
+  char const *host; 
+  int i;
+  size_t hlen;
+ 
+  sr->sr_use_srv = 0;
+
+  host = sr->sr_tpn->tpn_host;
+  hlen = strlen(host) + 1;
+
+  for (i = 0; sr->sr_tports[i]; i++) {
+    char const *prefix = sr->sr_tports[i]->prefix;
+    size_t plen = strlen(prefix);
+
+    sq = su_zalloc(home, (sizeof *sq) + plen + hlen);
+    if (sq) {
+      *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
+      sq->sq_domain = memcpy(sq + 1, prefix, plen);
+      memcpy((char *)sq->sq_domain + plen, host, hlen);
+      sq->sq_proto = sr->sr_tports[i]->name;
+      sq->sq_type = sres_type_srv;
+      sq->sq_priority = 1;
+      sq->sq_weight = 1;
+    }
+  }
+
+  outgoing_query_all(orq);
+
+  return 0;
+}
+
+/* Query A/AAAA records.  */
+static
+int outgoing_make_a_aaaa_query(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  su_home_t *home = msg_home(orq->orq_request);
+  tp_name_t *tpn = orq->orq_tpn;
+  struct sipdns_query *sq;
+
+  assert(sr);
+
+  sr->sr_use_a_aaaa = 0;
+
+  sq = su_zalloc(home, 2 * (sizeof *sq));
+  if (!sq)
+    return outgoing_resolving(orq);
+
+  sq->sq_type = sr->sr_a_aaaa1;
+  sq->sq_domain = tpn->tpn_host;
+  sq->sq_priority = 1;
+
+  /* Append */
+  *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
+
+  outgoing_query_all(orq);
+
+  return 0;
+}
+
+
+/** Start SRV/A/AAAA queries */
+static
+void outgoing_query_all(nta_outgoing_t *orq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  struct sipdns_query *sq = sr->sr_head;
+
+  if (sq == NULL) {
+    outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+    return;
+  }
+
+  /* Remove from intermediate list */
+  if (!(sr->sr_head = sq->sq_next))
+    sr->sr_tail = &sr->sr_head;
+
+  if (sq->sq_type == sres_type_srv)
+    outgoing_query_srv(orq, sq);
+#if SU_HAVE_IN6
+  else if (sq->sq_type == sres_type_aaaa)
+    outgoing_query_aaaa(orq, sq);
+#endif
+  else if (sq->sq_type == sres_type_a)
+    outgoing_query_a(orq, sq);
+  else
+    outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+}
+
+/** Query NAPTR record. */
+static
+int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  sres_record_t **answers;
+
+  sr->sr_use_naptr = 0;
+
+  sr->sr_target = domain;
+
+  answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+				sres_type_naptr, domain);
+
+  SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+              orq->orq_tpn->tpn_host, domain, "NAPTR",
+              answers ? " (cached)" : ""));
+
+  if (answers) {
+    outgoing_answer_naptr(orq, NULL, answers);
+    return 0;
+  }
+  else {
+    sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+			      outgoing_answer_naptr, orq,
+			      sres_type_naptr, domain);
+    return outgoing_resolving(orq);
+  }
+}
+
+/* Process NAPTR records */
+static
+void outgoing_answer_naptr(sres_context_t *orq,
+			   sres_query_t *q,
+			   sres_record_t *answers[])
+{
+  int i, j, order = -1;
+  size_t rlen;
+  su_home_t *home = msg_home(orq->orq_request);
+  nta_agent_t *agent = orq->orq_agent;
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  tp_name_t tpn[1];
+  struct sipdns_query *sq, *selected = NULL, **tail = &selected, **at;
+
+  assert(sr);
+
+  sr->sr_query = NULL;
+
+  *tpn = *sr->sr_tpn;
+
+  /* The NAPTR results are sorted first by Order then by Preference */
+  sres_sort_answers(orq->orq_agent->sa_resolver, answers);
+
+  for (i = 0; answers && answers[i]; i++) {
+    sres_naptr_record_t const *na = answers[i]->sr_naptr;
+    uint16_t type;
+
+    if (na->na_record->r_status)
+      continue;
+    if (na->na_record->r_type != sres_type_naptr)
+      continue;
+
+    /* RFC 2915 p 4:
+     * Order
+     *    A 16-bit unsigned integer specifying the order in which the
+     *    NAPTR records MUST be processed to ensure the correct ordering
+     *    of rules. Low numbers are processed before high numbers, and
+     *    once a NAPTR is found whose rule "matches" the target, the
+     *    client MUST NOT consider any NAPTRs with a higher value for
+     *    order (except as noted below for the Flags field).
+     */
+    if (order >= 0 && order != na->na_order)
+      break;
+
+    /* Check if NAPTR matches our target */
+    if (strncasecmp(na->na_services, "SIP+", 4) && 
+	strncasecmp(na->na_services, "SIPS+", 5))
+      /* Not a SIP/SIPS service */
+      continue;
+
+    /* Use NAPTR results, don't try extra SRV/A/AAAA records */
+    sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0;		
+    
+    /* Check if we have a transport mathing with service */
+    for (j = 0; sr->sr_tports[j]; j++) {
+      /*
+       * Syntax of services is actually more complicated 
+       * but comparing the values in the transport list 
+       * match with those values that make any sense
+       */
+      if (strcasecmp(na->na_services, sr->sr_tports[j]->service) != 0)
+	continue;
+
+      tpn->tpn_proto = sr->sr_tports[j]->name;
+
+      if (tport_primary_by_name(agent->sa_tports, tpn))
+	break;
+    }
+
+    SU_DEBUG_5(("nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n",
+		na->na_record->r_name,
+		na->na_order, na->na_prefer,
+		na->na_flags, na->na_services,
+		na->na_regexp, na->na_replace,
+		!sr->sr_tports[j] ? " (not supported)" : ""));
+
+    if (!sr->sr_tports[j])
+      continue;
+
+    /* OK, we found matching NAPTR */ 
+    order = na->na_order;
+
+    /*
+     * The "S" flag means that the next lookup should be for SRV records
+     * ... "A" means that the next lookup should be for either an A, AAAA,
+     * or A6 record.
+     */
+    if (na->na_flags[0] == 's' || na->na_flags[0] == 'S')
+      type = sres_type_srv; /* SRV */
+    else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A')
+      type = sr->sr_a_aaaa1; /* A / AAAA */
+    else
+      continue;
+
+    rlen = strlen(na->na_replace) + 1;
+    sq = su_zalloc(home, (sizeof *sq) + rlen);
+
+    *tail = sq, tail = &sq->sq_next;    
+    sq->sq_priority = na->na_prefer;
+    sq->sq_weight = j;
+    sq->sq_type = type;
+    sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen);
+    sq->sq_proto = sr->sr_tports[j]->name;
+  }
+
+  sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+  /* RFC2915: 
+     Preference [...] specifies the order in which NAPTR
+     records with equal "order" values SHOULD be processed, low
+     numbers being processed before high numbers. */
+  at = sr->sr_tail;
+  while (selected) {
+    sq = selected, selected = sq->sq_next;
+
+    for (tail = at; *tail; tail = &(*tail)->sq_next) {
+      if (sq->sq_priority < (*tail)->sq_priority)
+	break;
+      if (sq->sq_priority == (*tail)->sq_priority &&
+	  sq->sq_weight < (*tail)->sq_weight)
+	break;
+    }
+    /* Insert */
+    sq->sq_next = *tail, *tail = sq;
+
+    if (!sq->sq_next)		/* Last one */
+      sr->sr_tail = &sq->sq_next;
+  }
+
+  outgoing_resolve_next(orq);
+}
+
+/* Query SRV records */
+static
+int outgoing_query_srv(nta_outgoing_t *orq, 
+		       struct sipdns_query *sq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  sres_record_t **answers;
+
+  sr->sr_target = sq->sq_domain;
+  sr->sr_current = sq;
+
+  answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+				sres_type_srv, sq->sq_domain);
+
+  SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+              orq->orq_tpn->tpn_host, sq->sq_domain, "SRV",
+              answers ? " (cached)" : ""));
+
+  if (answers) {
+    outgoing_answer_srv(orq, NULL, answers);
+    return 0;
+  }
+  else {
+    sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+			      outgoing_answer_srv, orq,
+			      sres_type_srv, sq->sq_domain);
+    return outgoing_resolving(orq);
+  }
+}
+
+/* Process SRV records */
+static
+void
+outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
+		    sres_record_t *answers[])
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  su_home_t *home = msg_home(orq->orq_request);
+  struct sipdns_query *sq0, *sq, *selected = NULL, **tail = &selected, **at;
+  int i;
+  size_t tlen;
+
+  sr->sr_query = NULL;
+
+  sq0 = sr->sr_current; 
+  assert(sq0 && sq0->sq_type == sres_type_srv);
+  assert(sq0->sq_domain); assert(sq0->sq_proto);
+
+  /* Sort by priority, weight? */
+  sres_sort_answers(orq->orq_agent->sa_resolver, answers);
+
+  for (i = 0; answers && answers[i]; i++) {
+    sres_srv_record_t const *srv = answers[i]->sr_srv;
+
+    if (srv->srv_record->r_status /* There was an error */ ||
+        srv->srv_record->r_type != sres_type_srv)
+      continue;
+
+    tlen = strlen(srv->srv_target) + 1;
+
+    sq = su_zalloc(home, (sizeof *sq) + tlen);
+
+    if (sq) {
+      *tail = sq, tail = &sq->sq_next;
+
+      sq->sq_type = sr->sr_a_aaaa1;
+      sq->sq_proto = sq0->sq_proto;
+      sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
+      snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
+
+      sq->sq_priority = srv->srv_priority;
+      sq->sq_weight = srv->srv_weight;
+    }
+  }
+
+  sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+  at = &sr->sr_head;
+
+  /* Insert sorted by priority, randomly select by weigth */
+  while (selected) {
+    unsigned long weight = 0;
+    unsigned N = 0;
+    uint16_t priority = selected->sq_priority;
+
+    /* Total weight of entries with same priority */
+    for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) {
+      weight += sq->sq_weight;
+      N ++;
+    }
+
+    tail = &selected;
+
+    /* Select by weighted random. Entries with weight 0 are kept in order */
+    if (N > 1 && weight > 0) {
+      unsigned rand = su_randint(0,  weight - 1);
+
+      while (rand >= (*tail)->sq_weight) {
+	rand -= (*tail)->sq_weight;
+	tail = &(*tail)->sq_next;
+      }
+    }
+
+    /* Remove selected */
+    sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority);
+
+    /* Append at *at */
+    sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at;
+
+    SU_DEBUG_5(("nta: %s IN SRV %u %u  %s %s (%s)\n",
+		sq0->sq_domain,
+		(unsigned)sq->sq_priority, (unsigned)sq->sq_weight,
+		sq->sq_port, sq->sq_domain, sq->sq_proto));
+  }
+
+  /* This is not needed anymore (?) */
+  sr->sr_current = NULL; 
+  sq0->sq_next = sr->sr_done; sr->sr_done = sq0; 
+
+  outgoing_resolve_next(orq);
+}
+
+#if SU_HAVE_IN6
+/* Query AAAA records */
+static
+int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  sres_record_t **answers;
+
+  sr->sr_target = sq->sq_domain;
+  sr->sr_current = sq;
+
+  answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+				sres_type_aaaa, sq->sq_domain);
+
+  SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+              orq->orq_tpn->tpn_host, sq->sq_domain, "AAAA", 
+              answers ? " (cached)" : ""));
+
+  if (answers) {
+    outgoing_answer_aaaa(orq, NULL, answers);
+    return 0;
+  }
+
+  sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+			      outgoing_answer_aaaa, orq,
+			      sres_type_aaaa, sq->sq_domain);
+
+  return outgoing_resolving(orq);
+}
+
+/* Process AAAA records */
+static
+void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
+			  sres_record_t *answers[])
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  su_home_t *home = msg_home(orq->orq_request);
+  struct sipdns_query *sq = sr->sr_current;
+
+  size_t i, j, found;
+  char *result, **results = NULL;
+
+  assert(sq); assert(sq->sq_type == sres_type_aaaa);
+
+  sr->sr_query = NULL;
+
+  for (i = 0, found = 0; answers && answers[i]; i++) {
+    sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
+    if (aaaa->aaaa_record->r_status == 0 &&
+        aaaa->aaaa_record->r_type == sres_type_aaaa)
+      found++;
+  }
+
+  if (found > 1)
+    results = su_zalloc(home, (found + 1) * (sizeof *results));
+  else if (found)
+    results = &result;
+
+  for (i = j = 0; results && answers && answers[i]; i++) {
+    char addr[SU_ADDRSIZE];
+    sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
+
+    if (aaaa->aaaa_record->r_status ||
+        aaaa->aaaa_record->r_type != sres_type_aaaa)
+      continue;			      /* There was an error */
+
+    inet_ntop(AF_INET6, &aaaa->aaaa_addr, addr, sizeof(addr));
+
+    if (j == 0)
+      SU_DEBUG_5(("nta(%p): %s IN AAAA %s\n", orq, 
+		  aaaa->aaaa_record->r_name, addr));
+    else
+      SU_DEBUG_5(("nta(%p):  AAAA %s\n", orq, addr));
+
+    assert(j < found);
+    results[j++] = su_strdup(home, addr);
+  }
+
+  sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+  outgoing_query_results(orq, sq, results, found);
+}
+#endif /* SU_HAVE_IN6 */
+
+/* Query A records */
+static
+int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  sres_record_t **answers;
+
+  sr->sr_target = sq->sq_domain;
+  sr->sr_current = sq;
+
+  answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+				sres_type_a, sq->sq_domain);
+
+  SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+	      orq->orq_tpn->tpn_host, sq->sq_domain, "A",
+	      answers ? " (cached)" : ""));
+
+  if (answers) {
+    outgoing_answer_a(orq, NULL, answers);
+    return 0;
+  }
+
+  sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+			      outgoing_answer_a, orq,
+			      sres_type_a, sq->sq_domain);
+
+  return outgoing_resolving(orq);
+}
+
+/* Process A records */
+static
+void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
+		       sres_record_t *answers[])
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+  su_home_t *home = msg_home(orq->orq_request);
+  struct sipdns_query *sq = sr->sr_current;
+
+  int i, j, found;
+  char *result, **results = NULL;
+
+  assert(sq); assert(sq->sq_type == sres_type_a);
+
+  sr->sr_query = NULL;
+
+  for (i = 0, found = 0; answers && answers[i]; i++) {
+    sres_a_record_t const *a = answers[i]->sr_a;
+    if (a->a_record->r_status == 0 &&
+        a->a_record->r_type == sres_type_a)
+      found++;
+  }
+
+  if (found > 1)
+    results = su_zalloc(home, (found + 1) * (sizeof *results));
+  else if (found)
+    results = &result;
+
+  for (i = j = 0; answers && answers[i]; i++) {
+    char addr[SU_ADDRSIZE];
+    sres_a_record_t const *a = answers[i]->sr_a;
+
+    if (a->a_record->r_status ||
+	a->a_record->r_type != sres_type_a)
+      continue;			      /* There was an error */
+
+    inet_ntop(AF_INET, &a->a_addr, addr, sizeof(addr));
+
+    if (j == 0)
+      SU_DEBUG_5(("nta: %s IN A %s\n", a->a_record->r_name, addr));
+    else
+      SU_DEBUG_5(("nta(%p):  A %s\n", orq, addr));
+
+    assert(j < found);
+    results[j++] = su_strdup(home, addr);
+  }
+
+  sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+  outgoing_query_results(orq, sq, results, found);
+}
+
+/** Store A/AAAA query results */
+static void
+outgoing_query_results(nta_outgoing_t *orq,
+		       struct sipdns_query *sq,
+		       char *results[],
+		       size_t rlen)
+{
+  struct sipdns_resolver *sr = orq->orq_resolver;
+
+  if (sq->sq_type == sr->sr_a_aaaa1 &&
+      sq->sq_type != sr->sr_a_aaaa2) {
+    sq->sq_type = sr->sr_a_aaaa2;
+
+    SU_DEBUG_7(("nta(%p): %s %s record still unresolved\n", orq,
+		sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"));
+
+    /*
+     * Three possible policies: 
+     * 1) try each host for AAAA/A, then A/AAAA
+     * 2) try everything first for AAAA/A, then everything for A/AAAA
+     * 3) try one SRV record results for AAAA/A, then for A/AAAA,
+     *    then next SRV record 
+     */
+
+    /* We use now policy #1 */
+    if (!(sq->sq_next = sr->sr_head))
+      sr->sr_tail = &sq->sq_next;
+    sr->sr_head = sq;
+  }
+  else {
+    sq->sq_next = sr->sr_done, sr->sr_done = sq;
+  }
+
+  if (rlen > 1) 
+    sr->sr_results = results;
+  else
+    sr->sr_current = NULL;
+
+  if (rlen > 0) {
+    orq->orq_resolved = 1;
+    orq->orq_tpn->tpn_host = results[0];
+    if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto;
+    if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port;
+    outgoing_prepare_send(orq);
+  } else {
+    outgoing_resolve_next(orq);
+  }
+}
+
+
+#endif
+
+/* ====================================================================== */
+/* 10) Reliable responses */
+
+static nta_prack_f nta_reliable_destroyed;
+
+/**
+ * Check that server transaction can be used to send reliable provisional
+ * responses.
+ */
+static inline
+int reliable_check(nta_incoming_t *irq)
+{
+  if (irq == NULL || irq->irq_status >= 200 || !irq->irq_agent)
+    return 0;
+
+  if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200)
+    return 0;
+
+  /* @RSeq is initialized to nonzero when request requires/supports 100rel */
+  if (irq->irq_rseq == 0)
+    return 0;
+
+  if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */
+    return 0;
+
+  return 1;
+}
+
+/** Respond reliably.
+ *
+ * @param irq
+ * @param callback
+ * @param rmagic
+ * @param status
+ * @param phrase
+ * @param tag, value, ..
+ */
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq,
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    int status, char const *phrase,
+				    tag_type_t tag,
+				    tag_value_t value, ...)
+{
+  ta_list ta;
+  msg_t *msg;
+  sip_t *sip;
+  nta_reliable_t *retval = NULL;
+
+  if (!reliable_check(irq) || (status <= 100 || status >= 200))
+    return NULL;
+
+  msg = nta_msg_create(irq->irq_agent, 0);
+  sip = sip_object(msg);
+
+  if (!sip)
+    return NULL;
+
+  ta_start(ta, tag, value);
+
+  if (0 > nta_incoming_complete_response(irq, msg, status, phrase, 
+					 ta_tags(ta)))
+    msg_destroy(msg);
+  else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip)))
+    msg_destroy(msg);
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/** Respond reliably with @a msg.
+ *
+ * @note 
+ * The stack takes over the ownership of @a msg. (It is destroyed even if
+ * sending the response fails.)
+ *
+ * @param irq
+ * @param callback
+ * @param rmagic
+ * @param msg
+ */
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    msg_t *msg)
+{
+  sip_t *sip = sip_object(msg);
+
+  if (!reliable_check(irq)) {
+    msg_destroy(msg);
+    return NULL;
+  }
+
+  if (sip == NULL || !sip->sip_status || sip->sip_status->st_status <= 100) {
+    msg_destroy(msg);
+    return NULL;
+  }
+
+  if (sip->sip_status->st_status >= 200) {
+    incoming_final_failed(irq, msg);
+    return NULL;
+  }
+
+  return reliable_mreply(irq, callback, rmagic, msg, sip);
+}
+
+static
+nta_reliable_t *reliable_mreply(nta_incoming_t *irq,
+				nta_prack_f *callback,
+				nta_reliable_magic_t *rmagic,
+				msg_t *msg,
+				sip_t *sip)
+{
+  nta_reliable_t *rel;
+  nta_agent_t *agent;
+
+  agent = irq->irq_agent;
+
+  if (callback == NULL)
+    callback = nta_reliable_destroyed;
+
+  rel = su_zalloc(agent->sa_home, sizeof(*rel));
+  if (rel) {
+    rel->rel_irq = irq;
+    rel->rel_callback = callback;
+    rel->rel_magic = rmagic;
+    rel->rel_unsent = msg;
+    rel->rel_status = sip->sip_status->st_status;
+    rel->rel_precious = sip->sip_payload != NULL;
+    rel->rel_next = irq->irq_reliable;
+
+    /*
+     * If there already is a un-pr-acknowledged response, queue this one
+     * until at least one response is pr-acknowledged.
+     */
+    if (irq->irq_reliable &&
+	(irq->irq_reliable->rel_next == NULL ||
+	 irq->irq_reliable->rel_rseq == 0)) {
+      return irq->irq_reliable = rel;
+    }
+
+    if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
+      msg_destroy(msg);
+      su_free(agent->sa_home, rel);
+      return NULL;
+    }
+
+    irq->irq_reliable = rel;
+
+    return callback ? rel : (nta_reliable_t *)-1;
+  }
+
+  msg_destroy(msg);
+  return NULL;
+}
+
+static
+int reliable_send(nta_incoming_t *irq,
+		  nta_reliable_t *rel,
+		  msg_t *msg,
+		  sip_t *sip)
+{
+  nta_agent_t *sa = irq->irq_agent;
+  su_home_t *home = msg_home(msg);
+  sip_rseq_t rseq[1];
+  sip_rseq_init(rseq);
+
+  if (sip->sip_require)
+    msg_header_replace_param(home, sip->sip_require->k_common, "100rel");
+  else
+    sip_add_make(msg, sip, sip_require_class, "100rel");
+
+  rel->rel_rseq = rseq->rs_response = irq->irq_rseq;
+  sip_add_dup(msg, sip, (sip_header_t *)rseq);
+
+  if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) {
+    msg_destroy(msg);
+    return -1;
+  }
+
+  irq->irq_rseq++;
+
+  if (irq->irq_queue == sa->sa_in.preliminary)
+    /* Make sure we are moved to the tail */
+    incoming_remove(irq);
+
+  incoming_queue(sa->sa_in.preliminary, irq); /* P1 */
+  incoming_set_timer(irq, sa->sa_t1); /* P2 */
+  
+  return 0;
+}
+
+/** Queue final response when there are unsent precious preliminary responses */
+static
+int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+  nta_reliable_t *r;
+  unsigned already_in_callback;
+  /*
+   * We delay sending final response if it's 2XX and
+   * an unpracked reliable response contains session description
+   */
+  /* Get last unpracked response from queue */
+  if (sip->sip_status->st_status < 300)
+    for (r = irq->irq_reliable; r; r = r->rel_next)
+      if (r->rel_unsent && r->rel_precious) {
+	/* Delay sending 2XX */
+	reliable_mreply(irq, NULL, NULL, msg, sip);
+	return 0;
+      }
+
+  /* Flush unsent responses. */
+  already_in_callback = irq->irq_in_callback;
+  irq->irq_in_callback = 1;
+  reliable_flush(irq);
+  irq->irq_in_callback = already_in_callback;
+
+  if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) {
+    incoming_free(irq);
+    msg_destroy(msg);
+    return 0;
+  }
+
+  return 1;
+}
+
+/** Get latest reliably sent response */
+static
+msg_t *reliable_response(nta_incoming_t *irq)
+{
+  nta_reliable_t *r, *rel;
+
+  /* Get last unpracked response from queue */
+  for (rel = NULL, r = irq->irq_reliable; r; r = r->rel_next)
+    if (!r->rel_pracked)
+      rel = r;
+
+  assert(rel);
+
+  return rel->rel_unsent;
+}
+
+/** Process incoming PRACK with matching @RAck field */
+static
+int reliable_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tp)
+{
+  sip_rack_t *rack = sip->sip_rack;
+  nta_reliable_t *rel;
+  nta_incoming_t *pr_irq;
+  int status;
+
+  for (rel = irq->irq_reliable; rel; rel = rel->rel_next)
+    if (rel->rel_pracked)
+      return -1;
+    else if (rel->rel_rseq == rack->ra_response)
+      break;
+
+  if (!rel)
+    return -1;			/* Process normally */
+
+  rel->rel_pracked = 1;
+  msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+
+  pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag);
+  if (!pr_irq) {
+    nta_msg_treply(irq->irq_agent, msg,
+		   SIP_500_INTERNAL_SERVER_ERROR, 
+		   NTATAG_TPORT(tp),
+		   TAG_END());
+    return 0;
+  }
+
+  if (irq->irq_status < 200) {
+    incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */
+    incoming_reset_timer(irq);	/* Reset P2 */
+  }
+
+  irq->irq_in_callback = pr_irq->irq_in_callback = 1;
+  status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL;
+  irq->irq_in_callback = pr_irq->irq_in_callback = 0;
+
+  if (pr_irq->irq_destroyed && pr_irq->irq_terminated) {
+    incoming_free(pr_irq);
+  }
+  else if (status != 0) {
+    if (status < 200 || status > 299) {
+      SU_DEBUG_3(("nta_reliable(): invalid status %03d from callback\n",
+		  status));
+      status = 200;
+    }
+    nta_incoming_treply(pr_irq, status, "OK", TAG_END());
+    nta_incoming_destroy(pr_irq);
+  } 
+
+  /* If there are queued unsent reliable responses, send them all. */
+  while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) {
+    nta_reliable_t *r;
+
+    for (r = irq->irq_reliable; r; r = r->rel_next)
+      if (r->rel_rseq == 0)
+	rel = r;
+
+    msg = rel->rel_unsent, sip = sip_object(msg);
+
+    if (sip->sip_status->st_status < 200) {
+      if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
+	assert(!"send reliable response");
+      }
+    } 
+    else {
+      /*
+       * XXX
+       * Final response should be delayed until a reliable provisional
+       * response has been pracked
+       */
+      rel->rel_unsent = NULL, rel->rel_rseq = (uint32_t)-1;
+      if (incoming_reply(irq, msg, sip) < 0) {
+	assert(!"send delayed final response");
+      }
+    }
+  }
+
+  return 0;
+}
+
+/** Flush unacknowledged and unsent reliable responses */
+void reliable_flush(nta_incoming_t *irq)
+{
+  nta_reliable_t *r, *rel;
+
+  do {
+    for (r = irq->irq_reliable, rel = NULL; r; r = r->rel_next)
+      if (r->rel_unsent)
+	rel = r;
+
+    if (rel) {
+      rel->rel_pracked = 1;
+      msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+      rel->rel_callback(rel->rel_magic, rel, NULL, NULL);
+    }
+  } while (rel);
+}
+
+void reliable_timeout(nta_incoming_t *irq, int timeout)
+{
+  if (timeout)
+    SU_DEBUG_5(("nta: response timeout with %u\n", irq->irq_status));
+
+  irq->irq_in_callback = 1;
+
+  reliable_flush(irq);
+
+  if (irq->irq_callback)
+    irq->irq_callback(irq->irq_magic, irq, NULL);
+
+  irq->irq_in_callback = 0;
+
+  if (irq->irq_completed && irq->irq_destroyed)
+    incoming_free(irq), irq = NULL;
+
+  if (timeout && irq && irq->irq_status < 200)
+    nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END());
+}
+
+#if 0 /* Not needed, yet. */
+/** Use this callback when normal leg callback is supposed to
+ *  process incoming PRACK requests
+ */
+int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
+			   nta_reliable_t *rel, 
+			   nta_incoming_t *irq, 
+			   sip_t const *sip)
+{
+  nta_agent_t *agent;
+  nta_leg_t *leg;
+  char const *method_name;
+  url_t url[1];
+  int retval;
+
+  if (irq == NULL || sip == NULL || rel == NULL || 
+      sip_object(irq->irq_request) != sip)
+    return 500;
+
+  agent = irq->irq_agent;
+  method_name = sip->sip_request->rq_method_name;
+  *url = *sip->sip_request->rq_url; url->url_params = NULL;
+  agent_aliases(agent, url, irq->irq_tport); /* canonize urls */
+
+  if ((leg = leg_find(irq->irq_agent, 
+		      method_name, url, 
+		      sip->sip_call_id,
+		      sip->sip_from->a_tag, sip->sip_from->a_url, 
+		      sip->sip_to->a_tag, sip->sip_to->a_url))) {
+    /* Use existing dialog */
+    SU_DEBUG_5(("nta: %s (%u) %s\n",
+		method_name, sip->sip_cseq->cs_seq, 
+		"PRACK processed by default callback, too"));
+    retval = leg->leg_callback(leg->leg_magic, leg, irq, sip);
+  }
+  else {
+    retval = 500;
+  }
+
+  nta_reliable_destroy(rel);
+
+  return retval;
+}
+#endif
+
+/** Destroy a reliable response.
+ *
+ * The function nta_reliable_destroy() marks a reliable response object for
+ * destroyal, and frees it if possible.
+ */
+void nta_reliable_destroy(nta_reliable_t *rel)
+{
+  if (rel == NULL || rel == NONE)
+    return;
+
+  if (rel->rel_callback == nta_reliable_destroyed)
+    SU_DEBUG_1(("%s(%p): already destroyed\n", __func__, rel));
+
+  rel->rel_callback = nta_reliable_destroyed;
+
+  if (rel->rel_response)
+    return;
+
+  nta_reliable_destroyed(NULL, rel, NULL, NULL);
+}
+
+/** Free and unallocate the nta_reliable_t structure. */
+static
+int nta_reliable_destroyed(nta_reliable_magic_t *rmagic,
+			   nta_reliable_t *rel,
+			   nta_incoming_t *prack,
+			   sip_t const *sip)
+{
+  nta_reliable_t **prev;
+
+  assert(rel); assert(rel->rel_irq);
+
+  for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next)
+    if (*prev == rel)
+      break;
+
+  if (!*prev) {
+    assert(*prev);
+    SU_DEBUG_1(("%s(%p): not linked\n", __func__, rel));
+    return 200;
+  }
+
+  *prev = rel->rel_next;
+
+  if (rel->rel_unsent)
+    msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+
+  su_free(rel->rel_irq->irq_agent->sa_home, rel);
+
+  return 200;
+}
+
+/** Validate a reliable response. */
+int outgoing_recv_reliable(nta_outgoing_t *orq,
+			   msg_t *msg,
+			   sip_t *sip)
+{
+  short status = sip->sip_status->st_status;
+  char const *phrase = sip->sip_status->st_phrase;
+  uint32_t rseq = sip->sip_rseq->rs_response;
+
+  SU_DEBUG_7(("nta: %03u %s is reliably received with RSeq: %u\n",
+	      status, phrase, rseq));
+
+  /* Cannot handle reliable responses unless we have a full dialog */
+  if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) {
+    SU_DEBUG_5(("nta: %03u %s with initial RSeq: %u outside dialog\n",
+		status, phrase, rseq));
+    return 0;
+  }
+
+  if (rseq <= orq->orq_rseq) {
+    SU_DEBUG_3(("nta: %03u %s already received (RSeq: %u, expecting %u)\n",
+		status, phrase, rseq, orq->orq_rseq + 1));
+    return -1;
+  }
+
+  if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) {
+    SU_DEBUG_3(("nta: %03d %s is not expected (RSeq: %u, expecting %u)\n",
+		status, sip->sip_status->st_phrase,
+		rseq, orq->orq_rseq + 1));
+    return -1;
+  }
+
+  return 0;
+}
+
+/** Create a tagged fork of outgoing request.
+ *
+ * When a dialog-creating INVITE request is forked, each response from
+ * diffent fork will create an early dialog with a distinct tag in @To
+ * header. When each fork should be handled separately, a tagged INVITE
+ * request can be used. It will only receive responses from the specified
+ * fork. Please note that the tagged transaction should be terminated with
+ * the final response from another fork, too.
+ *
+ * @param orq
+ * @param callback
+ * @param magic
+ * @param to_tag
+ * @param rseq
+ */
+nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    char const *to_tag,
+				    sip_rseq_t const *rseq)
+{
+  nta_agent_t *agent;
+  su_home_t *home;
+  nta_outgoing_t *tagged;
+  sip_to_t *to;
+
+  if (orq == NULL || to_tag == NULL)
+    return NULL;
+  if (orq->orq_to->a_tag) {
+    SU_DEBUG_1(("%s: transaction %p already in dialog\n", __func__, orq));
+    return NULL;
+  }
+
+  assert(orq->orq_agent); assert(orq->orq_request);
+
+  agent = orq->orq_agent;
+  tagged = su_alloc(agent->sa_home, sizeof(*tagged));
+  home = msg_home((msg_t *)orq->orq_request);
+
+  *tagged = *orq;
+  tagged->orq_callback = callback;
+  tagged->orq_magic = magic;
+
+  tagged->orq_prev = NULL, tagged->orq_next = NULL, tagged->orq_queue = NULL;
+  tagged->orq_rprev = NULL, tagged->orq_rnext = NULL;
+
+  if (tagged->orq_cc)
+    nta_compartment_ref(tagged->orq_cc);
+
+  sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag);
+
+  tagged->orq_to 	   = to;
+  tagged->orq_tport        = tport_ref(orq->orq_tport);
+  tagged->orq_request      = (msg_t *)msg_ref_create(orq->orq_request);
+  tagged->orq_response     = NULL;
+  tagged->orq_cancel       = NULL;
+
+  tagged->orq_pending = tport_pend(orq->orq_tport, 
+				   orq->orq_request, 
+				   outgoing_tport_error, 
+				   tagged);
+  if (tagged->orq_pending < 0)
+    tagged->orq_pending = 0;
+
+  tagged->orq_rseq = 0;
+
+  outgoing_queue(orq->orq_queue, tagged);
+  outgoing_insert(agent, tagged);
+
+  return tagged;
+}
+
+/**PRACK a provisional response.
+ *
+ * The function nta_outgoing_prack() creates and sends a PRACK request used
+ * to acknowledge a provisional response. 
+ *
+ * The request is sent using the route of the original request @a oorq.
+ *
+ * When NTA receives response to the prack request, it invokes the @a
+ * callback function.
+ *
+ * @param leg         dialog object
+ * @param oorq        original transaction request
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param route_url   optional URL used to route transaction requests
+ * @param resp        (optional) response message to be acknowledged
+ * @param tag,value,... optional
+ *
+ * @return
+ * If successful, the function nta_outgoing_prack() returns a pointer
+ * to newly created client transaction object for PRACK request, NULL
+ * otherwise.
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ */
+nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
+				   nta_outgoing_t *oorq,
+				   nta_response_f *callback,
+				   nta_outgoing_magic_t *magic,
+				   url_string_t const *route_url,
+				   sip_t const *resp,
+				   tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  msg_t *msg;
+  su_home_t *home;
+  sip_t *sip;
+  sip_to_t const *to = NULL;
+  sip_route_t *route = NULL, r0[1];
+  nta_outgoing_t *orq = NULL;
+  sip_rack_t *rack = NULL, rack0[1];
+
+  if (!leg || !oorq) {
+    SU_DEBUG_1(("%s: invalid arguments\n", __func__));
+    return NULL;
+  }
+
+  sip_rack_init(rack0);
+
+  if (resp) {
+    if (!resp->sip_status) {
+      SU_DEBUG_1(("%s: invalid arguments\n", __func__));
+      return NULL;
+    }
+
+    if (resp->sip_status->st_status <= 100 ||
+	resp->sip_status->st_status >= 200) {
+      SU_DEBUG_1(("%s: %u response cannot be PRACKed\n",
+		  __func__, resp->sip_status->st_status));
+      return NULL;
+    }
+    
+    if (!resp->sip_rseq) {
+      SU_DEBUG_1(("%s: %u response missing RSeq\n",
+		__func__, resp->sip_status->st_status));
+      return NULL;
+    }
+
+    if (resp->sip_rseq->rs_response <= oorq->orq_rseq) {
+      SU_DEBUG_1(("%s: %u response RSeq does not match received RSeq\n",
+		  __func__, resp->sip_status->st_status));
+      return NULL;
+    }
+    if (!oorq->orq_must_100rel &&
+	!sip_has_feature(resp->sip_require, "100rel")) {
+      SU_DEBUG_1(("%s: %u response does not require 100rel\n",
+		  __func__, resp->sip_status->st_status));
+      return NULL;
+    }
+
+    if (!resp->sip_to->a_tag) {
+      SU_DEBUG_1(("%s: %u response has no To tag\n",
+		  __func__, resp->sip_status->st_status));
+      return NULL;
+    }
+    if (str0casecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) ||
+	str0casecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) {
+      SU_DEBUG_1(("%s: %u response To tag does not agree with dialog tag\n",
+		  __func__, resp->sip_status->st_status));
+      return NULL;
+    }
+
+    to = resp->sip_to;
+    rack = rack0;
+
+    rack->ra_response    = resp->sip_rseq->rs_response;
+    rack->ra_cseq        = resp->sip_cseq->cs_seq;
+    rack->ra_method      = resp->sip_cseq->cs_method;
+    rack->ra_method_name = resp->sip_cseq->cs_method_name;
+  }
+
+  msg = nta_msg_create(leg->leg_agent, 0);
+  sip = sip_object(msg); home = msg_home(msg);
+
+  if (!sip)
+    return NULL;
+
+  if (!leg->leg_route && resp) {
+    /* Insert contact into route */
+    if (resp->sip_contact) {
+      sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0];
+      route = sip_route_dup(home, r0);
+    }
+    
+    /* Reverse record route */
+    if (resp->sip_record_route) {
+      sip_route_t *r, *r_next;
+      for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) {
+	r_next = r->r_next, r->r_next = route, route = r;
+      }
+    }
+  }
+
+  ta_start(ta, tag, value);
+
+  if (!resp) {
+    tagi_t const *t;
+
+    if ((t = tl_find(ta_args(ta), ntatag_rseq)) && t->t_value) {
+      rack = rack0;
+      rack->ra_response = (uint32_t)t->t_value;
+    }
+
+    if (rack) {
+      rack->ra_cseq = orq->orq_cseq->cs_seq;
+      rack->ra_method = orq->orq_cseq->cs_method;
+      rack->ra_method_name = orq->orq_cseq->cs_method_name;
+    }
+  }
+
+  if (sip_add_tl(msg, sip,
+		 TAG_IF(rack, SIPTAG_RACK(rack)),
+		 TAG_IF(to, SIPTAG_TO(to)),
+		 ta_tags(ta)) < 0)
+    ;
+  else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0)
+    ;
+  else if (!sip->sip_rack) 
+    SU_DEBUG_1(("%s: RAck header missing\n", __func__));
+  else if (nta_msg_request_complete(msg, leg,
+				    SIP_METHOD_PRACK,
+				    (url_string_t *)oorq->orq_url) < 0)
+    ;
+  else
+    orq = outgoing_create(leg->leg_agent, callback, magic,
+			  route_url, NULL, msg, ta_tags(ta));
+
+  ta_end(ta);
+
+  if (!orq)
+    msg_destroy(msg);
+  else if (rack)
+    oorq->orq_rseq = rack->ra_response;
+  else if (sip->sip_rack)
+    oorq->orq_rseq = sip->sip_rack->ra_response;
+
+  return orq;
+}
+
+/** Get @RSeq value stored with client transaction. */
+uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq)
+{
+  return orq ? orq->orq_rseq : 0;
+}
+
+/** Set @RSeq value stored with client transaction. 
+ *
+ * @return 0 if rseq was set successfully
+ * @return -1 if rseq is invalid or orq is NULL.
+ */
+int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq)
+{
+  if (orq && orq->orq_rseq <= rseq) {
+    orq->orq_rseq = rseq;      
+    return 0;
+  }
+
+  return -1;
+}
+
+/* ------------------------------------------------------------------------ */
+/* 11) SigComp handling and public transport interface */
+
+#include <sofia-sip/nta_tport.h>
+
+static inline tport_t *
+nta_transport_(nta_agent_t *agent,
+	       nta_incoming_t *irq,
+	       msg_t *msg)
+{
+  if (irq)
+    return irq->irq_tport;
+  else if (agent && msg)
+    return tport_delivered_by(agent->sa_tports, msg);
+
+  errno = EINVAL;
+  return NULL;
+}
+
+
+tport_t *
+nta_incoming_transport(nta_agent_t *agent,
+		       nta_incoming_t *irq,
+		       msg_t *msg)
+{
+  return tport_ref(nta_transport_(agent, irq, msg));
+}
+
+nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa)
+{
+  if (!nta_compressor_vtable || !sa)
+    return NULL;
+
+  if (sa->sa_compressor == NULL) {
+    char const * const *l = sa->sa_sigcomp_option_list;
+    nta_compressor_t *comp;
+    comp = nta_compressor_vtable->ncv_init_agent(sa, l);
+    sa->sa_compressor = comp;
+  }
+
+  return sa->sa_compressor;
+}
+
+void nta_agent_deinit_sigcomp(nta_agent_t *sa)
+{
+  if (nta_compressor_vtable && sa && sa->sa_compressor) {
+    nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor);
+    sa->sa_compressor = NULL;
+  }
+}
+
+struct sigcomp_compartment *
+nta_incoming_compartment(nta_incoming_t *irq)
+{
+  if (nta_compressor_vtable && irq && irq->irq_cc) 
+    return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc);
+  else
+    return NULL;
+}
+
+tport_t *
+nta_outgoing_transport(nta_outgoing_t *orq)
+{
+  if (orq)
+    return tport_ref(orq->orq_tport);
+  else
+    return NULL;
+}
+
+
+struct sigcomp_compartment *
+nta_outgoing_compartment(nta_outgoing_t *orq)
+{
+  if (nta_compressor_vtable && orq && orq->orq_cc) 
+    return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc);
+  else
+    return NULL;
+}
+
+
+struct sigcomp_compartment *
+nta_compartment_ref(struct sigcomp_compartment *cc)
+{
+  if (nta_compressor_vtable)
+    return nta_compressor_vtable->ncv_compartment_ref(cc);
+  else
+    return NULL;
+}
+
+void
+nta_compartment_decref(struct sigcomp_compartment **pcc)
+{
+  if (nta_compressor_vtable && pcc && *pcc) 
+    nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL;
+}
+
+
+/** Get compartment for connection, create it when needed. */
+static
+struct sigcomp_compartment *
+agent_compression_compartment(nta_agent_t *sa, 
+			      tport_t *tp,
+			      tp_name_t const *tpn,
+			      int new_if_needed)
+{
+  if (nta_compressor_vtable) {
+    char const * const *l = sa->sa_sigcomp_option_list;
+    return nta_compressor_vtable->
+      ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed);
+  }
+  else
+    return NULL;
+}
+
+static
+int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
+			    struct sigcomp_compartment *cc)
+{
+  if (nta_compressor_vtable) {
+    nta_compressor_t *msc = sa->sa_compressor;
+    tport_compressor_t *sc = NULL;
+    if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0)
+      return 0;
+    return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc);
+  }
+  else
+    return 0;
+}
+
+/** Close compressor (lose its state). */
+static
+int agent_close_compressor(nta_agent_t *sa,
+			   struct sigcomp_compartment *cc)
+{
+  if (nta_compressor_vtable)
+    return nta_compressor_vtable->ncv_close_compressor(sa, cc);
+  return 0;
+}
+
+/** Close both compressor and decompressor */
+static
+int agent_zap_compressor(nta_agent_t *sa,
+			 struct sigcomp_compartment *cc)
+{
+  if (nta_compressor_vtable)
+    return nta_compressor_vtable->ncv_zap_compressor(sa, cc);
+  return 0;
+}
+
+/** Bind transport update callback */
+int nta_agent_bind_tport_update(nta_agent_t *agent,
+				nta_update_magic_t *magic,
+				nta_update_tport_f *callback)
+{
+  if (!agent)
+    return su_seterrno(EFAULT), -1;
+  agent->sa_update_magic = magic;
+  agent->sa_update_tport = callback;
+  return 0;
+}
+
+/** Check if public transport binding is in progress */
+int nta_agent_tport_is_updating(nta_agent_t *agent)
+{
+  return agent && tport_is_updating(agent->sa_tports);
+}
+
+/** Initiate STUN keepalive controller to TPORT */
+int nta_tport_keepalive(nta_outgoing_t *orq)
+{
+  tport_t *tp;
+
+  assert(orq); (void)tp;
+
+  return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request),
+			 TAG_END());
+}
+
+/** Close all transports. @since Experimental in @VERSION_1_12_2. */
+int nta_agent_close_tports(nta_agent_t *agent)
+{
+  int i;
+  outgoing_htable_t *oht = agent->sa_outgoing;
+  incoming_htable_t *iht = agent->sa_incoming;
+
+  for (i = oht->oht_size; i-- > 0;)
+    /* while */ if (oht->oht_table[i]) {
+      nta_outgoing_t *orq = oht->oht_table[i];
+      
+      if (orq->orq_pending && orq->orq_tport)
+	tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, 
+		      NULL, orq, 0);
+      
+      orq->orq_pending = 0;
+      tport_unref(orq->orq_tport), orq->orq_tport = NULL;
+    }  
+  
+  
+  for (i = iht->iht_size; i-- > 0;)
+    /* while */ if (iht->iht_table[i]) {
+      nta_incoming_t *irq = iht->iht_table[i];
+      tport_unref(irq->irq_tport), irq->irq_tport = NULL;
+    }  
+  
+  tport_destroy(agent->sa_tports), agent->sa_tports = NULL;
+  
+  msg_header_free(agent->sa_home, (void *)agent->sa_vias);
+  agent->sa_vias = NULL;
+  msg_header_free(agent->sa_home, (void *)agent->sa_public_vias);
+  agent->sa_public_vias = NULL;
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,572 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nta" - SIP Transactions Module
+ *
+ * @section nta_meta Module Meta Information
+ *
+ * Sofia SIP Transaction API (nta) provides simple interface to the SIP
+ * transaction, transport and message handling. The @b nta interface is
+ * intended for both network and user elements. The public interface for @b
+ * nta is mostly defined in <sofia-sip/nta.h>, but tag parameters are
+ * defined in <sofia-sip/nta_tag.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section nta_objects NTA Objects
+ * 
+ * The NTA deals with a few kinds of objects: @e agent (#nta_agent_t), @e
+ * call @e legs (#nta_leg_t), @e outgoing @e client @e requests
+ * (#nta_outgoing_t), and @e incoming @e server @e requests
+ * (#nta_incoming_t).
+ * 
+ * NTA also uses SIP message objects #msg_t and #sip_t for handling
+ * messages, as defined in <msg.h> and <sip.h>, respectively. The various
+ * SIP headers are also defined in <sip.h>.
+ * 
+ * @section nta_agent_t Creating an NTA Agent
+ * 
+ * Most of the SIP entities, like @e user @e agent or @e proxy, consist of a
+ * SIP server and a SIP client working together.  The NTA provides a simple
+ * interface to SIP server and client with the #nta_agent_t objects.
+ * 
+ * The #nta_agent_t object is created by calling nta_agent_create(). The
+ * object listens for incoming connections, receives messages, parses them,
+ * and pass them to the application. It also takes care of resolving the
+ * domain names and sending the messages.
+ * 
+ * The agent needs a #su_root_t object to schedule its execution. A root
+ * object is used to wait for the network events, schedule the timer
+ * routines, and pass messages asyncronously. A root object can be created
+ * by, e.g., the function su_root_create(). The root object can be have its
+ * own thread, or its main loop can be executed by an application thread by
+ * calling the function su_root_run(). The main loop can be terminated by
+ * calling the function su_root_break().
+ * 
+ * A simple agent could be created as follows:
+ * @code
+ *  registrar->reg_root = su_root_create(NULL);
+ * 
+ *  if (registrar->reg_root) {
+ *    registrar->reg_agent = nta_agent_create(registrar->reg_root,
+ *                                            (url_string_t*)argv[1],
+ *                                            NULL,
+ *                                            NULL,
+ *                                            NULL);
+ * 
+ *    if (registrar->reg_agent) {
+ *      su_root_run(registrar->reg_root);
+ *      nta_agent_destroy(registrar->reg_agent);
+ *    }
+ * 
+ *    su_root_destroy(registrar->reg_root);
+ *  }
+ * @endcode
+ * 
+ * @section nta_server SIP Server Action
+ * 
+ * A SIP server responds to the transactions sent by a client. The SIP
+ * server can operate in two modes; it can be stateless or stateful. This
+ * section describes how a stateful SIP server uses NTA.
+ * 
+ * @subsection nta_leg_t The NTA Legs
+ * 
+ * A leg is required for stateful transaction processing.  A default
+ * leg is created like this:
+ * @code
+ * default_leg = nta_leg_tcreate(agent, process_requests, context,
+ *                               URLTAG_URL(url), 
+ *                               NTATAG_NO_DIALOG(1),
+ *                               TAG_END());
+ * @endcode			       
+ * 
+ * The @a url parameter is used to specify which URLs match to the leg. If
+ * it is given, only requests with requestURI matching are processed by the
+ * leg. The nta_leg_tcreate() is a @ref tagarg "tagarg" function, taking a
+ * tagged argument list as its arguments.
+ * 
+ * Other, ordinary legs can be used to match incoming requests with existing
+ * dialogs, calls or transaction contexts, or to provide outgoing requests
+ * with consistent headers. When a call leg is created, it is provided with
+ * @From and @To headers, and optionally with other headers like
+ * @CallID, @Route, or @CSeq.
+ * 
+ * A new call leg can be created as follows:
+ * @code
+ * call_leg = nta_leg_tcreate(agent,
+ *                            process_call_requests, call_context,
+ *                            SIPTAG_CALL_ID(sip->sip_call_id),
+ *                            SIPTAG_TO(sip->sip_from),   
+ *                            SIPTAG_FROM(sip->sip_to),
+ *                            TAG_END());
+ * @endcode
+ *
+ * @note In the example above, the @From and @To are reversed. This
+ * happens if the headers are taken from an incoming request; the @From
+ * and @To headers change direction when an outgoing request is initiated.
+ *
+ * @note An existing leg can be used in any direction, however.  If the leg
+ * was created for an incoming INVITE transaction, it is also possible to
+ * use the leg for an outgoing BYE transaction.
+ * 
+ * @subsection nta_leg_tag Tagging the Call Leg
+ * 
+ * All the SIP UAS elements are required to tag the @To header in their
+ * final responses. The function nta_leg_tag() adds a tag to the leg's local
+ * address. Local address is used as the @To header in the reply messages,
+ * and as the @From header in the requests. The function nta_incoming_tag()
+ * adds a tag to a incoming transaction. They are usually used in together,
+ * using the tag from initial response to the dialog, too:
+ * e.g.,
+ * @code
+ *   if (!nta_leg_tag(leg, nta_incoming_tag(irq, NULL)))
+ *    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ * @endcode
+ * 
+ * @subsection nta_incoming_t Incoming Transactions
+ * 
+ * An incoming transaction object (nta_incoming_t) is created by NTA for
+ * each unique incoming request message. When NTA has created the incoming
+ * transaction object, it invokes the callback function provided with 
+ * nta_leg_tcreate().  
+ * 
+ * The simplest way to reply to the request is to return a valid status code
+ * from the callback function. Valid status codes are in range of 100 to
+ * 699, inclusive.  If no automatic response is desired, the callback
+ * function should return 0.
+ * 
+ * @note If the status code is final, the incoming transaction object will
+ * be destroyed immediately after the callback function returns. It can not
+ * be used afterwards.
+ * 
+ * @note It is not possible to respond with a 2xx status code to an incoming
+ * INVITE transaction by returning the status code from the callback.
+ * 
+ * Valid return values for callback function are as follows:
+ * @li 0, 100 .. 699 for requests other than INVITE, and
+ * @li 0, 100 .. 199, 300..699 for INVITE requests.
+ * 
+ * All other return codes are interpreted as 500, that is, a @e 500 @e
+ * Internal @e Server @e Error reply message is sent back to the client and
+ * the request is immediately destroyed.
+ * 
+ * The simple registrar/redirect server may have a incoming request callback
+ * as follows:
+ * @code
+ * int process_request(server_t *server,
+ * 	               nta_leg_t *leg,
+ * 	     	       nta_incoming_t *irq,
+ * 	     	       sip_t const *sip)
+ * {
+ *   sip_contact_t *m;
+ * 
+ *   switch (sip->sip_request->rq_method) {
+ *   case sip_method_register:
+ *     return registrar_add(server, leg, reply, sip);
+ * 
+ *   case sip_method_ack:
+ *     return 500;
+ * 
+ *   case sip_method_cancel:
+ *     return 200;
+ * 
+ *   default:
+ *     if (registrar_find(server, sip->sip_request->rq_url, &m) {
+ *       nta_incoming_treply(irq, SIP_302_MOVED_TEMPORARILY, 
+ *                           SIPTAG_CONTACT(m), TAG_END());
+ *       return 302;
+ *     }
+ *     else {
+ *       nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END());
+ *       return 404;
+ *     }
+ *   }
+ * }
+ * @endcode
+ * 
+ * The default reply message will contain the status line with default
+ * phrase, then @Via, @To, @From, @CallID, @CSeq, and @ContentLength headers.
+ * If a more complex response message is required, the application should
+ * respond using the function nta_incoming_treply(): 
+ * @code
+ * nta_incoming_treply(reply, SIP_200_OK, 
+ *                     SIPTAG_CONTACT(contact),
+ *                     SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+ *                     SIPTAG_PAYLOAD(sdp),
+ *                     TAG_END());
+ * @endcode
+ * 
+ * The nta_incoming_treply() is a @ref tagarg "tagarg" function, taking a
+ * tagged argument list as its argument.
+ * 
+ * @note It is possible to send provisional replies (containing 1xx status
+ * codes) several times with nta_incoming_treply(), but only one final
+ * reply (containing status codes 2xx..6xx) can be sent. However, with
+ * INVITE requests, a proxy can send a final 2xx reply even after an error
+ * reply (3xx..6xx).
+ * 
+ * @section nta_100rel Reliable Provisional Responses - "100rel"
+ * 
+ * The <A href="../specs/rfc3262.txt"><B>100rel</B></A> SIP extension
+ * provides reliable provisional responses, provisional responses that are
+ * retransmitted until a special acknowledgement request, PRACK, is
+ * received. In addition the PRACK method, the extension defines two
+ * headers, @RSeq and @RAck, that are used to identify different
+ * response messages. PRACK method is usable on INVITE requests only.
+ * 
+ * Using reliable responses is negotiated using the "100rel" option tag. The
+ * UAC (party sending the INVITE) can include the option tag to the
+ * @Supported or @Require header. In the first case, the UAC just
+ * announces support for reliable responses, in the second case, the UAC
+ * requires that the UAS (party responding to the call) always sends
+ * provisional responses in reliable manner.
+ *
+ * When reliable responses are enabled with NTATAG_REL100() tag, the @b nta
+ * engine automatically inserts the "100rel" option tag to the @Supported
+ * header in the INVITE requests.
+ *
+ * @subsection nta_reliable_t Responding Reliably
+ *
+ * When a UAS wants to respond reliably to a INVITE request, instead of
+ * familiar nta_incoming_treply() or nta_incoming_mreply() it uses the
+ * functions nta_reliable_treply() or nta_reliable_mreply(). These functions
+ * return a pointer to a special object, nta_reliable_t, that is used to
+ * keep track of unacknowledged responses and respond to the the PRACK
+ * acknowledgement request. 
+ * 
+ * Both the functions nta_reliable_treply () and nta_reliable_mreply() take
+ * a callback funtion pointer and an application context pointer as their
+ * arguments. The callback function is similar to the leg callback function. 
+ * The callback is invoked when a corresponding PRACK request is received,
+ * or when there is a timeout.
+ *
+ * The @b nta takes care of assigning a serial number to each reliable
+ * response and resending them if no PRACK request is received. It also
+ * automatically adds the 100rel option tag to the @Require header.
+ *
+ * Also, if a request with 100rel in @Require header is responded with usual
+ * nta_incoming_treply()/nta_incoming_mreply() functions, the @b nta creates
+ * a reliable response object for each provisional response in behalf of
+ * application. As the application can not provide a PRACK callback function
+ * to @b nta, the PRACK requests are not delivered to the application. 
+ *
+ * @subsection early_dialog UAC Receives a Reliable Response
+ *
+ * When a UAC receives a provisional response with a @RSeq header, it is
+ * required to acknowledge it. In order to do that, it must establish an @e
+ * early @e dialog with the UAS. In another view, a reliable response is
+ * used to establish the early dialog. UAC establishes a leg object for the
+ * early dialog by calling nta_leg_tcreate() with the parameters derived
+ * from the response message. 
+ *
+ * @code
+ * int invite_callback(call_t *call,
+ * 		    nta_outgoing_t *orq,
+ * 		    sip_t const *sip)
+ * {
+ *   int status = sip->sip_status->st_status;
+ * 
+ *   if (!call->has_dialog && 
+ *       (status >= 200 || (status > 100 && sip->sip_rseq))) {
+ *     nta_leg_t *early = 
+ *       nta_leg_tcreate(call->nta_agent, mid_dialog_request, call,
+ * 		      SIPTAG_TO(sip->sip_to),
+ * 		      SIPTAG_FROM(sip->sip_from),
+ * 		      SIPTAG_CALL_ID(sip->sip_call_id),
+ * 		      SIPTAG_CSEQ(sip->sip_cseq),
+ * 		      TAG_END());
+ * 
+ *     nta_leg_client_route(early, 
+ * 			 sip->sip_record_route,
+ * 			 sip->sip_contact);
+ * 
+ *     fork = call_fork(call, leg = early);
+ * 
+ *     if (!fork) {
+ *       handle error;
+ *     }
+ *     call = fork;
+ *   }				       
+ * @endcode
+ * 
+ * The original dialog object and client transaction object are used to
+ * process other call forks. For instance, if the early dialog is
+ * established with an announcement server it will never lead to an fully
+ * established call, but an another dialog will be used when the call is
+ * completed.
+ *
+ * @subsection nta_prack Acknowledging Reliable Response
+ *
+ * After an early dialog has been established, acknowledging the reliable
+ * response is trivial. The application can create a PRACK client
+ * transaction object by calling nta_outgoing_prack()
+ *
+ * @section nta_client SIP Client Action
+ * 
+ * A SIP client initiates the transactions. In some cases, a SIP client is
+ * also required to invoke additional transactions, like @b ACK or @b
+ * CANCEL, to finalize the original transaction. This section describes how
+ * a SIP client uses NTA to make transactions.
+ * 
+ * @subsection client_nta_leg_t Creating the Call Leg
+ * 
+ * If the client does not have a suitable call leg, it must create it by
+ * calling the function nta_leg_tcreate():
+ * @code
+ * context->leg = nta_leg_tcreate(agent,
+ *                                callback, context,
+ *                                SIPTAG_CALL_ID(call_id),
+ *                                SIPTAG_FROM(from),
+ *                                SIPTAG_TO(to),
+ *                                TAG_END());
+ * @endcode
+ * 
+ * The @p callback function and @p context pointer are used for incoming
+ * transactions, and they may be @c NULL if no such transactions are
+ * expected.  If the callback is @c NULL, NTA responds to incoming
+ * transactions with status @e 403 @e Forbidden.
+ * 
+ * The @a call_id may be @c NULL or left out. In that case, NTA generates a
+ * new call ID.
+ * 
+ * The @a from and @a to are used in outgoing transactions. They are also
+ * used to select which incoming messages belong to this leg.
+ *
+ * The initial sequence number can be supplied with SIPTAG_CSEQ() (taking a
+ * @CSeq structure as parameter).
+ *
+ * The additional parameters (after @a to) are included in outgoing messages
+ * using this leg. Currently, only @c SIPTAG_ROUTE() is supported.
+ * 
+ * @note Additional tagged parameters are ignored.
+ * 
+ * @subsection nta_outgoing_t Outgoing requests
+ * 
+ * The outgoing request is created and sent by nta_outgoing_tcreate(). It
+ * can be used as follows:
+ * @code
+ * oreq = nta_outgoing_tcreate(leg, response_to_register, reg,
+ *                             proxy_url,
+ *                             SIP_METHOD_REGISTER,
+ *                             registrar_url,
+ *                             SIPTAG_CONTACT(my_contact),
+ *                             TAG_END());
+ * @endcode
+ * 
+ * NTA invokes the callback function response_to_register() each time a
+ * provisional answer is received, and when a final answer is received.
+ * 
+ * @note There may be multiple final answers to the INVITE request.
+ * 
+ * If NTA does not receive answer in timely manner, it will generate a
+ * @e 408 @e Timeout response and hand that back to the application. 
+ * 
+ * @note After a provisional answer to the INVITE request, no timeout will
+ * occur inside NTA.  Application must itself timeout the INVITE
+ * transactions if any answer has been received.
+ * 
+ * The request can be destroyed with NTA function nta_outgoing_destroy().
+ * If no final answer has been received, the request is cancelled when it is
+ * destroyed, too.  The application can also cancel the outgoing request by
+ * calling nta_outgoing_cancel().
+ * 
+ * @subsection nta_ack Acknowledging Answers to INVITE
+ * 
+ * The final answers to the INVITE request must be acknowledged. NTA takes
+ * care of acknowledging automatically the 3xx..6xx answers; the appliction
+ * must explicitly create a separate acknowledge transaction to final 2xx
+ * answers. 
+ * 
+ * The final answer can be acknowledged like this:
+ * @code
+ *  url = sip->sip_contact ? sip->sip_contact->m_url : original_url;
+ *  ack = nta_outgoing_tcreate(leg, NULL, NULL,
+ *                             SIP_METHOD_ACK,
+ *                             (url_string_t*)url,
+ *                             SIPTAG_CSEQ(sip->sip_cseq),
+ *                             SIPTAG_PAYLOAD(sdp),
+ *                             TAG_END());
+ * @endcode
+ * 
+ * @note The ACK transaction should be sent to the @Contact specified in the 
+ * 2xx reply.  
+ * 
+ * <a name="nta_register_f"></a>
+ * @section nta_stateless_callback Stateless Processing of SIP Messages
+ *
+ * When an NTA agent is created, it is possible to provide it with a
+ * stateless callback function. The callback function will be called when an
+ * incoming SIP request or response message does not match with an existing
+ * transaction.
+ *
+ * Before invoking the stateless callback the agent will try to match the
+ * incoming request message with an existing dialog or dialog-less leg (or
+ * default leg). So, if you have created a default leg, all request messages
+ * are processed statefully by it instead of being passed to the stateless
+ * callback function.
+ *
+ * If you want to process request messages with stateless callback and still
+ * use dialog-less legs (for instance, in order to look up domains with
+ * nta_leg_by_uri()), you have to switch over to @em stateless @em mode by
+ * including NTATAG_STATELESS(1) in nta_agent_create() or
+ * nta_agent_set_params() arguments.
+ *
+ * Also, if a response message does not match with an existing client
+ * transaction, the agent will try to use the default outgoing (client)
+ * transaction. If you have created an default outgoing transaction, all
+ * stray response messages are passed to it instead of the stateless
+ * processing function.
+ *
+ * @section nta_message_f_example Stateless Callback Function
+ *
+ * In addition to the message (@a msg) and its
+ * parsed contents (@a sip) the callback function gets the
+ * application-specific context pointer (in this case, @a registrar) and a
+ * pointer to the NTA agent (@a agent) as its arguments:
+ * 
+ * @code 
+ * int process_message(nta_agent_context_t *registrar,
+ * 		       nta_agent_t *agent,
+ * 		       msg_t *msg,
+ * 		       sip_t *sip);
+ * @endcode
+ * 
+ * The application has three functions that can be used to process the
+ * messages in stateless manner:
+ * @li nta_msg_discard() ignores and destroys the message,
+ * @li nta_msg_tsend() forwards a request or response message, and
+ * @li nta_msg_treply() replies to a request message in a stateless way.
+ * 
+ * Additionally, it is possible to process a request message statefully with
+ * nta_incoming_create().
+ *
+ * The functionality of the stateless callback function can vary greatly,
+ * depending the purpose of the application. An user-agent, a proxy or a
+ * registrar/redirect server each have very different callback functions.
+ * 
+ * A simple redirect server could have a message callback function as
+ * follows.
+ *
+ * @code
+ * int process_message(redirect_t *r,
+ * 		       nta_agent_t *agent,
+ * 		       msg_t *msg,
+ * 		       sip_t *sip)
+ * {
+ *   sip_contact_t *m;
+ *   sip_unsupported_t *u;
+ * 
+ * @endcode
+ *
+ * The incoming response messages are simply ignored. The @b ACK requests can
+ * safely be discarded, too, because the redirect server keeps no state.
+ * 
+ * @code
+ *   if (!sip->sip_request || sip->sip_request->rq_method == sip_method_ack) {
+ *     nta_msg_discard(agent, msg); 
+ *     return 0;
+ *   }
+ * @endcode
+ *
+ * Next, the redirect server first checks if processing the request requires
+ * a feature that is not supported by it:
+ * @code
+ *   u = sip_unsupported(msg_home(msg), sip->sip_require, r->r_supported);
+ *   if (u) {
+ *     nta_msg_treply(agent, msg, SIP_420_BAD_EXTENSION, 
+ *                    SIPTAG_SUPPORTED(r->r_supported),
+ *                    SIPTAG_UNSUPPORTED(u),
+ *                    TAG_END());
+ *     return 0;
+ *   }
+ * @endcode
+ *
+ * The @b CANCEL requests terminate a transacton. A stateless redirect
+ * server does not have transactions, so it redirect replies with a @e 481
+ * @e Call @e Leg/Transaction @e Does @e Not @e Exist message:
+ * @code
+ *   if (sip->sip_request->rq_method == sip_method_cancel) {
+ *     nta_msg_treply(agent, msg, SIP_481_NO_TRANSACTION, TAG_END());
+ *     return 0;
+ *   }
+ * @endcode
+ *
+ *  All other requests are answered normally with a 302 response. 
+ *  The location service is
+ *  searched for the request uri, and if a matching address was found, a
+ *  list of active bindings is returned to the client.
+ * @code
+ *   m = location_find(redirect, sip->sip_request->rq_url);
+ *   if (m) {
+ *     nta_msg_treply(agent, msg, SIP_302_MOVED_TEMPORARILY, 
+ *                    SIPTAG_CONTACT(m),
+ *                    TAG_END());
+ *   } 
+ * @endcode
+ *
+ *   Otherwise, @e 404 @e Not @e Found is sent:
+ * @code
+ *   else {
+ *     nta_msg_treply(agent, msg, SIP_404_NOT_FOUND, TAG_END());
+ *   }
+ * 
+ *   return 0;
+ * }
+ * @endcode
+ * 
+ */
+
+/**@page internal NTA Semantics and Internal Data Flows
+ * 
+ * NTA implements simple state machines at transaction level. The figure
+ * below illustrates how a message is processed by NTA.
+ * 
+ * @image html nta-receiving-message.gif "NTA processing incoming messages." 
+ * @image latex nta-receiving-message.eps "NTA processing incoming messages." 
+ * 
+ * 
+ */
+
+int invite_callback(call_t *call,
+		    nta_outgoing_t *orq,
+		    sip_t const *sip)
+{
+  int status = sip->sip_status->st_status;
+  nta_leg_t *leg = call->leg;
+
+  if (!call->has_dialog && 
+      (status >= 200 || (status > 100 && sip->sip_rseq))) {
+    nta_leg_t *early = 
+      nta_leg_tcreate(call->nta_agent, mid_dialog_request, call,
+		      SIPTAG_TO(sip->sip_to),
+		      SIPTAG_FROM(sip->sip_from),
+		      SIPTAG_CALL_ID(sip->sip_call_id),
+		      SIPTAG_CSEQ(sip->sip_cseq),
+		      TAG_END());
+
+    nta_leg_client_route(early, 
+			 sip->sip_record_route,
+			 sip->sip_contact);
+
+    fork = call_fork(call, leg = early);
+
+    if (!fork) {
+      handle error;
+    }
+    call = fork;
+  }				       
+  
+  if (status > 100 && status < 200 && sip->sip_rseq) {
+    nta_outgoing_t *prack = 
+      nta_outgoing_prack(leg, orq, NULL, NULL, NULL,
+			 sip, 
+			 TAG_END());
+    nta_outgoing_destroy(prack);
+    return 0;
+  }
+  
+  ...
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_check.c
+ * @brief Checks for features, MIME types, session timer.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 16:35:05 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/nta.h>
+
+/* ======================================================================== */
+/* Request validation */
+
+/**Check that we support all features which UAC requires.
+ *
+ * The list of supported features is compared with the list of features
+ * required by the UAC. If some features are not listed as supported, return
+ * 420. If @a irq is non-NULL, the 420 response message is sent to the
+ * client along with list of unsupported features in the @Unsupported
+ * header, too.
+ *
+ * @param   irq incoming transaction object (may be NULL).
+ * @param   sip contents of the SIP message
+ * @param supported   list of protocol features supported
+ * @param tag, value, ... optional list of tagged arguments used
+ *                        when responding to the transaction
+ *
+ * @return 0 if successful.
+ * 420 if any of the required features is not supported.
+ */
+int nta_check_required(nta_incoming_t *irq,
+		       sip_t const *sip,
+		       sip_supported_t const *supported,
+		       tag_type_t tag, tag_value_t value, ...)
+{
+  int status = 0;
+
+  if (sip->sip_require) {
+    su_home_t home[SU_HOME_AUTO_SIZE(512)];
+    sip_unsupported_t *us;
+
+    su_home_auto(home, sizeof home);
+
+    us = sip_has_unsupported(home, supported, sip->sip_require);
+
+    if (us) {
+      status = 420;
+      if (irq) {
+	ta_list ta;
+	ta_start(ta, tag, value);
+	nta_incoming_treply(irq,
+			    SIP_420_BAD_EXTENSION,
+			    SIPTAG_UNSUPPORTED(us),
+			    SIPTAG_SUPPORTED(supported),
+			    ta_tags(ta));
+	ta_end(ta);
+      }
+    }
+
+    su_home_deinit(home);
+  }
+
+  return status;
+}
+
+/** Check that UAC supports all the required features.
+ *
+ * The list of required features is compared with the features supported by
+ * the UAC. If some features are not supported, return 421. If @a irq is
+ * non-NULL, the 421 response message is sent to the client, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param require   list of required protocol features
+ * @param tag, value, ... optional list of tagged arguments used
+ *                        when responding to the transaction
+ *
+ * @return 0 if successful.
+ * 421 if any of the required features is not supported.
+ */
+int nta_check_supported(nta_incoming_t *irq,
+			sip_t const *sip,
+			sip_require_t *require,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  if (!sip_has_unsupported(NULL, sip->sip_supported, require))
+    return 0;
+
+  if (irq) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    nta_incoming_treply(irq,
+			SIP_421_EXTENSION_REQUIRED,
+			SIPTAG_REQUIRE(require),
+			ta_tags(ta));
+    ta_end(ta);
+  }
+
+  return 421;
+}
+
+/** Check that we allow the request method.
+ *
+ * The request-method is compared with the list of supported methods in @a
+ * allow. If match is found, 0 is is returned. Otherwise, if the
+ * request-method is well-known, 405 is returned. If the request-method is
+ * unknown, 501 is returned. If @a irq is non-NULL, the 405 or 501 response
+ * message is sent to the client, too.
+ *
+ * @param irq 	incoming transaction object (may be NULL).
+ * @param sip 	contents of the SIP message
+ * @param allow   list of allowed methods
+ * @param tag, value, ...   optional list of tagged arguments used
+ *                          when responding to the transaction
+ *
+ * @return 0 if successful, 405 is request-method is not allowed, 501 if
+ * request-method is unknown.
+ */
+int nta_check_method(nta_incoming_t *irq,
+		     sip_t const *sip,
+		     sip_allow_t const *allow,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  /* Check extensions */
+  sip_method_t method = sip->sip_request->rq_method;
+  char const *name = sip->sip_request->rq_method_name;
+
+  if (sip_is_allowed(allow, method, name))
+    return 0;
+
+  if (irq) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+
+    if (method != sip_method_unknown)
+      /* Well-known method */
+      nta_incoming_treply(irq,
+			  SIP_405_METHOD_NOT_ALLOWED,
+			  SIPTAG_ALLOW(allow),
+			  ta_tags(ta));
+    else
+      /* Completeley unknown method */
+      nta_incoming_treply(irq,
+			  SIP_501_NOT_IMPLEMENTED,
+			  SIPTAG_ALLOW(allow),
+			  ta_tags(ta));
+    ta_end(ta);
+  }
+
+  return method != sip_method_unknown ? 405 : 501;
+}
+
+static char const application_sdp[] = "application/sdp";
+
+/** Check that we understand session content in the request.
+ *
+ * If there is no @ContentDisposition header or the @ContentDisposition
+ * header indicated "session", the message body and content-type is compared
+ * with the acceptable session content-types listed in @a session_accepts.
+ * (typically, @c "application/sdp"). If no match is found, a 415 is
+ * returned. If @a irq is non-NULL, the 415 response message is sent to the
+ * client, too.
+ *
+ * If the @ContentDisposition header indicates something else but "session",
+ * and it does not contain "handling=optional" parameter, a 415 response is
+ * returned, too.
+ *
+ * Also, the @ContentEncoding header is checked. If it is not empty
+ * (indicating no content-encoding), a 415 response is returned, too.
+ *
+ * @param irq 	incoming (server) transaction object (may be NULL).
+ * @param sip 	contents of the SIP message
+ * @param session_accepts   list of acceptable content-types for "session"
+ *                          content disposition
+ * @param tag, value, ...   optional list of tagged arguments used
+ *                          when responding to the transaction
+ *
+ * @return 0 if successful, 415 if content-type is not acceptable.
+ */
+int nta_check_session_content(nta_incoming_t *irq,
+			      sip_t const *sip,
+			      sip_accept_t const *session_accepts,
+			      tag_type_t tag, tag_value_t value, ...)
+{
+  sip_content_type_t const *c = sip->sip_content_type;
+  sip_content_disposition_t const *cd = sip->sip_content_disposition;
+  int acceptable_type = 0, acceptable_encoding = 0;
+
+  if (sip->sip_payload == NULL)
+    return 0;
+
+  if (cd == NULL || strcasecmp(cd->cd_type, "session") == 0) {
+    sip_accept_t const *ab = session_accepts;
+    char const *c_type;
+
+    if (c)
+      c_type = c->c_type;
+    else if (sip->sip_payload->pl_len > 3 &&
+	     strncasecmp(sip->sip_payload->pl_data, "v=0", 3) == 0)
+      /* Missing Content-Type, but it looks like SDP  */
+      c_type = application_sdp;
+    else
+      /* No chance */
+      ab = NULL, c_type = NULL;
+
+    for (; ab; ab = ab->ac_next) {
+      if (strcasecmp(c_type, ab->ac_type) == 0)
+	break;
+    }
+
+    if (ab)
+      acceptable_type = 1;
+  }
+  else if (cd->cd_optional)
+    acceptable_type = 1;
+
+  /* Empty or missing Content-Encoding */
+  if (!sip->sip_content_encoding ||
+      !sip->sip_content_encoding->k_items ||
+      !sip->sip_content_encoding->k_items[0] ||
+      !sip->sip_content_encoding->k_items[0][0])
+    acceptable_encoding = 1;
+
+  if (acceptable_type && acceptable_encoding)
+    return 0;
+
+  if (irq) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    nta_incoming_treply(irq,
+			SIP_415_UNSUPPORTED_MEDIA,
+			SIPTAG_ACCEPT(session_accepts),
+			ta_tags(ta));
+    ta_end(ta);
+  }
+
+  return 415;
+}
+
+
+/**Check that UAC accepts one of listed MIME content-types.
+ *
+ * The list of acceptable content-types are compared with the acceptable
+ * content-types. If match is found, it is returned in @a return_acceptable.
+ * If no match is found, a 406 is returned. If @a irq is non-NULL, the 406
+ * response message is sent to the client, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param acceptable list of acceptable content types
+ * @param return_acceptable optional return-value parameter for
+ *                          matched content-type
+ * @param tag, value, ... optional list of tagged arguments used
+ *                        when responding to the transaction
+ *
+ * @return 406 if no content-type is acceptable by client, 0 if successful.
+ */
+int nta_check_accept(nta_incoming_t *irq,
+		     sip_t const *sip,
+		     sip_accept_t const *acceptable,
+		     sip_accept_t const **return_acceptable,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  sip_accept_t const *ac, *ab;
+  sip_method_t method;
+
+  if (!acceptable)
+    return 0;
+
+  if (sip->sip_request)
+    method = sip->sip_request->rq_method;
+  else /* if (sip->sip_cseq) */
+    method = sip->sip_cseq->cs_method;
+
+  /* Missing Accept header implies support for SDP in INVITE and OPTIONS
+   * (and PRACK and UPDATE?)
+   */
+  if (!sip->sip_accept && (method == sip_method_invite ||
+			   method == sip_method_options ||
+			   method == sip_method_prack ||
+			   method == sip_method_update)) {
+    for (ab = acceptable; ab; ab = ab->ac_next)
+      if (strcasecmp(application_sdp, ab->ac_type) == 0) {
+	if (return_acceptable) *return_acceptable = ab;
+	return 0;
+      }
+  }
+
+  for (ac = sip->sip_accept; ac; ac = ac->ac_next) {
+    if (sip_q_value(ac->ac_q) == 0 || !ac->ac_type)
+      continue;
+
+    for (ab = acceptable; ab; ab = ab->ac_next)
+      if (strcasecmp(ac->ac_type, ab->ac_type) == 0) {
+	if (return_acceptable) *return_acceptable = ab;
+	return 0;
+      }
+  }
+
+  if (irq) {
+    ta_start(ta, tag, value);
+    nta_incoming_treply(irq,
+			SIP_406_NOT_ACCEPTABLE,
+			SIPTAG_ACCEPT(acceptable),
+			ta_tags(ta));
+    ta_end(ta);
+  }
+
+  return 406;
+}
+
+/**Check @SessionExpires header.
+ *
+ * If the proposed session-expiration time is smaller than @MinSE or our
+ * minimal session expiration time, respond with 422 containing our minimal
+ * session expiration time in @MinSE header.
+ *
+ * @param irq 	incoming transaction object (may be NULL).
+ * @param sip 	contents of the SIP message
+ * @param my_min_se   minimal session expiration time in seconds
+ * @param tag, value, ...   optional list of tagged arguments used
+ *                          when responding to the transaction
+ *
+ * @return 422 if session expiration time is too small, 0 when successful.
+ */
+int nta_check_session_expires(nta_incoming_t *irq,
+			      sip_t const *sip,
+			      sip_time_t my_min_se,
+			      tag_type_t tag, tag_value_t value, ...)
+{
+  if ((sip->sip_min_se &&
+       sip->sip_session_expires->x_delta < sip->sip_min_se->min_delta)
+      || sip->sip_session_expires->x_delta < my_min_se) {
+    ta_list ta;
+
+    sip_min_se_t min_se[1];
+
+    sip_min_se_init(min_se)->min_delta = my_min_se;
+
+    if (irq) {
+      ta_start(ta, tag, value);
+      nta_incoming_treply(irq,
+			  SIP_422_SESSION_TIMER_TOO_SMALL,
+			  SIPTAG_MIN_SE(min_se),
+			  ta_tags(ta));
+      ta_end(ta);
+    }
+
+    return 422;
+  }
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,951 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_compat.c 
+ * @brief Compatibility functions for Nokia SIP Transaction API 
+ *
+ * These functions are deprecated and should not be used anymore.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/nta.h"
+#include "nta_compat.h"
+#include "nta_internal.h"
+
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+
+/** Set UAS flag value. 
+ * 
+ * The function nta_agent_set_uas() is used to set or clear User Agent
+ * Server flag.  
+ *
+ * Currently, the flag determines how the agent handles 2XX replies to an
+ * incoming INVITE request.  If flag is set, the agent resends the 2XX final
+ * responses to an INVITE.
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_UA() instead.
+ */
+int nta_agent_set_uas(nta_agent_t *agent, int value)
+{
+  int retval = 1;
+
+  nta_agent_set_params(agent, NTATAG_UA(value != 0), TAG_END());
+  nta_agent_get_params(agent, NTATAG_UA_REF(retval), TAG_END());
+
+  return retval;
+}
+
+/** Set branch key.
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_BRANCH_KEY() instead.
+ */
+msg_param_t nta_agent_set_branch(nta_agent_t *agent, 
+				 msg_param_t branch)
+{
+  msg_param_t retval = "";
+
+  nta_agent_set_params(agent, NTATAG_BRANCH_KEY(branch), TAG_END());
+  nta_agent_get_params(agent, NTATAG_BRANCH_KEY_REF(retval), TAG_END());
+
+  return retval;
+}
+
+/** Set default proxy. 
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_DEFAULT_PROXY() instead.
+ */
+int nta_agent_set_proxy(nta_agent_t *agent, url_string_t const *u)
+{
+  if (agent)
+    nta_agent_set_params(agent, NTATAG_DEFAULT_PROXY(u), TAG_END());
+  return 0;
+}
+
+/**Return default @b Tag.
+ *
+ * The function nta_agent_tag() returns the default @To @b tag
+ * which is used by NTA agent.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The default tag used by NTA agent.
+ *
+ * @deprecated Use nta_agent_newtag() to generate a new, unique tag value.
+ *
+ * @sa NTATAG_TAG_3261().
+ */
+msg_param_t nta_agent_tag(nta_agent_t const *agent)
+{
+  return 
+    (agent && agent->sa_2543_tag)
+    ? agent->sa_2543_tag + strlen("tag=") 
+    : NULL;
+}
+
+/** Reply to the request message. */
+int nta_msg_reply(nta_agent_t *agent,
+		  msg_t *msg,
+		  int status, char const *phrase,
+		  void *extra, ...)
+{
+  int retval;
+  va_list(headers);
+  va_start(headers, extra);
+  retval = nta_msg_vreply(agent, msg, status, phrase, extra, headers);
+  va_end(headers);
+  return retval;
+}
+
+/** Reply to the request message (stdarg version of nta_msg_reply()). */
+int nta_msg_vreply(nta_agent_t *agent,
+		  msg_t *req_msg,
+		  int status, char const *phrase,
+		  void *extra, va_list headers)
+{
+  msg_t *reply = nta_msg_create(agent, 0);
+  sip_t *sip = sip_object(reply);
+
+  if (sip_add_headers(reply, sip, extra, headers) < 0)
+    sip = NULL;
+
+  return nta_msg_mreply(agent, reply, sip,
+			status, phrase, req_msg, TAG_END());
+}
+
+/** Send the message (stdarg version of nta_msg_send()). */
+int nta_msg_vsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+		  void *extra, va_list headers)
+{
+  sip_t *sip = sip_object(msg);
+
+  if (extra && sip_add_headers(msg, sip, extra, headers) < 0) {
+    msg_destroy(msg);
+    return -1;
+  }
+
+  return nta_msg_tsend(agent, msg, u, TAG_END());
+}
+
+/** Send the message. */
+int nta_msg_send(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+		 void *extra, ...)
+{
+  int retval;
+  va_list headers;
+  va_start(headers, extra);
+  retval = nta_msg_vsend(agent, msg, u, extra, headers);
+  va_end(headers);
+
+  return retval;
+}
+
+/**
+ * Create a new leg object for incoming request message.
+ *
+ * @param agent    agent object
+ * @param callback function which is called for each 
+ *                 incoming request belonging to this leg
+ * @param magic    call leg context
+ * @param msg      a request message
+ *
+ * @note The ownership of @a msg will pass back to NTA upon successful call
+ * to the function nta_msg_leg(). In other words, if the call to @a
+ * nta_msg_leg() is successful, the application may not do anything with @a
+ * msg anymore.  Instead of that, NTA will create of a new incoming request
+ * object for the @a msg and eventually return the request to application by
+ * calling the @a callback function.
+ *
+ * @deprecated Use nta_leg_stateful() instead.
+ */
+nta_leg_t *nta_msg_leg(nta_agent_t *agent,
+		       msg_t *msg,
+		       nta_request_f *callback,
+		       nta_leg_magic_t *magic,
+		       ...)
+{
+  nta_leg_t *leg;
+  sip_t *sip = sip_object(msg);
+
+  SU_DEBUG_9(("\tnta_msg_leg(): called\n"));
+
+  assert(msg && sip && sip->sip_request);
+
+  if (!msg || !sip || !sip->sip_request || !callback)
+    return NULL;
+
+  leg = nta_leg_tcreate(agent, callback, magic,
+			SIPTAG_CALL_ID(sip->sip_call_id),
+			SIPTAG_FROM(sip->sip_to), /* local address */
+			SIPTAG_TO(sip->sip_from), /* remote address */
+			TAG_END());
+  if (!leg) 
+    /* xyzzy */;
+  else if (nta_leg_server_route(leg, sip->sip_record_route, 
+				sip->sip_contact) < 0)
+    nta_leg_destroy(leg), leg = NULL;
+  else if (nta_leg_stateful(leg, msg) < 0)
+    nta_leg_destroy(leg), leg = NULL;
+
+  SU_DEBUG_9(("\tnta_msg_leg(): returns %p\n", leg));
+
+  return leg;
+}
+
+static void sm_leg_recv(su_root_magic_t *rm,
+			su_msg_r msg,
+			union sm_arg_u *u);
+
+/** Process msg statefully using the leg. */
+int nta_leg_stateful(nta_leg_t *leg, msg_t *msg)
+{
+  su_msg_r su_msg = SU_MSG_RINITIALIZER;
+  nta_agent_t *agent = leg->leg_agent;
+  su_root_t *root = agent->sa_root;
+  struct leg_recv_s *a;
+
+  /* Create a su message that is passed to NTA network thread */
+  if (su_msg_create(su_msg,
+		    su_root_task(root),
+		    su_root_task(root),
+		    sm_leg_recv, /* Function to call */
+		    sizeof(struct leg_recv_s)) == SU_FAILURE)
+    return -1;
+
+  agent->sa_stats->as_trless_to_tr++;
+
+  a = su_msg_data(su_msg)->a_leg_recv;
+
+  a->leg = leg;
+  a->msg = msg;
+
+  a->tport = tport_incref(tport_delivered_by(agent->sa_tports, msg));
+
+  return su_msg_send(su_msg);
+}
+
+/** @internal Delayed leg_recv(). */
+static
+void sm_leg_recv(su_root_magic_t *rm,
+		 su_msg_r msg,
+		 union sm_arg_u *u)
+{
+  struct leg_recv_s *a = u->a_leg_recv;
+  leg_recv(a->leg, a->msg, sip_object(a->msg), a->tport);
+  tport_decref(&a->tport);
+}
+
+/**Create a new leg object
+ *
+ * @param agent    agent object
+ * @param callback function which is called for each
+ *                 incoming request belonging to this leg
+ * @param magic    call leg context
+ * @param i        optional @CallID
+ *                 (if @c NULL, an ID generated by @b NTA is used)
+ * @param from     optional @From (local address)
+ * @param to       optional @To (remote address)
+ * @param extra, ... optional extra headers, terminated with a @c NULL
+ *
+ * @deprecated Use nta_leg_tcreate() instead.
+ */
+nta_leg_t *nta_leg_create(nta_agent_t *agent,
+			  nta_request_f *callback,
+			  nta_leg_magic_t *magic,
+			  sip_call_id_t const *i,
+			  sip_from_t const *from,
+			  sip_to_t const *to,
+			  void const *extra, ...)
+{
+  nta_leg_t *leg;
+  va_list headers;
+  va_start(headers, extra);
+  leg = nta_leg_vcreate(agent, callback, magic,
+			i, from, to,
+			extra, headers);
+  va_end(headers);
+  return leg;
+}
+
+/**
+ * Create a new leg object
+ *
+ * @param agent    agent object
+ * @param callback function which is called for each
+ *                 incoming request belonging to this leg
+ * @param magic    call leg context
+ * @param i        optional @CallID
+ *                 (if @c NULL, an ID generated by @b NTA is used)
+ * @param from     optional @From (local address)
+ * @param to       optional @To (remote address)
+ * @param extra    optional extra header
+ * @param headers  va_list of optional extra headers
+ *
+ * @deprecated Use nta_leg_tcreate() instead.
+ */
+nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,
+			   nta_request_f *callback,
+			   nta_leg_magic_t *magic,
+			   sip_call_id_t const *i,
+			   sip_from_t const *from,
+			   sip_to_t const *to,
+			   void const *extra, va_list headers)
+{
+  sip_route_t const *route = NULL;
+  sip_cseq_t const *cseq = NULL;
+
+  for (; extra ; extra = va_arg(headers, void *)) {
+    sip_header_t const *h = (sip_header_t const *)extra;
+
+    if (h == SIP_NONE)
+      continue;
+    else if (sip_call_id_p(h)) {
+      if (i == NULL) i = h->sh_call_id;
+    }
+    else if (sip_from_p(h)) {
+      if (from == NULL) from = h->sh_from;
+    }
+    else if (sip_to_p(h)) {
+      if (to == NULL) to = h->sh_to;
+    }
+    else if (sip_route_p(h)) {
+      route = h->sh_route;
+    }
+    else if (sip_cseq_p(h)) {
+      cseq = h->sh_cseq;
+    }
+    else {
+      SU_DEBUG_3(("nta_leg_create: extra header %s\n", 
+		  sip_header_name(h, 0)));
+    }
+  }
+
+  return nta_leg_tcreate(agent, callback, magic,
+			 NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id),
+			 TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)),
+			 TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)),
+			 TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)),
+			 SIPTAG_ROUTE(route),
+			 SIPTAG_CSEQ(cseq),
+			 TAG_END());
+}
+
+/**Mark leg as branchable.
+ *
+ * This function does currently absolutely nothing.
+ * 
+ * @param leg leg to be marked branchable.
+ *
+ * @note Currently, all legs @b are branchable.
+ *
+ * @deprecated Do not use.
+ */
+int nta_leg_branch(nta_leg_t *leg)
+{
+  return 0;
+}
+
+/** Add route from final response 
+ *
+ * @deprecated Use nta_leg_client_route().
+ */
+int nta_leg_route(nta_leg_t *leg, 
+		   sip_record_route_t const *route, 
+		   sip_contact_t const *contact,
+		   url_string_t const *url)
+{
+  return nta_leg_client_route(leg, route, contact);
+}
+
+#if 0
+/**Get response message.
+ *
+ * The function nta_incoming_getresponse() retrieves a copy of the latest
+ * outgoing response message.  The response message is copied; the original
+ * copy is kept by the transaction.
+ *
+ * @param irq incoming (server) transaction handle
+ *
+ * @retval
+ * A pointer to the copy of the response message is returned, or NULL if an
+ * error occurred.
+ */
+msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
+{
+  if (irq && irq->irq_response) {
+    msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+    sip_t *sip = sip_object(msg);
+
+    msg_clone(msg, irq->irq_response);
+
+    /* Copy the SIP headers from the old message */
+    if (msg_copy_all(msg, sip, sip_object(irq->irq_response)) >= 0)
+      return msg;
+
+    msg_destroy(msg);
+  }
+
+  return NULL;
+}
+
+/**Get request message.
+ *
+ * The function nta_outgoing_getrequest() retrieves the request message sent
+ * to the network. The request message is copied; the original copy is kept
+ * by the transaction.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to the copy of the request message is returned, or NULL if an
+ * error occurred.
+ */
+msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
+{
+  if (orq && orq->orq_request) {
+    msg_t *msg = nta_msg_create(orq->orq_agent, 0);
+    sip_t *sip = sip_object(msg);
+
+    msg_clone(msg, orq->orq_request);
+
+    /* Copy the SIP headers from the old message */
+    if (sip_copy_all(msg, sip, sip_object(orq->orq_request)) >= 0)
+      return msg;
+
+    msg_destroy(msg);
+  }
+
+  return NULL;
+}
+
+/**Get latest response message.
+ *
+ * The function nta_outgoing_getresponse() retrieves the latest incoming
+ * response message to the outgoing transaction.  Note that the message is
+ * not copied, but removed from the transaction.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to response message is returned, or NULL if no response message
+ * has been received or the response message has already been retrieved.
+ */
+msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
+{
+  msg_t *msg = NULL;
+
+  if (orq && orq->orq_response)
+    msg = orq->orq_response, orq->orq_response = NULL;
+
+  return msg;
+}
+#endif
+
+/** Create an outgoing request belonging to the leg.
+ *
+ * The function nta_outgoing_create() creates an outgoing transaction and
+ * sends the request.  The request is sent to the @a route_url (if
+ * non-NULL), default proxy (as specified by nta_agent_set_proxy()), or to
+ * the address specified by @a request_uri.  In the latest case, all the
+ * tranport parameters are stripped from the request_uri.  If no @a
+ * request_uri is specified, it is taken from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @c callback
+ * function.  
+ *
+ * @param leg         call leg object
+ * @param callback    callback function (may be @c NULL)
+ * @param magic       application context pointer
+ * @param route_url   URL used to route transaction requests
+ * @param method      method type
+ * @param name        method name 
+ * @param request_uri Request-URI
+ * @param extra, ...  list of extra headers
+ *
+ * @return
+ * The function nta_outgoing_create() returns a pointer to newly created
+ * outgoing transaction object if successful, and NULL otherwise.
+ *
+ * @deprecated
+ * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_create(nta_leg_t *leg,
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    url_string_t const *route_url,
+				    sip_method_t method,
+				    char const *name,
+				    url_string_t const *request_uri,
+				    void const *extra, ...)
+{
+  nta_outgoing_t *orq;
+  va_list headers;
+
+  va_start(headers, extra);
+  orq = nta_outgoing_vcreate(leg, callback, magic,
+			     route_url, method, name, request_uri,
+			     extra, headers);
+  va_end(headers);
+  return orq;
+}
+
+/**Create a request belonging to the leg
+ * (stdarg version of nta_outgoing_create()). 
+ *
+ * @deprecated
+ * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     sip_method_t method,
+				     char const *name,
+				     url_string_t const *request_uri,
+				     void const *extra,
+				     va_list headers)
+{
+  nta_agent_t *agent = leg->leg_agent;
+  msg_t *msg = nta_msg_create(agent, 0);
+  sip_t *sip = sip_object(msg);
+  nta_outgoing_t *orq;
+
+  if (extra && 
+      sip_add_headers(msg, sip, extra, headers) < 0)
+    orq = NULL;
+  else if (route_url && leg->leg_route && !sip->sip_route &&
+	   sip_add_dup(msg, sip, (sip_header_t *)leg->leg_route) < 0)
+    orq = NULL;
+  else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
+    orq = NULL;
+  else
+    orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);
+
+  if (!orq)
+    msg_destroy(msg);
+
+  return orq;
+}
+
+/**Forward a request.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent,
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    url_string_t const *route_url,
+				    msg_t *parent,
+				    tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  msg_t *msg;
+  nta_outgoing_t *orq = NULL;
+
+  if (parent == NULL)
+    return NULL;
+  if ((msg = nta_msg_create(agent, 0)) == NULL)
+    return NULL;
+
+  ta_start(ta, tag, value);
+
+  msg_clone(msg, parent);
+
+  if (parent && sip_copy_all(msg, sip_object(msg), sip_object(parent)) < 0)
+    ;
+  else if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) < 0)
+    ;
+  else
+    orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); 
+
+  ta_end(ta);
+
+  if (!orq)
+    msg_destroy(msg);
+
+  return orq;
+  
+}
+
+/** Forward a request belonging to the leg.
+ * 
+ * The function nta_outgoing_forward() will create an outgoing transaction
+ * based on the incoming transaction.  The forwarded message is specified by
+ * @a isip parameter.  The caller rewrite the URL by giving non-NULL @a
+ * request_url. 
+ *
+ * The request is sent to the server specified by @a route_url if it is
+ * non-NULL.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_forward(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     url_string_t const *request_uri,
+				     nta_incoming_t *ireq,
+				     sip_t const *isip,
+				     void const *extra, ...)
+{
+  nta_outgoing_t *orq;
+  va_list headers;
+
+  va_start(headers, extra);
+  orq = nta_outgoing_vforward(leg, callback, magic, route_url, request_uri,
+			      ireq, isip, extra, headers);
+  va_end(headers);
+  return orq;
+}
+
+/**Forward a request belonging to the leg 
+ * (stdarg version of nta_outgoing_forward()).
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
+				      nta_response_f *callback,
+				      nta_outgoing_magic_t *magic,
+				      url_string_t const *route_url,
+				      url_string_t const *request_uri,
+				      nta_incoming_t const *ireq,
+				      sip_t const *isip,
+				      void const *extra,
+				      va_list headers)
+{
+  nta_agent_t *agent = leg->leg_agent;
+  nta_outgoing_t *orq = NULL;
+  msg_t *msg, *imsg;
+  sip_t *sip;
+  su_home_t *home;
+
+  assert(leg); assert(ireq); 
+
+  if (isip == NULL) 
+    imsg = ireq->irq_request, isip = sip_object(ireq->irq_request);
+  else if (isip == sip_object(ireq->irq_request))
+    imsg = ireq->irq_request;
+  else if (isip == sip_object(ireq->irq_request2))
+    imsg = ireq->irq_request2;
+  else {
+    SU_DEBUG_3(("nta_outgoing_forward: invalid arguments\n"));
+    return NULL;
+  }
+
+  assert(isip); assert(isip->sip_request);
+
+  if (!route_url)
+    route_url = (url_string_t *)agent->sa_default_proxy;
+
+  if (!(msg = nta_msg_create(agent, 0)))
+    return NULL;
+
+  msg_clone(msg, imsg);
+
+  sip = sip_object(msg); 
+  home = msg_home(msg);
+  
+  /* Copy the SIP headers from the @c imsg message */
+  do {
+    if (sip_copy_all(msg, sip, isip) < 0)
+      break;
+    if (sip_add_headers(msg, sip, extra, headers) < 0)
+      break;
+    if (!route_url && sip->sip_route) {
+      request_uri = (url_string_t *)sip->sip_route->r_url;
+      if (!sip_route_remove(msg, sip))
+	break;
+    }
+    if (request_uri) {
+      sip_request_t *rq;
+
+      rq = sip_request_create(home,
+			      sip->sip_request->rq_method, 
+			      sip->sip_request->rq_method_name, 
+			      request_uri,
+			      NULL);
+
+      if (!rq || sip_header_insert(msg, sip, (sip_header_t *)rq) < 0)
+	break;
+    }
+    
+    if ((orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg)))
+      return orq;
+
+  } while (0);
+
+  msg_destroy(msg);
+  return NULL;
+}
+
+
+/** Fork an outgoing request toward another destination.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_fork(nta_outgoing_t *old_orq,
+				  nta_response_f *callback,
+				  nta_outgoing_magic_t *magic,
+				  url_string_t const *route_url,
+				  url_string_t const *request_uri,
+				  void const *extra, ...)
+{
+  nta_outgoing_t *orq;
+  va_list headers;
+
+  va_start(headers, extra);
+  orq = nta_outgoing_vfork(old_orq, callback, magic, route_url,
+			   request_uri, extra, headers);
+  va_end(headers);
+  return orq;
+}
+
+/** Fork an outgoing request (stdarg version of nta_outgoing_fork()). 
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq,
+				   nta_response_f *callback,
+				   nta_outgoing_magic_t *magic,
+				   url_string_t const *route_url,
+				   url_string_t const *request_uri,
+				   void const *extra,
+				   va_list headers)
+{
+  nta_outgoing_t * orq;
+  msg_t *msg, *imsg;
+  sip_t *sip, *isip;
+  nta_agent_t *agent;
+  su_home_t *home;
+
+  if (!old_orq || !old_orq->orq_request || !request_uri)
+    return NULL;
+
+  agent = old_orq->orq_agent;
+  imsg = old_orq->orq_request;
+  
+  if (!(msg = nta_msg_create(agent, 0)))
+    return NULL;
+
+  msg_clone(msg, imsg);
+
+  sip = sip_object(msg); isip = sip_object(imsg);
+  home = msg_home(msg);
+
+  /* Copy the SIP headers from the imsg message */
+  if (sip_copy_all(msg, sip, isip) < 0)
+    orq = NULL;
+  else if (sip_via_remove(msg, sip) == NULL)
+    orq = NULL;
+  else if (sip_add_dup(msg, sip_object(msg), 
+		       (sip_header_t const *)
+		       sip_request_create(home,
+					  sip->sip_request->rq_method, 
+					  sip->sip_request->rq_method_name, 
+					  request_uri,
+					  NULL)) < 0)
+    orq = NULL;
+  else if (sip_add_headers(msg, sip, extra, headers) < 0)
+    orq = NULL;
+  else
+    orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);
+
+  if (!orq)
+    msg_destroy(msg);
+
+  return orq;
+}
+
+/**
+ * Reply to an incoming transaction request.
+ *
+ * This function creates and sends a response message to an incoming request.
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ * 
+ * @param irq    incoming request
+ * @param status status code
+ * @param phrase status phrase (may be NULL if status code is well-known)
+ * @param extra, ...    optional additional headers terminated by NULL
+ *
+ * @deprecated
+ * Use nta_incoming_treply() instead.
+ */
+int nta_incoming_reply(nta_incoming_t *irq,
+		       int status,
+		       char const *phrase,
+		       void const *extra,
+		       ...)
+{
+  int retval;
+  va_list headers;
+  va_start(headers, extra);
+  retval = nta_incoming_vreply(irq, status, phrase, extra, headers);
+  va_end(headers);
+  return retval;
+}
+
+/**Reply to an incoming transaction request (stdarg version).
+ *
+ * @deprecated
+ * Use nta_incoming_treply() instead.
+ */
+int nta_incoming_vreply(nta_incoming_t *irq,
+			int status,
+			char const *phrase,
+			void const *extra, va_list headers)
+{
+  if (irq->irq_status < 200 || status < 200 || 
+      (irq->irq_method == sip_method_invite && status < 300)) {
+    msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+    sip_t *sip = sip_object(msg);
+
+    if (!msg) 
+      return -1;
+    else if (nta_msg_response_complete(msg, irq, status, phrase) < 0) 
+      msg_destroy(msg);      
+    else if (sip_add_headers(msg, sip, extra, headers) < 0 )
+      msg_destroy(msg);
+    else if (sip_message_complete(msg) < 0)
+      msg_destroy(msg);      
+    else if (nta_incoming_mreply(irq, msg) < 0)
+      msg_destroy(msg);
+    else
+      return 0;
+  }
+
+  return -1;
+}
+
+
+/**
+ * Forward a response to incoming transaction.
+ *
+ * This function forwards a response message from outgoing request to an
+ * incoming request.  It copies the message save the first via field, and
+ * send the response message to the address specified in the second via.
+ *
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ *
+ * @param irq    incoming request
+ * @param orq
+ * @param sip    message structure for outgoing transaction
+ * @param extra, ...  list of optional additional headers terminated by NULL
+ *
+ * @bug Adding extra headers is unimplemented. 
+ *
+ * @deprecated Use nta_incoming_mreply() instead.
+ */
+int nta_incoming_forward(nta_incoming_t *irq,
+			 nta_outgoing_t *orq,
+			 sip_t const *sip,
+			 void const *extra, ...)
+{
+  msg_t *msg = nta_outgoing_response(orq);
+  int status;
+
+  if (irq == NULL || sip == NULL || msg == NULL || sip != sip_object(msg))
+    return -1;
+
+  status = sip->sip_status->st_status;
+
+  sip_via_remove(msg, (sip_t *)sip);  /* Remove topmost via */
+
+  if (sip_message_complete(msg) < 0)
+    msg_destroy(msg);      
+  if (nta_incoming_mreply(irq, msg) < 0)
+    msg_destroy(msg);
+  else
+    return 0;
+
+  return -1;
+}
+
+/** Send a BYE to an INVITE.
+ *
+ * @deprecated
+ * This function should used only if application requires 
+ * RFC2543 compatibility.
+ */
+nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq,
+				  nta_response_f *callback,
+				  nta_outgoing_magic_t *magic,
+				  url_string_t const *route_url,
+				  tag_type_t tag, tag_value_t value, ...)
+{
+  msg_t *msg;
+  sip_t *sip, *inv;
+  sip_cseq_t *cs;
+  sip_request_t *rq;
+  su_home_t *home;
+  url_string_t *url;
+
+  if (orq == NULL || orq->orq_method != sip_method_invite)
+    return NULL;
+
+  inv = sip_object(orq->orq_request);
+  msg = nta_msg_create(orq->orq_agent, 0);
+  home = msg_home(msg);
+  sip = sip_object(msg);
+
+  if (inv == NULL || sip == NULL) {
+    msg_destroy(msg);
+    return NULL;
+  }
+
+  sip_add_tl(msg, sip,
+	     SIPTAG_TO(inv->sip_to),
+	     SIPTAG_FROM(inv->sip_from),
+	     SIPTAG_CALL_ID(inv->sip_call_id),
+	     SIPTAG_ROUTE(inv->sip_route),
+	     TAG_END());
+
+  url = (url_string_t *)inv->sip_request->rq_url;
+
+  rq = sip_request_create(home, SIP_METHOD_BYE, url, NULL);
+  sip_header_insert(msg, sip, (sip_header_t*)rq);
+
+  cs = sip_cseq_create(home, inv->sip_cseq->cs_seq + 1, SIP_METHOD_BYE);
+  sip_header_insert(msg, sip, (sip_header_t*)cs);
+
+  return nta_outgoing_mcreate(orq->orq_agent, callback, magic, 
+			      route_url, msg);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_COMPAT_H
+/** Defined when <nta_compat.h> has been included. */
+#define NTA_COMPAT_H;
+
+/**@file nta_compat.h   
+ * @brief Deprecated NTA functions and types.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep  4 15:54:57 2001 ppessi
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+typedef msg_t nta_msg_t;
+
+sip_param_t nta_agent_set_branch(nta_agent_t *agent, sip_param_t branch);
+
+sip_param_t nta_agent_tag(nta_agent_t const *a);
+
+int nta_agent_set_uas(nta_agent_t *agent, int value);
+
+int nta_agent_set_proxy(nta_agent_t *agent, url_string_t const *u);
+
+int nta_msg_send(nta_agent_t *agent, msg_t *msg, 
+		 url_string_t const *route_url,
+		 void *extra, ...);
+
+int nta_msg_reply(nta_agent_t *self, 
+		  msg_t *request_msg,
+		  int status, char const *phrase,
+		  void *extra, ...);
+
+nta_leg_t *nta_msg_leg(nta_agent_t *agent,  
+		       msg_t *msg,
+		       nta_request_f *req_callback,
+		       nta_leg_magic_t *magic, ...);
+
+nta_leg_t *nta_leg_create(nta_agent_t *agent,  
+			  nta_request_f *req_callback,
+			  nta_leg_magic_t *magic,
+			  sip_call_id_t const *i,
+			  sip_from_t const *from,
+			  sip_to_t const *to,
+			  void const *extra, ...);
+
+int nta_leg_branch(nta_leg_t *leg);
+
+int nta_leg_route(nta_leg_t *, sip_record_route_t const *, 
+		  sip_contact_t const *, url_string_t const *);
+
+int nta_incoming_reply(nta_incoming_t *irq, 
+		       int status, char const *phrase, 
+		       void const *extra, ...);
+
+int nta_incoming_forward(nta_incoming_t *ireq,
+			 nta_outgoing_t *request,
+			 sip_t const *sip,
+			 void const *extra, ...);
+
+int nta_incoming_tforward(nta_incoming_t *ireq,
+			  nta_outgoing_t *request,
+			  sip_t const *sip,
+			  tag_type_t tag, tag_value_t value, ...);
+
+nta_outgoing_t *nta_outgoing_create(nta_leg_t *leg, 
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    url_string_t const *route_url, 
+				    sip_method_t method, 
+				    char const *method_name,
+				    url_string_t const *req_url,
+				    void const *extra_headers, ...);
+
+/** Create a new outgoing request with old contents, but new url */
+nta_outgoing_t *nta_outgoing_fork(nta_outgoing_t *,
+				  nta_response_f *callback,
+				  nta_outgoing_magic_t *magic,
+				  url_string_t const *route_url,
+				  url_string_t const *request_url,
+				  void const *extra, ...);
+
+nta_outgoing_t *nta_outgoing_forward(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     url_string_t const *request_url,
+				     nta_incoming_t *ireq,
+				     sip_t const *sip,
+				     void const *extra, ...);
+
+nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent,
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    url_string_t const *route_url,
+				    msg_t *parent,
+				    tag_type_t tag, tag_value_t value, ...);
+
+nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq,
+				  nta_response_f *callback,
+				  nta_outgoing_magic_t *magic,
+				  url_string_t const *route_url,
+				  tag_type_t tag, tag_value_t value, ...);
+
+/** Process message statefully using @a leg. */
+int nta_leg_stateful(nta_leg_t *leg, msg_t *msg);
+
+typedef nta_ack_cancel_f nta_incoming_f;
+
+#define nta_incoming_request  nta_incoming_getrequest
+#define nta_outgoing_response nta_outgoing_getresponse 
+
+#define nta_get_params nta_agent_get_params
+#define nta_set_params nta_agent_set_params
+
+int nta_msg_vsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+		  void *extra, va_list headers);
+
+int nta_msg_vreply(nta_agent_t *self, 
+		   msg_t *msg,
+		   int status, char const *phrase,
+		   void *extra, va_list headers);
+
+nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,  
+			   nta_request_f *req_callback,
+			   nta_leg_magic_t *magic,
+			   sip_call_id_t const *i,
+			   sip_from_t const *from,
+			   sip_to_t const *to,
+			   void const *extra, va_list header);
+
+int nta_incoming_vreply(nta_incoming_t *irq, 
+			int status, char const *phrase, 
+			void const *extra, va_list header);
+
+int nta_incoming_vforward(nta_incoming_t *ireq,
+			  nta_outgoing_t *request,
+			  sip_t const *sip,
+			  void const *extra, va_list header);
+
+nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     sip_method_t method,
+				     char const *method_name,
+				     url_string_t const *request_uri,
+				     void const *extra,
+				     va_list headers);
+
+nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
+				      nta_response_f *callback,
+				      nta_outgoing_magic_t *magic,
+				      url_string_t const *route_url,
+				      url_string_t const *request_url,
+				      nta_incoming_t const *ireq,
+				      sip_t const *isip,
+				      void const *extra,
+				      va_list headers);
+nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq,
+				   nta_response_f *callback,
+				   nta_outgoing_magic_t *magic,
+				   url_string_t const *route_url,
+				   url_string_t const *request_url,
+				   void const *extra, va_list headers);
+
+enum {
+  NTA_RETRY_TIMER_INI = NTA_SIP_T1,
+  NTA_RETRY_TIMER_MAX = NTA_SIP_T2,
+  NTA_LINGER_TIMER = NTA_SIP_T4,
+  NTA_RETRY_COUNT = 11,
+  NTA_INVITE_COUNT = 7,
+};
+
+#define NTATAG_RETRY_TIMER_INI     NTATAG_SIP_T1
+#define NTATAG_RETRY_TIMER_INI_REF NTATAG_SIP_T1_REF
+#define NTATAG_RETRY_TIMER_MAX     NTATAG_SIP_T2
+#define NTATAG_RETRY_TIMER_MAX_REF NTATAG_SIP_T2_REF
+#define NTATAG_LINGER_TIMER        NTATAG_SIP_T4
+#define NTATAG_LINGER_TIMER_REF    NTATAG_SIP_T4_REF
+
+#define NTATAG_RETRY_COUNT(x)     tag_skip, (tag_value_t)0
+#define NTATAG_RETRY_COUNT_REF(x) tag_skip, (tag_value_t)0
+
+#define NTATAG_INVITE_COUNT(x)     tag_skip, (tag_value_t)0
+#define NTATAG_INVITE_COUNT_REF(x) tag_skip, (tag_value_t)0
+
+#endif /* !defined(NTA_COMPAT_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,587 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_INTERNAL_H
+/** Defined when <nta_internal.h> has been included. */
+#define NTA_INTERNAL_H 
+
+/**@IFILE nta_internal.h
+ * @brief Internals of NTA objects.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 18 09:18:32 2000 ppessi
+ */
+
+/* Resolver context type */
+#define SRES_CONTEXT_T    nta_outgoing_t
+
+/* We are customer of tport_t */
+#define TP_AGENT_T        nta_agent_t
+#define TP_MAGIC_T        sip_via_t 
+#define TP_CLIENT_T       nta_outgoing_t
+
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/tport.h>
+
+#if HAVE_SOFIA_SRESOLV
+#include <sofia-sip/sresolv.h>
+#endif
+
+#include <sofia-sip/htable.h>
+
+#if HAVE_SMIME
+#include "smimec.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** A sip_flag telling that this message is internally generated. */
+#define NTA_INTERNAL_MSG (1<<15)
+
+/** Resolving order */
+enum nta_res_order_e
+{
+  nta_res_ip6_ip4,
+  nta_res_ip4_ip6,
+  nta_res_ip6_only,
+  nta_res_ip4_only
+};
+
+HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
+HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
+HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
+
+typedef struct outgoing_queue_t {
+  nta_outgoing_t **q_tail;
+  nta_outgoing_t  *q_head;
+  size_t           q_length;
+  unsigned         q_timeout;
+} outgoing_queue_t;
+
+typedef struct incoming_queue_t {
+  nta_incoming_t **q_tail;
+  nta_incoming_t  *q_head;
+  size_t           q_length;
+  unsigned         q_timeout;
+} incoming_queue_t;
+
+typedef struct nta_compressor nta_compressor_t;
+
+struct nta_agent_s
+{
+  su_home_t             sa_home[1];
+  su_root_t            *sa_root;
+  su_timer_t           *sa_timer;
+  nta_agent_magic_t    *sa_magic;
+  nta_message_f        *sa_callback;     
+
+  uint32_t              sa_nw_updates; /* Shall we enable network detector? */
+
+  nta_update_magic_t   *sa_update_magic;
+  nta_update_tport_f   *sa_update_tport;
+
+  su_time_t             sa_now;	/**< Timestamp in microsecond resolution. */
+  uint32_t              sa_millisec; /**< Timestamp in milliseconds resolution. */
+
+  uint32_t              sa_flags;	/**< Message flags */
+  msg_mclass_t         *sa_mclass;
+
+  sip_contact_t        *sa_contact;
+  sip_via_t            *sa_vias;   /**< @Via headers for all transports */
+  sip_via_t            *sa_public_vias;   /**< @Vias for public transports */
+  sip_contact_t        *sa_aliases;/**< List of aliases for agent */
+
+  uint64_t              sa_branch; /**< Counter for generating branch parameter */
+  uint64_t              sa_tags;   /**< Counter for generating tag parameters */
+
+  char const           *sa_2543_tag; /**< Fixed tag added to @To when responding */
+
+#if HAVE_SOFIA_SRESOLV
+  sres_resolver_t      *sa_resolver; /**< DNS resolver */
+#endif
+
+  tport_t              *sa_tports;
+  
+  /* Default outbound proxy */
+  url_t                *sa_default_proxy;
+
+#if HAVE_SMIME
+  sm_object_t          *sa_smime;
+#else
+  void                 *sa_smime;
+#endif
+
+
+  /** Request error mask */
+  unsigned              sa_bad_req_mask;
+  /** Response error mask */
+  unsigned              sa_bad_resp_mask;
+
+  /** Maximum size of incoming messages */
+  size_t                sa_maxsize;
+  
+  /** Maximum size of outgoing UDP requests */
+  size_t                sa_udp_mtu;
+
+  /** SIP T1 - initial interval of retransmissions (500 ms) */
+  unsigned              sa_t1;
+  /** SIP T2 - maximum interval of retransmissions (4000 ms) */
+  unsigned              sa_t2;
+  /** SIP T4 - clear message time (5000 ms) */
+  unsigned              sa_t4;
+
+  /** SIP T1X64 - transaction lifetime (32 s) */
+  unsigned              sa_t1x64;
+
+  /** Progress timer - interval between provisional responses sent */
+  unsigned              sa_progress;
+
+  /** Blacklisting period */
+  unsigned              sa_blacklist;
+
+  /** NTA is used to test packet drop */
+  unsigned              sa_drop_prob : 10;
+  /** NTA is acting as an User Agent server */
+  unsigned              sa_is_a_uas : 1;
+  /** Process requests outside dialog statelessly */
+  unsigned              sa_is_stateless : 1;
+  /** Let application provide @Via headers */
+  unsigned              sa_user_via:1;
+  /** Respond with "100 Trying" if application has not responded. */
+  unsigned              sa_extra_100:1;
+  /** The "100 Trying" provisional answers are passed to the application */
+  unsigned              sa_pass_100:1;
+  /** If true, a "408 Request Timeout" message is generated when outgoing
+      request expires. */
+  unsigned              sa_timeout_408:1;
+  /** If true, a "408 Request Timeout" responses are passed to client. */
+  unsigned              sa_pass_408:1;
+  /** If true, a "482 Request Merged" response is sent to merged requests. */
+  unsigned              sa_merge_482 : 1;
+  /** If true, send a CANCEL to an INVITE without an provisional response. */
+  unsigned              sa_cancel_2543 : 1;
+  /** If true, reply with 487 response when a CANCEL is received. */
+  unsigned              sa_cancel_487 : 1;
+  /** If true, use unique tags. */
+  unsigned              sa_tag_3261 : 1;
+  /** If true, include 100rel in INVITE requests. */
+  unsigned              sa_invite_100rel : 1;
+  /** If true, insert @Timestamp in requests. */
+  unsigned              sa_timestamp : 1;
+
+  /** If true, transports support IPv4. */
+  unsigned              sa_tport_ip4 : 1;
+  /** If true, transports support IPv6. */
+  unsigned              sa_tport_ip6 : 1;
+  /** If true, transports support UDP. */
+  unsigned              sa_tport_udp : 1;
+  /** If true, transports support TCP. */
+  unsigned              sa_tport_tcp : 1;
+  /** If true, transports support SCTP. */
+  unsigned              sa_tport_sctp : 1;
+  /** If true, transports support TLS. */
+  unsigned              sa_tport_tls : 1;
+
+  /** If true, use NAPTR lookup */
+  unsigned              sa_use_naptr : 1;
+  /** If true, use SRV lookup */
+  unsigned              sa_use_srv : 1;
+
+  /** If true, transports use threadpool */
+  unsigned              sa_tport_threadpool : 1;
+
+  /** If true, use rport at client */
+  unsigned              sa_rport:1;
+  /** If true, use rport at server */
+  unsigned              sa_server_rport:1;
+  /** If true, use rport with tcp, too */
+  unsigned              sa_tcp_rport:1;
+
+  /** If true, automatically create compartments */
+  unsigned              sa_auto_comp:1;
+
+  unsigned              :0;
+
+  /** Messages memory preload. */
+  unsigned              sa_preload;
+
+  /** Name of SigComp algorithm */
+  char const           *sa_algorithm;
+  /** Options for SigComp. */
+  char const           *sa_sigcomp_options;
+  char const* const    *sa_sigcomp_option_list;
+  char const           *sa_sigcomp_option_free;
+
+  nta_compressor_t     *sa_compressor;
+
+  /** Resolving order (AAAA/A) */
+  enum nta_res_order_e  sa_res_order;
+
+  /** @MaxForwards */
+
+  sip_max_forwards_t    sa_max_forwards[1];
+
+  /* Statistics */
+  struct {
+    uint32_t            as_recv_msg;
+    uint32_t            as_recv_request;
+    uint32_t            as_recv_response;
+    uint32_t            as_bad_message;
+    uint32_t            as_bad_request;
+    uint32_t            as_bad_response;
+    uint32_t            as_drop_request;
+    uint32_t            as_drop_response;
+    uint32_t            as_client_tr;
+    uint32_t            as_server_tr;
+    uint32_t            as_dialog_tr;
+    uint32_t            as_acked_tr;
+    uint32_t            as_canceled_tr;
+    uint32_t            as_trless_request;
+    uint32_t            as_trless_to_tr;
+    uint32_t            as_trless_response;
+    uint32_t            as_trless_200;
+    uint32_t            as_merged_request;
+    uint32_t            as_sent_msg;
+    uint32_t            as_sent_request;
+    uint32_t            as_sent_response;
+    uint32_t            as_retry_request;
+    uint32_t            as_retry_response;
+    uint32_t            as_recv_retry;
+    uint32_t            as_tout_request;
+    uint32_t            as_tout_response;
+  }                  sa_stats[1];
+
+  /** Hash of dialogs. */
+  leg_htable_t          sa_dialogs[1];
+  /** Default leg */
+  nta_leg_t            *sa_default_leg;
+  /** Hash of legs without dialogs. */
+  leg_htable_t          sa_defaults[1];
+  /** Hash table for outgoing transactions */
+  outgoing_htable_t     sa_outgoing[1];
+  nta_outgoing_t       *sa_default_outgoing;
+  /** Hash table for incoming transactions */
+  incoming_htable_t     sa_incoming[1]; 
+  nta_incoming_t       *sa_default_incoming;
+
+  /* Queues (states) for outgoing client transactions */
+  struct {
+    /** Queue for retrying client transactions */
+    nta_outgoing_t   *re_list;
+    nta_outgoing_t  **re_t1;	        /**< Special place for T1 timer */
+    size_t            re_length;	/**< Length of sa_out.re_list */
+
+    outgoing_queue_t  delayed[1]; 
+    outgoing_queue_t  resolving[1]; 
+
+    outgoing_queue_t  trying[1];	/* Timer F/E */
+    outgoing_queue_t  completed[1];	/* Timer K */
+    outgoing_queue_t  terminated[1];
+
+    /* Special queues (states) for outgoing INVITE transactions */
+    outgoing_queue_t  inv_calling[1];	/* Timer B/A */
+    outgoing_queue_t  inv_proceeding[1];
+    outgoing_queue_t  inv_completed[1];	/* Timer D */
+
+    /* Temporary queue for transactions waiting to be freed */
+    outgoing_queue_t *free;
+  } sa_out;
+
+  /* Queues (states) for incoming server transactions */
+  struct {
+    /** Queue for retransmitting response of server transactions */
+    nta_incoming_t   *re_list;
+    nta_incoming_t  **re_t1;	        /**< Special place for T1 timer */
+    size_t            re_length;
+
+    incoming_queue_t  proceeding[1];	/**< Request received */
+    incoming_queue_t  preliminary[1];   /**< 100rel sent  */
+    incoming_queue_t  completed[1];	/**< Final answer sent (non-invite). */
+    incoming_queue_t  inv_completed[1];	/**< Final answer sent (INVITE). */
+    incoming_queue_t  inv_confirmed[1];	/**< Final answer sent, ACK recvd. */
+    incoming_queue_t  terminated[1];	/**< Terminated, ready to free. */
+    incoming_queue_t  final_failed[1];   
+  } sa_in;
+
+  /* Special task for freeing memory */
+  su_clone_r          sa_terminator;
+};
+
+struct nta_leg_s
+{
+  su_home_t         leg_home[1];
+  hash_value_t      leg_hash;
+  unsigned          leg_dialog : 1;
+  unsigned          leg_stateless : 1;   /**< Process requests statelessly */
+#ifdef NTA_STRICT_ROUTING
+  unsigned          leg_contact_set : 1;
+#else
+  unsigned          leg_loose_route : 1; /**< Topmost route in set is LR */
+#endif
+  unsigned          leg_local_is_to : 1; /**< Backwards-compatibility. */
+  unsigned:0;
+  nta_request_f    *leg_callback;
+  nta_leg_magic_t  *leg_magic;
+  nta_agent_t      *leg_agent;
+  /** Leg URL.
+   *
+   * This is the URL used to match incoming requests.
+   */
+  url_t const      *leg_url;
+  char const       *leg_method;	/**< Method for this dialog. */
+
+  uint32_t	    leg_seq;    /**< Sequence number for next transaction */
+  uint32_t	    leg_rseq;   /**< Remote sequence number */
+  sip_call_id_t	   *leg_id;	/**< Call ID */
+  sip_from_t   	   *leg_remote;	/**< Remote address (@To/@From) */
+  sip_to_t     	   *leg_local;	/**< Local address (@From/@To) */
+
+  sip_route_t      *leg_route;  /**< @Route for outgoing requests. */
+  sip_contact_t    *leg_target; /**< Remote destination (from @Contact). */
+};
+
+#define leg_has_id(leg) ((leg)->leg_id != NULL)
+
+struct nta_incoming_s
+{
+  su_home_t            *irq_home;
+  hash_value_t          irq_hash;
+  nta_agent_t          *irq_agent;
+  nta_ack_cancel_f     *irq_callback;
+  nta_incoming_magic_t *irq_magic;
+
+  /* Timeout/state queue */
+  nta_incoming_t      **irq_prev;
+  nta_incoming_t       *irq_next;
+  incoming_queue_t     *irq_queue;
+  
+  /* Retry queue */
+  nta_incoming_t      **irq_rprev;
+  nta_incoming_t       *irq_rnext;
+
+  sip_method_t        	irq_method;
+  sip_request_t        *irq_rq;
+  sip_from_t           *irq_from;
+  sip_to_t             *irq_to;
+  char const           *irq_tag;
+  sip_cseq_t           *irq_cseq;
+  sip_call_id_t        *irq_call_id;
+  sip_via_t            *irq_via;
+  sip_record_route_t   *irq_record_route;
+  char const           *irq_branch;
+
+  uint32_t              irq_rseq;
+
+  sip_timestamp_t      *irq_timestamp;
+  su_time_t             irq_received;
+
+  su_duration_t       	irq_timeout;    /**< Timer H, I, J */
+  su_duration_t       	irq_retry;      /**< Timer G */
+  unsigned short      	irq_interval;	/**< Next timer  */
+
+  short               	irq_status;
+
+  unsigned              irq_retries : 8;
+  unsigned              irq_default : 1;    /**< Default transaction */
+  unsigned              irq_canceled : 1;   /**< Transaction is canceled */
+  unsigned              irq_completed : 1;  /**< Transaction is completed */
+  unsigned              irq_confirmed : 1;  /**< Response has been acked */
+  unsigned              irq_terminated :1;  /**< Transaction is terminated */
+  unsigned              irq_final_failed:1; /**< Sending final response failed */
+  unsigned              irq_destroyed :1;   /**< Transaction is destroyed */
+  unsigned              irq_in_callback:1;  /**< Callback is being invoked */
+  unsigned              irq_reliable_tp:1;  /**< Transport is reliable */
+  unsigned              irq_sigcomp_zap:1;  /**< Reset SigComp */
+  unsigned              irq_must_100rel:1;  /**< 100rel is required */
+  unsigned              irq_tag_set:1;      /**< Tag is not from request */
+  unsigned              :0;
+
+  tp_name_t             irq_tpn[1];
+  tport_t              *irq_tport;
+  struct sigcomp_compartment *irq_cc;
+  msg_t		       *irq_request;
+  msg_t		       *irq_request2;       /**< ACK/CANCEL */
+  msg_t		       *irq_response;
+
+  nta_reliable_t       *irq_reliable;       /**< List of reliable responses */
+};
+
+struct nta_reliable_s
+{
+  nta_reliable_t       *rel_next;
+  nta_incoming_t       *rel_irq;
+  nta_prack_f          *rel_callback;
+  nta_reliable_magic_t *rel_magic;
+  uint32_t              rel_rseq;
+  unsigned short        rel_status;
+  unsigned              rel_pracked : 1;
+  unsigned              rel_precious : 1;
+  msg_t                *rel_response;
+  msg_t                *rel_unsent;
+};
+
+typedef struct sipdns_resolver sipdns_resolver_t;
+
+struct nta_outgoing_s
+{
+  hash_value_t          orq_hash;    /**< Hash value */
+  nta_agent_t          *orq_agent;
+  nta_response_f       *orq_callback;
+  nta_outgoing_magic_t *orq_magic;
+
+  /* Timeout/state queue */
+  nta_outgoing_t      **orq_prev;
+  nta_outgoing_t       *orq_next;
+  outgoing_queue_t     *orq_queue;
+  
+  /* Retry queue */
+  nta_outgoing_t      **orq_rprev;
+  nta_outgoing_t       *orq_rnext;
+
+  sip_method_t        	orq_method;
+  char const           *orq_method_name;
+  sip_from_t const     *orq_from;
+  sip_to_t const       *orq_to;
+  sip_cseq_t const     *orq_cseq;
+  sip_call_id_t const  *orq_call_id;
+
+  char const           *orq_tag;        /**< Tag from final response. */
+
+  su_time_t             orq_sent;       /**< When request was sent? */
+  unsigned              orq_delay;      /**< RTT estimate */
+
+  su_duration_t         orq_retry;	/**< Timer A, E */
+  su_duration_t       	orq_timeout;	/**< Timer B, D, F, K */
+
+  unsigned short      	orq_interval;	/**< Next timer A/E */
+
+  unsigned short      	orq_status;
+  unsigned char         orq_retries;    /**< Number of tries this far */
+  unsigned orq_default : 1;	        /**< This is default transaction */
+  unsigned orq_inserted : 1;
+  unsigned orq_resolved : 1;
+  unsigned orq_prepared : 1; /**< outgoing_prepare() called */
+  unsigned orq_canceled : 1;
+  unsigned orq_terminated : 1;
+  unsigned orq_destroyed : 1;
+  unsigned orq_completed : 1;
+  unsigned orq_delayed : 1;
+  unsigned orq_stripped_uri : 1;
+  unsigned orq_try_tcp_instead : 1;
+  unsigned orq_try_udp_instead : 1;
+  unsigned orq_reliable : 1; /**< Transport is reliable */
+  unsigned orq_ack_error : 1; /**< ACK is sent by NTA */
+  /* Attributes */
+  unsigned orq_user_via : 1;
+  unsigned orq_stateless : 1;
+  unsigned orq_pass_100 : 1;
+  unsigned orq_sigcomp_new:1;	/**< Create compartment if needed */
+  unsigned orq_sigcomp_zap:1;	/**< Reset SigComp after completing */
+  unsigned orq_must_100rel : 1;
+  unsigned orq_timestamp : 1;	/**< insert @Timestamp header. */
+  unsigned : 0;	/* pad */
+
+  uint32_t              orq_rseq;       /**< Latest incoming rseq */
+
+#if HAVE_SOFIA_SRESOLV
+  sipdns_resolver_t    *orq_resolver;
+#endif
+  enum nta_res_order_e  orq_res_order;  /**< AAAA/A first? */
+
+  url_t                *orq_route;      /**< Route URL */
+  tp_name_t             orq_tpn[1];     /**< Where to send request */
+  char const           *orq_scheme;     /**< Transport URL type */
+
+  tport_t              *orq_tport;
+  struct sigcomp_compartment *orq_cc;
+  tagi_t               *orq_tags;       /**< Tport tag items */
+  int                   orq_pending;    /**< Request is pending in tport */
+
+  char const           *orq_branch;	/**< Transaction branch */
+  char const           *orq_via_branch;	/**< @Via branch */
+  url_t const          *orq_url;        /**< Original RequestURI */
+
+  msg_t		       *orq_request;
+  msg_t                *orq_response;
+
+  nta_outgoing_t       *orq_cancel;     /**< CANCEL transaction */
+};
+
+/* Virtual function table for plugging in SigComp */
+typedef struct
+{
+  int ncv_size;
+  char const *ncv_name;
+
+  nta_compressor_t *(*ncv_init_agent)(nta_agent_t *sa, 
+				     char const * const *options);
+
+  void (*ncv_deinit_agent)(nta_agent_t *sa, nta_compressor_t *);
+
+  struct sigcomp_compartment *(*ncv_compartment)(nta_agent_t *sa,
+						 tport_t *tport, 
+						 nta_compressor_t *msc,
+						 tp_name_t const *tpn,
+						 char const * const *options,
+						 int new_if_needed);
+
+  int (*ncv_accept_compressed)(nta_agent_t *sa,
+			       nta_compressor_t *msc,
+			       tport_compressor_t *sc,
+			       msg_t *msg,
+			       struct sigcomp_compartment *cc);
+
+  int (*ncv_close_compressor)(nta_agent_t *sa,
+			      struct sigcomp_compartment *cc);
+  int (*ncv_zap_compressor)(nta_agent_t *sa,
+			    struct sigcomp_compartment *cc);
+
+  struct sigcomp_compartment *(*ncv_compartment_ref)
+    (struct sigcomp_compartment *);
+
+  void (*ncv_compartment_unref)(struct sigcomp_compartment *);
+ 
+} nta_compressor_vtable_t;
+
+extern nta_compressor_vtable_t *nta_compressor_vtable;
+
+SOFIAPUBFUN nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa);
+SOFIAPUBFUN void nta_agent_deinit_sigcomp(nta_agent_t *sa);
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG   nta_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+SOFIAPUBVAR su_log_t nta_log[];
+
+SOFIA_END_DECLS
+
+#endif /* NTA_INTERNAL_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_tag.c
+ * @brief Tags for Nokia SIP Transaction API
+ *
+ * @note This file is used to automatically generate 
+ * nta_tag_ref.c and nta_tag_dll.c
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nta"
+
+#include "sofia-sip/nta_tag.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+#include <sofia-sip/sip_protos.h>
+
+tag_typedef_t ntatag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t ntatag_mclass = PTRTAG_TYPEDEF(mclass);
+
+tag_typedef_t ntatag_bad_req_mask = UINTTAG_TYPEDEF(bad_req_mask);
+tag_typedef_t ntatag_bad_resp_mask = UINTTAG_TYPEDEF(bad_resp_mask);
+
+tag_typedef_t ntatag_default_proxy = URLTAG_TYPEDEF(default_proxy);
+tag_typedef_t ntatag_contact = SIPHDRTAG_NAMED_TYPEDEF(contact, contact);
+tag_typedef_t ntatag_target = SIPHDRTAG_NAMED_TYPEDEF(target, contact);
+tag_typedef_t ntatag_aliases = SIPHDRTAG_NAMED_TYPEDEF(aliases, contact);
+
+tag_typedef_t ntatag_method = STRTAG_TYPEDEF(method);
+tag_typedef_t ntatag_branch_key = STRTAG_TYPEDEF(branch_key);
+tag_typedef_t ntatag_ack_branch = STRTAG_TYPEDEF(ack_branch);
+tag_typedef_t ntatag_comp = CSTRTAG_TYPEDEF(comp);
+tag_typedef_t ntatag_msg = PTRTAG_TYPEDEF(msg);
+tag_typedef_t ntatag_tport = PTRTAG_TYPEDEF(tport);
+tag_typedef_t ntatag_smime = PTRTAG_TYPEDEF(smime);
+tag_typedef_t ntatag_remote_cseq = UINTTAG_TYPEDEF(remote_cseq);
+
+tag_typedef_t ntatag_maxsize = USIZETAG_TYPEDEF(maxsize);
+tag_typedef_t ntatag_udp_mtu = UINTTAG_TYPEDEF(udp_mtu);
+tag_typedef_t ntatag_max_forwards = UINTTAG_TYPEDEF(max_forwards);
+tag_typedef_t ntatag_sip_t1 = UINTTAG_TYPEDEF(sip_t1);
+tag_typedef_t ntatag_sip_t1x64 = UINTTAG_TYPEDEF(sip_t1x64);
+tag_typedef_t ntatag_sip_t2 = UINTTAG_TYPEDEF(sip_t2);
+tag_typedef_t ntatag_sip_t4 = UINTTAG_TYPEDEF(sip_t4);
+tag_typedef_t ntatag_progress = UINTTAG_TYPEDEF(progress);
+tag_typedef_t ntatag_blacklist = UINTTAG_TYPEDEF(blacklist);
+tag_typedef_t ntatag_debug_drop_prob = UINTTAG_TYPEDEF(debug_drop_prob);
+
+tag_typedef_t ntatag_sigcomp_options = STRTAG_TYPEDEF(sigcomp_options);
+tag_typedef_t ntatag_sigcomp_close = BOOLTAG_TYPEDEF(sigcomp_close);
+tag_typedef_t ntatag_sigcomp_aware = BOOLTAG_TYPEDEF(sigcomp_aware);
+tag_typedef_t ntatag_sigcomp_algorithm = STRTAG_TYPEDEF(sigcomp_algorithm);
+
+tag_typedef_t ntatag_ua = BOOLTAG_TYPEDEF(ua);
+tag_typedef_t ntatag_stateless = BOOLTAG_TYPEDEF(stateless);
+tag_typedef_t ntatag_user_via = BOOLTAG_TYPEDEF(user_via);
+tag_typedef_t ntatag_pass_100 = BOOLTAG_TYPEDEF(pass_100);
+tag_typedef_t ntatag_extra_100 = BOOLTAG_TYPEDEF(extra_100);
+tag_typedef_t ntatag_timeout_408 = BOOLTAG_TYPEDEF(timeout_408);
+tag_typedef_t ntatag_pass_408 = BOOLTAG_TYPEDEF(pass_408);
+tag_typedef_t ntatag_merge_482 = BOOLTAG_TYPEDEF(merge_482);
+tag_typedef_t ntatag_cancel_2543 = BOOLTAG_TYPEDEF(cancel_2543);
+tag_typedef_t ntatag_cancel_408 = BOOLTAG_TYPEDEF(cancel_408);
+tag_typedef_t ntatag_cancel_487 = BOOLTAG_TYPEDEF(cancel_487);
+tag_typedef_t ntatag_tag_3261 = BOOLTAG_TYPEDEF(tag_3261);
+tag_typedef_t ntatag_rel100 = BOOLTAG_TYPEDEF(rel100);
+tag_typedef_t ntatag_no_dialog = BOOLTAG_TYPEDEF(no_dialog);
+tag_typedef_t ntatag_use_timestamp = BOOLTAG_TYPEDEF(use_timestamp);
+tag_typedef_t ntatag_sipflags = UINTTAG_TYPEDEF(sipflags);
+tag_typedef_t ntatag_client_rport = BOOLTAG_TYPEDEF(client_rport);
+tag_typedef_t ntatag_server_rport = BOOLTAG_TYPEDEF(server_rport);
+tag_typedef_t ntatag_tcp_rport = BOOLTAG_TYPEDEF(tcp_rport);
+tag_typedef_t ntatag_preload = UINTTAG_TYPEDEF(preload);
+tag_typedef_t ntatag_use_naptr = BOOLTAG_TYPEDEF(naptr);
+tag_typedef_t ntatag_use_srv = BOOLTAG_TYPEDEF(srv);
+tag_typedef_t ntatag_rseq = UINTTAG_TYPEDEF(rseq);
+
+/* Status */
+
+tag_typedef_t ntatag_s_irq_hash =         UINTTAG_TYPEDEF(s_irq_hash);
+tag_typedef_t ntatag_s_orq_hash =         UINTTAG_TYPEDEF(s_orq_hash);
+tag_typedef_t ntatag_s_leg_hash =         UINTTAG_TYPEDEF(s_leg_hash);
+tag_typedef_t ntatag_s_irq_hash_used =    UINTTAG_TYPEDEF(s_irq_hash_used);
+tag_typedef_t ntatag_s_orq_hash_used =    UINTTAG_TYPEDEF(s_orq_hash_used);
+tag_typedef_t ntatag_s_leg_hash_used =    UINTTAG_TYPEDEF(s_leg_hash_used);
+tag_typedef_t ntatag_s_recv_msg =         UINTTAG_TYPEDEF(s_recv_msg);
+tag_typedef_t ntatag_s_recv_request =     UINTTAG_TYPEDEF(s_recv_request);
+tag_typedef_t ntatag_s_recv_response =    UINTTAG_TYPEDEF(s_recv_response);
+tag_typedef_t ntatag_s_bad_message =      UINTTAG_TYPEDEF(s_bad_message);
+tag_typedef_t ntatag_s_bad_request =      UINTTAG_TYPEDEF(s_bad_request);
+tag_typedef_t ntatag_s_bad_response =     UINTTAG_TYPEDEF(s_bad_response);
+tag_typedef_t ntatag_s_drop_request =     UINTTAG_TYPEDEF(s_drop_request);
+tag_typedef_t ntatag_s_drop_response =    UINTTAG_TYPEDEF(s_drop_response);
+tag_typedef_t ntatag_s_client_tr =        UINTTAG_TYPEDEF(s_client_tr);
+tag_typedef_t ntatag_s_server_tr =        UINTTAG_TYPEDEF(s_server_tr);
+tag_typedef_t ntatag_s_dialog_tr =        UINTTAG_TYPEDEF(s_dialog_tr);
+tag_typedef_t ntatag_s_acked_tr =         UINTTAG_TYPEDEF(s_acked_tr);
+tag_typedef_t ntatag_s_canceled_tr =      UINTTAG_TYPEDEF(s_canceled_tr);
+tag_typedef_t ntatag_s_trless_request =   UINTTAG_TYPEDEF(s_trless_request);
+tag_typedef_t ntatag_s_trless_to_tr =     UINTTAG_TYPEDEF(s_trless_to_tr);
+tag_typedef_t ntatag_s_trless_response =  UINTTAG_TYPEDEF(s_trless_response);
+tag_typedef_t ntatag_s_trless_200 =       UINTTAG_TYPEDEF(s_trless_200);
+tag_typedef_t ntatag_s_merged_request =   UINTTAG_TYPEDEF(s_merged_request);
+tag_typedef_t ntatag_s_sent_msg =      	  UINTTAG_TYPEDEF(s_sent_msg);
+tag_typedef_t ntatag_s_sent_request =  	  UINTTAG_TYPEDEF(s_sent_request);
+tag_typedef_t ntatag_s_sent_response = 	  UINTTAG_TYPEDEF(s_sent_response);
+tag_typedef_t ntatag_s_retry_request = 	  UINTTAG_TYPEDEF(s_retry_request);
+tag_typedef_t ntatag_s_retry_response =   UINTTAG_TYPEDEF(s_retry_response);
+tag_typedef_t ntatag_s_recv_retry =       UINTTAG_TYPEDEF(s_recv_retry);
+tag_typedef_t ntatag_s_tout_request =     UINTTAG_TYPEDEF(s_tout_request);
+tag_typedef_t ntatag_s_tout_response =    UINTTAG_TYPEDEF(s_tout_response);
+
+/* Internal */
+tag_typedef_t ntatag_delay_sending = BOOLTAG_TYPEDEF(delay_sending);
+tag_typedef_t ntatag_incomplete = BOOLTAG_TYPEDEF(incomplete);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,243 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file portbind.c
+ * @brief bind a socket to an UDP/TCP port and return the port number
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 25 12:12:25 2004 ppessi
+ */
+
+#include "config.h"
+
+char const name[] = "portbind";
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#if HAVE_SYS_SOCKET_T
+#include <sys/socket.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "sofia-sip/su.h"
+
+#if !defined(IPPROTO_SCTP)
+#define IPPROTO_SCTP (132)
+#endif
+
+static
+char const helptext[] =
+  "usage: portbind OPTIONS [port]\n"
+  "  where OPTIONS are\n"
+  "    [-t] bind to TCP\n"
+  "    [-u] bind to UDP\n"
+  "    [-s] bind to SCTP\n"
+#if HAVE_SIN6
+  "    [-6] bind to IPv6 only\n"
+  "    [-4] bind to IPv4 only\n"
+  "  By default, portbind binds to UDP and TCP on IPv6 and IPv4.\n"
+#else
+  "  By default, portbind binds to UDP and TCP.\n"
+#endif
+;
+
+void usage(int returncode)
+{
+  fprintf(returncode ? stderr : stdout, helptext);
+  exit(returncode);
+}
+
+int main(int argc, char *argv[])
+{
+  char *o_port = "0", *o_protocol = NULL;
+  int o_tcp = 0, o_udp = 0, o_sctp = 0;
+  char *names[5] = { NULL };
+  int protos[5] = { 0 };
+  int types[5] = { 0 };
+  int n, N = 0;
+  unsigned long portno;
+  unsigned short port;
+  int af;
+  su_socket_t s;
+  socklen_t salen;
+  struct sockaddr_storage ss[1];
+  struct sockaddr *sa = (void *)ss;
+  struct sockaddr_in *sin = (void *)ss;
+#if HAVE_SIN6
+  int o_ip6 = 0, o_ip4 = 0;
+  struct sockaddr_in6 *sin6 = (void *)ss;
+#endif
+
+  for (argv++; *argv && **argv == '-';) {
+    char *opt = *argv++ + 1;
+    if (strcmp(opt, "-") == 0)
+      break;
+    else if (strcmp(opt, "P") == 0 && *argv)
+      o_protocol = *argv++;
+    else if (strcmp(opt, "u") == 0)
+      o_udp = 1;
+    else if (strcmp(opt, "t") == 0)
+      o_tcp = 1;
+    else if (strcmp(opt, "s") == 0)
+      o_sctp = 1;
+    else if (strcmp(opt, "h") == 0)
+      usage(0);
+    else if (strcmp(opt, "-help") == 0)
+      usage(0);
+#if HAVE_SIN6
+    else if (strcmp(opt, "6") == 0)
+      o_ip6 = AF_INET6;
+    else if (strcmp(opt, "4") == 0)
+      o_ip4 = 0;
+#endif
+    else 
+      usage(1);
+  }
+
+  if (argv[0]) {
+    char *s = NULL;
+
+    portno = strtoul(argv[0], &s, 10);
+
+    if (portno != (portno & 65535) || s == argv[0] || *s) {
+      fprintf(stderr, "%s: invalid port %s\n", name, argv[0]);
+      exit(1);
+    }
+  } else {
+    portno = 0;
+  }
+
+#if HAVE_SIN6
+  if (o_ip6)
+    af = AF_INET6;
+  else if (o_ip4)
+    af = AF_INET;
+  else
+    af = AF_INET6;
+#else
+  af = AF_INET;
+#endif
+
+  memset(ss, 0, sizeof ss);
+
+  if (!o_tcp || !o_udp || !o_sctp || !o_protocol)
+    o_tcp = o_udp = 1;
+
+  if (o_protocol) {
+    struct protoent *pent = getprotobyname(o_protocol);
+
+    if (!pent) {
+      fprintf(stderr, "%s: %s\n", o_protocol, "unknown protocol");
+      exit(1);
+    }
+    names[N] = pent->p_name, protos[N] = pent->p_proto, types[N++] = SOCK_RAW;
+  }
+
+  if (o_tcp) 
+    names[N] = "TCP", protos[N] = IPPROTO_TCP, types[N++] = SOCK_STREAM;
+  if (o_udp)
+    names[N] = "UDP", protos[N] = IPPROTO_UDP, types[N++] = SOCK_DGRAM;
+  if (o_sctp)
+    names[N] = "SCTP", protos[N] = IPPROTO_SCTP, types[N++] = SOCK_SEQPACKET;
+
+  assert(N != 0);
+
+  port = portno;
+
+  for (n = 0; n < N;) {
+    s = su_socket(sa->sa_family = af, types[n], protos[n]);
+
+#if HAVE_SIN6
+    if (s == INVALID_SOCKET && af == AF_INET6 && !o_ip6)
+      s = su_socket(sa->sa_family = af = AF_INET, types[n], protos[n]);
+#endif
+
+    if (s == INVALID_SOCKET) {
+      fprintf(stderr, "%s: socket(AF_INET%s, 0, %s): %s\n", 
+	      name, af == AF_INET ? "" : "6", names[n], strerror(errno));
+      exit(1);
+    }
+
+#if HAVE_SIN6
+    if (af == AF_INET6 && !o_ip6 && !o_ip4)
+      o_ip6 = o_ip4;
+    if (af == AF_INET6)
+      salen = sizeof *sin6;
+    else
+#endif
+      salen = sizeof *sin;
+
+    sin->sin_port = htons(port);
+
+    if (bind(s, sa, salen) == -1) {
+      if (errno == EADDRINUSE) {
+	if (++port == 0)
+	  port = 1024;
+	if (port != portno) {
+	  close(s);
+	  n = 0;
+	  continue;
+	}
+      }
+	
+      fprintf(stderr, "%s: bind(%s): %s\n", name, o_port, strerror(errno));
+      exit(1);
+    }
+
+    if (portno == 0) {
+      struct sockaddr_storage ss[1];
+      struct sockaddr *sa = (void *)ss;
+      struct sockaddr_in *sin = (void *)ss;
+      
+      salen = sizeof *ss;
+      if (getsockname(s, sa, &salen) == -1) {
+	fprintf(stderr, "%s: getsockname(): %s\n", name, strerror(errno));
+	exit(1);
+      }
+
+      portno = port = ntohs(sin->sin_port);
+    }
+
+    close(s);
+
+    n++;
+  }
+
+  printf("%u\n", ntohs(sin->sin_port));
+
+  return 0;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,214 @@
+#! /bin/bash
+#
+# Run nta_test with our own name server
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+#set -x
+
+s=${0%/*}
+
+resolvfile=.test$$.resolv.conf
+namedfile=.test$$.named.conf
+pidfile=.test$$.named.pid
+zonefile=.test$$.example.zone
+
+test x$s = x$0 && s=`pwd`
+
+test -z "$srcdir" && srcdir=$s
+export srcdir
+
+PATH=/usr/sbin:/usr/local/sbin:/sbin:$PATH
+
+export PATH
+
+me6="::1"
+
+if ../su/localinfo -6 -n -g -s >& /dev/null ; then
+    ipv6=true aaaa=aaaa v6flag=-6
+    me6=$(../su/localinfo -6 -n -s -g | awk '{print $1; exit(0); }')
+else
+    if ! ../su/localinfo '--help' >& /dev/null ; then
+	echo "warning: $0: missing 'localinfo', cannot test IPv6"
+    else
+	echo "warning: $0: no valid IPv6 addresses available"
+    fi
+    ipv6=false aaaa=a
+fi
+
+if type named >& /dev/null && ./portbind --help >& /dev/null
+then
+
+port=$(./portbind $v6flag) sink=$port
+port=$(./portbind $v6flag $((port + 1))) down=$port
+port=$(./portbind $v6flag $((port + 1))) bind=$port
+port=$(./portbind $v6flag $((port + 1))) contact=$port
+
+# Disable IPv6 resolver for now 
+if false && eval $ipv6 ; then
+    listen="listen-on-v6 port $bind { any; };"
+    ns=$me6
+else
+    listen="listen-on port $bind { 127.0.0.1; };"
+    ns="127.0.0.1"
+fi
+
+cat > $resolvfile <<EOF
+nameserver $ns
+domain example.com
+port $bind
+EOF
+
+cat > $namedfile <<EOF
+options {
+	pid-file "$pidfile";
+	$listen
+};
+
+zone "example.org" in {
+        type master;
+        file "$zonefile";
+};
+EOF
+
+cat > $zonefile << EOF
+;
+; Zone file for example.org
+; SIP targets: example.org
+;              srv.example.org
+;		down.example.org
+;              na.example.org
+;              ipv6-20-80.example.org
+;              ipv.example.org
+;
+\$TTL     60
+@ 	IN SOA ns root (
+	    2002042901 ; SERIAL
+	    7200       ; REFRESH
+	    600        ; RETRY
+	    36000000   ; EXPIRE
+	    60         ; MINIMUM
+	    )
+	NS	ns
+	;;  order pref flags service           regexp  replacement
+        NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp
+        NAPTR 40 25 "s" "SIPS+D2T" "" _sips._tcp
+        NAPTR 40 50 "s" "SIP+D2T" "" _sip._tcp
+
+ns	AAAA	$me6
+	A	127.0.0.1
+
+_sip._udp	SRV 1 100 $contact me
+_sips._tcp	SRV 3 100 $contact me
+_sip._tcp	SRV 2 100 $contact me
+
+_sip._udp.srv	SRV 1 100 $contact a
+_sips._tcp.srv	SRV 3 100 $contact a
+_sip._tcp.srv	SRV 2 100 $contact $aaaa
+
+_sip._udp.srv2	SRV 1 200 $contact c
+	        SRV 1 100 $contact b
+	        SRV 1 50 $contact a
+
+me	AAAA	$me6
+	A	127.0.0.1
+
+a	A	127.0.0.1
+b	A	0.0.0.2
+c	A	0.0.0.3
+
+aaaa	AAAA	$me6
+
+; Directly from NAPTR to A/AAAA (Test 1.6c)
+na      NAPTR 20 15 "a" "SIP+D2T" "" a2
+
+; No sensible NAPTR match (and we get 503)
+na503   NAPTR 20 15 "S" "SIP+D2F" "" a2
+
+; No SIP NAPTR match 
+nona   NAPTR 20 15 "S" "ZIP+D2U" "" a2
+_sip._udp.nona   SRV 1 10 $contact ip4
+
+; No SIP SRV match 
+nosrv	NAPTR 20 1 "s" "SIP+D2U" "" _sip._udp.nosrv
+        NAPTR 20 2 "s" "SIP+D2U" "" _sip._udp.srv
+
+; This fails (and we get 503)
+a2	A	127.0.0.2
+
+; IP6 should get 80%, IP4 20%
+ipv6-20-80 NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp.ipv6-20-80
+
+_sip._udp.ipv6-20-80 SRV 1 80 $contact ip6
+		     SRV 1 20 $contact ip4
+
+_sip._udp.ipv	SRV 1 100 $contact ip6
+_sip._udp.ipv	SRV 1 100 $contact ip4
+
+ip6	AAAA	$me6
+ip4	A	127.0.0.1
+
+; SRV failover to me...
+down	NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp.down
+_sip._udp.down	SRV 1 100 $down me
+_sip._udp.down	SRV 2 100 $contact me
+
+; A failover
+down2	A	0.0.0.2
+	A	0.0.0.3
+	A	127.0.0.1
+EOF
+
+# -g is also very nice option for named
+named -f -c $namedfile &
+pid=$!
+while ! test -r $pidfile && kill -0 $!
+do 
+    sleep 1
+done
+
+if test -r $pidfile ; then
+# export SOFIA_DEBUG=9
+    sink=$sink down=$down \
+    ipv6=$ipv6 \
+    SIPCONTACT="sip:*:$contact;comp=sigcomp" \
+    $VALGRIND ./test_nta "$@" - $resolvfile
+    exit=$?
+    kill $(cat $pidfile)
+    rm $pidfile $zonefile $resolvfile $namedfile 2>/dev/null
+    exit $exit
+fi
+exit $?
+
+else # not having BIND and portbind
+
+ipv6=$ipv6 $VALGRIND ./test_nta "$@"
+exit $?
+fi
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+#! /bin/bash
+#
+# Run test_nta_api
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+#set -x
+
+s=${0%/*}
+
+exec $VALGRIND ./test_nta_api "$@"
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils 
+ * @CFILE sl_read_payload.c
+ *
+ * @brief Functions for reading SIP message payload from a file.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Thu Sep  5 00:44:34 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/sl_utils.h>
+
+/** Read payload from named file.
+ *
+ * The function sl_read_payload() reads the contents to a SIP payload
+ * structure from a the named file. If @a fname is NULL, the payload
+ * contents are read from standard input.
+ */
+sip_payload_t *sl_read_payload(su_home_t *home, char const *fname)
+{
+  FILE *f;
+  sip_payload_t *pl;
+
+  if (fname == NULL || strcmp(fname, "-") == 0)
+    f = stdin, fname = "<stdin>";
+  else
+    f = fopen(fname, "rb");
+
+  if (f == NULL)
+    return NULL;
+
+  pl = sl_fread_payload(home, f);
+  if (f != stdin)
+    fclose(f);
+
+  return pl;
+}
+
+sip_payload_t *sl_fread_payload(su_home_t *home, FILE *f)
+{
+  sip_payload_t *pl;
+  size_t n;
+  char *buf;
+  char const *who;
+  size_t used, size;
+
+  if (f == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  pl = sip_payload_create(home, NULL, 0);
+
+  if (pl == NULL)
+    return NULL;
+
+  /* Read block by block */
+  used = 0;
+  size = 4096;
+  buf = malloc(size);
+  who = "sl_fread_payload: malloc";
+
+  while (buf) {
+    n = fread(buf + used, 1, size - used, f);
+    used += n;
+    if (n < size - used) {
+      if (feof(f))
+	;
+      else if (ferror(f)) {
+	free(buf); buf = NULL;
+	who = "sl_fread_payload: fread";
+      }
+      break;
+    }
+    buf = realloc(buf, size = 2 * size);
+    if (buf == NULL)
+      who = "sl_fread_payload: realloc";
+  }
+
+  if (buf == NULL) {
+    perror(who);
+    su_free(home, pl); 
+    return NULL;
+  }
+  
+  if (used < size)
+    buf[used] = '\0';
+
+  pl->pl_common->h_data = pl->pl_data = buf;
+  pl->pl_common->h_len = pl->pl_len = used;
+
+  return pl;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+/* -*- c -*- */
+
+/**@defgroup sl_utils SIP Library Utilities - "sl_utils"
+ * 
+ * SIP library utilities provide some simple utility functions for printing
+ * and managing SIP headers or messages.
+ *
+ */
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils
+ *
+ * @CFILE sl_utils_log.c  
+ * @brief Implementation of SIP library utility logging functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created:  Thu Oct  5 15:38:39 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_log.h>
+
+#include <sofia-sip/sip_header.h>
+#include "sofia-sip/sl_utils.h"
+
+/**Log a SIP message. 
+ *
+ * The function sl_message_log() logs shorthand information identifying
+ * the SIP message to the given @a log at level @a level.  The shorthand
+ * information include the method and URL by default.  If @a details is
+ * nonzero, topmost @Via, @CSeq, @To @b and @@From is included, too.
+ *
+ * @param log      output log (if @c NULL, su_default_log() is used).
+ * @param level    log level
+ * @param prefix   string logged before the first line.
+ * @param sip      message to be logged.
+ * @param details  flag specifying if detailed output is desired.
+ */
+void sl_sip_log(su_log_t *log,
+		int level,
+		char const *prefix, 
+		sip_t const *sip, 
+		int details)
+{
+  sip_cseq_t const *cs = sip->sip_cseq;
+
+  if (log == NULL)
+    log = su_log_default;
+
+  assert(cs);
+  
+  if (sip->sip_request) {
+    su_llog(log, level,
+	    "%s%s "URL_FORMAT_STRING" (CSeq %d %s)\n",
+	    prefix,
+	    sip->sip_request->rq_method_name,
+	    URL_PRINT_ARGS(sip->sip_request->rq_url),
+	    cs->cs_seq,
+	    cs->cs_method_name);
+
+    if (!details)
+      return;
+
+    if (sip->sip_via) {
+      char const *received = sip->sip_via->v_received;
+      char const *port = sip->sip_via->v_port;
+
+      su_llog(log, level,
+	      "\tvia %s%s%s%s%s%s\n",
+	      sip->sip_via->v_host,
+	      port ? ":" : "", port ? port : "",
+	      received ? " (" : "", received ? received : "",
+	      received ? ")" : "");
+    }
+  }
+  else {
+    su_llog(log, level,
+	    "%s%03u %s (CSeq %d %s)\n",
+	    prefix,
+	    sip->sip_status->st_status,
+	    sip->sip_status->st_phrase,
+	    cs->cs_seq,
+	    cs->cs_method_name);
+    if (!details)
+      return;
+  }
+
+  if (sip->sip_from)
+    sl_from_log(log, level, "\tFrom: %s\n", sip->sip_from);
+
+  if (sip->sip_to)
+    sl_to_log(log, level, "\tTo: %s\n", sip->sip_to);
+}
+
+/**Log a @From header. 
+ *
+ * The function sl_from_log() logs the contents of @a from header to
+ * the output @a log.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are logged.
+ * 
+ * @param log      output log
+ * @param level    logging level of output
+ * @param fmt      output format 
+ * @param from     @From header
+ */
+void sl_from_log(su_log_t *log, int level, 
+		 char const *fmt, sip_from_t const *from)
+{
+  sip_addr_t a[1];
+
+  if (from == NULL)
+    return;
+
+  memcpy(a, from, sizeof a);
+  a->a_params = NULL;
+  if (!a->a_display) a->a_display = "";
+    
+  return sl_header_log(log, level, fmt, (sip_header_t *)a);
+}
+
+/**Log a @To header.
+ *
+ * The function sl_to_log() logs the contents of @a to header to the
+ * log @a log with given @a level.  The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are logged.
+ * 
+ * @param log      output log
+ * @param level    logging level of output
+ * @param fmt      output format 
+ * @param to       @To header
+ */
+void sl_to_log(su_log_t *log, int level, char const *fmt, sip_to_t const *to)
+{
+  sl_from_log(log, level, fmt, (sip_from_t const *)to);
+}
+
+/**Log a @Contact header. 
+ *
+ * The function sl_contact_log() logs the contents of @a contact header
+ * to the log @a log with given @a level.  The @a fmt specifies the output
+ * format, where %s is replaced with header contents. If @a fmt is @c NULL,
+ * only the header contents are logged.
+ * 
+ * @param log      output log
+ * @param level    logging level of output
+ * @param fmt      output format 
+ * @param contact  @Contact header
+ */
+void sl_contact_log(su_log_t *log, int level, 
+		     char const *fmt, sip_contact_t const *m)
+{
+  sl_from_log(log, level, fmt, (sip_from_t const *)m);
+}
+
+/**Log an @Allow header(s). 
+ *
+ * The function sl_allow_log() logs the contents of @a allow header to
+ * the log @a log with given @a level.  The @a fmt specifies the output
+ * format, where %s is replaced with header contents. If @a fmt is @c NULL,
+ * only the header contents are logged.
+ * 
+ * @param log      output log
+ * @param level    logging level of output
+ * @param fmt      output format 
+ * @param allow    @Allow header
+ *
+ */
+void sl_allow_log(su_log_t *log, int level, 
+		  char const *fmt, sip_allow_t const *allow)
+{
+  sl_header_log(log, level, fmt, (sip_header_t *)allow);
+}
+
+
+/**Log a @Via header. 
+ *
+ * The function sl_via_log() logs the contents of @a via header to
+ * the @a log.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are logged.
+ * 
+ * @param log  output log
+ * @param fmt  format used when logging
+ * @param v    via header
+ */
+void sl_via_log(su_log_t *log, int level, char const *fmt, sip_via_t const *v)
+{
+  sl_header_log(log, level, fmt, (sip_header_t *)v);
+}
+
+
+/**Log message payload. 
+ *
+ * The function sl_payload_log() logs the contents of @a payload object
+ * to the output @a log.  Each line in the payload is prepended with the
+ * @a prefix.  If @a prefix is @c NULL, only the header contents are logged.
+ * For each line in payload, only first 70 charactes are logged, rest is
+ * replaced with "...".
+ * 
+ * @param log      output log
+ * @param level    logging level of output
+ * @param prefix   prefix appended to each payload line 
+ * @param pl       payload object
+ */
+void sl_payload_log(su_log_t *log, int level, 
+		    char const *prefix, 
+		    sip_payload_t const *pl)
+{
+  char *s = pl->pl_data, *end = pl->pl_data + pl->pl_len;
+  char line[74];
+
+  if (log == NULL)
+    log = su_log_default;
+
+  while (s < end && *s != '\0') {
+    size_t n = strncspn(s, end - s, "\r\n");
+    size_t crlf = strnspn(s + n, end - s - n, "\r\n");
+    if (n < 70) {
+      memcpy(line, s, n);
+      line[n] = '\0';
+    }
+    else {
+      memcpy(line, s, 70);
+      strcpy(line + 70, "...");
+    }
+    su_llog(log, level, "%s%s\n", prefix, line);
+    s += n + crlf;
+  }
+}
+
+/** Log a header. 
+ *
+ * Logs the contents of an header to the output @a stream. The @a fmt
+ * specifies the output format, where %s is replaced with header contents. 
+ * If @a fmt is @c NULL, only the header contents are logged.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param h        a SIP header object
+ */
+void sl_header_log(su_log_t *log, int level, char const *fmt,
+		   sip_header_t const *h)
+{
+  char *s, b[1024];
+  issize_t len;
+
+  len = sip_header_field_e(s = b, sizeof b, h, 0);
+  if (len == -1)
+    return;
+
+  if ((size_t)len >= sizeof b) {
+    s = malloc(len + 1); if (!s) return;
+    sip_header_field_e(s, len + 1, h, 0);
+  }    
+  s[len] = '\0';
+
+  if (fmt == NULL)
+    fmt = "%s\n";
+  su_llog(log, level, fmt, s);
+
+  if (s != b)
+    free(s);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils
+ *
+ * @CFILE sl_utils_print.c  
+ * @brief Implementation of SIP library utility print functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created:  Thu Oct  5 15:38:39 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <sofia-sip/sip_header.h>
+#include "sofia-sip/sl_utils.h"
+
+/**Print a SIP message. 
+ *
+ * The function sl_message_log() prints shorthand information identifying
+ * the SIP message to the given output @a stream.  The shorthand information
+ * include the method and URL by default.  If @a details is nonzero, topmost
+ * @Via, @CSeq, @To and @From is included, too.
+ *
+ * @param stream   output stream (if @c NULL, @c stdout is used).
+ * @param prefix   string printed before the first line.
+ * @param sip      message to be logged.
+ * @param details  flag specifying if detailed output is desired.
+ */
+void sl_message_log(FILE *stream, 
+		    char const *prefix, sip_t const *sip, int details)
+{
+  sip_cseq_t const *cs = sip->sip_cseq;
+
+  if (stream == NULL)
+    stream = stdout;
+
+  assert(cs);
+  
+  if (sip->sip_request) {
+    fprintf(stream,
+	    "%s%s "URL_FORMAT_STRING" (CSeq %d %s)\n",
+	    prefix,
+	    sip->sip_request->rq_method_name,
+	    URL_PRINT_ARGS(sip->sip_request->rq_url),
+	    cs->cs_seq,
+	    cs->cs_method_name);
+
+    if (!details)
+      return;
+
+    if (sip->sip_via) {
+      fputs(prefix, stream);
+      sl_via_print(stream, "Via: %s\n", sip->sip_via);
+    }
+  }
+  else {
+    fprintf(stream,
+	    "%s%03u %s (CSeq %d %s)\n",
+	    prefix,
+	    sip->sip_status->st_status,
+	    sip->sip_status->st_phrase,
+	    cs->cs_seq,
+	    cs->cs_method_name);
+    if (!details)
+      return;
+  }
+
+  if (sip->sip_from)
+    sl_from_print(stream, "\tFrom: %s\n", sip->sip_from);
+
+  if (sip->sip_to)
+    sl_to_print(stream, "\tTo: %s\n", sip->sip_to);
+}
+
+/** Print @From header. 
+ *
+ * The function sl_from_print() prints the contents of @a from header to
+ * the output @a stream.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param from     header object
+ * 
+ * @return 
+ * The function sl_from_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_from_print(FILE *stream, char const *fmt, sip_from_t const *from)
+{
+  sip_addr_t a[1];
+
+  if (from == NULL)
+    return -1;
+
+  memcpy(a, from, sizeof a);
+  a->a_params = NULL;
+  if (!a->a_display) a->a_display = "";
+    
+  return sl_header_print(stream, fmt, (sip_header_t *)a);
+}
+
+/** Print @To header.
+ *
+ * The function sl_to_print() prints the contents of @a to header to
+ * the output @a stream.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param to       header object
+ * 
+ * @return 
+ * The function sl_to_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_to_print(FILE *stream, char const *fmt, sip_to_t const *to)
+{
+  return sl_from_print(stream, fmt, (sip_from_t const *)to);
+}
+
+/** Print @Contact header. 
+ *
+ * The function sl_contact_print() prints the contents of @a contact
+ * header to the output @a stream.  The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param contact  header object
+ * 
+ * @return 
+ * The function sl_contact_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_contact_print(FILE *stream, char const *fmt,
+			  sip_contact_t const *m)
+{
+  return sl_from_print(stream, fmt, (sip_from_t const *)m);
+}
+
+/** Print @Allow header(s). 
+ *
+ * The function sl_allow_print() prints the contents of @a allow header to
+ * the output @a stream.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param allow    header object
+ * 
+ * @return 
+ * The function sl_allow_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_allow_print(FILE *stream,
+			char const *fmt,
+			sip_allow_t const *allow)
+{
+  return sl_header_print(stream, fmt, (sip_header_t *)allow);
+}
+
+
+/** Print message payload. 
+ *
+ * The function sl_payload_print() prints the contents of @a payload
+ * object to the output @a stream.  The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are printed.
+ * 
+ * @param stream   output stream
+ * @param prefix   prefix appended to each payload line 
+ * @param pl       payload object
+ * 
+ * @return 
+ * The function sl_payload_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_payload_print(FILE *stream, char const *prefix, sip_payload_t const *pl)
+{
+  char *s = pl->pl_data, *end = pl->pl_data + pl->pl_len;
+  size_t n, total = 0, crlf = 1; 
+
+  while (s < end && *s != '\0') {
+    n = strncspn(s, end - s, "\r\n");
+    crlf = strnspn(s + n, end - s - n, "\r\n");
+    if (prefix)
+      fputs(prefix, stream), total += strlen(prefix);
+    fwrite(s, 1, n + crlf, stream);
+    s += n + crlf;
+    total += n + crlf;
+  }
+  if (crlf == 0)
+    fputs("\n", stream), total++;
+
+  return (issize_t)total;
+}
+
+/** Print @Via header. 
+ *
+ * The function sl_via_print() prints the contents of @a via header to
+ * the output @a stream.  The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param v        header object
+ * 
+ * @return 
+ * The function sl_via_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_via_print(FILE *stream, char const *fmt, sip_via_t const *v)
+{
+  char s[1024];
+
+  sip_header_field_e(s, sizeof(s), (sip_header_t const *)v, 0);
+  s[sizeof(s) - 1] = '\0';
+
+  if (fmt && strcmp(fmt, "%s"))
+    return fprintf(stream, fmt, s);
+  if (fputs(s, stream) >= 0)
+    return (issize_t)strlen(s);
+  return -1;
+}
+
+/** Print a header. 
+ *
+ * Prints the contents of an header to the output @a stream. The @a fmt
+ * specifies the output format, where %s is replaced with header contents. 
+ * If @a fmt is @c NULL, only the header contents are printed.
+ * 
+ * @param stream   output stream
+ * @param fmt      output format 
+ * @param v        header object
+ * 
+ * @return 
+ * Number of bytes logged, or -1 upon an error.
+ */
+issize_t sl_header_print(FILE *stream, char const *fmt, sip_header_t const *h)
+{
+  char *s, b[1024];
+  issize_t len;
+
+  len = sip_header_field_e(s = b, sizeof b, h, 0);
+  if (len == -1)
+    return len;
+
+  if ((size_t)len >= sizeof b) {
+    s = malloc(len + 1); if (!s) return -1;
+    sip_header_field_e(s, len + 1, h, 0);
+  }    
+  s[len] = '\0';
+
+  if (fmt != NULL && strcmp(fmt, "%s") != 0)
+    len = fprintf(stream, fmt, s);
+  else if (fputs(s, stream) < 0)
+    len = -1;
+
+  if (s != b)
+    free(s);
+  
+  return len;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,479 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_H
+/** Defined when <sofia-sip/nta.h> has been included. */
+#define NTA_H
+
+/**@file sofia-sip/nta.h  @brief  Nokia Transaction API for SIP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 18 09:18:32 2000 ppessi
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Types 
+ */
+
+/** NTA agent */
+typedef struct nta_agent_s      nta_agent_t;
+/** NTA call leg */
+typedef struct nta_leg_s        nta_leg_t;
+/** NTA outgoing request */
+typedef struct nta_outgoing_s   nta_outgoing_t;
+/** NTA incoming request */
+typedef struct nta_incoming_s   nta_incoming_t;
+
+#ifndef NTA_AGENT_MAGIC_T
+/** Default type of application context for NTA agents.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_AGENT_MAGIC_T struct nta_agent_magic_s
+#endif
+#ifndef NTA_LEG_MAGIC_T
+/** Default type of application context for NTA call legs.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_LEG_MAGIC_T struct nta_leg_magic_s
+#endif
+#ifndef NTA_OUTGOING_MAGIC_T
+/** Default type of application context for outgoing NTA requests.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_OUTGOING_MAGIC_T struct nta_outgoing_magic_s
+#endif
+#ifndef NTA_INCOMING_MAGIC_T
+/** Default type of application context for incoming NTA requests.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_INCOMING_MAGIC_T struct nta_incoming_magic_s
+#endif
+
+/** Application context for NTA agents */
+typedef NTA_AGENT_MAGIC_T     nta_agent_magic_t;
+/** Application context for NTA call legs */
+typedef NTA_LEG_MAGIC_T       nta_leg_magic_t;
+/** Application context for outgoing NTA requests */
+typedef NTA_OUTGOING_MAGIC_T  nta_outgoing_magic_t;
+/** Application context for incoming NTA requests */
+typedef NTA_INCOMING_MAGIC_T  nta_incoming_magic_t;
+
+/* ----------------------------------------------------------------------
+ * 2) Constants 
+ */
+
+/** NTA API version number */
+#define NTA_VERSION "2.0"
+
+/** NTA module version */
+SOFIAPUBVAR char const nta_version[];
+
+enum {
+  /* Stack parameters */
+  NTA_SIP_T1 = 500,		/**< SIP T1, 500 milliseconds. */
+  NTA_SIP_T2 = 4000,		/**< SIP T2, 4 seconds. */
+  NTA_SIP_T4 = 5000,		/**< SIP T4, 5 seconds. */
+  NTA_TIME_MAX = 15 * 24 * 3600 * 1000
+				/**< Maximum value for timers. */
+};
+
+/* ----------------------------------------------------------------------
+ * 3) Agent-level prototypes
+ */
+
+typedef int nta_message_f(nta_agent_magic_t *context,
+			  nta_agent_t *agent,
+			  msg_t *msg,
+			  sip_t *sip);
+
+SOFIAPUBFUN 
+nta_agent_t *nta_agent_create(su_root_t *root,
+			      url_string_t const *name,
+			      nta_message_f *callback,
+			      nta_agent_magic_t *magic,
+			      tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN void nta_agent_destroy(nta_agent_t *agent);
+
+SOFIAPUBFUN char const *nta_agent_version(nta_agent_t const *a);
+SOFIAPUBFUN nta_agent_magic_t *nta_agent_magic(nta_agent_t const *a);
+
+SOFIAPUBFUN
+int nta_agent_add_tport(nta_agent_t *agent,
+			url_string_t const *url,
+			tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_agent_close_tports(nta_agent_t *agent);
+
+SOFIAPUBFUN sip_contact_t *nta_agent_contact(nta_agent_t const *a);
+SOFIAPUBFUN sip_via_t *nta_agent_via(nta_agent_t const *a);
+SOFIAPUBFUN sip_via_t *nta_agent_public_via(nta_agent_t const *a);
+
+SOFIAPUBFUN char const *nta_agent_newtag(su_home_t *,
+					 char const *fmt, nta_agent_t *);
+
+SOFIAPUBFUN int nta_agent_set_params(nta_agent_t *agent, 
+				     tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int nta_agent_get_params(nta_agent_t *agent, 
+				     tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_agent_get_stats(nta_agent_t *agent, 
+				    tag_type_t tag, tag_value_t value, ...);
+
+/* ----------------------------------------------------------------------
+ * 4) Message-level prototypes
+ */
+
+SOFIAPUBFUN msg_t *nta_msg_create(nta_agent_t *self, int flags);
+
+SOFIAPUBFUN int nta_msg_complete(msg_t *msg);
+
+SOFIAPUBFUN int nta_msg_request_complete(msg_t *msg, 
+					 nta_leg_t *leg, 
+					 sip_method_t method, 
+					 char const *method_name,
+					 url_string_t const *req_url);
+
+SOFIAPUBFUN int nta_is_internal_msg(msg_t const *msg);
+
+/* ----------------------------------------------------------------------
+ * 5) Leg-level prototypes
+ */
+typedef int nta_request_f(nta_leg_magic_t *lmagic, 
+			  nta_leg_t *leg,
+			  nta_incoming_t *irq, 
+			  sip_t const *sip);
+
+SOFIAPUBFUN 
+nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,  
+			   nta_request_f *req_callback,
+			   nta_leg_magic_t *magic,
+			   tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN void nta_leg_destroy(nta_leg_t *leg);
+
+SOFIAPUBFUN nta_leg_t *nta_default_leg(nta_agent_t const *agent);
+
+SOFIAPUBFUN nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
+					   nta_request_f *callback);
+
+SOFIAPUBFUN void nta_leg_bind(nta_leg_t *leg,
+			      nta_request_f *callback,
+			      nta_leg_magic_t *);
+
+/** Add local tag. */
+SOFIAPUBFUN char const *nta_leg_tag(nta_leg_t *leg, char const *tag);
+
+/** Get local tag. */
+SOFIAPUBFUN char const *nta_leg_get_tag(nta_leg_t const *leg);
+
+/** Add remote tag. */
+SOFIAPUBFUN char const *nta_leg_rtag(nta_leg_t *leg, char const *tag);
+
+/** Get remote tag. */
+SOFIAPUBFUN char const *nta_leg_get_rtag(nta_leg_t const *leg);
+
+/** Set UAC route. */
+SOFIAPUBFUN int nta_leg_client_route(nta_leg_t *leg, 
+				     sip_record_route_t const *route, 
+				     sip_contact_t const *contact);
+
+/** Set UAS route */
+SOFIAPUBFUN int nta_leg_server_route(nta_leg_t *leg, 
+				     sip_record_route_t const *route, 
+				     sip_contact_t const *contact);
+
+/** Get route */
+SOFIAPUBFUN int nta_leg_get_route(nta_leg_t *leg, 
+				  sip_route_t const **return_route, 
+				  sip_contact_t const **return_target);
+
+/** Get leg by destination */
+SOFIAPUBFUN nta_leg_t *nta_leg_by_uri(nta_agent_t const *,
+				      url_string_t const *);
+
+/** Get leg by dialog */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent, 
+			     url_t const *request_uri,
+			     sip_call_id_t const *call_id,
+			     char const *from_tag,
+			     url_t const *from_url,
+			     char const *to_tag,
+			     url_t const *to_url);
+
+/** Generate Replaces header */
+SOFIAPUBFUN sip_replaces_t *nta_leg_make_replaces(nta_leg_t *leg,
+						  su_home_t *home,
+						  int early_only);
+/** Get dialog leg by Replaces header */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_replaces(nta_agent_t *, sip_replaces_t const *);
+
+/* ----------------------------------------------------------------------
+ * 6) Prototypes for incoming transactions 
+ */
+
+SOFIAPUBFUN
+nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
+				    nta_leg_t *leg,
+				    msg_t *msg,
+				    sip_t *sip,
+				    tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN nta_incoming_t *nta_incoming_default(nta_agent_t *agent);
+
+typedef int nta_ack_cancel_f(nta_incoming_magic_t *imagic,
+			     nta_incoming_t *irq, 
+			     sip_t const *sip);
+
+SOFIAPUBFUN void nta_incoming_bind(nta_incoming_t *irq, 
+				   nta_ack_cancel_f *callback,
+				   nta_incoming_magic_t *imagic);
+
+SOFIAPUBFUN
+nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq, 
+					 nta_ack_cancel_f *callback);
+
+SOFIAPUBFUN
+nta_incoming_t *nta_incoming_find(nta_agent_t const *agent, 
+				  sip_t const *sip,
+				  sip_via_t const *v);
+
+SOFIAPUBFUN char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag);
+SOFIAPUBFUN char const *nta_incoming_gettag(nta_incoming_t const *irq);
+
+SOFIAPUBFUN int nta_incoming_status(nta_incoming_t const *irq);
+SOFIAPUBFUN sip_method_t nta_incoming_method(nta_incoming_t const *irq);
+SOFIAPUBFUN char const *nta_incoming_method_name(nta_incoming_t const *irq);
+SOFIAPUBFUN url_t const *nta_incoming_url(nta_incoming_t const *irq);
+SOFIAPUBFUN uint32_t nta_incoming_cseq(nta_incoming_t const *irq);
+
+SOFIAPUBFUN int nta_incoming_set_params(nta_incoming_t *irq,
+					tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN msg_t *nta_incoming_getrequest(nta_incoming_t *irq);
+SOFIAPUBFUN msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq);
+SOFIAPUBFUN msg_t *nta_incoming_getresponse(nta_incoming_t *irq);
+
+SOFIAPUBFUN
+int nta_incoming_complete_response(nta_incoming_t *irq,
+				   msg_t *msg,
+				   int status, 
+				   char const *phrase,
+				   tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int nta_incoming_treply(nta_incoming_t *ireq, 
+			int status, char const *phrase, 
+			tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg);
+
+SOFIAPUBFUN void nta_incoming_destroy(nta_incoming_t *irq);
+
+/* Functions for feature, method, mime, session-timer negotation */
+
+SOFIAPUBFUN
+int nta_check_required(nta_incoming_t *irq,
+		       sip_t const *sip,
+		       sip_supported_t const *supported,
+		       tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_supported(nta_incoming_t *irq,
+			sip_t const *sip,
+			sip_require_t *require,
+			tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_method(nta_incoming_t *irq,
+		     sip_t const *sip,
+		     sip_allow_t const *allow,
+		     tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_session_content(nta_incoming_t *irq, sip_t const *sip,
+			      sip_accept_t const *session_accepts,
+			      tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_accept(nta_incoming_t *irq,
+		     sip_t const *sip,
+		     sip_accept_t const *acceptable,
+		     sip_accept_t const **return_acceptable,
+		     tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int nta_check_session_expires(nta_incoming_t *irq,
+			      sip_t const *sip,
+			      sip_time_t my_min_se,
+			      tag_type_t tag, tag_value_t value, ...);
+
+/* ----------------------------------------------------------------------
+ * 7) Prototypes for outgoing transactions
+ */
+typedef int nta_response_f(nta_outgoing_magic_t *magic,
+			   nta_outgoing_t *request,
+			   sip_t const *sip);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url,
+				     sip_method_t method,
+				     char const *method_name,
+				     url_string_t const *request_uri,
+				     tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     url_string_t const *route_url, 
+				     msg_t *msg,
+				     tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic);
+
+SOFIAPUBFUN int nta_outgoing_status(nta_outgoing_t const *orq);
+SOFIAPUBFUN sip_method_t nta_outgoing_method(nta_outgoing_t const *orq);
+SOFIAPUBFUN char const *nta_outgoing_method_name(nta_outgoing_t const *orq);
+SOFIAPUBFUN uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN unsigned nta_outgoing_delay(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq);
+SOFIAPUBFUN url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq);
+SOFIAPUBFUN msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq, 
+				    nta_response_f *callback,
+				    nta_outgoing_magic_t *magic,
+				    char const *to_tag,
+				    sip_rseq_t const *rseq);
+
+SOFIAPUBFUN int nta_outgoing_cancel(nta_outgoing_t *);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq, 
+				     nta_response_f *callback,
+				     nta_outgoing_magic_t *magic,
+				     tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN void nta_outgoing_destroy(nta_outgoing_t *);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_find(nta_agent_t const *sa,
+				  msg_t const *msg,
+				  sip_t const *sip, 
+				  sip_via_t const *v);
+
+SOFIAPUBFUN int nta_tport_keepalive(nta_outgoing_t *orq);
+
+/* ----------------------------------------------------------------------
+ * 8) Reliable provisional responses (100rel)
+ */
+
+/* UAC side */
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
+				   nta_outgoing_t *oorq,
+				   nta_response_f *callback,
+				   nta_outgoing_magic_t *magic,
+				   url_string_t const *route_url,
+				   sip_t const *response_to_prack,
+				   tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq);
+SOFIAPUBFUN int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq);
+
+/* UAS side */
+
+/** NTA reliable response */
+typedef struct nta_reliable_s   nta_reliable_t;
+
+#ifndef NTA_RELIABLE_MAGIC_T
+/** Default type of application context for reliable NTA responses.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_RELIABLE_MAGIC_T struct nta_reliable_magic_s
+#endif
+
+/** Application context for reliable NTA requests */
+typedef NTA_RELIABLE_MAGIC_T  nta_reliable_magic_t;
+
+typedef int nta_prack_f(nta_reliable_magic_t *rmagic,
+			nta_reliable_t *rel,
+			nta_incoming_t *prack, 
+			sip_t const *sip);
+
+SOFIAPUBFUN
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *ireq,
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    int status, char const *phrase, 
+				    tag_type_t tag, 
+				    tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq, 
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    msg_t *msg);
+
+SOFIAPUBFUN void nta_reliable_destroy(nta_reliable_t *);
+
+/* ----------------------------------------------------------------------
+ * Backward-compatibility stuff - going away soon
+ */
+
+#define nta_outgoing_tmcreate nta_outgoing_mcreate
+#define nta_msg_response_complete(msg, irq, status, phrase) \
+  nta_incoming_complete_response((irq), (msg), (status), (phrase), TAG_END())
+
+SOFIAPUBFUN void nta_msg_discard(nta_agent_t *agent, msg_t *msg);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_STATELESS_H
+/** Defined when <sofia-sip/nta_stateless.h> has been included. */
+#define NTA_STATELESS_H 
+
+/**@file sofia-sip/nta_stateless.h   
+ * @brief NTA functions for stateless SIP processing.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep  4 15:54:57 2001 ppessi
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/**@typedef int nta_message_f(nta_agent_magic_t *context,
+ *                            nta_agent_t *agent,
+ *			      msg_t *msg,
+ *			      sip_t *sip);
+ *
+ * Callback for incoming messages.
+ * 
+ * The typedef nta_message_f() defines prototype for the callback functions
+ * invoked by NTA when it has received an incoming message that will be
+ * processed statelessly.
+ * 
+ * The application can either discard the message by calling
+ * nta_msg_discard(), forward it by calling nta_msg_tsend() or reply to the
+ * message by calling nta_msg_treply(). When application wants to process a
+ * request statefully, it passes the message to a leg with the function
+ * nta_leg_stateful(). A new leg can be created by calling the function
+ * nta_leg_tcreate().
+ * 
+ * @par Prototype
+ * @code
+ * int message_callback(nta_agent_magic_t *context,
+ *                      nta_agent_t *agent,
+ *                      msg_t *msg,
+ *                      sip_t *sip);
+ * @endcode
+ * 
+ * @param context agent context
+ * @param agent   agent handle
+ * @param msg     received message
+ * @param sip     contents of message
+ *
+ * @return
+ * This callback function should always return 0.
+ */
+
+/** Forward a request or response message. */
+SOFIAPUBFUN
+int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+		  tag_type_t tag, tag_value_t value, ...);
+
+/** Reply to a request message. */
+SOFIAPUBFUN
+int nta_msg_mreply(nta_agent_t *agent,
+		   msg_t *reply, sip_t *sip,
+		   int status, char const *phrase,
+		   msg_t *req_msg,
+		   tag_type_t tag, tag_value_t value, ...);
+
+/** Reply to a request message. */
+SOFIAPUBFUN
+int nta_msg_treply(nta_agent_t *self, 
+		   msg_t *msg,
+		   int status, char const *phrase,
+		   tag_type_t tag, tag_value_t value, ...);
+
+/** ACK and BYE an unknown 200 OK response to INVITE. */
+SOFIAPUBFUN int nta_msg_ackbye(nta_agent_t *a, msg_t *msg);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(NTA_STATELESS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,687 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_TAG_H
+/** Defined when <sofia-sip/nta_tag.h> has been included. */
+#define NTA_TAG_H
+
+/**@file sofia-sip/nta_tag.h   
+ * @brief NTA tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep  4 15:54:57 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all nta tags. */
+NTA_DLL extern tag_type_t nta_tag_list[];
+
+/** Filter tag matching any nta tag. */
+#define NTATAG_ANY()         ntatag_any, ((tag_value_t)0)
+NTA_DLL extern tag_typedef_t ntatag_any;
+
+/* Tags for parameters */
+
+NTA_DLL extern tag_typedef_t ntatag_mclass;
+/** Message class used by NTA. @HI */
+#define NTATAG_MCLASS(x) ntatag_mclass, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_mclass_ref;
+#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_req_mask;
+/** Mask for bad request messages. 
+ * 
+ * If an incoming request has erroneous headers matching with the mask, nta
+ * automatically returns a 400 Bad Message response to them. If no mask is
+ * specified, all requests with any bad header are dropped.
+ * 
+ */
+#define NTATAG_BAD_REQ_MASK(x) ntatag_bad_req_mask, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_req_mask_ref;
+#define NTATAG_BAD_REQ_MASK_REF(x) ntatag_bad_req_mask_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_resp_mask;
+/** Mask for bad response messages. 
+ * 
+ * If an incoming response has erroneous headers matching with the mask, nta
+ * drops the response message. If no mask is specified, all responses with
+ * any bad header are dropped.
+ */
+#define NTATAG_BAD_RESP_MASK(x) ntatag_bad_resp_mask, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_resp_mask_ref;
+#define NTATAG_BAD_RESP_MASK_REF(x) ntatag_bad_resp_mask_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_default_proxy;
+/** URL for (default) proxy. @HI */
+#define NTATAG_DEFAULT_PROXY(x) \
+ntatag_default_proxy, urltag_url_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_default_proxy_ref;
+#define NTATAG_DEFAULT_PROXY_REF(x) \
+ntatag_default_proxy_ref, urltag_url_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_contact;
+/** Contact used by NTA. @HI */
+#define NTATAG_CONTACT(x) \
+ntatag_contact, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_contact_ref;
+#define NTATAG_CONTACT_REF(x) \
+ntatag_contact_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_target;
+/** Dialog target (contact) used by NTA. @HI */
+#define NTATAG_TARGET(x) \
+ntatag_target, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_target_ref;
+#define NTATAG_TARGET_REF(x) \
+ntatag_target_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_aliases;
+/** Aliases used by NTA. @HI @deprecated */
+#define NTATAG_ALIASES(x) \
+ntatag_aliases, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_aliases_ref;
+#define NTATAG_ALIASES_REF(x) \
+ntatag_aliases_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_branch_key;
+/** Branch key. @HI */
+#define NTATAG_BRANCH_KEY(x) \
+ntatag_branch_key, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_branch_key_ref;
+#define NTATAG_BRANCH_KEY_REF(x) \
+ntatag_branch_key_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_ack_branch;
+/** Branch for ACKed transaction. @HI */
+#define NTATAG_ACK_BRANCH(x) \
+ntatag_ack_branch, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_ack_branch_ref;
+#define NTATAG_ACK_BRANCH_REF(x) \
+ntatag_ack_branch_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_comp;
+/** Compression algorithm. @HI */
+#define NTATAG_COMP(x) \
+ntatag_comp, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_comp_ref;
+#define NTATAG_COMP_REF(x) \
+ntatag_comp_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_msg;
+/** Pass a SIP message to treply()/tcreate() functions. @HI */
+#define NTATAG_MSG(x)     ntatag_msg, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_msg_ref;
+#define NTATAG_MSG_REF(x) ntatag_msg_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_tport;
+/** Pass a transport object to msg_tsend/msg_treply. @HI */
+#define NTATAG_TPORT(x)     ntatag_tport, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tport_ref;
+#define NTATAG_TPORT_REF(x) ntatag_tport_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_remote_cseq;
+/** Remote CSeq number. @HI */
+#define NTATAG_REMOTE_CSEQ(x) ntatag_remote_cseq, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_remote_cseq_ref;
+#define NTATAG_REMOTE_CSEQ_REF(x) ntatag_remote_cseq_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_smime;
+/** Provide S/MIME context to NTA. @HI */
+#define NTATAG_SMIME(x)     ntatag_smime, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_smime_ref;
+#define NTATAG_SMIME_REF(x) ntatag_smime_ref, tag_ptr_vr(&(x), (x))
+ 
+NTA_DLL extern tag_typedef_t ntatag_maxsize;
+/** Maximum size of incoming message. @HI */
+#define NTATAG_MAXSIZE(x) ntatag_maxsize, tag_usize_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_maxsize_ref;
+#define NTATAG_MAXSIZE_REF(x) ntatag_maxsize_ref, tag_usize_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_udp_mtu;
+/** Maximum size of outgoing UDP request. @HI */
+#define NTATAG_UDP_MTU(x) ntatag_udp_mtu, tag_usize_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_udp_mtu_ref;
+#define NTATAG_UDP_MTU_REF(x) ntatag_udp_mtu_ref, tag_usize_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_max_forwards;
+/** Default value for @MaxForwards header. 
+ *
+ * @since New in @VERSION_1_12_2.
+ * @hideinitializer 
+ */
+#define NTATAG_MAX_FORWARDS(x) ntatag_max_forwards, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_max_forwards_ref;
+#define NTATAG_MAX_FORWARDS_REF(x) ntatag_max_forwards_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1;
+/** Initial retransmission interval (in milliseconds) @HI */
+#define NTATAG_SIP_T1(x) ntatag_sip_t1, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1_ref;
+#define NTATAG_SIP_T1_REF(x) ntatag_sip_t1_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1x64;
+/** Transaction timeout (defaults to T1 * 64). @HI */
+#define NTATAG_SIP_T1X64(x) ntatag_sip_t1x64, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1x64_ref;
+#define NTATAG_SIP_T1X64_REF(x) ntatag_sip_t1x64_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t2;
+/** Maximum retransmission interval (in milliseconds) @HI */
+#define NTATAG_SIP_T2(x) ntatag_sip_t2, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t2_ref;
+#define NTATAG_SIP_T2_REF(x) ntatag_sip_t2_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t4;
+/** Transaction lifetime (in milliseconds) @HI */
+#define NTATAG_SIP_T4(x)    ntatag_sip_t4, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t4_ref;
+#define NTATAG_SIP_T4_REF(x) ntatag_sip_t4_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_progress;
+/** Progress timer for User-Agents (interval for retranmitting 1XXs) @HI */
+#define NTATAG_PROGRESS(x)    ntatag_progress, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_progress_ref;
+#define NTATAG_PROGRESS_REF(x) ntatag_progress_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_blacklist;
+/** Add Retry-After header to internally-generated error messages. @HI */
+#define NTATAG_BLACKLIST(x)  ntatag_blacklist, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_blacklist_ref;
+#define NTATAG_BLACKLIST_REF(x) ntatag_blacklist_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_debug_drop_prob;
+/** Packet drop probability for debugging. 
+ *
+ * The packet drop probability parameter is useful mainly in proxies for
+ * debugging purposes. The stack drops an incoming message with the given
+ * probability. The range is in 0 .. 1000, 500 means p=0.5.
+ @HI */
+#define NTATAG_DEBUG_DROP_PROB(x) ntatag_debug_drop_prob, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_debug_drop_prob_ref;
+#define NTATAG_DEBUG_DROP_PROB_REF(x) ntatag_debug_drop_prob_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_options;
+/** Semicolon-separate SigComp options. @HI */
+#define NTATAG_SIGCOMP_OPTIONS(x)    ntatag_sigcomp_options, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_options_ref;
+#define NTATAG_SIGCOMP_OPTIONS_REF(x) ntatag_sigcomp_options_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_close;
+/** Close SigComp compartment after completing transaction. @HI */
+#define NTATAG_SIGCOMP_CLOSE(x)  ntatag_sigcomp_close, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_close_ref;
+#define NTATAG_SIGCOMP_CLOSE_REF(x) ntatag_sigcomp_close_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_aware;
+/** Indicate that the application is SigComp-aware. */
+#define NTATAG_SIGCOMP_AWARE(x) ntatag_sigcomp_aware, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_aware_ref;
+#define NTATAG_SIGCOMP_AWARE_REF(x) ntatag_sigcomp_aware_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_algorithm;
+/** Specify SigComp algorithm. For example, NULL, LZSS, or LZSS-POC.
+ */
+#define NTATAG_SIGCOMP_ALGORITHM(x) ntatag_sigcomp_algorithm, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_algorithm_ref;
+#define NTATAG_SIGCOMP_ALGORITHM_REF(x) \
+ntatag_sigcomp_algorithm_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_ua;
+/** If true, NTA acts as User Agent Server or Client by default. @HI */
+#define NTATAG_UA(x) ntatag_ua, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_ua_ref;
+#define NTATAG_UA_REF(x) ntatag_ua_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_stateless;
+/** If true, agent processes incoming requests statelessly by default. @HI */
+#define NTATAG_STATELESS(x) ntatag_stateless, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_stateless_ref;
+#define NTATAG_STATELESS_REF(x) ntatag_stateless_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_user_via;
+/** Allow application to insert Via headers. @HI */
+#define NTATAG_USER_VIA(x) ntatag_user_via, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_user_via_ref;
+#define NTATAG_USER_VIA_REF(x) ntatag_user_via_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_extra_100;
+/** Respond with "100 Trying" if application has not responded. @HI */
+#define NTATAG_EXTRA_100(x)    ntatag_extra_100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_extra_100_ref;
+#define NTATAG_EXTRA_100_REF(x) ntatag_extra_100_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_100;
+/** Pass "100 Trying" provisional answers to the application. @HI */
+#define NTATAG_PASS_100(x) ntatag_pass_100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_100_ref;
+#define NTATAG_PASS_100_REF(x) ntatag_pass_100_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_timeout_408;
+/** Generate "408 Request Timeout" response when request times out. @HI */
+#define NTATAG_TIMEOUT_408(x)  ntatag_timeout_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_timeout_408_ref;
+#define NTATAG_TIMEOUT_408_REF(x) ntatag_timeout_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_408;
+/** Pass "408 Request Timeout" responses to client. @HI */
+#define NTATAG_PASS_408(x)  ntatag_pass_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_408_ref;
+#define NTATAG_PASS_408_REF(x) ntatag_pass_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_no_dialog;
+/** Create a leg without dialog. @HI */
+#define NTATAG_NO_DIALOG(x)       ntatag_no_dialog, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_no_dialog_ref;
+#define NTATAG_NO_DIALOG_REF(x)   ntatag_no_dialog_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_merge_482;
+/** Merge requests, send 482 to other requests. @HI */
+#define NTATAG_MERGE_482(x)       ntatag_merge_482, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_merge_482_ref;
+#define NTATAG_MERGE_482_REF(x)   ntatag_merge_482_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_2543;
+/** Send a CANCEL to an INVITE without an provisional response. @HI */
+#define NTATAG_CANCEL_2543(x)     ntatag_cancel_2543, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_2543_ref;
+#define NTATAG_CANCEL_2543_REF(x) ntatag_cancel_2543_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_408;
+/** Do not send a CANCEL but just timeout the request. @HI */
+#define NTATAG_CANCEL_408(x)     ntatag_cancel_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_408_ref;
+#define NTATAG_CANCEL_408_REF(x) ntatag_cancel_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_tag_3261;
+/** When responding to requests, use unique tags. @HI */
+#define NTATAG_TAG_3261(x)        ntatag_tag_3261, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tag_3261_ref;
+#define NTATAG_TAG_3261_REF(x)    ntatag_tag_3261_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_timestamp;
+/** Use Timestamp header. @HI */
+#define NTATAG_USE_TIMESTAMP(x) ntatag_use_timestamp, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_timestamp_ref;
+#define NTATAG_USE_TIMESTAMP_REF(x) ntatag_use_timestamp_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_method;
+/** Method name. @HI */
+#define NTATAG_METHOD(x)          ntatag_method, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_method_ref;
+#define NTATAG_METHOD_REF(x)      ntatag_method_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_487;
+/** When a CANCEL is received, reply with 487 response. True by default. @HI */
+#define NTATAG_CANCEL_487(x)     ntatag_cancel_487, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_487_ref;
+#define NTATAG_CANCEL_487_REF(x) ntatag_cancel_487_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_rel100;
+/** Include rel100 in INVITE requests. @HI */
+#define NTATAG_REL100(x)     ntatag_rel100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_rel100_ref;
+#define NTATAG_REL100_REF(x) ntatag_rel100_ref, tag_bool_vr(&(x))
+ 
+NTA_DLL extern tag_typedef_t ntatag_sipflags;
+/** Set SIP parser flags. @HI */
+#define NTATAG_SIPFLAGS(x)     ntatag_sipflags, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sipflags_ref;
+#define NTATAG_SIPFLAGS_REF(x) ntatag_sipflags_ref, tag_uint_vr(&(x))
+ 
+NTA_DLL extern tag_typedef_t ntatag_client_rport;
+/** Add rport at client. @HI */
+#define NTATAG_CLIENT_RPORT(x) ntatag_client_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_client_rport_ref;
+#define NTATAG_CLIENT_RPORT_REF(x) ntatag_client_rport_ref, tag_bool_vr(&(x))
+
+#define NTATAG_RPORT(x) ntatag_client_rport, tag_bool_v((x))
+#define NTATAG_RPORT_REF(x) ntatag_client_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_server_rport;
+/** Use rport at server. @HI */
+#define NTATAG_SERVER_RPORT(x) ntatag_server_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_server_rport_ref;
+#define NTATAG_SERVER_RPORT_REF(x) ntatag_server_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_tcp_rport;
+/** Use rport with TCP, too. @HI */
+#define NTATAG_TCP_RPORT(x) ntatag_tcp_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tcp_rport_ref;
+#define NTATAG_TCP_RPORT_REF(x) ntatag_tcp_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_preload;
+/** Preload by N bytes. @HI */
+#define NTATAG_PRELOAD(x) ntatag_preload, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_preload_ref;
+#define NTATAG_PRELOAD_REF(x) ntatag_preload_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_naptr;
+/** If true, try to use NAPTR records when resolving. @HI */
+#define NTATAG_USE_NAPTR(x) ntatag_use_naptr, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_naptr_ref;
+#define NTATAG_USE_NAPTR_REF(x) ntatag_use_naptr_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_srv;
+/** If true, try to use SRV records when resolving. @HI */
+#define NTATAG_USE_SRV(x) ntatag_use_srv, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_srv_ref;
+#define NTATAG_USE_SRV_REF(x) ntatag_use_srv_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_rseq;
+/** RSeq value for nta_outgoing_prack(), @HI */
+#define NTATAG_RSEQ(x)    ntatag_rseq, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_rseq_ref;
+#define NTATAG_RSEQ_REF(x) ntatag_rseq_ref, tag_uint_vr(&(x))
+
+/* ====================================================================== */
+/* Tags for statistics. */
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash;
+#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_ref;
+#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash;
+#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_ref;
+#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash;
+#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_ref;
+#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used;
+#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used_ref;
+#define NTATAG_S_IRQ_HASH_USED_REF(x) \
+ntatag_s_irq_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used;
+#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used_ref;
+#define NTATAG_S_ORQ_HASH_USED_REF(x) \
+ntatag_s_orq_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used;
+#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used_ref;
+#define NTATAG_S_LEG_HASH_USED_REF(x) \
+ntatag_s_leg_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_msg;
+#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_msg_ref;
+#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_request;
+#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_request_ref;
+#define NTATAG_S_RECV_REQUEST_REF(x)\
+ ntatag_s_recv_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_response;
+#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_response_ref;
+#define NTATAG_S_RECV_RESPONSE_REF(x)\
+ ntatag_s_recv_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_message;
+#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_message_ref;
+#define NTATAG_S_BAD_MESSAGE_REF(x)\
+ ntatag_s_bad_message_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_request;
+#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_request_ref;
+#define NTATAG_S_BAD_REQUEST_REF(x)\
+ ntatag_s_bad_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_response;
+#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_response_ref;
+#define NTATAG_S_BAD_RESPONSE_REF(x)\
+ ntatag_s_bad_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_request;
+#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_request_ref;
+#define NTATAG_S_DROP_REQUEST_REF(x)\
+ ntatag_s_drop_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_response;
+#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_response_ref;
+#define NTATAG_S_DROP_RESPONSE_REF(x)\
+ ntatag_s_drop_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_client_tr;
+#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_client_tr_ref;
+#define NTATAG_S_CLIENT_TR_REF(x)\
+ ntatag_s_client_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_server_tr;
+#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_server_tr_ref;
+#define NTATAG_S_SERVER_TR_REF(x)\
+ ntatag_s_server_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr;
+#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr_ref;
+#define NTATAG_S_DIALOG_TR_REF(x)\
+ ntatag_s_dialog_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_acked_tr;
+#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_acked_tr_ref;
+#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr;
+#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr_ref;
+#define NTATAG_S_CANCELED_TR_REF(x)  \
+ ntatag_s_canceled_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_request;
+#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_request_ref;
+#define NTATAG_S_TRLESS_REQUEST_REF(x)\
+ ntatag_s_trless_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr;
+#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr_ref;
+#define NTATAG_S_TRLESS_TO_TR_REF(x)\
+ ntatag_s_trless_to_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_response;
+#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_response_ref;
+#define NTATAG_S_TRLESS_RESPONSE_REF(x)\
+ ntatag_s_trless_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_200;
+#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_200_ref;
+#define NTATAG_S_TRLESS_200_REF(x)\
+ ntatag_s_trless_200_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_merged_request;
+#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_merged_request_ref;
+#define NTATAG_S_MERGED_REQUEST_REF(x)\
+ ntatag_s_merged_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_msg;
+#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_msg_ref;
+#define NTATAG_S_SENT_MSG_REF(x)\
+ ntatag_s_sent_msg_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_request;
+#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_request_ref;
+#define NTATAG_S_SENT_REQUEST_REF(x)\
+ ntatag_s_sent_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_response;
+#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_response_ref;
+#define NTATAG_S_SENT_RESPONSE_REF(x)\
+ ntatag_s_sent_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_request;
+#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_request_ref;
+#define NTATAG_S_RETRY_REQUEST_REF(x)\
+ ntatag_s_retry_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_response;
+#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_response_ref;
+#define NTATAG_S_RETRY_RESPONSE_REF(x)\
+ ntatag_s_retry_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_retry;
+#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_retry_ref;
+#define NTATAG_S_RECV_RETRY_REF(x)\
+ ntatag_s_recv_retry_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_request;
+#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_request_ref;
+#define NTATAG_S_TOUT_REQUEST_REF(x)\
+ ntatag_s_tout_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_response;
+#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_response_ref;
+#define NTATAG_S_TOUT_RESPONSE_REF(x)\
+ ntatag_s_tout_response_ref, tag_uint_vr(&(x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined(nta_tag_h) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_TPORT_H
+/** Defined when <sofia-sip/nta_tport.h> has been included. */
+#define NTA_TPORT_H
+
+/**
+ * @file sofia-sip/nta_tport.h
+ * @brief Transport and SigComp handling
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Oct  7 20:04:39 2004 ppessi
+ * 
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct tport_s;
+
+#ifndef TPORT_T
+#define TPORT_T struct tport_s
+typedef TPORT_T tport_t;
+#endif
+
+#ifndef NTA_UPDATE_MAGIC_T
+#define NTA_UPDATE_MAGIC_T void
+#endif
+typedef NTA_UPDATE_MAGIC_T nta_update_magic_t;
+
+struct sigcomp_compartment;
+struct sigcomp_udvm;
+
+#define nta_transport nta_incoming_transport
+
+SOFIAPUBFUN
+tport_t *nta_incoming_transport(nta_agent_t *, nta_incoming_t *, msg_t *msg);
+
+SOFIAPUBFUN
+struct sigcomp_compartment *nta_incoming_compartment(nta_incoming_t *irq);
+
+SOFIAPUBFUN tport_t *nta_outgoing_transport(nta_outgoing_t *orq);
+
+SOFIAPUBFUN
+struct sigcomp_compartment *
+nta_outgoing_compartment(nta_outgoing_t *orq);
+
+SOFIAPUBFUN void nta_compartment_decref(struct sigcomp_compartment **);
+
+typedef void nta_update_tport_f(nta_update_magic_t *, nta_agent_t *);
+
+SOFIAPUBFUN
+int nta_agent_bind_tport_update(nta_agent_t *agent,
+				nta_update_magic_t *magic,
+				nta_update_tport_f *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined NTA_TPORT_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SL_UTILS_H
+/** Defined when <sofia-sip/sl_utils.h> has been included. */
+#define SL_UTILS_H 
+
+/**@ingroup sl_utils 
+ * 
+ * @file sofia-sip/sl_utils.h @brief Prototypes for SIP helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct  5 15:38:39 2000 ppessi
+ */
+
+#include <stdio.h>
+
+#ifndef STRING0_H
+#include <sofia-sip/string0.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_LOG_T
+#define SU_LOG_T
+typedef struct su_log_s su_log_t;
+#endif
+
+/* Read from file */
+SOFIAPUBFUN sip_payload_t *sl_read_payload(su_home_t *home, char const *fname);
+SOFIAPUBFUN sip_payload_t *sl_fread_payload(su_home_t *home, FILE *);
+
+/* Printing functions */
+SOFIAPUBFUN void 
+sl_message_log(FILE *, char const *prefix, sip_t const *, int details);
+SOFIAPUBFUN issize_t
+sl_header_print(FILE *, char const *fmt, sip_header_t const *h),
+sl_from_print(FILE *, char const *fmt, sip_from_t const *from),
+sl_to_print(FILE *, char const *fmt, sip_to_t const *to),
+sl_contact_print(FILE *, char const *fmt, sip_contact_t const *m),
+sl_allow_print(FILE *, char const *fmt, sip_allow_t const *g),
+sl_payload_print(FILE *, char const *prefix, sip_payload_t const *pl),
+sl_via_print(FILE *, char const *fmt, sip_via_t const *v);
+
+/* Logging functions */
+SOFIAPUBFUN void 
+sl_sip_log(su_log_t*, int lvl, char const *, sip_t const *, int details),
+sl_header_log(su_log_t *, int lvl, char const *, sip_header_t const *h),
+sl_from_log(su_log_t *, int lvl, char const *, sip_from_t const *from),
+sl_to_log(su_log_t *, int lvl, char const *, sip_to_t const *to),
+sl_contact_log(su_log_t *, int lvl, char const *, sip_contact_t const *m),
+sl_allow_log(su_log_t *, int, char const *, sip_allow_t const *g),
+sl_via_log(su_log_t *, int, char const *, sip_via_t const *v),
+sl_payload_log(su_log_t *, int, char const *, sip_payload_t const *pl);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3485 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE test_nta.c
+ *
+ * Test functions for NTA.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+typedef struct agent_t agent_t;
+
+#define SU_ROOT_MAGIC_T      agent_t
+
+#include <sofia-sip/su_wait.h>
+
+#include <msg_internal.h>
+
+#define NTA_AGENT_MAGIC_T    agent_t
+#define NTA_LEG_MAGIC_T      agent_t
+#define NTA_OUTGOING_MAGIC_T agent_t
+#define NTA_INCOMING_MAGIC_T agent_t
+#define NTA_RELIABLE_MAGIC_T agent_t
+
+#include "sofia-sip/nta.h"
+#include "nta_internal.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+#include <sofia-sip/sresolv.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/sofia_features.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/string0.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+
+SOFIAPUBVAR su_log_t nta_log[];
+SOFIAPUBVAR su_log_t tport_log[];
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void *)-1)
+
+struct sigcomp_compartment;
+
+char const name[] = "test_nta";
+
+struct agent_t {
+  su_home_t       ag_home[1];
+  int             ag_flags;
+  su_root_t      *ag_root;
+  msg_mclass_t   *ag_mclass;
+  nta_agent_t    *ag_agent;
+
+  url_string_t   *ag_obp;	/**< Outbound proxy. */
+
+  nta_leg_t      *ag_server_leg; /**< Leg for sip:%@% */
+  nta_leg_t      *ag_default_leg; /**< Leg for rest */
+
+  unsigned        ag_drop;
+
+  nta_outgoing_t *ag_orq;
+  int             ag_status;
+
+  char const     *ag_comp;
+  struct sigcomp_compartment *ag_client_compartment;
+
+  /* Server side */
+  int             ag_response;	/**< What we answer by default */
+  nta_incoming_t *ag_irq;
+
+  struct sigcomp_compartment *ag_server_compartment;
+
+  char const     *ag_m;
+
+  sip_contact_t const *ag_contact;
+  sip_from_t     *ag_alice;
+  sip_to_t       *ag_bob;
+
+  sip_contact_t  *ag_m_alice;
+  sip_contact_t  *ag_m_bob;
+  sip_contact_t  *ag_aliases;
+
+  nta_leg_t      *ag_alice_leg;
+  nta_leg_t      *ag_bob_leg;
+
+  msg_t          *ag_request;
+
+  nta_leg_t      *ag_expect_leg;
+  nta_leg_t      *ag_latest_leg;
+  nta_leg_t      *ag_call_leg;
+  nta_leg_t      *ag_tag_remote; /**< If this is set, outgoing_callback()
+				  *   tags it with the tag from remote.
+				  */
+  int             ag_tag_status; /**< Which response established dialog */
+  msg_param_t     ag_call_tag;	 /**< Tag used to establish dialog */
+
+  nta_reliable_t *ag_reliable;
+
+  sip_via_t      *ag_out_via;	/**< Outgoing via */
+  sip_via_t      *ag_in_via;	/**< Incoming via */
+
+  sip_content_type_t *ag_content_type;
+  sip_payload_t  *ag_payload;
+
+  msg_t          *ag_probe_msg;
+
+  /* Dummy servers */
+  char const     *ag_sink_port;
+  su_socket_t     ag_sink_socket, ag_down_socket;
+};
+
+static int test_init(agent_t *ag, char const *resolv_conf);
+static int test_deinit(agent_t *ag);
+static int test_bad_messages(agent_t *ag);
+static int test_routing(agent_t *ag);
+static int test_tports(agent_t *ag);
+static int test_resolv(agent_t *ag, char const *resolv_conf);
+static int test_dialog(agent_t *ag);
+static int test_call(agent_t *ag);
+static int test_prack(agent_t *ag);
+static int test_fix_467(agent_t *ag);
+
+static int test_for_ack(agent_t *ag,
+			nta_incoming_t *irq, 
+			sip_t const *sip);
+static int test_for_ack_or_timeout(agent_t *ag,
+				   nta_incoming_t *irq, 
+				   sip_t const *sip);
+
+int agent_callback(agent_t *ag,
+		   nta_agent_t *nta,
+		   msg_t *msg,
+		   sip_t *sip)
+{
+  if (tstflags & tst_verbatim) {
+    if (sip->sip_request) {
+      printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	     name, __func__, sip->sip_request->rq_method_name, 
+	     URL_PRINT_ARGS(sip->sip_request->rq_url),
+	     sip->sip_request->rq_version);
+    }
+    else {
+      printf("%s: %s: %s %03d %s\n", name, __func__, 
+	     sip->sip_status->st_version, 
+	     sip->sip_status->st_status, 
+	     sip->sip_status->st_phrase);
+    }
+  }
+
+  msg_destroy(msg);
+
+  return 0;
+}
+
+static
+void leg_match(agent_t *ag, nta_leg_t *leg, int always, char const *func)
+{
+  char const *match = "unknown leg";
+
+  if (!always && (tstflags & tst_verbatim) != tst_verbatim)
+    return;
+
+  if (leg == ag->ag_default_leg)
+    match = "ag_default_leg";
+  else if (leg == ag->ag_server_leg) 
+    match = "ag_server_leg";
+  else if (leg == ag->ag_alice_leg)
+    match = "ag_alice_leg";
+  else if (leg == ag->ag_bob_leg)
+    match = "ag_bob_leg";
+
+  printf("%s: %s: %smatched with %s\n", name, func, 
+	 always ? "mis" : "", match);
+}
+
+static
+void leg_zap(agent_t *ag, nta_leg_t *leg)
+{
+  if (leg == ag->ag_default_leg)
+    ag->ag_default_leg = NULL;
+  else if (leg == ag->ag_server_leg) 
+    ag->ag_server_leg = NULL;
+  else if (leg == ag->ag_alice_leg)
+    ag->ag_alice_leg = NULL;
+  else if (leg == ag->ag_bob_leg)
+    ag->ag_bob_leg = NULL;
+  else 
+     printf("%s:%u: %s: did not exist\n", 
+	    __FILE__, __LINE__, __func__);
+
+  nta_leg_destroy(leg);
+}
+
+
+int leg_callback_200(agent_t *ag,
+		     nta_leg_t *leg,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  if (!sip->sip_content_length ||
+      !sip->sip_via ||
+      !sip->sip_from || !sip->sip_from->a_tag)
+    return 500;
+
+  if (ag->ag_in_via == NULL)
+    ag->ag_in_via = sip_via_dup(ag->ag_home, sip->sip_via);
+
+  if (ag->ag_request == NULL)
+    ag->ag_request = nta_incoming_getrequest(irq);
+
+  ag->ag_latest_leg = leg;
+
+  if (ag->ag_expect_leg && leg != ag->ag_expect_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+  leg_match(ag, leg, 0, __func__);
+
+  if (sip->sip_request->rq_method == sip_method_bye) {
+    leg_zap(ag, leg);
+  }
+
+  return 200;
+}
+
+int leg_callback_500(agent_t *ag,
+		     nta_leg_t *leg,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  return 500;
+}
+
+int new_leg_callback_200(agent_t *ag,
+			 nta_leg_t *leg,
+			 nta_incoming_t *irq,
+			 sip_t const *sip)
+{
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  if (!sip->sip_content_length ||
+      !sip->sip_via ||
+      !sip->sip_from || !sip->sip_from->a_tag)
+    return 500;
+
+  ag->ag_latest_leg = leg;
+
+  if (ag->ag_expect_leg && leg != ag->ag_expect_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+  leg_match(ag, leg, 0, __func__);
+
+  ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+				   leg_callback_200,
+				   ag,
+				   URLTAG_URL(sip->sip_request->rq_url),
+				   SIPTAG_CALL_ID(sip->sip_call_id),
+				   SIPTAG_FROM(sip->sip_to),
+				   SIPTAG_TO(sip->sip_from),
+				   TAG_END());
+  if (!ag->ag_bob_leg ||
+      !nta_leg_tag(ag->ag_bob_leg, NULL) ||
+      !nta_leg_get_tag(ag->ag_bob_leg) ||
+      !nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)))
+    return 500;
+
+  return 200;
+}
+
+
+int outgoing_callback(agent_t *ag,
+		      nta_outgoing_t *orq,
+		      sip_t const *sip)
+{
+  BEGIN();
+
+  int status = sip->sip_status->st_status;
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s %03d %s\n", name, __func__, 
+	   sip->sip_status->st_version, 
+	   sip->sip_status->st_status, 
+	   sip->sip_status->st_phrase);
+  }
+
+  TEST_P(orq, ag->ag_orq);
+
+  ag->ag_status = status;
+
+  if (status < 200)
+    return 0;
+
+  if (ag->ag_comp) {
+    nta_compartment_decref(&ag->ag_client_compartment);
+    ag->ag_client_compartment = nta_outgoing_compartment(orq);
+  }
+
+  if (ag->ag_out_via == NULL)
+    ag->ag_out_via = sip_via_dup(ag->ag_home, sip->sip_via);
+
+  if (ag->ag_tag_remote) {
+    TEST_S(nta_leg_rtag(ag->ag_tag_remote, sip->sip_to->a_tag), 
+	   sip->sip_to->a_tag);
+    ag->ag_tag_remote = NULL;
+  }
+
+  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+  nta_outgoing_destroy(orq);
+  ag->ag_orq = NULL;
+
+  END();
+}
+
+static
+int test_magic_branch(agent_t *ag, sip_t const *sip) 
+{
+  BEGIN();
+  
+  if (sip) {
+    TEST_1(sip->sip_via);
+    TEST_S(sip->sip_via->v_branch, "MagicalBranch");
+  }
+
+  END();
+}
+
+static
+int magic_callback(agent_t *ag,
+		   nta_outgoing_t *orq,
+		   sip_t const *sip)
+{
+  test_magic_branch(ag, sip);
+  return outgoing_callback(ag, orq, sip);
+}
+
+void 
+nta_test_run(agent_t *ag)
+{
+  for (ag->ag_status = 0; ag->ag_status < 200;) {
+    if (tstflags & tst_verbatim) {
+      fputs(".", stdout); fflush(stdout);
+    }
+    su_root_step(ag->ag_root, 500L);
+  }
+}
+
+#include <sofia-sip/msg_mclass.h>
+
+int test_init(agent_t *ag, char const *resolv_conf)
+{
+  char const *contact = "sip:*:*;comp=sigcomp";
+  su_sockaddr_t su;
+  socklen_t sulen, sulen0;
+  su_socket_t s; 
+  int af;
+
+  BEGIN();
+
+  TEST_1(ag->ag_root = su_root_create(ag));
+
+  TEST_1(ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0));
+
+#if SU_HAVE_IN6
+  if (str0cmp(getenv("ipv6"), "true") == 0) {
+    contact = "sip:[::]:*;comp=sigcomp";
+    af = AF_INET6, sulen0 = sizeof (struct sockaddr_in6);
+  }
+  else {
+    af = AF_INET, sulen0 = sizeof (struct sockaddr_in);
+    contact = "sip:0.0.0.0:*;comp=sigcomp";
+  }
+#else
+  af = AF_INET, sulen0 = sizeof (struct sockaddr_in);
+  contact = "sip:0.0.0.0:*;comp=sigcomp";
+#endif
+
+  if (ag->ag_m)
+    contact = ag->ag_m;
+  else if (getenv("SIPCONTACT"))
+    contact = getenv("SIPCONTACT");
+
+  /* Sink server */
+  s = socket(af, SOCK_DGRAM, 0); TEST_1(s != INVALID_SOCKET);
+  memset(&su, 0, sulen = sulen0);
+  su.su_family = af;
+  if (getenv("sink")) {
+    su.su_port = htons(atoi(getenv("sink")));
+  }
+  TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1);
+  TEST_1(getsockname(s, &su.su_sa, &sulen) == 0);
+
+  ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port));
+  ag->ag_sink_socket = s;
+
+  /* Down server */
+  s = socket(af, SOCK_STREAM, 0); TEST_1(s != INVALID_SOCKET);
+  memset(&su, 0, sulen = sulen0);
+  su.su_family = af;
+  if (getenv("down")) {
+    su.su_port = htons(atoi(getenv("down")));
+  }
+  TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1);
+  ag->ag_down_socket = s;
+  
+  /* Create agent */
+  TEST_1(ag->ag_agent = nta_agent_create(ag->ag_root,
+					 (url_string_t *)contact,
+					 NULL,
+					 NULL,
+					 NTATAG_MCLASS(ag->ag_mclass),
+					 NTATAG_USE_TIMESTAMP(1),
+					 SRESTAG_RESOLV_CONF(resolv_conf),
+					 NTATAG_USE_NAPTR(0),
+					 NTATAG_USE_SRV(0),
+					 NTATAG_PRELOAD(2048),
+					 TAG_END()));
+
+  {
+    /* Initialize our headers */
+    sip_from_t from[1];
+    sip_to_t to[1];
+    sip_contact_t m[1];
+
+    sip_from_init(from);
+    sip_to_init(to);
+    sip_contact_init(m);
+
+    TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent));
+
+    *m->m_url = *ag->ag_contact->m_url;
+    m->m_url->url_user = "bob";
+    TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m));
+
+    to->a_display = "Bob";
+    *to->a_url = *ag->ag_contact->m_url;
+    to->a_url->url_user = "bob";
+    to->a_url->url_port = NULL;
+    TEST_1(ag->ag_bob = sip_to_dup(ag->ag_home, to));
+
+    *m->m_url = *ag->ag_contact->m_url;
+    m->m_url->url_user = "alice";
+    TEST_1(ag->ag_m_alice = sip_contact_dup(ag->ag_home, m));
+
+    from->a_display = "Alice";
+    *from->a_url = *ag->ag_contact->m_url;
+    from->a_url->url_user = "alice";
+    from->a_url->url_port = NULL;
+    TEST_1(ag->ag_alice = sip_from_dup(ag->ag_home, from));
+  }
+  {
+    char const data[] = 
+      "v=0\r\n"
+      "o=- 425432 423412 IN IP4 127.0.0.1\r\n"
+      "s= \r\n"
+      "c=IN IP4 127.0.0.1\r\n"
+      "m=5004 audio 8 0\r\n";
+
+    ag->ag_content_type = sip_content_type_make(ag->ag_home, "application/sdp");
+    ag->ag_payload = sip_payload_make(ag->ag_home, data);
+  }
+
+  {
+    sip_contact_t *m;
+
+    ag->ag_aliases = 
+      sip_contact_make(ag->ag_home, "sip:127.0.0.1, sip:localhost, sip:[::1]");
+    TEST_1(ag->ag_aliases);
+    TEST_1(ag->ag_aliases->m_next);
+    TEST_1(ag->ag_aliases->m_next->m_next);
+    TEST_P(ag->ag_aliases->m_next->m_next->m_next, NULL);
+
+    for (m = ag->ag_aliases; m; m = m->m_next)
+      m->m_url->url_port = ag->ag_contact->m_url->url_port;
+
+    TEST_1(m = sip_contact_dup(ag->ag_home, ag->ag_contact));
+
+    m->m_next = ag->ag_aliases;
+    ag->ag_aliases = m;
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_REL100(1),
+			      NTATAG_UA(1), 
+			      NTATAG_USE_NAPTR(1),
+			      NTATAG_USE_SRV(1),
+			      NTATAG_MAX_FORWARDS(20),
+			      TAG_END()),
+	 6);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
+			      TAG_END()), 2);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_DEFAULT_PROXY(NULL),
+			      TAG_END()), 2);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_DEFAULT_PROXY("tel:+35878008000"),
+			      TAG_END()), -1);
+
+  }
+  
+  {
+    url_t url[1];
+
+    /* Create the server leg */
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "%";
+    TEST_1(ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent, 
+					       leg_callback_200,
+					       ag,
+					       NTATAG_NO_DIALOG(1),
+					       URLTAG_URL(url),
+					       TAG_END()));
+  }
+
+  END();
+}  
+
+int test_reinit(agent_t *ag)
+{
+  BEGIN();
+  /* Create a new default leg */
+  nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
+  TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, 
+					     leg_callback_200,
+					     ag,
+					     NTATAG_NO_DIALOG(1),
+					     TAG_END()));
+  END();
+}
+
+int test_deinit(agent_t *ag)
+{
+  BEGIN();
+
+  if (ag->ag_request) msg_destroy(ag->ag_request), ag->ag_request = NULL;
+
+  su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+  nta_leg_destroy(ag->ag_alice_leg);
+  nta_leg_destroy(ag->ag_bob_leg);
+  nta_leg_destroy(ag->ag_default_leg);
+  nta_leg_destroy(ag->ag_server_leg);
+
+  nta_agent_destroy(ag->ag_agent);
+  su_root_destroy(ag->ag_root);
+
+  su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL;
+
+  free(ag->ag_mclass), ag->ag_mclass = NULL;
+
+  END();
+}  
+
+static
+int readfile(FILE *f, void **contents)
+{
+  /* Read in whole (binary!) file */
+  char *buffer = NULL;
+  long size;
+  size_t len;
+  
+  /* Read whole file in */
+  if (fseek(f, 0, SEEK_END) < 0 ||
+      (size = ftell(f)) < 0 ||
+      fseek(f, 0, SEEK_SET) < 0 ||
+      (long)(len = (size_t)size) != size) {
+    fprintf(stderr, "%s: unable to determine file size (%s)\n", 
+	    __func__, strerror(errno));
+    return -1;
+  }
+
+  if (!(buffer = malloc(len + 2)) ||
+      fread(buffer, 1, len, f) != len) {
+    fprintf(stderr, "%s: unable to read file (%s)\n", __func__, strerror(errno));
+    if (buffer)
+      free(buffer);
+    return -1;
+  }
+
+  buffer[len] = '\0';
+
+  *contents = buffer;
+
+  return len;
+}
+
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#endif 
+
+static int test_bad_messages(agent_t *ag)
+{
+#if HAVE_DIRENT_H
+  DIR *dir;
+  struct dirent *d;
+  char name[PATH_MAX + 1] = "../sip/tests/";
+  size_t offset;
+  char const *host, *port;
+  su_addrinfo_t *ai,  hints[1];
+  su_socket_t s;
+  su_sockaddr_t su[1];
+  socklen_t sulen;
+  char via[64];
+  size_t vlen;
+  int i;
+
+  dir = opendir(name);
+  if (dir == NULL && getenv("srcdir")) {
+    strncpy(name, getenv("srcdir"), PATH_MAX);
+    strncat(name, "/../sip/tests/", PATH_MAX);
+    dir = opendir(name);
+  }
+
+  if (dir == NULL) {
+    fprintf(stderr, "test_nta: cannot find sip torture messages\n"); 
+    fprintf(stderr, "test_nta: tried %s\n", name); 
+    return 0;
+  }
+
+  offset = strlen(name);
+
+  BEGIN();
+
+  TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, 
+					      leg_callback_500,
+					      ag,
+					      NTATAG_NO_DIALOG(1),
+					      TAG_END()));
+
+  host = ag->ag_contact->m_url->url_host;
+  if (host_is_ip6_reference(host)) {
+    host = strcpy(via, host + 1);
+    via[strlen(via) - 1] = '\0';
+  }
+  port = url_port(ag->ag_contact->m_url);
+
+  memset(hints, 0, sizeof hints);
+  hints->ai_socktype = SOCK_DGRAM;
+  hints->ai_protocol = IPPROTO_UDP;
+  
+  TEST(su_getaddrinfo(host, port, hints, &ai), 0); TEST_1(ai);
+  s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); TEST_1(s != -1);
+  memset(su, 0, sulen = sizeof su); 
+  su->su_len = sizeof su; su->su_family = ai->ai_family;
+  TEST_1(bind(s, &su->su_sa, sulen) == 0);
+  TEST_1(getsockname(s, &su->su_sa, &sulen) == 0);
+  sprintf(via, "v: SIP/2.0/UDP is.invalid:%u\r\n", ntohs(su->su_port));
+  vlen = strlen(via);
+
+  for (d = readdir(dir); d; d = readdir(dir)) {
+    size_t len = strlen(d->d_name);
+    FILE *f;
+    int blen, n;
+    void *buffer; char *r;
+
+    if (len < strlen(".txt"))
+      continue;
+    if (strcmp(d->d_name + len - strlen(".txt"), ".txt"))
+      continue;
+    strncpy(name + offset, d->d_name, PATH_MAX - offset);
+    TEST_1(f = fopen(name, "rb"));
+    TEST_1((blen = readfile(f, &buffer)) > 0);
+    r = buffer;
+
+    if (strncmp(r, "JUNK ", 5) == 0) {
+      TEST_SIZE(su_sendto(s, r, blen, 0, ai->ai_addr, ai->ai_addrlen), blen);
+    }
+    else if (strncmp(r, "INVITE ", 7) != 0) {
+      su_iovec_t vec[3];
+      n = strcspn(r, "\r\n"); n += strspn(r + n, "\r\n");
+      vec[0].siv_base = r, vec[0].siv_len = n;
+      vec[1].siv_base = via, vec[1].siv_len = vlen;
+      vec[2].siv_base = r + n, vec[2].siv_len = blen - n;
+      TEST_SIZE(su_vsend(s, vec, 3, 0, (void *)ai->ai_addr, ai->ai_addrlen),
+		blen + vlen);
+    }
+    free(buffer);
+    su_root_step(ag->ag_root, 1);
+  }
+
+  su_close(s);
+
+  for (i = 0; i < 20; i++)
+    su_root_step(ag->ag_root, 1);
+
+  nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
+
+  closedir(dir);
+
+  END();
+#else
+  return 0;
+#endif /* HAVE_DIRENT_H */
+}
+
+static unsigned char const code[] = 
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#include <sofia-sip/su_uniqueid.h>
+
+sip_payload_t *test_payload(su_home_t *home, size_t size)
+{
+  sip_payload_t *pl = sip_payload_create(home, NULL, (isize_t)size);
+
+  if (pl) {
+    size_t i;
+    char *data = (char *)pl->pl_data;
+    
+    for (i = 0; i < size; i++) {
+      if ((i & 63) != 63)
+	data[i] = code[su_randint(0, 63)];
+      else
+	data[i] = '\n';
+    }
+  }
+
+  return pl;
+}
+
+/* Test transports */
+
+int test_tports(agent_t *ag)
+{
+  int udp = 0, tcp = 0, sctp = 0, tls = 0;
+  sip_via_t const *v, *v_udp_only = NULL;
+  char const *udp_comp = NULL;
+  char const *tcp_comp = NULL;
+
+  url_t url[1];
+
+  BEGIN();
+
+  *url = *ag->ag_contact->m_url;
+  url->url_port = "*";
+  url->url_params = "transport=tcp";
+
+  url->url_params = "transport=udp";
+
+  TEST_1(nta_agent_add_tport(ag->ag_agent, (url_string_t *)url, 
+			     TAG_END()) == 0);
+
+  TEST_1(v = nta_agent_via(ag->ag_agent));
+
+  for (; v; v = v->v_next) {
+    if (strcasecmp(v->v_protocol, sip_transport_udp) == 0) {
+      if (udp)
+	v_udp_only = v;
+      udp = 1;
+      if (udp_comp == NULL)
+	udp_comp = v->v_comp;
+    }
+    else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0) {
+      tcp = 1;
+      if (tcp_comp == NULL)
+	tcp_comp = v->v_comp;
+    }
+    else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0) {
+      sctp = 1;
+    }
+    else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0) {
+      tls = 1;
+    }
+  }
+
+  *url = *ag->ag_aliases->m_url;
+  url->url_user = "bob";
+
+  if (udp_comp || tcp_comp)
+    ag->ag_comp = "sigcomp";
+
+  {
+    /* Test 0.1
+     * Send a message from default leg to default leg 
+     */
+    char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n";
+    url_t url[1];
+
+    *url = *ag->ag_contact->m_url;
+    url->url_params = NULL;
+    ag->ag_expect_leg = ag->ag_default_leg;
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, 
+			       outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.1"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       SIPTAG_HEADER_STR(p_acid),
+			       TAG_END()));
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    TEST_1(ag->ag_request);
+
+    msg_destroy(ag->ag_request), ag->ag_request = NULL;
+
+    TEST_1(ag->ag_out_via->v_comp == NULL);
+
+    nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+  }
+
+  {
+    /* Test 0.1.2: test url_headers
+     *
+     * Send a message from default leg to default leg.
+     */
+    url_t url[1];
+    sip_t *sip;
+    
+    *url = *ag->ag_contact->m_url;
+    /* Test that method parameter is stripped and headers in query are used */
+    url->url_params = "method=MESSAGE;user=IP";
+    url->url_headers = "organization=United%20Testers";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, 
+			       outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.1.2"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    TEST_1(ag->ag_request);
+    TEST_1(sip = sip_object(ag->ag_request));
+
+    TEST_1(sip->sip_organization);
+    TEST_S(sip->sip_organization->g_string, "United Testers");
+    TEST_S(sip->sip_request->rq_url->url_params, "user=IP");
+    
+    TEST_1(ag->ag_out_via->v_comp == NULL);
+
+    nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+  }
+
+  /* Test 0.1.3
+   * Send a message from Bob to Alice using SIGCOMP and TCP
+   */
+  if (tcp_comp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    size_t size = 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+    if (url->url_params)
+      url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+    else
+      url->url_params = "transport=tcp";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    TEST_1(ag->ag_orq = 
+	   nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+				ag->ag_obp,
+				SIP_METHOD_MESSAGE,
+				(url_string_t *)url,
+				NTATAG_COMP("sigcomp"),
+				SIPTAG_SUBJECT_STR("Test 0.1.3"),
+				SIPTAG_FROM(ag->ag_bob),
+				SIPTAG_TO(ag->ag_alice),
+				SIPTAG_CONTACT(ag->ag_m_bob),
+				SIPTAG_PAYLOAD(pl),
+				TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_1(ag->ag_client_compartment);
+    nta_compartment_decref(&ag->ag_client_compartment);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_S(ag->ag_out_via->v_comp, "sigcomp");
+  }
+
+  /* Test 0.2
+   * Send a message from Bob to Alice
+   * This time specify a TCP URI, and include a large payload 
+   * of 512 kB
+   */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 512 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+    url->url_params = "transport=tcp";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       NULL,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.2"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       NTATAG_DEFAULT_PROXY(ag->ag_obp),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.3
+   * Send a message from Bob to Alice
+   * This time include a large payload of 512 kB, let NTA choose transport.
+   */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 512 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.3"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.4.1:
+   * Send a message from Bob to Alice
+   * This time include a payload of 2 kB, let NTA choose transport.
+   */
+  {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 2 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.4.1"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_out_via);
+    TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
+	   strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
+    su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+  }
+
+  /* Test 0.4.2:
+   * Send a message from Bob to Alices UDP-only address
+   * This time include a payload of 2 kB, let NTA choose transport.
+   */
+  if (v_udp_only) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 2 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+    url->url_host = v_udp_only->v_host;
+    url->url_port = v_udp_only->v_port;
+    url->url_params = NULL;	/* No sigcomp */
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_default_leg;
+
+    su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.4.2"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    TEST_1(ag->ag_in_via);
+    TEST_1(strcasecmp(ag->ag_in_via->v_protocol, "SIP/2.0/UDP") == 0);
+    su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+  }
+
+  /* Test 0.5:
+   * Send a message from Bob to Alice
+   * This time include a payload of 2 kB, try to use UDP.
+   */
+  if (udp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 2 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.5"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TPTAG_MTU(0xffffffff),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_out_via);
+    TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
+  }
+
+  if (udp) {
+    /* Send a message from default leg to server leg 
+     * using a prefilled Via header
+     */
+    sip_via_t via[1];
+
+    sip_via_init(via);
+
+    via->v_protocol = sip_transport_udp;
+    
+    via->v_host = ag->ag_contact->m_url->url_host;
+    via->v_port = ag->ag_contact->m_url->url_port;
+    
+    sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch");
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_ALIASES(ag->ag_aliases),
+			 NTATAG_USER_VIA(1),
+			 TAG_END());
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, 
+			       magic_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.6"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       SIPTAG_VIA(via),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_USER_VIA(0),
+			 TAG_END());
+  }
+
+  /* Test 0.7
+   * Send a message from Bob to Alice using SCTP 
+   */
+  if (sctp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 16 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+#if 0
+    if (url->url_params)
+      url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params);
+    else
+#endif
+      url->url_params = "transport=sctp";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.7"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.8: Send a too large message */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 128 * 1024;
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_MAXSIZE(65536),
+			 TAG_END());
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_latest_leg = NULL;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.8"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 413);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, NULL);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_MAXSIZE(2 * 1024 * 1024),
+			 TAG_END());
+  }
+
+  /* Test 0.9: Timeout */
+  {
+    url_t url[1];
+
+    printf("%s: starting MESSAGE timeout test, completing in 4 seconds\n",
+	   name);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_TIMEOUT_408(1),
+			 NTATAG_SIP_T1(25), 
+			 NTATAG_SIP_T1X64(64 * 25), 
+			 NTATAG_SIP_T2(8 * 25),
+			 NTATAG_SIP_T4(10 * 25),
+			 TAG_END());
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "timeout";
+    url->url_port = ag->ag_sink_port;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_latest_leg = NULL;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.9"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       TAG_END()));
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 408);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, NULL);
+
+    nta_agent_set_params(ag->ag_agent,
+			 NTATAG_SIP_T1(500),
+			 NTATAG_SIP_T1X64(64 * 500),
+			 NTATAG_SIP_T2(NTA_SIP_T2),
+			 NTATAG_SIP_T4(NTA_SIP_T4),
+			 TAG_END());
+  }
+  
+
+  END();
+}
+
+int leg_callback_destroy(agent_t *ag,
+			 nta_leg_t *leg,
+			 nta_incoming_t *irq,
+			 sip_t const *sip)
+{
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  ag->ag_latest_leg = leg;
+
+  nta_incoming_destroy(irq);
+
+  return 0;
+}
+
+int leg_callback_save(agent_t *ag,
+		      nta_leg_t *leg,
+		      nta_incoming_t *irq,
+		      sip_t const *sip)
+{
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  ag->ag_latest_leg = leg;
+  ag->ag_irq = irq;
+  ag->ag_status = 1000;
+
+  return 0;
+}
+
+
+int test_destroy_incoming(agent_t *ag)
+{
+  BEGIN();
+
+  url_t url[1];
+
+  *url = *ag->ag_contact->m_url;
+
+  /* Test 3.1
+   * Check that when a incoming request is destroyed in callback, 
+   * a 500 response is sent
+   */
+  ag->ag_expect_leg = ag->ag_default_leg;
+  nta_leg_bind(ag->ag_default_leg, leg_callback_destroy, ag);
+
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_default_leg, 
+			      outgoing_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_MESSAGE,
+			      (url_string_t *)url,
+			      SIPTAG_SUBJECT_STR("Test 3.1"),
+			      SIPTAG_FROM(ag->ag_alice),
+			      SIPTAG_TO(ag->ag_bob),
+			      TAG_END()));
+
+  nta_test_run(ag);
+  TEST(ag->ag_status, 500);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
+  /* Test 3.1
+   * Check that when a incoming request is destroyed, a 500 response is sent
+   */
+  nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag);
+
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_default_leg, 
+			      outgoing_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_MESSAGE,
+			      (url_string_t *)url,
+			      SIPTAG_SUBJECT_STR("Test 3.1"),
+			      SIPTAG_FROM(ag->ag_alice),
+			      SIPTAG_TO(ag->ag_bob),
+			      TAG_END()));
+
+  nta_test_run(ag);
+  TEST(ag->ag_status, 1000);
+  TEST_1(ag->ag_irq);
+  TEST_1(ag->ag_orq);
+  TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL;
+  nta_test_run(ag);
+  TEST(ag->ag_status, 500);
+  TEST_P(ag->ag_orq, NULL);
+
+  END();
+}
+
+int test_resolv(agent_t *ag, char const *resolv_conf)
+{
+  int udp = 0, tcp = 0, sctp = 0, tls = 0;
+  sip_via_t const *v;
+
+  url_t *url;
+
+  if (!resolv_conf)
+    return 0;
+
+  BEGIN();
+
+  nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+
+  nta_agent_set_params(ag->ag_agent, 
+		       NTATAG_SIP_T1(8 * 25), 
+		       NTATAG_SIP_T1X64(64 * 25), 
+		       NTATAG_SIP_T4(10 * 25),
+		       TAG_END());
+
+
+  TEST_1(v = nta_agent_via(ag->ag_agent));
+  for (; v; v = v->v_next) {
+    if (strcasecmp(v->v_protocol, sip_transport_udp) == 0)
+      udp = 1;
+    else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0)
+      tcp = 1;
+    else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0)
+      sctp = 1;
+    else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0)
+      tls = 1;
+  }
+
+  url = url_hdup(ag->ag_home, (void *)"sip:example.org"); TEST_1(url);
+
+  {
+    /* Test 1.1
+     * Send a message to sip:example.org
+     */
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.1"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.2
+     * Send a message to sip:srv.example.org
+     */
+    url->url_host = "srv.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.2"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.3
+     * Send a message to sip:ipv.example.org
+     */
+    url->url_host = "ipv.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.3"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.4.1
+     * Send a message to sip:down.example.org
+     */
+    url->url_host = "down.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.4.1"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
+  }
+
+  {
+    /* Test 1.4.2
+     * Send a message to sip:na503.example.org
+     */
+    url->url_host = "na503.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.4.2"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 503);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.4.3
+     * Send a message to sip:nona.example.org
+     */
+    url->url_host = "nona.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.4.3"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.4.4
+     * Send a message to sip:nosrv.example.org
+     * After failing to find _sip._udp.nosrv.example.org,
+     * second SRV with _sip._udp.srv.example.org succeeds
+     */
+    url->url_host = "nosrv.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.4.4"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.5.1 
+     * Send a message to sip:srv.example.org;transport=tcp
+     * Test outgoing_make_srv_query()
+     */
+    url->url_host = "srv.example.org";
+    url->url_params = "transport=tcp";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.5.1: outgoing_make_srv_query()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    url->url_params = NULL;
+  }
+
+  {
+    /* Test 1.5.2
+     * Send a message to sip:srv.example.org;transport=udp
+     * Test outgoing_make_srv_query()
+     */
+    url->url_host = "srv.example.org";
+    url->url_params = "transport=udp";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.5.2: outgoing_make_srv_query()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    url->url_params = NULL;
+  }
+
+  {
+    /* Test 1.5.3
+     * Send a message to sip:srv2.example.org;transport=udp
+     * Test outgoing_query_srv_a()
+     */
+    url->url_host = "srv2.example.org";
+    url->url_params = "transport=udp";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.5: outgoing_query_srv_a()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    url->url_params = NULL;
+  }
+
+  {
+    /* Test 1.6.1
+     * Send a message to sip:srv.example.org:$port
+     * Test outgoing_make_a_aaaa_query()
+     */
+    url->url_host = "srv.example.org";
+    url->url_port = ag->ag_contact->m_url->url_port;
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.6.1: outgoing_make_a_aaaa_query()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 503);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  {
+    /* Test 1.6.2
+     * Send a message to sip:a.example.org:$port
+     * Test outgoing_make_a_aaaa_query()
+     */
+    url->url_host = "a.example.org";
+    url->url_port = ag->ag_contact->m_url->url_port;
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.6.2: outgoing_make_a_aaaa_query()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    url->url_port = NULL;
+  }
+
+#if 0				/* This must be run on host *without* proxy */
+  {
+    /* Test 1.6c
+     * Send a message to sip:na.example.org
+     * Test outgoing_query_all() with NAPTR "A" flag
+     */
+    url->url_host = "na.example.org";
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.6c"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 503);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+#endif
+
+  {
+    /* Test 1.7
+     * Send a message to sip:down2.example.org:$port
+     * Test A record failover.
+     */
+    url->url_host = "down2.example.org";
+    url->url_port = ag->ag_contact->m_url->url_port;
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.7: outgoing_make_a_aaaa_query()"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+    url->url_params = NULL;
+  }
+
+#if 0
+  /* Test 0.1.1
+   * Send a message from Bob to Alice using SIGCOMP and TCP
+   */
+  if (tcp_comp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+    if (url->url_params)
+      url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+    else
+      url->url_params = "transport=tcp";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+	   nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+				ag->ag_obp,
+				SIP_METHOD_MESSAGE,
+				(url_string_t *)url,
+				SIPTAG_SUBJECT_STR("Test 0.1.1"),
+				SIPTAG_FROM(ag->ag_bob),
+				SIPTAG_TO(ag->ag_alice),
+				SIPTAG_CONTACT(ag->ag_m_bob),
+				SIPTAG_PAYLOAD(pl),
+				TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.2
+   * Send a message from Bob to Alice
+   * This time specify a TCP URI, and include a large payload 
+   * of 512 kB
+   */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 512 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+#if 0
+    if (url->url_params)
+      url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+    else
+#endif
+      url->url_params = "transport=tcp";
+
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.2"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.3
+   * Send a message from Bob to Alice
+   * This time include a large payload of 512 kB, let NTA choose transport.
+   */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 512 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.3"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.4:
+   * Send a message from Bob to Alice
+   * This time include a payload of 2 kB, let NTA choose transport.
+   */
+  {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 2 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.4"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_out_via);
+    TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
+	   strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
+  }
+
+  /* Test 0.5:
+   * Send a message from Bob to Alice
+   * This time include a payload of 2 kB, try to use UDP.
+   */
+  if (udp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 2 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.5"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TPTAG_MTU(0xffffffff),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+    TEST_1(ag->ag_out_via);
+    TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
+  }
+
+  if (udp) {
+    /* Send a message from default leg to server leg 
+     * using a prefilled Via header
+     */
+    sip_via_t via[1];
+
+    sip_via_init(via);
+
+    via->v_protocol = sip_transport_udp;
+    
+    via->v_host = ag->ag_contact->m_url->url_host;
+    via->v_port = ag->ag_contact->m_url->url_port;
+    
+    sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch");
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_USER_VIA(1),
+			 TAG_END());
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, 
+			       magic_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.6"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       SIPTAG_VIA(via),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_USER_VIA(0),
+			 TAG_END());
+  }
+
+  /* Test 0.7
+   * Send a message from Bob to Alice using SCTP 
+   */
+  if (sctp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 16 * 1024;
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+#if 0
+    if (url->url_params)
+      url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params);
+    else
+#endif
+      url->url_params = "transport=sctp";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.7"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_server_leg);
+  }
+
+  /* Test 0.8: Send a too large message */
+  if (tcp) {
+    url_t url[1];
+    sip_payload_t *pl;
+    usize_t size = 128 * 1024;
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_MAXSIZE(65536),
+			 TAG_END());
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "alice";
+
+    TEST_1(pl = test_payload(ag->ag_home, size));
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_latest_leg = NULL;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.8"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       SIPTAG_PAYLOAD(pl),
+			       TAG_END()));
+    su_free(ag->ag_home, pl);
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 413);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, NULL);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_MAXSIZE(2 * 1024 * 1024),
+			 TAG_END());
+  }
+
+  /* Test 0.9: Timeout */
+  {
+    url_t url[1];
+
+    printf("%s: starting MESSAGE timeout test, test will complete in 4 seconds\n",
+	   name);
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_TIMEOUT_408(1),
+			 NTATAG_SIP_T1(25), 
+			 NTATAG_SIP_T1X64(64 * 25), 
+			 TAG_END());
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "timeout";
+    url->url_port = ag->ag_sink_port;
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_latest_leg = NULL;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 0.9"),
+			       SIPTAG_FROM(ag->ag_bob),
+			       SIPTAG_TO(ag->ag_alice),
+			       SIPTAG_CONTACT(ag->ag_m_bob),
+			       TAG_END()));
+
+    nta_test_run(ag);
+    TEST(ag->ag_status, 408);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, NULL);
+
+    nta_agent_set_params(ag->ag_agent,
+			 NTATAG_SIP_T1(500),
+			 NTATAG_SIP_T1X64(64 * 500),
+			 TAG_END());
+  }
+#endif  
+
+  nta_agent_set_params(ag->ag_agent,
+		       NTATAG_SIP_T1(500),
+		       NTATAG_SIP_T1X64(64 * 500),
+		       NTATAG_SIP_T2(NTA_SIP_T2),
+		       NTATAG_SIP_T4(NTA_SIP_T4),
+		       TAG_END());
+
+  END();
+}
+
+/* Test default routing */
+
+int test_routing(agent_t *ag)
+{
+  url_t url[1];
+
+  *url = *ag->ag_aliases->m_url;
+  url->url_user = "bob";
+
+  nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+
+  nta_agent_set_params(ag->ag_agent, 
+		       NTATAG_MAXSIZE(2 * 1024 * 1024),
+		       TAG_END());
+
+  BEGIN();
+
+  {
+    /* 
+     * Send a message from default leg to default leg 
+     *
+     * We are now using url with an explicit port that does not match with
+     * our own port number.
+     */
+    url_t url2[1];
+
+    *url2 = *url;
+    url2->url_port = "9";	/* discard service */
+
+    ag->ag_expect_leg = ag->ag_default_leg;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       (url_string_t *)url,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)url2,
+			       SIPTAG_SUBJECT_STR("Test 1.2"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+  }
+
+  END();
+}
+
+/* Test dialogs and the tag handling */
+
+int test_dialog(agent_t *ag)
+{
+  BEGIN();
+
+  /*
+   * Test establishing a dialog
+   *
+   * Alice sends a message to Bob, then Bob back to the Alice, and again
+   * Alice to Bob.
+   */
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					   leg_callback_200,
+					   ag,
+					   SIPTAG_FROM(ag->ag_alice),
+					   SIPTAG_TO(ag->ag_bob),
+					   TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+  nta_leg_bind(ag->ag_server_leg, new_leg_callback_200, ag);
+
+  /* Send message from Alice to Bob establishing the dialog */
+  ag->ag_expect_leg = ag->ag_server_leg;
+  ag->ag_tag_remote = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+        nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
+			     ag->ag_obp,
+			     SIP_METHOD_MESSAGE,
+			     (url_string_t *)ag->ag_m_bob->m_url,
+			     SIPTAG_SUBJECT_STR("Test 2.1"),
+			     SIPTAG_FROM(ag->ag_alice),
+			     SIPTAG_TO(ag->ag_bob),
+			     SIPTAG_CONTACT(ag->ag_m_alice),
+			     TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg != NULL);
+
+  nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag);
+
+  /* Send message from Bob to Alice */
+  ag->ag_expect_leg = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+        nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+      		       NULL,
+      		       SIP_METHOD_MESSAGE,
+      		       (url_string_t *)ag->ag_m_alice->m_url,
+      		       SIPTAG_SUBJECT_STR("Test 2.2"),
+      		       TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+
+  /* Send again message from Alice to Bob */
+  ag->ag_expect_leg = ag->ag_bob_leg;
+  TEST_1(ag->ag_orq = 
+        nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
+      		       NULL,
+      		       SIP_METHOD_MESSAGE,
+      		       (url_string_t *)ag->ag_m_bob->m_url,
+      		       SIPTAG_SUBJECT_STR("Test 2.3"),
+      		       TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_bob_leg);
+
+  /* Send message from Bob to Alice
+   * This time, however, specify request URI 
+   */
+  {
+    ag->ag_expect_leg = ag->ag_alice_leg;
+    TEST_1(ag->ag_orq = 
+          nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+      			 NULL,
+      			 SIP_METHOD_MESSAGE,
+      			 (url_string_t *)ag->ag_m_alice->m_url,
+      			 SIPTAG_SUBJECT_STR("Test 2.4"),
+      			 TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+  }
+
+  nta_leg_destroy(ag->ag_alice_leg), ag->ag_alice_leg = NULL;
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+
+  END();
+}
+
+/* ---------------------------------------------------------------------- */
+/* Test INVITE, dialogs */
+
+static
+int test_for_ack(agent_t *ag,
+		 nta_incoming_t *irq, 
+		 sip_t const *sip)
+{
+  sip_method_t method;
+
+  BEGIN();
+
+  method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+  nta_incoming_destroy(irq);
+  TEST_P(irq, ag->ag_irq);
+  ag->ag_irq = NULL;
+
+  TEST(method, sip_method_ack);
+  
+  ag->ag_status = 200;
+
+  END();
+}
+
+static
+int test_for_prack(agent_t *ag,
+		   nta_reliable_t *rel,
+		   nta_incoming_t *prack,
+		   sip_t const *sip)
+{
+  sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+  nta_incoming_treply(ag->ag_irq, 
+		      SIP_200_OK, 
+		      SIPTAG_CONTACT(ag->ag_m_alice),
+		      TAG_END());
+
+  TEST(method, sip_method_prack);
+		     
+  return 200;
+}
+
+int alice_leg_callback(agent_t *ag,
+		       nta_leg_t *leg,
+		       nta_incoming_t *irq,
+		       sip_t const *sip)
+{
+  BEGIN();
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  if (sip->sip_request->rq_method == sip_method_prack)
+    return 481;
+
+  ag->ag_latest_leg = leg;
+
+  if (leg != ag->ag_alice_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+
+  if (sip->sip_request->rq_method == sip_method_invite) {
+    TEST_1(sip_has_feature(sip->sip_supported, "100rel"));
+    nta_incoming_bind(irq, test_for_ack, ag);
+    nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_DEBUG_DROP_PROB(ag->ag_drop),
+			 TAG_END());
+
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  NULL, NULL,
+			  SIP_183_SESSION_PROGRESS,
+			  SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			  SIPTAG_PAYLOAD(ag->ag_payload),
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  NULL, NULL,
+			  184, "Next",
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  test_for_prack, ag,
+			  185, "Last",
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    ag->ag_irq = irq;
+    return 0;
+  } 
+
+  if (sip->sip_request->rq_method == sip_method_bye) {
+    leg_zap(ag, leg);
+  }
+  if (sip)
+  return 200;
+
+  END();
+}
+
+
+int bob_leg_callback(agent_t *ag,
+		     nta_leg_t *leg,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  BEGIN();
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  if (sip->sip_request->rq_method == sip_method_prack)
+    return 481;
+
+  ag->ag_latest_leg = leg;
+
+  if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+
+  if (ag->ag_bob_leg == NULL) {
+    nta_leg_bind(leg, leg_callback_500, ag);
+    ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+				     bob_leg_callback,
+				     ag,
+				     SIPTAG_CALL_ID(sip->sip_call_id),
+				     SIPTAG_FROM(sip->sip_to),
+				     SIPTAG_TO(sip->sip_from),
+				     TAG_END());
+    TEST_1(ag->ag_bob_leg);
+    TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+    TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+    TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+    TEST(nta_leg_server_route(ag->ag_bob_leg, 
+			      sip->sip_record_route, 
+			      sip->sip_contact), 0);
+  }
+
+  if (sip->sip_request->rq_method != sip_method_invite) {
+    return 200;
+  } else {
+	nta_incoming_bind(irq, test_for_ack, ag); 
+#if 1
+    nta_incoming_treply(irq,
+			SIP_180_RINGING,
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+    nta_incoming_treply(irq,
+			SIP_180_RINGING,
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+#endif
+    nta_incoming_treply(irq,
+			SIP_200_OK,
+			SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			SIPTAG_PAYLOAD(ag->ag_payload),
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+    ag->ag_irq = irq;
+  }
+
+  END();
+}
+
+int outgoing_invite_callback(agent_t *ag,
+			     nta_outgoing_t *orq,
+			     sip_t const *sip)
+{
+  BEGIN();
+
+  int status = sip->sip_status->st_status;
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s %03d %s\n", name, __func__, 
+	   sip->sip_status->st_version, 
+	   sip->sip_status->st_status, 
+	   sip->sip_status->st_phrase);
+  }
+
+  {
+    msg_t *msg;
+
+    TEST_1(msg = nta_outgoing_getresponse(orq));
+    TEST_1(msg->m_refs == 2);
+    TEST_1(sip_object(msg) == sip);
+    if (ag->ag_probe_msg == NULL)
+      ag->ag_probe_msg = msg;
+    msg_destroy(msg);
+  }
+
+  if (status < 200) {
+    if (sip->sip_require && sip_has_feature(sip->sip_require, "100rel")) {
+      TEST_1(sip->sip_rseq);
+      orq = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
+			       NULL,
+			       sip, 
+			       TAG_END());
+      TEST_1(orq);
+      nta_outgoing_destroy(orq);
+    }
+    return 0;
+  }
+
+  if (status < 300) {
+    nta_outgoing_t *ack;
+
+    TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+    
+    TEST(nta_leg_client_route(ag->ag_call_leg, 
+			      sip->sip_record_route,
+			      sip->sip_contact), 0);
+
+    ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+			       NULL,
+			       SIP_METHOD_ACK,
+			       NULL,
+			       SIPTAG_CSEQ(sip->sip_cseq),
+			       TAG_END());
+    TEST_1(ack);
+    nta_outgoing_destroy(ack);
+  }
+  else {
+    ag->ag_status = status;
+  }
+
+  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+  nta_outgoing_destroy(orq);
+  ag->ag_orq = NULL;
+  ag->ag_call_leg = NULL;
+  END();
+}
+
+
+int test_call(agent_t *ag)
+{
+  sip_content_type_t *c = ag->ag_content_type;
+  sip_payload_t      *sdp = ag->ag_payload;
+  nta_leg_t *old_leg;
+  sip_replaces_t *r1, *r2;
+
+  BEGIN();
+
+  /*
+   * Test establishing a call
+   *
+   * Alice sends a INVITE to Bob, then Bob sends 200 Ok.
+   */
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					   alice_leg_callback,
+					   ag,
+					   SIPTAG_FROM(ag->ag_alice),
+					   SIPTAG_TO(ag->ag_bob),
+					   TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+  nta_leg_bind(ag->ag_server_leg, bob_leg_callback, ag);
+  
+  /* Send INVITE */
+  ag->ag_expect_leg = ag->ag_server_leg;
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+			      outgoing_invite_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_INVITE,
+			      (url_string_t *)ag->ag_m_bob->m_url,
+			      SIPTAG_SUBJECT_STR("Call 1"),
+			      SIPTAG_CONTACT(ag->ag_m_alice),
+			      SIPTAG_CONTENT_TYPE(c),
+			      SIPTAG_ACCEPT_CONTACT_STR("*;audio"),
+			      SIPTAG_PAYLOAD(sdp),
+			      NTATAG_USE_TIMESTAMP(1),
+			      NTATAG_PASS_100(1),
+			      TAG_END()));
+
+  /* Try to CANCEL it immediately */
+  TEST_1(nta_outgoing_cancel(ag->ag_orq) == 0);
+  /* As Bob immediately answers INVITE with 200 Ok, 
+     cancel should be answered with 487. */
+
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg != NULL);
+
+  TEST_1(r1 = nta_leg_make_replaces(ag->ag_alice_leg, ag->ag_home, 0));
+  TEST_1(r2 = sip_replaces_format(ag->ag_home, "%s;from-tag=%s;to-tag=%s",
+				  r1->rp_call_id, r1->rp_to_tag, r1->rp_from_tag));
+
+  TEST_P(ag->ag_alice_leg, nta_leg_by_replaces(ag->ag_agent, r2));
+  TEST_P(ag->ag_bob_leg, nta_leg_by_replaces(ag->ag_agent, r1));
+
+  /* Re-INVITE from Bob to Alice.
+   *
+   * Alice first sends 183, waits for PRACK, then sends 184 and 185,
+   * waits for PRACKs, then sends 200, waits for ACK.
+   */
+  ag->ag_expect_leg = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+	nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg, 
+			     outgoing_invite_callback, ag,
+			     NULL,
+			     SIP_METHOD_INVITE,
+			     NULL,
+			     SIPTAG_SUBJECT_STR("Re-INVITE"),
+			     SIPTAG_CONTACT(ag->ag_m_bob),
+			     SIPTAG_SUPPORTED_STR("foo"),
+			     SIPTAG_CONTENT_TYPE(c),
+			     SIPTAG_PAYLOAD(sdp),
+			     TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+
+  nta_agent_set_params(ag->ag_agent, 
+		       NTATAG_DEBUG_DROP_PROB(0),
+		       TAG_END());
+
+  /* Send BYE from Bob to Alice */
+  old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+	nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+			     NULL,
+			     SIP_METHOD_BYE,
+			     NULL,
+			     SIPTAG_SUBJECT_STR("Hangup"),
+			     SIPTAG_FROM(ag->ag_alice),
+			     SIPTAG_TO(ag->ag_bob),
+			     SIPTAG_CONTACT(ag->ag_m_alice),
+			     SIPTAG_CONTENT_TYPE(c),
+			     SIPTAG_PAYLOAD(sdp),
+			     TAG_END()));
+
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, old_leg);
+  TEST_P(ag->ag_alice_leg, NULL);
+
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+  ag->ag_latest_leg = NULL;
+  ag->ag_call_leg = NULL;
+
+  END();
+}
+
+/* ============================================================================ */
+/* Test early dialogs, PRACK */
+
+int test_for_ack_or_timeout(agent_t *ag,
+			    nta_incoming_t *irq, 
+			    sip_t const *sip)
+{
+  BEGIN();
+
+  sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+  if (method == sip_method_ack) {
+    TEST(method, sip_method_ack);
+  
+    ag->ag_status = 200;
+  }
+  else if (method == sip_method_cancel) {
+    nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END());
+  }
+  else {
+    if (ag->ag_bob_leg) {
+      nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+    }
+  }
+
+  nta_incoming_destroy(irq);
+  TEST_P(irq, ag->ag_irq);
+  ag->ag_irq = NULL;
+
+  END();
+}
+
+/* */
+int bob_leg_callback2(agent_t *ag,
+		      nta_leg_t *leg,
+		      nta_incoming_t *irq,
+		      sip_t const *sip)
+{
+  BEGIN();
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  ag->ag_latest_leg = leg;
+
+  if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+
+  if (ag->ag_bob_leg == NULL) {
+    nta_leg_bind(leg, leg_callback_500, ag);
+    ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+				     bob_leg_callback,
+				     ag,
+				     SIPTAG_CALL_ID(sip->sip_call_id),
+				     SIPTAG_FROM(sip->sip_to),
+				     SIPTAG_TO(sip->sip_from),
+				     TAG_END());
+    TEST_1(ag->ag_bob_leg);
+    TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+    TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+    TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+    TEST(nta_leg_server_route(ag->ag_bob_leg, 
+			      sip->sip_record_route, 
+			      sip->sip_contact), 0);
+  }
+
+  if (sip->sip_request->rq_method != sip_method_invite) {
+    return 200;
+  } else {
+    nta_incoming_bind(irq, test_for_ack_or_timeout, ag); 
+    nta_incoming_treply(irq,
+			SIP_183_SESSION_PROGRESS,
+			SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			SIPTAG_PAYLOAD(ag->ag_payload),
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+    if (0)
+    nta_incoming_treply(irq,
+			SIP_180_RINGING,
+			SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			SIPTAG_PAYLOAD(ag->ag_payload),
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+    nta_incoming_treply(irq,
+			SIP_200_OK,
+			SIPTAG_CONTACT(ag->ag_m_bob),
+			TAG_END());
+    ag->ag_irq = irq;
+  }
+
+  END();
+}
+
+
+int invite_prack_callback(agent_t *ag,
+			  nta_outgoing_t *orq,
+			  sip_t const *sip)
+{
+  BEGIN();
+
+  int status = sip->sip_status->st_status;
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s %03d %s\n", name, __func__, 
+	   sip->sip_status->st_version, 
+	   sip->sip_status->st_status, 
+	   sip->sip_status->st_phrase);
+  }
+
+  if (!ag->ag_call_tag && (status >= 200 || (status > 100 && sip->sip_rseq))) {
+    nta_outgoing_t *tagged;
+    TEST_1(sip->sip_to->a_tag);
+    ag->ag_tag_status = status;
+    ag->ag_call_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag);
+    TEST_S(ag->ag_call_tag, sip->sip_to->a_tag);
+    TEST_S(nta_leg_rtag(ag->ag_call_leg, ag->ag_call_tag), ag->ag_call_tag);
+    TEST(nta_leg_client_route(ag->ag_call_leg, 
+			      sip->sip_record_route,
+			      sip->sip_contact), 0);
+    tagged = nta_outgoing_tagged(orq, 
+				 invite_prack_callback,
+				 ag,
+				 ag->ag_call_tag,
+				 sip->sip_rseq);
+    TEST_1(tagged);
+    nta_outgoing_destroy(orq);
+    if (ag->ag_orq == orq)
+      ag->ag_orq = tagged;
+    orq = tagged;
+  }
+
+  if (status > 100 && status < 200 && sip->sip_rseq) {
+    nta_outgoing_t *prack;
+    prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
+			       NULL,
+			       sip, 
+			       TAG_END());
+    TEST_1(prack);
+    nta_outgoing_destroy(prack);
+    return 0;
+  }
+
+  if (status < 200)
+    return 0;
+
+  if (status < 300) {
+    nta_outgoing_t *ack;
+    msg_t *msg;
+    sip_t *osip;
+
+    TEST_1(msg = nta_outgoing_getrequest(orq));
+    TEST_1(osip = sip_object(msg));
+
+    TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+    
+    TEST(nta_leg_client_route(ag->ag_call_leg, 
+			      sip->sip_record_route,
+			      sip->sip_contact), 0);
+
+    ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+			       NULL,
+			       SIP_METHOD_ACK,
+			       NULL,
+			       SIPTAG_CSEQ(sip->sip_cseq),
+			       NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
+			       TAG_END());
+    TEST_1(ack);
+    nta_outgoing_destroy(ack);
+    msg_destroy(msg);
+  }
+  else {
+    ag->ag_status = status;
+  }
+
+  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+  nta_outgoing_destroy(orq);
+  ag->ag_orq = NULL;
+  ag->ag_call_leg = NULL;
+
+  END();
+}
+
+static int process_prack(nta_reliable_magic_t *arg,
+			 nta_reliable_t *rel,
+			 nta_incoming_t *irq,
+			 sip_t const *sip)
+{
+  agent_t *ag = (agent_t *)arg;
+  if (ag->ag_irq) {
+    nta_incoming_treply(ag->ag_irq, 
+			504, "Reliable Response Timeout",
+			TAG_END());
+    nta_incoming_destroy(ag->ag_irq);
+  }
+  return 504;
+}
+
+/* send invite, wait for 183, send CANCEL */
+int bob_leg_callback3(agent_t *ag,
+		      nta_leg_t *leg,
+		      nta_incoming_t *irq,
+		      sip_t const *sip)
+{
+  BEGIN();
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  ag->ag_latest_leg = leg;
+
+  if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+
+  if (ag->ag_bob_leg == NULL) {
+    nta_leg_bind(leg, leg_callback_500, ag);
+    ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+				     bob_leg_callback,
+				     ag,
+				     SIPTAG_CALL_ID(sip->sip_call_id),
+				     SIPTAG_FROM(sip->sip_to),
+				     SIPTAG_TO(sip->sip_from),
+				     TAG_END());
+    TEST_1(ag->ag_bob_leg);
+    TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+    TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+    TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+    TEST(nta_leg_server_route(ag->ag_bob_leg, 
+			      sip->sip_record_route, 
+			      sip->sip_contact), 0);
+  }
+
+  if (sip->sip_request->rq_method != sip_method_invite) {
+    return 200;
+  } else {
+    nta_reliable_t *rel;
+    nta_incoming_bind(irq, test_for_ack_or_timeout, ag);
+    rel = nta_reliable_treply(irq, process_prack, ag,
+			      SIP_183_SESSION_PROGRESS,
+			      SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			      SIPTAG_PAYLOAD(ag->ag_payload),
+			      SIPTAG_CONTACT(ag->ag_m_bob),
+			      TAG_END());
+    ag->ag_irq = irq;
+  }
+
+  END();
+}
+
+
+int invite_183_cancel_callback(agent_t *ag,
+			       nta_outgoing_t *orq,
+			       sip_t const *sip)
+{
+  BEGIN();
+
+  int status = sip->sip_status->st_status;
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s %03d %s\n", name, __func__, 
+	   sip->sip_status->st_version, 
+	   sip->sip_status->st_status, 
+	   sip->sip_status->st_phrase);
+  }
+
+  if (status > 100 && status < 200) {
+    nta_outgoing_cancel(orq);
+    return 0;
+  }
+
+  if (status < 200)
+    return 0;
+
+  if (status < 300) {
+    nta_outgoing_t *ack;
+    msg_t *msg;
+    sip_t *osip;
+
+    TEST_1(msg = nta_outgoing_getrequest(orq));
+    TEST_1(osip = sip_object(msg));
+
+    TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+    
+    TEST(nta_leg_client_route(ag->ag_call_leg, 
+			      sip->sip_record_route,
+			      sip->sip_contact), 0);
+
+    ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+			       NULL,
+			       SIP_METHOD_ACK,
+			       NULL,
+			       SIPTAG_CSEQ(sip->sip_cseq),
+			       NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
+			       TAG_END());
+    TEST_1(ack);
+    nta_outgoing_destroy(ack);
+    msg_destroy(msg);
+  }
+  else {
+    ag->ag_status = status;
+  }
+
+  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+  nta_outgoing_destroy(orq);
+  ag->ag_orq = NULL;
+  ag->ag_call_leg = NULL;
+
+  END();
+}
+
+/*
+ * Test establishing a call with an early dialog / 100 rel / timeout
+ *
+ * Alice sends a INVITE to Bob, then Bob sends 183, Alice sends PRACK,
+ * Bob sends 200 to PRACK, Bob sends 200 to INVITE.
+ * Bob sends BYE, Alice 200.
+ */
+
+int test_prack(agent_t *ag)
+{
+  sip_content_type_t *c = ag->ag_content_type;
+  sip_payload_t      *sdp = ag->ag_payload;
+  nta_leg_t *old_leg;
+
+  BEGIN();
+
+  {
+    /* Send a PRACK from default leg, NTA responds to it with error */
+    url_t url[1];
+
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "bob";
+
+    ag->ag_expect_leg = ag->ag_server_leg;
+    ag->ag_latest_leg = NULL;
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_PRACK,
+			       (url_string_t *)url,
+			       SIPTAG_SUBJECT_STR("Test 1.1"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       SIPTAG_RACK_STR("1432432 42332432 INVITE"),
+			       TAG_END()));
+    nta_test_run(ag);
+    TEST(ag->ag_status, 481);
+    TEST_P(ag->ag_orq, NULL);
+    TEST_P(ag->ag_latest_leg, NULL);
+  }
+
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					   alice_leg_callback,
+					   ag,
+					   SIPTAG_FROM(ag->ag_alice),
+					   SIPTAG_TO(ag->ag_bob),
+					   TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+  /* Send INVITE */
+  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+  ag->ag_expect_leg = ag->ag_server_leg;
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+			      invite_prack_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_INVITE,
+			      (url_string_t *)ag->ag_m_bob->m_url,
+			      SIPTAG_SUBJECT_STR("Call 2"),
+			      SIPTAG_CONTACT(ag->ag_m_alice),
+			      SIPTAG_REQUIRE_STR("100rel"),
+			      SIPTAG_CONTENT_TYPE(c),
+			      SIPTAG_PAYLOAD(sdp),
+			      TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  /*TEST(ag->ag_tag_status, 183);*/
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg != NULL);
+
+  /* Send BYE from Bob to Alice */
+  old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+	nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+			     NULL,
+			     SIP_METHOD_BYE,
+			     NULL,
+			     SIPTAG_SUBJECT_STR("Hangup"),
+			     SIPTAG_FROM(ag->ag_alice),
+			     SIPTAG_TO(ag->ag_bob),
+			     SIPTAG_CONTACT(ag->ag_m_alice),
+			     SIPTAG_CONTENT_TYPE(c),
+			     SIPTAG_PAYLOAD(sdp),
+			     TAG_END()));
+
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, old_leg);
+  TEST_P(ag->ag_alice_leg, NULL);
+
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+  ag->ag_latest_leg = NULL;
+  ag->ag_call_leg = NULL;
+
+  /* Test CANCELing a call after received PRACK */
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					   alice_leg_callback,
+					   ag,
+					   SIPTAG_FROM(ag->ag_alice),
+					   SIPTAG_TO(ag->ag_bob),
+					   TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+  /* Send INVITE */
+  nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
+  ag->ag_expect_leg = ag->ag_server_leg;
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+			      invite_183_cancel_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_INVITE,
+			      (url_string_t *)ag->ag_m_bob->m_url,
+			      SIPTAG_SUBJECT_STR("Call 2b"),
+			      SIPTAG_CONTACT(ag->ag_m_alice),
+			      SIPTAG_REQUIRE_STR("100rel"),
+			      SIPTAG_CONTENT_TYPE(c),
+			      SIPTAG_PAYLOAD(sdp),
+			      TAG_END()));
+  nta_test_run(ag);
+  TEST_1(ag->ag_status == 487 || ag->ag_status == 504);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg != NULL);
+
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+  ag->ag_latest_leg = NULL;
+  ag->ag_call_leg = NULL;
+
+  if (getenv("EXPENSIVE_CHECKS")) {
+  printf("%s: starting 100rel timeout test, test will complete in 4 seconds\n",
+	 name);
+  
+  TEST(nta_agent_set_params(ag->ag_agent,
+			    NTATAG_SIP_T1(25),
+			    NTATAG_SIP_T1X64(64 * 25),
+			    TAG_END()), 2);
+
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					   alice_leg_callback,
+					   ag,
+					   SIPTAG_FROM(ag->ag_alice),
+					   SIPTAG_TO(ag->ag_bob),
+					   TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+  /* Send INVITE, 
+   * send precious provisional response
+   * do not send PRACK, 
+   * timeout (after 64 * t1 ~ 3.2 seconds),
+   */
+  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+  ag->ag_expect_leg = ag->ag_server_leg;
+  TEST_1(ag->ag_orq = 
+	 nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+			      outgoing_callback, ag,
+			      ag->ag_obp,
+			      SIP_METHOD_INVITE,
+			      (url_string_t *)ag->ag_m_bob->m_url,
+			      SIPTAG_SUBJECT_STR("Call 3"),
+			      SIPTAG_CONTACT(ag->ag_m_alice),
+			      SIPTAG_REQUIRE_STR("100rel"),
+			      SIPTAG_CONTENT_TYPE(c),
+			      SIPTAG_PAYLOAD(sdp),
+			      TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 503);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg == NULL);
+
+  TEST(nta_agent_set_params(ag->ag_agent, 
+			    NTATAG_SIP_T1(500), 
+			    NTATAG_SIP_T1X64(64 * 500), 
+			    TAG_END()), 2);
+  }
+  END();
+/*
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+  ag->ag_latest_leg = NULL;
+  ag->ag_call_leg = NULL;
+  if (ag->ag_call_tag)
+    su_free(ag->ag_home, (void *)ag->ag_call_tag), ag->ag_call_tag = NULL;
+*/
+}
+
+int alice_leg_callback2(agent_t *ag,
+			nta_leg_t *leg,
+			nta_incoming_t *irq,
+			sip_t const *sip)
+{
+  BEGIN();
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  if (sip->sip_request->rq_method == sip_method_prack)
+    return 481;
+
+  ag->ag_latest_leg = leg;
+
+  if (leg != ag->ag_alice_leg) {
+    leg_match(ag, leg, 1, __func__);
+    return 500;
+  }
+
+  if (sip->sip_request->rq_method == sip_method_invite) {
+    TEST_1(sip_has_feature(sip->sip_supported, "100rel"));
+    nta_incoming_bind(irq, test_for_ack, ag);
+    nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+    nta_agent_set_params(ag->ag_agent, 
+			 NTATAG_DEBUG_DROP_PROB(ag->ag_drop),
+			 TAG_END());
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  NULL, NULL,
+			  SIP_183_SESSION_PROGRESS,
+			  SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+			  SIPTAG_PAYLOAD(ag->ag_payload),
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  NULL, NULL,
+			  184, "Next",
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    ag->ag_reliable = 
+      nta_reliable_treply(irq,
+			  NULL, NULL,
+			  185, "Last",
+			  SIPTAG_CONTACT(ag->ag_m_alice),
+			  TAG_END());
+    TEST_1(ag->ag_reliable);
+    TEST(nta_incoming_treply(irq, SIP_200_OK, TAG_END()), 0);
+    ag->ag_irq = irq;
+    return 0;
+  } 
+
+  if (sip->sip_request->rq_method == sip_method_bye) {
+    leg_zap(ag, leg);
+  }
+
+  if(sip)
+	return 200;
+
+  END();
+}
+/*
+ * Test establishing a call with an early dialog / 100 rel / timeout
+ *
+ * Alice sends a INVITE to Bob, then Bob sends 183, 184, 185, and 200.
+ * Bob sends BYE, Alice 200.
+ *
+ * See bug #467.
+ */
+int test_fix_467(agent_t *ag)
+{
+  sip_content_type_t *c = ag->ag_content_type;
+  sip_payload_t      *sdp = ag->ag_payload;
+  nta_leg_t *old_leg;
+
+  BEGIN();
+
+  TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent, 
+					    alice_leg_callback2,
+					    ag,
+					    SIPTAG_FROM(ag->ag_alice),
+					    SIPTAG_TO(ag->ag_bob),
+					    TAG_END()));
+  TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+  ag->ag_bob_leg = NULL;
+  ag->ag_call_tag = NULL;
+
+  /* Send INVITE */
+  nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+  ag->ag_expect_leg = ag->ag_server_leg;
+  TEST_1(ag->ag_orq = 
+	nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, 
+			     invite_prack_callback, ag,
+			     ag->ag_obp,
+			     SIP_METHOD_INVITE,
+			     (url_string_t *)ag->ag_m_bob->m_url,
+			     SIPTAG_SUBJECT_STR("Call 5"),
+			     SIPTAG_CONTACT(ag->ag_m_alice),
+			     SIPTAG_REQUIRE_STR("100rel"),
+			     SIPTAG_CONTENT_TYPE(c),
+			     SIPTAG_PAYLOAD(sdp),
+			     TAG_END()));
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  /*TEST(ag->ag_tag_status, 183);*/
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+  TEST_1(ag->ag_bob_leg != NULL);
+
+  /* Send BYE from Bob to Alice */
+  old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+  TEST_1(ag->ag_orq = 
+	nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+			     NULL,
+			     SIP_METHOD_BYE,
+			     NULL,
+			     SIPTAG_SUBJECT_STR("Hangup"),
+			     SIPTAG_FROM(ag->ag_alice),
+			     SIPTAG_TO(ag->ag_bob),
+			     SIPTAG_CONTACT(ag->ag_m_alice),
+			     SIPTAG_CONTENT_TYPE(c),
+			     SIPTAG_PAYLOAD(sdp),
+			     TAG_END()));
+
+  
+  nta_test_run(ag);
+  TEST(ag->ag_status, 200);
+  TEST_P(ag->ag_orq, NULL);
+  TEST_P(ag->ag_latest_leg, old_leg);
+  TEST_P(ag->ag_alice_leg, NULL);
+
+  END();
+/*
+  nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+  ag->ag_latest_leg = NULL;
+  ag->ag_call_leg = NULL;
+*/
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+static
+char const nta_test_usage[] = 
+  "usage: %s OPTIONS\n"
+  "where OPTIONS are\n"
+  "   -v | --verbose    be verbose\n"
+  "   -q | --quiet      be quiet\n"
+  "   -1                quit on first error\n"
+  "   -l level          set logging level (0 by default)\n"
+  "   -p uri            specify uri of outbound proxy\n"
+  "   -m uri            bind to local uri\n"
+  "   --attach          print pid, wait for a debugger to be attached\n"
+#if HAVE_ALARM
+  "   --no-alarm        don't ask for guard ALARM\n"
+#endif
+  ;
+
+void usage(void)
+{
+  fprintf(stderr, nta_test_usage, name);
+  exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0, quit_on_single_failure = 0;
+  int i, o_attach = 0, o_alarm = 1;
+
+  agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
+      tstflags &= ~tst_verbatim;
+    else if (strcmp(argv[i], "-1") == 0)
+      quit_on_single_failure = 1;
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      int level = 3;
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage();
+      
+      su_log_set_level(nta_log, level);
+      su_log_set_level(tport_log, level);
+    }
+    else if (strncmp(argv[i], "-p", 2) == 0) {
+      if (argv[i][2])
+	ag->ag_obp = (url_string_t *)(argv[i] + 2);
+      else if (argv[i + 1])
+	ag->ag_obp = (url_string_t *)(argv[++i]);
+      else
+	usage();
+    }
+    else if (strncmp(argv[i], "-m", 2) == 0) {
+      if (argv[i][2])
+	ag->ag_m = argv[i] + 2;
+      else if (argv[i + 1])
+	ag->ag_m = argv[++i];
+      else
+	usage();
+    }
+    else if (strcmp(argv[i], "--attach") == 0) {
+      o_attach = 1;
+    }
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (argv[i][0] != '-') {
+      break;
+    }
+    else
+      usage();
+  }
+
+  if (o_attach) {
+    char line[10], *got;
+    printf("nua_test: pid %u\n", getpid());
+    printf("<Press RETURN to continue>\n");
+    got = fgets(line, sizeof line, stdin); (void)got;
+  }
+#if HAVE_ALARM
+  else if (o_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  su_init();
+
+  if (!(TSTFLAGS & tst_verbatim)) {
+    su_log_soft_set_level(nta_log, 0);
+    su_log_soft_set_level(tport_log, 0);
+  }
+
+#define SINGLE_FAILURE_CHECK()						\
+  do { fflush(stdout);							\
+    if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+  } while(0)
+
+  retval |= test_init(ag, argv[i]); SINGLE_FAILURE_CHECK();
+  if (retval == 0) {
+    retval |= test_bad_messages(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_reinit(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_tports(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_destroy_incoming(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_resolv(ag, argv[i]); SINGLE_FAILURE_CHECK();
+    retval |= test_routing(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_dialog(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_call(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_prack(ag); SINGLE_FAILURE_CHECK();
+    retval |= test_fix_467(ag); SINGLE_FAILURE_CHECK();
+  }
+  retval |= test_deinit(ag); fflush(stdout);
+
+  su_home_deinit(ag->ag_home);
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1345 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE test_nta_api.c
+ *
+ * Test functions for NTA.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+typedef struct agent_t agent_t;
+#define SU_ROOT_MAGIC_T      agent_t
+
+#include <sofia-sip/su_wait.h>
+
+#include <msg_internal.h>
+
+#define NTA_AGENT_MAGIC_T    agent_t
+#define NTA_LEG_MAGIC_T      agent_t
+#define NTA_OUTGOING_MAGIC_T agent_t
+#define NTA_INCOMING_MAGIC_T agent_t
+#define NTA_RELIABLE_MAGIC_T agent_t
+
+#include "sofia-sip/nta.h"
+#include "nta_internal.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+#include <sofia-sip/sresolv.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/sofia_features.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+#include <time.h>
+#include "sofia-sip/string0.h"
+
+extern su_log_t nta_log[];
+extern su_log_t tport_log[];
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+char const name[] = "test_nta_api";
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void *)-1)
+
+struct sigcomp_compartment;
+
+struct agent_t {
+  su_home_t       ag_home[1];
+  int             ag_flags;
+  su_root_t      *ag_root;
+  msg_mclass_t   *ag_mclass;
+  nta_agent_t    *ag_agent;
+
+  nta_leg_t      *ag_default_leg; /**< Leg for rest */
+  nta_leg_t      *ag_server_leg;  /**< Leg for <sip:%@%>;methods=<PUBLISH>;events=<presence> */
+
+  unsigned        ag_drop;
+
+  nta_outgoing_t *ag_orq;
+  int             ag_status;
+  msg_t          *ag_response;
+
+  /* Server side */
+  nta_incoming_t *ag_irq;
+
+  sip_contact_t const *ag_contact;
+  sip_from_t     *ag_alice;
+  sip_to_t       *ag_bob;
+
+  sip_contact_t  *ag_m_alice;
+  sip_contact_t  *ag_m_bob;
+  sip_contact_t  *ag_aliases;
+
+  nta_leg_t      *ag_alice_leg;
+  nta_leg_t      *ag_bob_leg;
+
+  msg_t          *ag_request;
+
+  nta_leg_t      *ag_expect_leg;
+  nta_leg_t      *ag_latest_leg;
+  nta_leg_t      *ag_call_leg;
+  nta_leg_t      *ag_tag_remote; /**< If this is set, outgoing_callback()
+				  *   tags it with the tag from remote.
+				  */
+  int             ag_tag_status; /**< Which response established dialog */
+  msg_param_t     ag_call_tag;	 /**< Tag used to establish dialog */
+
+  nta_reliable_t *ag_reliable;
+
+  sip_via_t      *ag_out_via;	/**< Outgoing via */
+  sip_via_t      *ag_in_via;	/**< Incoming via */
+
+  sip_content_type_t *ag_content_type;
+  sip_payload_t  *ag_payload;
+
+  msg_t          *ag_probe_msg;
+};
+
+
+static int incoming_callback_1(agent_t *ag,
+			       nta_incoming_t *irq, 
+			       sip_t const *sip)
+{
+  return 0;
+}
+
+static int incoming_callback_2(agent_t *ag,
+			       nta_incoming_t *irq, 
+			       sip_t const *sip)
+{
+  return 0;
+}
+
+int agent_callback(agent_t *ag,
+		   nta_agent_t *nta,
+		   msg_t *msg,
+		   sip_t *sip)
+{
+  msg_destroy(msg);
+  return 0;
+}
+
+int leg_callback(agent_t *ag,
+		 nta_leg_t *leg,
+		 nta_incoming_t *irq,
+		 sip_t const *sip)
+{
+  BEGIN();
+  msg_t *msg;
+  char const *tag;
+  
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+	   name, __func__, sip->sip_request->rq_method_name, 
+	   URL_PRINT_ARGS(sip->sip_request->rq_url),
+	   sip->sip_request->rq_version);
+  }
+
+  TEST_1(sip->sip_content_length);
+  TEST_1(sip->sip_via);
+  TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+  TEST_VOID(nta_incoming_bind(irq, incoming_callback_1, ag));
+  TEST_P(nta_incoming_magic(irq, incoming_callback_1), ag);
+  TEST_P(nta_incoming_magic(irq, incoming_callback_2), 0);
+  
+  TEST_1(tag = nta_incoming_tag(irq, "tag=foofaa"));
+  TEST_S(nta_incoming_gettag(irq), tag);
+  TEST_S(tag, "foofaa");
+  TEST_1(tag = nta_incoming_tag(irq, "foofaa"));
+
+  TEST(nta_incoming_status(irq), 0);
+  TEST(nta_incoming_method(irq), sip_method_message);
+  TEST_S(nta_incoming_method_name(irq), "MESSAGE");
+  TEST_1(nta_incoming_url(irq) != NULL);
+  TEST_1(nta_incoming_cseq(irq) != 0);
+  
+  TEST(nta_incoming_set_params(irq, TAG_END()), 0);
+  
+  TEST_1(msg = nta_incoming_getrequest(irq)); msg_destroy(msg);
+  TEST_P(nta_incoming_getrequest_ackcancel(irq), NULL);
+  TEST_P(nta_incoming_getresponse(irq), NULL);
+
+  TEST(nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()), 0);
+  TEST_1(msg = nta_incoming_getresponse(irq)); msg_destroy(msg);
+  msg = nta_msg_create(ag->ag_agent, 0);
+  TEST(nta_incoming_complete_response(irq, msg, SIP_200_OK, TAG_END()), 0);
+  TEST(nta_incoming_mreply(irq, msg), 0);
+
+  END();
+}
+
+int outgoing_callback(agent_t *ag,
+		      nta_outgoing_t *orq,
+		      sip_t const *sip)
+{
+  BEGIN();
+  msg_t *msg;
+
+  int status = sip->sip_status->st_status;
+
+  if (tstflags & tst_verbatim) {
+    printf("%s: %s: %s %03d %s\n", name, __func__, 
+	   sip->sip_status->st_version, 
+	   sip->sip_status->st_status, 
+	   sip->sip_status->st_phrase);
+  }
+
+  ag->ag_status = status;
+
+  if (status < 200)
+    return 0;
+
+  TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+  /* Test API functions */
+  TEST(nta_outgoing_status(orq), status);
+  TEST_1(nta_outgoing_request_uri(orq));
+  TEST_1(!nta_outgoing_route_uri(orq));
+  TEST(nta_outgoing_method(orq), sip_method_message);
+  TEST_S(nta_outgoing_method_name(orq), "MESSAGE");
+  TEST(nta_outgoing_cseq(orq), sip->sip_cseq->cs_seq);
+  TEST_1(nta_outgoing_delay(orq) < UINT_MAX);
+  
+  TEST_1(msg = nta_outgoing_getresponse(orq));
+  msg_destroy(msg);
+  
+  TEST_1(msg = nta_outgoing_getrequest(orq));
+  msg_destroy(msg);
+
+  nta_outgoing_destroy(orq);	
+  /* Call it twice */
+  nta_outgoing_destroy(orq);
+
+  ag->ag_orq = NULL;
+
+  END();
+}
+
+void 
+nta_test_run(agent_t *ag)
+{
+  time_t now = time(NULL);
+
+  for (ag->ag_status = 0; ag->ag_status < 200;) {
+    if (tstflags & tst_verbatim) {
+      fputs(".", stdout); fflush(stdout);
+    }
+    su_root_step(ag->ag_root, 500L);
+
+    if (!getenv("NTA_TEST_DEBUG") && time(NULL) > now + 5) {
+      fprintf(stderr, "nta_test_run: timeout\n");
+      return;
+    }
+  }
+}
+
+int api_test_init(agent_t *ag)
+{
+  BEGIN();
+
+  char const *contact = NULL;
+
+  if (getenv("SIPCONTACT"))
+    contact = getenv("SIPCONTACT");
+
+  if (contact == NULL || contact[0] == '\0')
+    contact = "sip:0.0.0.0:*;comp=sigcomp";
+
+  TEST_1(ag->ag_root = su_root_create(ag));
+  TEST_1(ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0));
+
+  /* Create agent */
+  TEST_1(ag->ag_agent = nta_agent_create(ag->ag_root,
+					 (url_string_t *)contact,
+					 NULL,
+					 NULL,
+					 NTATAG_MCLASS(ag->ag_mclass),
+					 NTATAG_USE_TIMESTAMP(1),
+					 NTATAG_USE_NAPTR(0),
+					 NTATAG_USE_SRV(0),
+					 NTATAG_PRELOAD(2048),
+					 TAG_END()));
+  /* Create a default leg */
+  TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent, 
+					     leg_callback,
+					     ag,
+					     NTATAG_NO_DIALOG(1),
+					     TAG_END()));
+
+  {
+    /* Initialize our headers */
+    sip_from_t from[1];
+    sip_to_t to[1];
+    sip_contact_t m[1];
+
+    sip_from_init(from);
+    sip_to_init(to);
+    sip_contact_init(m);
+
+    TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent));
+
+    *m->m_url = *ag->ag_contact->m_url;
+    m->m_url->url_user = "bob";
+    TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m));
+
+    to->a_display = "Bob";
+    *to->a_url = *ag->ag_contact->m_url;
+    to->a_url->url_user = "bob";
+    to->a_url->url_port = NULL;
+    TEST_1(ag->ag_bob = sip_to_dup(ag->ag_home, to));
+
+    url_strip_transport(ag->ag_bob->a_url);
+
+    *m->m_url = *ag->ag_contact->m_url;
+    m->m_url->url_user = "alice";
+    TEST_1(ag->ag_m_alice = sip_contact_dup(ag->ag_home, m));
+
+    from->a_display = "Alice";
+    *from->a_url = *ag->ag_contact->m_url;
+    from->a_url->url_user = "alice";
+    from->a_url->url_port = NULL;
+
+    TEST_1(ag->ag_alice = sip_from_dup(ag->ag_home, from));
+
+    url_strip_transport(ag->ag_alice->a_url);
+  }
+
+  {
+    char const data[] = 
+      "v=0\r\n"
+      "o=- 425432 423412 IN IP4 127.0.0.1\r\n"
+      "s= \r\n"
+      "c=IN IP4 127.0.0.1\r\n"
+      "m=5004 audio 8 0\r\n";
+
+    ag->ag_content_type = sip_content_type_make(ag->ag_home, "application/sdp");
+    ag->ag_payload = sip_payload_make(ag->ag_home, data);
+  }
+
+  {
+    sip_contact_t *m;
+
+    ag->ag_aliases = 
+      sip_contact_make(ag->ag_home, "sip:127.0.0.1, sip:localhost, sip:[::1]");
+    TEST_1(ag->ag_aliases);
+    TEST_1(ag->ag_aliases->m_next);
+    TEST_1(ag->ag_aliases->m_next->m_next);
+    TEST_P(ag->ag_aliases->m_next->m_next->m_next, NULL);
+
+    for (m = ag->ag_aliases; m; m = m->m_next)
+      m->m_url->url_port = ag->ag_contact->m_url->url_port;
+
+    TEST_1(m = sip_contact_dup(ag->ag_home, ag->ag_contact));
+
+    m->m_next = ag->ag_aliases;
+    ag->ag_aliases = m;
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_REL100(1),
+			      NTATAG_UA(1), 
+			      NTATAG_USE_NAPTR(1),
+			      NTATAG_USE_SRV(1),
+			      TAG_END()),
+	 5);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
+			      TAG_END()), 2);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_ALIASES(ag->ag_aliases),
+			      NTATAG_DEFAULT_PROXY(NULL),
+			      TAG_END()), 2);
+
+    TEST(nta_agent_set_params(ag->ag_agent, 
+			      NTATAG_DEFAULT_PROXY("tel:+35878008000"),
+			      TAG_END()), -1);
+
+  }
+  
+  {
+    url_t url[1];
+
+    /* Create the server leg */
+    *url = *ag->ag_aliases->m_url;
+    url->url_user = "%";
+    TEST_1(ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent, 
+					       leg_callback,
+					       ag,
+					       NTATAG_NO_DIALOG(1),
+					       URLTAG_URL(url),
+					       TAG_END()));
+  }
+
+  END();
+}  
+
+int api_test_deinit(agent_t *ag)
+{
+  BEGIN();
+
+  if (ag->ag_request) msg_destroy(ag->ag_request), ag->ag_request = NULL;
+  if (ag->ag_response) msg_destroy(ag->ag_response), ag->ag_response = NULL;
+
+  su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+  nta_leg_destroy(ag->ag_alice_leg);
+  nta_leg_destroy(ag->ag_bob_leg);
+  nta_leg_destroy(ag->ag_default_leg);
+  nta_leg_destroy(ag->ag_server_leg);
+
+  nta_agent_destroy(ag->ag_agent);
+  su_root_destroy(ag->ag_root);
+
+  free(ag->ag_mclass), ag->ag_mclass = NULL;
+
+  END();
+}  
+
+/* Get and check parameters */
+int api_test_params(agent_t *ag)
+{
+  BEGIN();
+  nta_agent_t *nta;
+
+  sip_contact_t const *aliases = (void *)-1;
+  msg_mclass_t *mclass = (void *)-1;
+  unsigned sip_t1 = -1;
+  unsigned sip_t2 = -1;
+  unsigned sip_t4    = -1;
+  unsigned debug_drop_prob = -1;
+  int ua              = -1;
+  int user_via        = -1;
+  int extra_100       = -1;
+  int pass_100        = -1;
+  int timeout_408     = -1;
+  int pass_408        = -1;
+  int merge_482       = -1;
+  int cancel_2543     = -1;
+  int cancel_487      = -1;
+  int rel100          = -1;
+  int use_timestamp   = -1;
+  int use_naptr       = -1;
+  int use_srv         = -1;
+  unsigned preload = (unsigned)-1;
+  char const *s = NONE;
+
+  TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
+				NULL, NULL, TAG_END()));
+  TEST(nta_agent_get_params(nta,
+			    NTATAG_MCLASS_REF(mclass),
+			    NTATAG_ALIASES_REF(aliases),
+			    NTATAG_SIP_T1_REF(sip_t1),
+			    NTATAG_SIP_T2_REF(sip_t2),
+			    NTATAG_SIP_T4_REF(sip_t4),
+			    NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob),
+			    NTATAG_UA_REF(ua),
+			    NTATAG_USER_VIA_REF(user_via),
+			    NTATAG_EXTRA_100_REF(extra_100),
+			    NTATAG_PASS_100_REF(pass_100),
+			    NTATAG_TIMEOUT_408_REF(timeout_408),
+			    NTATAG_PASS_408_REF(pass_408),
+			    NTATAG_MERGE_482_REF(merge_482),
+			    NTATAG_CANCEL_2543_REF(cancel_2543),
+			    NTATAG_CANCEL_487_REF(cancel_487),
+			    NTATAG_REL100_REF(rel100),
+			    NTATAG_USE_TIMESTAMP_REF(use_timestamp),
+			    NTATAG_USE_NAPTR_REF(use_naptr),
+			    NTATAG_USE_SRV_REF(use_srv),
+			    TAG_END()), 
+       /* Number of parameters */ 19);
+  
+  TEST_P(mclass, sip_default_mclass());
+  TEST_P(aliases, NULL);
+  TEST(sip_t1, NTA_SIP_T1);
+  TEST(sip_t2, NTA_SIP_T2);
+  TEST(sip_t4, NTA_SIP_T4);
+  TEST(debug_drop_prob, 0);
+  TEST(ua,              0);
+  TEST(user_via,        0);
+  TEST(extra_100,       0);
+  TEST(pass_100,        0);
+  TEST(timeout_408,     1);
+  TEST(pass_408,        0);
+  TEST(merge_482,       0);
+  TEST(cancel_2543,     0);
+  TEST(cancel_487,      1);
+  TEST(rel100,          0);
+  TEST(use_timestamp,   0);
+  TEST(use_naptr,       1);
+  TEST(use_srv,         1);
+
+  TEST(nta_agent_set_params(NULL, 
+      		      NTATAG_PRELOAD(2048),
+      		      TAG_END()), -1);
+  TEST(nta_agent_get_params(NULL, 
+      		      NTATAG_PRELOAD_REF(preload),
+      		      TAG_END()), -1);
+
+  TEST(nta_agent_set_params(nta, 
+      		      NTATAG_PRELOAD(2048),
+      		      TAG_END()), 1);
+  TEST(nta_agent_get_params(nta, 
+      		      NTATAG_PRELOAD_REF(preload),
+      		      TAG_END()), 1);
+  TEST(preload, 2048);
+
+  TEST(nta_agent_set_params(nta, 
+			    NTATAG_SIGCOMP_OPTIONS("sip"),
+			    TAG_END()), 1);
+  TEST(nta_agent_set_params(nta, 
+			    NTATAG_SIGCOMP_OPTIONS(","),
+			    TAG_END()), -1);
+  TEST(nta_agent_set_params(nta, 
+			    NTATAG_SIGCOMP_OPTIONS("sip;dms=16384"),
+			    TAG_END()), 1);
+  s = NONE;
+  TEST(nta_agent_get_params(nta, 
+			    NTATAG_SIGCOMP_OPTIONS_REF(s),
+			    TAG_END()), 1);
+  TEST_S(s, "sip;dms=16384");
+
+  TEST_VOID(nta_agent_destroy(nta));
+
+  END();
+}
+
+int api_test_stats(agent_t *ag)
+{
+  BEGIN();
+
+  nta_agent_t *nta;
+
+  uint32_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
+  uint32_t recv_msg = -1, sent_msg = -1;
+  uint32_t recv_request = -1, recv_response = -1;
+  uint32_t bad_message = -1, bad_request = -1, bad_response = -1;
+  uint32_t drop_request = -1, drop_response = -1;
+  uint32_t client_tr = -1, server_tr = -1, dialog_tr = -1;
+  uint32_t acked_tr = -1, canceled_tr = -1;
+  uint32_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
+  uint32_t trless_200 = -1, merged_request = -1;
+  uint32_t sent_request = -1, sent_response = -1;
+  uint32_t retry_request = -1, retry_response = -1, recv_retry = -1;
+  uint32_t tout_request = -1, tout_response = -1;
+
+  TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
+				NULL, NULL, TAG_END()));
+
+  TEST(nta_agent_get_stats(NULL,
+      		     NTATAG_S_TOUT_REQUEST_REF(tout_request),
+      		     NTATAG_S_TOUT_RESPONSE_REF(tout_response),
+      		     TAG_END()), -1);
+
+  TEST(nta_agent_get_stats(nta,
+      		     NTATAG_S_IRQ_HASH_REF(irq_hash),
+      		     NTATAG_S_ORQ_HASH_REF(orq_hash),
+      		     NTATAG_S_LEG_HASH_REF(leg_hash),
+      		     NTATAG_S_RECV_MSG_REF(recv_msg),
+      		     NTATAG_S_SENT_MSG_REF(sent_msg),
+      		     NTATAG_S_RECV_REQUEST_REF(recv_request),
+      		     NTATAG_S_RECV_RESPONSE_REF(recv_response),
+      		     NTATAG_S_BAD_MESSAGE_REF(bad_message),
+      		     NTATAG_S_BAD_REQUEST_REF(bad_request),
+      		     NTATAG_S_BAD_RESPONSE_REF(bad_response),
+      		     NTATAG_S_DROP_REQUEST_REF(drop_request),
+      		     NTATAG_S_DROP_RESPONSE_REF(drop_response),
+      		     NTATAG_S_CLIENT_TR_REF(client_tr),
+      		     NTATAG_S_SERVER_TR_REF(server_tr),
+      		     NTATAG_S_DIALOG_TR_REF(dialog_tr),
+      		     NTATAG_S_ACKED_TR_REF(acked_tr),
+      		     NTATAG_S_CANCELED_TR_REF(canceled_tr),
+      		     NTATAG_S_TRLESS_REQUEST_REF(trless_request),
+      		     NTATAG_S_TRLESS_TO_TR_REF(trless_to_tr),
+      		     NTATAG_S_TRLESS_RESPONSE_REF(trless_response),
+      		     NTATAG_S_TRLESS_200_REF(trless_200),
+      		     NTATAG_S_MERGED_REQUEST_REF(merged_request),
+      		     NTATAG_S_SENT_REQUEST_REF(sent_request),
+      		     NTATAG_S_SENT_RESPONSE_REF(sent_response),
+      		     NTATAG_S_RETRY_REQUEST_REF(retry_request),
+      		     NTATAG_S_RETRY_RESPONSE_REF(retry_response),
+      		     NTATAG_S_RECV_RETRY_REF(recv_retry),
+      		     NTATAG_S_TOUT_REQUEST_REF(tout_request),
+      		     NTATAG_S_TOUT_RESPONSE_REF(tout_response),
+      		     TAG_END()), 29);
+
+  TEST_1(irq_hash == HTABLE_MIN_SIZE);
+  TEST_1(orq_hash == HTABLE_MIN_SIZE);
+  TEST_1(leg_hash == HTABLE_MIN_SIZE);
+  TEST_1(recv_msg == 0);
+  TEST_1(sent_msg == 0);
+  TEST_1(recv_request == 0);
+  TEST_1(recv_response == 0);
+  TEST_1(bad_message == 0);
+  TEST_1(bad_request == 0);
+  TEST_1(bad_response == 0);
+  TEST_1(drop_request == 0);
+  TEST_1(drop_response == 0);
+  TEST_1(client_tr == 0);
+  TEST_1(server_tr == 0);
+  TEST_1(dialog_tr == 0);
+  TEST_1(acked_tr == 0);
+  TEST_1(canceled_tr == 0);
+  TEST_1(trless_request == 0);
+  TEST_1(trless_to_tr == 0);
+  TEST_1(trless_response == 0);
+  TEST_1(trless_200 == 0);
+  TEST_1(merged_request == 0);
+  TEST_1(sent_request == 0);
+  TEST_1(sent_response == 0);
+  TEST_1(retry_request == 0);
+  TEST_1(retry_response == 0);
+  TEST_1(recv_retry == 0);
+  TEST_1(tout_request == 0);
+  TEST_1(tout_response == 0);
+
+  TEST_VOID(nta_agent_destroy(nta));
+
+  END();
+}
+
+/* Test handling transports */
+int api_test_tport(agent_t *ag)
+{
+  sip_via_t const *v;
+
+  url_t url[1];
+
+  BEGIN();
+
+  nta_agent_t *agent;
+  sip_contact_t const *m;
+
+  *url = *ag->ag_contact->m_url;
+  url->url_port = "*";
+  url->url_params = "transport=tcp";
+
+  TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+  TEST_1(!nta_agent_via(agent));
+  TEST_1(!nta_agent_public_via(agent));
+  TEST_1(!nta_agent_contact(agent));
+
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+  TEST_1(v = nta_agent_via(agent)); TEST_1(!v->v_next);
+  TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+  TEST_1(m = nta_agent_contact(agent));
+  TEST_S(m->m_url->url_params, "transport=tcp");
+
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, 
+			     TPTAG_SERVER(0), TAG_END()) == 0);
+  TEST_1(v = nta_agent_public_via(agent)); TEST_1(!v->v_next);
+  TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+  TEST_1(host_has_domain_invalid(v->v_host));
+  TEST_1(m = nta_agent_contact(agent));
+  TEST_S(m->m_url->url_params, "transport=tcp");
+
+  url->url_params = "transport=udp";
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+  TEST_1(v = nta_agent_via(agent)); TEST_1(v = v->v_next);
+  TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+
+  TEST_VOID(nta_agent_destroy(agent));
+
+  TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+  TEST_1(v = nta_agent_via(agent)); TEST_1(!v->v_next);
+  TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+  TEST_1(m = nta_agent_contact(agent));
+  TEST_S(m->m_url->url_params, "transport=udp");
+  TEST_VOID(nta_agent_destroy(agent));
+
+  url->url_params = "transport=tcp,udp";
+
+  TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+  TEST_1(v = nta_agent_via(agent)); 
+  TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+  TEST_1(v = v->v_next);  
+  TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+  TEST_1(m = nta_agent_contact(agent));
+  TEST_1(!m->m_url->url_params);
+  TEST_VOID(nta_agent_destroy(agent));
+
+  url->url_params = NULL;
+
+  TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+  TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+  TEST_1(v = nta_agent_via(agent)); 
+  TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+  TEST_1(v = v->v_next);
+  TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+  TEST_1(m = nta_agent_contact(agent));
+  TEST_1(!m->m_url->url_params);
+  TEST_VOID(nta_agent_destroy(agent));
+
+
+  END();
+}
+
+static int api_test_dialogs(agent_t *ag)
+{
+  BEGIN();
+#if 0
+  {
+    /* Test 0.1
+     * Send a message from default leg to default leg 
+     */
+    char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n";
+    msg_t *msg;
+
+    ag->ag_expect_leg = ag->ag_default_leg;
+
+    TEST_1(ag->ag_orq = 
+	  nta_outgoing_tcreate(ag->ag_default_leg, 
+			       outgoing_callback, ag,
+			       ag->ag_obp,
+			       SIP_METHOD_MESSAGE,
+			       (url_string_t *)ag->ag_contact->m_url,
+			       SIPTAG_SUBJECT_STR("Test 0.1"),
+			       SIPTAG_FROM(ag->ag_alice),
+			       SIPTAG_TO(ag->ag_bob),
+			       SIPTAG_CONTACT(ag->ag_m_alice),
+			       SIPTAG_HEADER_STR(p_acid),
+			       TAG_END()));
+
+    TEST(nta_outgoing_getresponse(ag->ag_orq), NULL);
+    TEST_1(msg = nta_outgoing_getrequest(ag->ag_orq));
+    TEST(nta_outgoing_method(ag->ag_orq), sip_method_message);
+    TEST_S(nta_outgoing_method_name(ag->ag_orq), "MESSAGE");
+    msg_destroy(msg);
+
+    TEST(nta_outgoing_delay(ag->ag_orq), UINT_MAX);
+    nta_test_run(ag);
+    TEST(ag->ag_status, 200);
+    TEST(ag->ag_orq, NULL);
+    TEST(ag->ag_latest_leg, ag->ag_default_leg);
+    TEST_1(ag->ag_request);
+
+    nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+  }
+#endif
+
+  END();
+}
+
+
+int outgoing_default(agent_t *ag,
+		     nta_outgoing_t *orq,
+		     sip_t const *sip)
+{
+  BEGIN();
+  msg_t *msg;
+
+  int status = sip->sip_status->st_status;
+
+  ag->ag_status = status;
+
+  if (status < 200)
+    return 0;
+
+  /* Test API functions */
+  TEST(nta_outgoing_status(orq), status);
+  TEST_1(!nta_outgoing_request_uri(orq));
+  TEST_1(!nta_outgoing_route_uri(orq));
+  TEST(nta_outgoing_method(orq), sip_method_invalid);
+  TEST_S(nta_outgoing_method_name(orq), "*");
+  TEST(nta_outgoing_cseq(orq), 0);
+  TEST_1(nta_outgoing_delay(orq) == UINT_MAX);
+  
+  TEST_1(msg = nta_outgoing_getresponse(orq));
+  if (ag->ag_response == NULL)
+    ag->ag_response = msg;
+  else
+    msg_destroy(msg);
+
+  TEST_1(!nta_outgoing_getrequest(orq));
+
+  END();
+}
+
+/* Test default incoming and outgoing */
+static int api_test_default(agent_t *ag)
+{
+  BEGIN();
+  nta_agent_t *nta;
+  nta_incoming_t *irq;
+  nta_outgoing_t *orq;
+  sip_via_t via[1];
+
+  TEST_1(nta = ag->ag_agent);
+
+  TEST_1(irq = nta_incoming_default(nta));
+
+  TEST_VOID(nta_incoming_bind(irq, incoming_callback_1, ag));
+  TEST_P(nta_incoming_magic(irq, incoming_callback_1), ag);
+  TEST_P(nta_incoming_magic(irq, incoming_callback_2), 0);
+  
+  TEST_P(nta_incoming_tag(irq, NULL), NULL);
+  TEST_P(nta_incoming_gettag(irq), NULL);
+
+  TEST(nta_incoming_status(irq), 0);
+  TEST(nta_incoming_method(irq), sip_method_invalid);
+  TEST_S(nta_incoming_method_name(irq), "*");
+  TEST_P(nta_incoming_url(irq), NULL);
+  TEST(nta_incoming_cseq(irq), 0);
+  
+  TEST(nta_incoming_set_params(irq, TAG_END()), 0);
+  
+  TEST_P(nta_incoming_getrequest(irq), NULL);
+  TEST_P(nta_incoming_getrequest_ackcancel(irq), NULL);
+  TEST_P(nta_incoming_getresponse(irq), NULL);
+  
+  TEST(nta_incoming_complete_response(irq, NULL, SIP_200_OK, TAG_END()), -1);
+
+  TEST(nta_incoming_treply(irq, SIP_200_OK, TAG_END()), -1);
+  TEST(nta_incoming_mreply(irq, NULL), -1);
+  
+  TEST_VOID(nta_incoming_destroy(irq));
+  
+  TEST_1(orq = nta_outgoing_default(nta, outgoing_default, ag));
+
+  TEST(nta_outgoing_status(orq), 0);
+  TEST(nta_outgoing_method(orq), sip_method_invalid);
+  TEST_S(nta_outgoing_method_name(orq), "*");
+  TEST(nta_outgoing_cseq(orq), 0);
+
+  TEST(nta_outgoing_delay(orq), UINT_MAX);
+  TEST_P(nta_outgoing_request_uri(orq), NULL);
+  TEST_P(nta_outgoing_route_uri(orq), NULL);
+
+  TEST_P(nta_outgoing_getresponse(orq), NULL);
+  TEST_P(nta_outgoing_getrequest(orq), NULL);
+
+  TEST_P(nta_outgoing_tagged(orq, NULL, NULL, NULL, NULL), NULL);
+  TEST(nta_outgoing_cancel(orq), -1);
+  TEST_P(nta_outgoing_tcancel(orq, NULL, NULL, TAG_END()), NULL);
+
+  TEST_VOID(nta_outgoing_destroy(orq));
+  
+  TEST_1(irq = nta_incoming_default(nta));
+  TEST_1(orq = nta_outgoing_default(nta, outgoing_default, ag));
+
+  via[0] = nta_agent_via(nta)[0];
+  via->v_next = NULL;
+
+  TEST_1(nta_incoming_treply
+	 (irq, 
+	  SIP_200_OK,
+	  SIPTAG_VIA(via),
+	  SIPTAG_CALL_ID_STR("oishciucnkrcoihciunskcisj"),
+	  SIPTAG_CSEQ_STR("1 MESSAGE"),
+	  SIPTAG_FROM_STR("Arska <sip:arska at example.com>;tag=aiojcidscd0i"),
+	  SIPTAG_TO_STR("Jaska <sip:jaska at example.net>;tag=iajf8wru"),
+	  TAG_END()) == 0);
+
+  for (ag->ag_status = 0; ag->ag_status < 200; ) {
+    su_root_step(ag->ag_root, 200);
+  }
+
+  TEST(nta_outgoing_status(orq), 0);
+
+  TEST_VOID(nta_outgoing_destroy(orq));
+  TEST_VOID(nta_incoming_destroy(irq));
+  
+  END();
+}
+
+/** Test API for errors */
+static int api_test_errors(agent_t *ag)
+{
+  nta_agent_t *nta;
+  su_root_t *root;
+  su_home_t home[1];
+
+  BEGIN();
+
+  memset(home, 0, sizeof home);
+  home->suh_size = sizeof home;
+  su_home_init(home);
+
+  TEST_P(nta_agent_create(NULL,
+			  (url_string_t *)"sip:*:*",
+			  NULL,
+			  NULL,
+			  TAG_END()), NULL);
+
+  TEST_1(root = su_root_create(NULL));
+
+  TEST_P(nta_agent_create(root,
+			  (url_string_t *)"http://localhost:*/invalid/bind/url",
+			  NULL,
+			  NULL,
+			  TAG_END()), NULL);
+
+  TEST_P(nta_agent_create(root,
+			  (url_string_t *)"sip:*:*;transport=XXX",
+			  NULL,
+			  NULL,
+			  TAG_END()), NULL);
+
+  TEST_1(nta = nta_agent_create(root,
+				(url_string_t *)"sip:*:*",
+				NULL,
+				NULL,
+				TAG_END()));
+
+  TEST_VOID(nta_agent_destroy(NULL));
+  TEST_VOID(nta_agent_destroy(nta));
+
+  TEST_1(nta = nta_agent_create(root,
+				(url_string_t *)"sip:*:*",
+				agent_callback,
+				ag,
+				TAG_END()));
+
+  TEST_P(nta_agent_contact(NULL), NULL);
+  TEST_P(nta_agent_via(NULL), NULL);
+  TEST_S(nta_agent_version(nta), nta_agent_version(NULL));
+  TEST_P(nta_agent_magic(NULL), NULL);
+  TEST_P(nta_agent_magic(nta), (void *)ag);
+  TEST(nta_agent_add_tport(NULL, NULL, TAG_END()), -1);
+  TEST_P(nta_agent_newtag(home, "tag=%s", NULL), NULL);
+  TEST_1(nta_agent_newtag(home, "tag=%s", nta));
+
+  {
+    msg_t *msg;
+    TEST_1(nta_msg_create(NULL, 0) == NULL);
+    TEST(nta_msg_complete(NULL), -1);
+
+    TEST_1(msg = nta_msg_create(nta, 0));
+    TEST(nta_msg_complete(msg), -1);
+    TEST(nta_msg_request_complete(msg, NULL, 
+				  sip_method_unknown, "FOO", NULL), -1);
+    TEST(nta_is_internal_msg(NULL), 0);
+    TEST(nta_is_internal_msg(msg), 0);
+    TEST_1(msg_set_flags(msg, NTA_INTERNAL_MSG));
+    TEST(nta_is_internal_msg(msg), 1);
+    TEST_VOID(msg_destroy(msg));
+  }
+
+  TEST_P(nta_leg_tcreate(NULL, NULL, NULL, TAG_END()), NULL);
+  TEST_VOID(nta_leg_destroy(NULL));
+  TEST_P(nta_leg_magic(NULL, NULL), NULL);
+  TEST_VOID(nta_leg_bind(NULL, NULL, NULL));
+  TEST_P(nta_leg_tag(NULL, "fidsafsa"), NULL);
+  TEST_P(nta_leg_rtag(NULL, "fidsafsa"), NULL);
+  TEST_P(nta_leg_get_tag(NULL), NULL);
+  TEST(nta_leg_client_route(NULL, NULL, NULL), -1);
+  TEST(nta_leg_server_route(NULL, NULL, NULL), -1);
+  TEST_P(nta_leg_by_uri(NULL, NULL), NULL);
+  TEST_P(nta_leg_by_dialog(NULL,  NULL, NULL, NULL, NULL, NULL, NULL), NULL);
+  TEST_P(nta_leg_by_dialog(nta, NULL, NULL, NULL, NULL, NULL, NULL), NULL);
+
+  TEST_P(nta_leg_make_replaces(NULL, NULL, 1), NULL);
+  TEST_P(nta_leg_by_replaces(NULL, NULL), NULL);
+
+  TEST_P(nta_incoming_create(NULL, NULL, NULL, NULL, TAG_END()), NULL);
+  TEST_P(nta_incoming_create(nta, NULL, NULL, NULL, TAG_END()), NULL);
+
+  TEST_VOID(nta_incoming_bind(NULL, NULL, NULL));
+  TEST_P(nta_incoming_magic(NULL, NULL), NULL);
+  
+  TEST_P(nta_incoming_find(NULL, NULL, NULL), NULL);
+  TEST_P(nta_incoming_find(nta, NULL, NULL), NULL);
+
+  TEST_P(nta_incoming_tag(NULL, NULL), NULL);
+  TEST_P(nta_incoming_gettag(NULL), NULL);
+
+  TEST(nta_incoming_status(NULL), 400);
+  TEST(nta_incoming_method(NULL), sip_method_invalid);
+  TEST_P(nta_incoming_method_name(NULL), NULL);
+  TEST_P(nta_incoming_url(NULL), NULL);
+  TEST(nta_incoming_cseq(NULL), 0);
+
+  TEST(nta_incoming_set_params(NULL, TAG_END()), -1);
+
+  TEST_P(nta_incoming_getrequest(NULL), NULL);
+  TEST_P(nta_incoming_getrequest_ackcancel(NULL), NULL);
+  TEST_P(nta_incoming_getresponse(NULL), NULL);
+
+  TEST(nta_incoming_complete_response(NULL, NULL, 800, "foo", TAG_END()), -1);
+
+  TEST(nta_incoming_treply(NULL, SIP_200_OK, TAG_END()), -1);
+  TEST(nta_incoming_mreply(NULL, NULL), -1);
+
+  TEST_VOID(nta_incoming_destroy(NULL));
+  
+  TEST_P(nta_outgoing_tcreate(NULL, outgoing_callback, ag, 
+			    URL_STRING_MAKE("sip:localhost"),
+			    SIP_METHOD_MESSAGE,
+			    URL_STRING_MAKE("sip:localhost"),
+			    TAG_END()), NULL);
+
+  TEST_P(nta_outgoing_mcreate(NULL, outgoing_callback, ag, 
+			    URL_STRING_MAKE("sip:localhost"),
+			    NULL,
+			    TAG_END()), NULL);
+
+  TEST_P(nta_outgoing_default(NULL, NULL, NULL), NULL);
+
+  TEST(nta_outgoing_status(NULL), 500);
+  TEST(nta_outgoing_method(NULL), sip_method_invalid);
+  TEST_P(nta_outgoing_method_name(NULL), NULL);
+  TEST(nta_outgoing_cseq(NULL), 0);
+
+  TEST(nta_outgoing_delay(NULL), UINT_MAX);
+  TEST_P(nta_outgoing_request_uri(NULL), NULL);
+  TEST_P(nta_outgoing_route_uri(NULL), NULL);
+
+  TEST_P(nta_outgoing_getresponse(NULL), NULL);
+  TEST_P(nta_outgoing_getrequest(NULL), NULL);
+
+  TEST_P(nta_outgoing_tagged(NULL, NULL, NULL, NULL, NULL), NULL);
+  TEST(nta_outgoing_cancel(NULL), -1);
+  TEST_P(nta_outgoing_tcancel(NULL, NULL, NULL, TAG_END()), NULL);
+  TEST_VOID(nta_outgoing_destroy(NULL));
+
+  TEST_P(nta_outgoing_find(NULL, NULL, NULL, NULL), NULL);
+  TEST_P(nta_outgoing_find(nta, NULL, NULL, NULL), NULL);
+
+  TEST(nta_outgoing_status(NONE), 500);
+  TEST(nta_outgoing_method(NONE), sip_method_invalid);
+  TEST_P(nta_outgoing_method_name(NONE), NULL);
+  TEST(nta_outgoing_cseq(NONE), 0);
+
+  TEST(nta_outgoing_delay(NONE), UINT_MAX);
+  TEST_P(nta_outgoing_request_uri(NONE), NULL);
+  TEST_P(nta_outgoing_route_uri(NONE), NULL);
+
+  TEST_P(nta_outgoing_getresponse(NONE), NULL);
+  TEST_P(nta_outgoing_getrequest(NONE), NULL);
+
+  TEST_P(nta_outgoing_tagged(NONE, NULL, NULL, NULL, NULL), NULL);
+  TEST(nta_outgoing_cancel(NONE), -1);
+  TEST_P(nta_outgoing_tcancel(NONE, NULL, NULL, TAG_END()), NULL);
+  TEST_VOID(nta_outgoing_destroy(NONE));
+
+#if 0
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *ireq,
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    int status, char const *phrase, 
+				    tag_type_t tag, 
+				    tag_value_t value, ...);
+
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq, 
+				    nta_prack_f *callback,
+				    nta_reliable_magic_t *rmagic,
+				    msg_t *msg);
+
+void nta_reliable_destroy(nta_reliable_t *);
+
+#endif  
+
+  TEST_VOID(nta_agent_destroy(nta)); 
+  TEST_VOID(su_root_destroy(root));
+  TEST_VOID(su_home_deinit(home));
+
+  END();
+}
+
+static int api_test_dialog_matching(agent_t *ag)
+{
+  nta_agent_t *nta;
+  su_root_t *root;
+  su_home_t home[1];
+  nta_leg_t *leg, *dialog1, *dialog2, *dst, *defdst;
+  sip_from_t *a1, *a2;
+  sip_call_id_t *i;
+
+  BEGIN();
+
+  memset(home, 0, sizeof home);
+  home->suh_size = sizeof home;
+  su_home_init(home);
+
+  TEST_1(root = su_root_create(NULL));
+
+  TEST_1(nta = nta_agent_create(root,
+				(url_string_t *)"sip:*:*",
+				NULL,
+				NULL,
+				TAG_END()));
+
+  TEST_1(dst = nta_leg_tcreate(nta, NULL, NULL, 
+				NTATAG_NO_DIALOG(1),
+				URLTAG_URL("sip:joe at localhost"),
+				TAG_END()));
+
+  TEST_1(defdst = nta_leg_tcreate(nta, NULL, NULL, 
+				  NTATAG_NO_DIALOG(1),
+				  TAG_END()));
+
+  TEST_1(dialog1 = 
+	 nta_leg_tcreate(nta, NULL, NULL, 
+			 URLTAG_URL("sip:pc.al.us"),
+			 SIPTAG_CALL_ID_STR("foobarbaz"),
+			 /* local */
+			 SIPTAG_FROM_STR("<sip:me.myself.i at foo.com>;tag=foo"),
+			 /* remote */
+			 SIPTAG_TO_STR("<sip:joe.boy at al.us>"),
+			 TAG_END()));
+
+  TEST_1(a1 = sip_from_make(home, "<sip:me.myself.i at foo.com>;tag=foo"));
+  TEST_1(a2 = sip_from_make(home, "<sip:joe.boy at al.us>;tag=al"));
+  TEST_1(i = sip_call_id_make(home, "foobarbaz"));
+
+  TEST_1(dialog2 = 
+	 nta_leg_tcreate(nta, NULL, NULL, 
+			 SIPTAG_CALL_ID(i),
+			 /* local */
+			 SIPTAG_FROM(a2),
+			 /* remote */
+			 SIPTAG_TO(a1),
+			 TAG_END()));
+
+  TEST_1(!nta_leg_by_dialog(nta, NULL, NULL, 
+			    a1->a_tag, a1->a_url, a2->a_tag, a2->a_url));
+  TEST_1(!nta_leg_by_dialog(NULL, NULL, i, 
+			    a1->a_tag, a1->a_url, a2->a_tag, a2->a_url));
+  TEST_1(!nta_leg_by_dialog(nta, (void *)"sip:no.such.url", i, 
+			    a2->a_tag, a2->a_url, a1->a_tag, a1->a_url));
+  TEST_1(!nta_leg_by_dialog(nta, a2->a_url, i, 
+			    a2->a_tag, a2->a_url, a1->a_tag, a1->a_url));
+
+  TEST_P(leg = nta_leg_by_dialog(nta, NULL, i, 
+				 /* local */ a1->a_tag, a1->a_url, 
+				 /* remote */ a2->a_tag, a2->a_url),
+	 dialog2);
+  TEST_P(leg = nta_leg_by_dialog(nta, (void *)"sip:no.such.url", i, 
+				 /* local */ a1->a_tag, a1->a_url, 
+				 /* remote */ a2->a_tag, a2->a_url),
+	 dialog2);
+  TEST_P(leg = nta_leg_by_dialog(nta, a2->a_url, i, 
+				 a1->a_tag, a1->a_url, a2->a_tag, a2->a_url),
+	 dialog2);
+
+  TEST_P(leg = nta_leg_by_dialog(nta, NULL, i, 
+				 a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+	 dialog1);
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+	 dialog1);
+  /* local tag is required because there is tag */
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, "xyzzy", a1->a_url),
+	 NULL);
+  /* local URI is ignored because we have tag */
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, a1->a_tag, a2->a_url),
+	 dialog1);
+
+  /* remote tag is ignored because there is no tag */
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 "xyzzy", a2->a_url, a1->a_tag, a1->a_url),
+	 dialog1);
+  /* remote url is required */
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a1->a_url, a1->a_tag, a1->a_url),
+	 NULL);
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, NULL, a1->a_tag, a1->a_url),
+	 dialog1);
+
+  /* local url is used if there is no local tag */
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, NULL, NULL),
+	 NULL);
+
+  nta_leg_tag(dialog1, "al");
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+	 dialog1);
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, "xyzzy", a1->a_url),
+	 NULL);
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+	 dialog1);
+  TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i, 
+				 a2->a_tag, a2->a_url, NULL, a1->a_url),
+	 NULL);
+		
+  nta_leg_destroy(defdst);
+  nta_leg_destroy(dst);
+  nta_leg_destroy(dialog1);
+  nta_leg_destroy(dialog2);
+	    
+  TEST_VOID(nta_agent_destroy(nta)); 
+  TEST_VOID(su_root_destroy(root));
+  TEST_VOID(su_home_deinit(home));
+
+  END();
+
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+static
+char const nta_test_api_usage[] =
+  "usage: %s OPTIONS\n"
+  "where OPTIONS are\n"
+  "   -v | --verbose    be verbose\n"
+  "   -q | --quiet      be quiet\n"
+  "   -1                quit on first error\n"
+  "   -l level          set logging level (0 by default)\n"
+  "   --attach          print pid, wait for a debugger to be attached\n"
+#if HAVE_ALARM
+  "   --no-alarm        don't ask for guard ALARM\n"
+#endif
+  ;
+
+void usage(void)
+{
+  fprintf(stderr, nta_test_api_usage, name);
+  exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0, quit_on_single_failure = 0;
+  int i, o_attach = 0, o_alarm = 1;
+
+  agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-q") == 0)
+      tstflags &= ~tst_verbatim;
+    else if (strcmp(argv[i], "-1") == 0)
+      quit_on_single_failure = 1;
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      int level = 3;
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage();
+      
+      su_log_set_level(nta_log, level);
+      su_log_set_level(tport_log, level);
+    }
+    else if (strcmp(argv[i], "--attach") == 0) {
+      o_attach = 1;
+    }
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (argv[i][0] != '-') {
+      break;
+    }
+    else
+      usage();
+  }
+
+  if (o_attach) {
+    char line[10];
+    printf("nua_test: pid %lu\n", (unsigned long)getpid());
+    printf("<Press RETURN to continue>\n");
+    fgets(line, sizeof line, stdin);
+  }
+#if HAVE_ALARM
+  else if (o_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  su_init();
+
+  if (!(TSTFLAGS & tst_verbatim)) {
+    su_log_soft_set_level(nta_log, 0);
+    su_log_soft_set_level(tport_log, 0);
+  }
+
+#define SINGLE_FAILURE_CHECK()						\
+  do { fflush(stderr); fflush(stdout); \
+       if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+  } while(0)
+
+  retval |= api_test_init(ag); fflush(stdout); SINGLE_FAILURE_CHECK();
+  if (retval == 0) {
+    retval |= api_test_errors(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_params(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_stats(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_dialog_matching(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_tport(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_dialogs(ag); SINGLE_FAILURE_CHECK();
+    retval |= api_test_default(ag); SINGLE_FAILURE_CHECK();
+  }
+  retval |= api_test_deinit(ag); fflush(stdout); 
+
+  su_home_deinit(ag->ag_home);
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2005-08-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added agent.pem and cafile.pem.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+PROJECT_NAME         = "nth"
+OUTPUT_DIRECTORY     = ../docs/html/nth
+
+INPUT 		     = nth.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += \
+	"../docs/su.doxytags=../su" \
+	"../docs/ipt.doxytags=../ipt" \
+	"../docs/bnf.doxytags=../bnf" \
+	"../docs/url.doxytags=../url" \
+	"../docs/msg.doxytags=../msg" \
+	"../docs/http.doxytags=../http" \
+
+GENERATE_TAGFILE    = ../docs/nth.doxytags
+
+ALIASES +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+#
+# Makefile.am for nth module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../iptsec -I../iptsec \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../http -I../http \
+		-I$(srcdir)/../sresolv -I../sresolv \
+		-I$(srcdir)/../tport -I../tport \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libnth.la
+
+check_PROGRAMS = 	test_nth http-client http-server
+
+TESTS = 		test_nth
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		nth_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nth.h sofia-sip/nth_tag.h
+
+libnth_la_SOURCES = 	nth_client.c nth_server.c nth_tag.c nth_tag_ref.c
+
+COVERAGE_INPUT = 	$(libnth_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libnth.la \
+			../iptsec/libiptsec.la \
+			../ipt/libipt.la \
+			../http/libhttp.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../sresolv/libsresolv.la \
+			../url/liburl.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nth_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile nth.docs $(BUILT_SOURCES) \
+			agent.pem cafile.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,746 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nth module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnth_la_SOURCES) http-client.c http-server.c test_nth.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_nth$(EXEEXT) http-client$(EXEEXT) \
+	http-server$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nth
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnth_la_LIBADD =
+am_libnth_la_OBJECTS = nth_client.lo nth_server.lo nth_tag.lo \
+	nth_tag_ref.lo
+libnth_la_OBJECTS = $(am_libnth_la_OBJECTS)
+http_client_SOURCES = http-client.c
+http_client_OBJECTS = http-client.$(OBJEXT)
+http_client_LDADD = $(LDADD)
+http_client_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+	../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+	../tport/libtport.la ../stun/libstun.la \
+	../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+	../bnf/libbnf.la ../su/libsu.la
+http_server_SOURCES = http-server.c
+http_server_OBJECTS = http-server.$(OBJEXT)
+http_server_LDADD = $(LDADD)
+http_server_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+	../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+	../tport/libtport.la ../stun/libstun.la \
+	../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+	../bnf/libbnf.la ../su/libsu.la
+test_nth_SOURCES = test_nth.c
+test_nth_OBJECTS = test_nth.$(OBJEXT)
+test_nth_LDADD = $(LDADD)
+test_nth_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+	../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+	../tport/libtport.la ../stun/libstun.la \
+	../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+	../bnf/libbnf.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libnth_la_SOURCES) http-client.c http-server.c test_nth.c
+DIST_SOURCES = $(libnth_la_SOURCES) http-client.c http-server.c \
+	test_nth.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../iptsec -I../iptsec \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../http -I../http \
+		-I$(srcdir)/../sresolv -I../sresolv \
+		-I$(srcdir)/../tport -I../tport \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnth.la
+TESTS = test_nth
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nth_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nth.h sofia-sip/nth_tag.h
+
+libnth_la_SOURCES = nth_client.c nth_server.c nth_tag.c nth_tag_ref.c
+COVERAGE_INPUT = $(libnth_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnth.la \
+			../iptsec/libiptsec.la \
+			../ipt/libipt.la \
+			../http/libhttp.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../sresolv/libsresolv.la \
+			../url/liburl.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nth_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
+			agent.pem cafile.pem
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/nth/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/nth/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnth.la: $(libnth_la_OBJECTS) $(libnth_la_DEPENDENCIES) 
+	$(LINK)  $(libnth_la_LDFLAGS) $(libnth_la_OBJECTS) $(libnth_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+http-client$(EXEEXT): $(http_client_OBJECTS) $(http_client_DEPENDENCIES) 
+	@rm -f http-client$(EXEEXT)
+	$(LINK) $(http_client_LDFLAGS) $(http_client_OBJECTS) $(http_client_LDADD) $(LIBS)
+http-server$(EXEEXT): $(http_server_OBJECTS) $(http_server_DEPENDENCIES) 
+	@rm -f http-server$(EXEEXT)
+	$(LINK) $(http_server_LDFLAGS) $(http_server_OBJECTS) $(http_server_LDADD) $(LIBS)
+test_nth$(EXEEXT): $(test_nth_OBJECTS) $(test_nth_DEPENDENCIES) 
+	@rm -f test_nth$(EXEEXT)
+	$(LINK) $(test_nth_LDFLAGS) $(test_nth_OBJECTS) $(test_nth_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http-client.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http-server.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_client.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nth.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,407 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file http-client.c  Simple HTTP tool.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Mar 30 12:05:21 2001 ppessi
+ */
+
+#include "config.h"
+
+/**@page http_client Make HTTP request
+ * 
+ * @par Name    
+ * http-client - HTTP request tool
+ *
+ * @par Synopsis
+ *
+ * <tt>http-client [OPTIONS] url</tt>
+ *
+ * @par Description
+ * 
+ * The @em http-client utility sends a HTTP request to an HTTP server or proxy.
+ *
+ * @par 
+ *
+ * The @em http-client tool will print out status line and interesting
+ * headers from the response. The message body is also printed.
+ *
+ * @par Options
+ *
+ * The @e http-client utility accepts following command line options:
+ * <dl>
+ * <dt>--method=name</dt>
+ * <dd>Specify the request method name (GET by default).
+ * </dd>
+ * <dt>--proxy=url</dt>
+ * <dd>Specifies the proxy via which the request will be sent.
+ * </dd>
+ * <dt>--ua=value</dt>
+ * <dd>Specifies the User-Agent header field.
+ * </dd>
+ * <dt>--mf=n</dt>
+ * <dd>Specify the initial Max-Forwards count.
+ * </dd>
+ * <dt>--pipe</dt>
+ * <dd>Use pipelining (do not shutdown client connection after request).
+ * </dd>
+ * <dt>--extra</dt>
+ * <dd>Insert standard input to the requests.
+ * </dd>
+ * </dl>
+ *
+ * @par Examples
+ *
+ * You want to query supported features of http://connecting.nokia.com:
+ * @code
+ * $ http-client --method OPTIONS http://connecting.nokia.com
+ * @endcode
+ *
+ * @par Environment
+ * @c NTH_DEBUG, @c TPORT_DEBUG, @c TPORT_LOG.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * <hr>
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct context_s context_t;
+#define NTH_CLIENT_MAGIC_T context_t
+
+#include <sofia-sip/nth.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/auth_client.h>
+
+struct context_s {
+  su_home_t   	  c_home[1];
+  su_root_t   	 *c_root;
+  nth_engine_t 	 *c_engine;
+  nth_client_t   *c_clnt;
+  char const     *c_user;
+  char const     *c_pass;
+  auth_client_t  *c_auth;
+  int             c_pre;
+  int             c_pending;
+};
+
+static
+char const name[] = "http-client";
+
+static
+int header_print(FILE *stream, char const *fmt, http_header_t const *h)
+{
+  char s[1024];
+
+  msg_header_field_e(s, sizeof(s), (msg_header_t*)h, 0);
+  s[sizeof(s) - 1] = '\0';
+
+  if (fmt && strcmp(fmt, "%s"))
+    return fprintf(stream, fmt, s);
+  if (fputs(s, stream) >= 0)
+    return strlen(s);
+  return -1;
+}
+
+static
+int payload_print(FILE *stream, msg_payload_t const *pl)
+{
+  for (; pl; pl = pl->pl_next) {
+    fprintf(stream, "%.*s", (int)pl->pl_len, pl->pl_data);
+  }
+  return 0;
+}
+
+static 
+char *read_file(FILE *stream)
+{
+  int n;
+  char *buf;
+  off_t used, size;
+
+  if (stream == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  /* Read block by block */
+  used = 0;
+  size = 512;
+  buf = malloc(size);
+
+  while (buf) {
+    n = fread(buf + used, 1, size - used - 1, stream);
+    used += n;
+    if (n < size - used - 1) {
+      if (feof(stream))
+	;
+      else if (ferror(stream))
+	free(buf), buf = NULL;
+      break;
+    }
+    buf = realloc(buf, 2 * size);
+  }
+
+  if (buf)
+    if (used < size)
+      buf[used] = '\0';
+
+  return buf;
+}
+
+char const _usage[] = 
+"usage: %s [OPTIONS] url\n"
+"       where OPTIONS are as follows\n"
+"       --method=name\n"
+"       --proxy=url\n"
+"       --user=user:password\n"
+"       --ua=value\n"
+"       --mf=n\n"
+"       --pipe\n"
+"       --extra\n";
+
+static
+void usage(int rc)
+{
+  fprintf(stderr, _usage, name);
+  exit(rc);
+}
+
+static int response(context_t *context,
+			       nth_client_t *oreq,
+			       http_t const *http);
+
+int main(int argc, char *argv[])
+{
+  su_home_t *home;
+  context_t context[1] = {{{SU_HOME_INIT(context)}}};
+  http_method_t method;
+  char 
+    *o_proxy = NULL, 
+    *o_user = NULL,
+    *o_max_forwards = NULL,
+    *o_method_name = "GET",
+    *o_user_agent = "http-client/1.0 " "nth/" NTH_VERSION;
+  int 
+    o_pipe = 0, o_extra = 0;
+   
+  char *extra = NULL;
+  char *v;
+
+#define MATCH(s, o) \
+      ((strcmp(s, o) == 0))
+#define MATCH1(s, o) \
+      ((strncmp(s, o, strlen(o)) == 0) && \
+       (v = (s[strlen(o)] ? s + strlen(o) : argv++[1])))
+#define MATCH2(s, o) \
+      ((strncmp(s, o, strlen(o)) == 0) && \
+       (s[strlen(o)] == '=' || s[strlen(o)] == '\0') && \
+       (v = s[strlen(o)] ? s + strlen(o) + 1 : argv++[1]))
+
+  while ((v = argv++[1])) {
+    if (v[0] != '-')                 { argv--; break; }
+    else if (MATCH(v, "-"))          { break; }
+    else if (MATCH2(v, "--method"))  { o_method_name = v;  continue; }
+    else if (MATCH2(v, "--mf"))      { o_max_forwards = v; continue; }
+    else if (MATCH2(v, "--proxy"))   { o_proxy = v;        continue; }
+    else if (MATCH2(v, "--user"))    { o_user = v;         continue; }
+    else if (MATCH2(v, "--ua"))      { o_user_agent = v;   continue; }
+    else if (MATCH(v, "--pipe"))     { o_pipe = 1;         continue; }
+    else if (MATCH(v, "--extra"))    { o_extra = 1;        continue; }
+    else if (MATCH(v, "--help"))     { usage(0);           continue; }
+    else 
+      usage(1);
+  }
+
+  if (!argv[1])
+    usage(1);
+
+  method = http_method_code(o_method_name);
+
+  if (o_user) {
+    char *pass = strchr(o_user, ':');
+    if (pass) *pass++ = '\0';
+    context->c_user = o_user, context->c_pass = pass;
+  }
+
+  su_init();
+
+  su_home_init(home = context->c_home);
+
+  if (o_extra) {
+    if (isatty(0)) 
+      fprintf(stderr, 
+	      "Type extra HTTP headers, empty line then HTTP message body "
+	      "(^D when complete):\n");
+    fflush(stderr);
+
+    extra = read_file(stdin);
+  }
+
+  context->c_root = su_root_create(context);
+
+  if (context->c_root) {
+    context->c_engine = 
+      nth_engine_create(context->c_root, 
+			NTHTAG_ERROR_MSG(0),
+			TAG_END());
+
+    if (context->c_engine) {
+      while ((v = argv++[1])) {
+	nth_client_t *clnt;
+	clnt = nth_client_tcreate(context->c_engine,
+				  response, context, 
+				  method, o_method_name,
+				  URL_STRING_MAKE(v),
+				  NTHTAG_PROXY(o_proxy),
+				  HTTPTAG_USER_AGENT_STR(o_user_agent),
+				  HTTPTAG_MAX_FORWARDS_STR(o_max_forwards),
+				  TPTAG_REUSE(o_pipe),
+				  HTTPTAG_HEADER_STR(extra),
+				  TAG_END());
+	if (clnt)
+	  context->c_pending++;
+      }
+
+      if (context->c_pending)
+	su_root_run(context->c_root); 
+
+      nth_engine_destroy(context->c_engine), context->c_engine = NULL;
+    }
+    su_root_destroy(context->c_root);
+  }
+
+  su_deinit();
+
+  return 0;
+}
+
+/** Handle responses to request */
+static
+int response(context_t *c,
+	     nth_client_t *clnt,
+	     http_t const *http)
+{
+  nth_client_t *newclnt = NULL;
+  int status;
+
+  if (http) {
+    status = http->http_status->st_status;
+  } else {
+    status = nth_client_status(clnt);
+    fprintf(stderr, "HTTP/1.1 %u Error\n", status);
+  } 
+
+  if (http && (c->c_pre || status >= 200)) {
+    http_header_t *h = (http_header_t *)http->http_status;
+    char hname[64];
+
+    for (; h; h = (http_header_t *)h->sh_succ) {
+      if (h == (http_header_t *)http->http_payload)
+	continue;
+      else if (h == (http_header_t *)http->http_separator)
+	continue;
+      else if (!h->sh_class->hc_name)
+	header_print(stdout, NULL, h);
+      else if (h->sh_class->hc_name[0]) {
+	snprintf(hname, sizeof hname, "%s: %%s\n", h->sh_class->hc_name);
+	header_print(stdout, hname, h); 
+      } else {
+	header_print(stdout, "%s\n", h); 
+      }
+    }
+
+    printf("\n");
+    if (http->http_payload)
+      payload_print(stdout, http->http_payload);
+
+    fflush(stdout);
+  }
+
+  if (status < 200)
+    return 0;
+
+  if (status == 401 && http->http_www_authenticate) {
+    char const *user = c->c_user;
+    char const *pass = c->c_pass;
+
+    if (!user || !pass) {
+      url_t const *url = nth_client_url(clnt);
+      if (url) {
+	user = url->url_user, pass = url->url_password;
+       }
+    }
+
+    //if (user && pass &&
+    if (
+	auc_challenge(&c->c_auth, c->c_home, 
+		      http->http_www_authenticate,
+		      http_authorization_class) > 0) {
+      char const *scheme = NULL;
+      char const *realm = NULL;
+
+      scheme = http->http_www_authenticate->au_scheme;
+      realm = msg_params_find(http->http_www_authenticate->au_params,
+				"realm=");
+      if (auc_all_credentials(&c->c_auth, scheme, realm, user, pass)
+	  >= 0)
+	newclnt = nth_client_tcreate(c->c_engine, 
+				     NULL, NULL, HTTP_NO_METHOD, NULL,
+				     NTHTAG_AUTHENTICATION(&c->c_auth),
+				     NTHTAG_TEMPLATE(clnt),
+				     TAG_END());
+    }
+  }
+
+  if (status == 302 && http->http_location) {
+    url_t loc[1];
+    
+    *loc = *http->http_location->loc_url;
+
+    newclnt = nth_client_tcreate(c->c_engine, NULL, NULL,
+				 HTTP_NO_METHOD, 
+				 (url_string_t *)loc,
+				 NTHTAG_TEMPLATE(clnt),
+				 TAG_END());
+  }
+
+
+  if (newclnt)
+    c->c_pending++;
+  
+  nth_client_destroy(clnt);
+  if (c->c_pending-- == 1)
+    su_root_break(c->c_root);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@nofile http-server.c
+ * @brief Test HTTP server
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Sat Oct 19 02:56:23 2002 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+
+typedef struct context_s context_t;
+#define NTH_SITE_MAGIC_T context_t
+#define SU_ROOT_MAGIC_T context_t
+
+#include <sofia-sip/nth.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/http_header.h>
+
+struct context_s {
+  su_home_t   	  c_home[1];
+  su_root_t   	 *c_root;
+  nth_site_t 	 *c_site;
+  char const     *c_server;
+  char const     *c_expires;
+  char const     *c_content_type;
+  http_content_length_t *c_content_length;
+  msg_payload_t *c_body;
+};
+
+char const name[] = "http-server";
+
+static
+void usage(int rc)
+{
+  fprintf(rc ? stderr : stdout,
+	  "usage: %s OPTIONS url [content]\n",
+	  name
+	  );
+  exit(rc);
+}
+
+static int request(context_t *context,
+		   nth_site_t *site,
+		   nth_request_t *req,
+		   http_t const *http,
+		   char const *path);
+su_msg_r server_intr_msg = SU_MSG_R_INIT;
+static RETSIGTYPE server_intr_handler(int signum);
+static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg);
+
+static msg_payload_t *read_payload(su_home_t *home, char const *fname);
+static msg_payload_t *fread_payload(su_home_t *home, FILE *f);
+
+int main(int argc, char *argv[])
+{
+  su_home_t *home;
+  context_t *c, context[1] = {{{SU_HOME_INIT(context)}}};
+  char *o_url = NULL, *o_body = NULL;
+  int o_extra = 0;
+  int o_timeout = 300;
+  char *s;
+
+  c = context;
+  su_init();
+  su_home_init(home = context->c_home);
+
+#define MATCH(s, v) \
+      ((strncmp(s, v, strlen(v)) == 0))
+#define MATCH1(s, v) \
+      ((strncmp(s, v, strlen(v)) == 0) && \
+       (s = (s[strlen(v)] ? s + strlen(v) : argv++[1])))
+#define MATCH2(s, v) \
+      ((strncmp(s, v, strlen(v)) == 0) && \
+       (s[strlen(v)] == '=' ? (s = s + strlen(v) + 1) : (s = argv++[1])))
+
+  while ((s = argv++[1])) {
+    if (*s != '-') break;
+    s++;
+    if (MATCH2(s, "-expires")) 	         { c->c_expires = s; 	    continue; }
+    else if (MATCH2(s, "-tcp-timeout"))  { o_timeout = strtoul(s, &s, 0); continue; }
+    else if (MATCH2(s, "-ct"))           { c->c_content_type = s;   continue; }
+    else if (MATCH2(s, "-content-type")) { c->c_content_type = s;   continue; }
+    else if (MATCH2(s, "-server"))       { c->c_server = s;         continue; }
+    else if (MATCH(s, "-help"))          { usage(0);                continue; }
+    else if (MATCH(s, "x")||MATCH(s, "-extra")) { o_extra = 1;      continue; }
+    else
+      usage(2);
+  }
+
+  if (!(o_url = s))
+    usage(1);
+  else
+    o_body = argv++[1];
+
+  context->c_root = su_root_create(context);
+
+  context->c_body = read_payload(context->c_home, o_body);
+  if (!context->c_body) {
+    perror("contents");
+    exit(1);
+  }
+
+  context->c_content_length =
+    msg_content_length_create(context->c_home, context->c_body->pl_len);
+
+  su_msg_create(server_intr_msg,
+		su_root_task(context->c_root),
+		su_root_task(context->c_root),
+		server_break, 0);
+
+  signal(SIGINT, server_intr_handler);
+
+#ifndef _WIN32
+  signal(SIGPIPE, server_intr_handler);
+  signal(SIGQUIT, server_intr_handler);
+  signal(SIGHUP, server_intr_handler);
+#endif
+
+  if (context->c_root) {
+    context->c_site =
+      nth_site_create(NULL,	             /* This is a top-level site */
+		      request, context,
+		      (url_string_t *)o_url,
+		      NTHTAG_ROOT(context->c_root),
+		      TPTAG_TIMEOUT(o_timeout * 1000),
+		      TAG_END());
+
+    if (context->c_site) {
+      su_root_run(context->c_root);
+      nth_site_destroy(context->c_site);
+    }
+
+    su_root_destroy(context->c_root);
+  }
+
+  su_deinit();
+
+  return 0;
+}
+
+static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg)
+{
+  fprintf(stderr, "%s: received signal, exiting\n", name);
+
+  su_root_break(c->c_root);
+}
+
+static RETSIGTYPE server_intr_handler(int signum)
+{
+  su_msg_send(server_intr_msg);
+}
+
+
+static int request(context_t *c,
+		   nth_site_t *site,
+		   nth_request_t *req,
+		   http_t const *http,
+		   char const *path)
+{
+  fprintf(stderr, "request to /%s\n", path);
+
+  if (path && strlen(path))
+    return 404;
+
+  if (http->http_request->rq_method != http_method_get) {
+    nth_request_treply(req, HTTP_405_NOT_ALLOWED,
+		       HTTPTAG_ALLOW_STR("GET"),
+		       TAG_END());
+    return 405;
+  }
+
+  nth_request_treply(req, HTTP_200_OK,
+		     HTTPTAG_SERVER_STR(c->c_server),
+		     HTTPTAG_EXPIRES_STR(c->c_expires),
+		     HTTPTAG_CONTENT_TYPE_STR(c->c_content_type),
+		     HTTPTAG_CONTENT_LENGTH(c->c_content_length),
+		     HTTPTAG_PAYLOAD(c->c_body),
+		     TAG_END());
+  return 200;
+}
+
+/** Read message body from named file.
+ *
+ * The function read_payload() reads the contents to a SIP payload
+ * structure from a the named file. If @a fname is NULL, the payload
+ * contents are read from standard input.
+ */
+msg_payload_t *read_payload(su_home_t *home, char const *fname)
+{
+  FILE *f;
+  msg_payload_t *pl;
+
+  if (fname == NULL || strcmp(fname, "-") == 0)
+    f = stdin, fname = "<stdin>";
+  else
+    f = fopen(fname, "rb");
+
+  if (f == NULL)
+    return NULL;
+
+  pl = fread_payload(home, f);
+  if (f != stdin)
+    fclose(f);
+
+  return pl;
+}
+
+msg_payload_t *fread_payload(su_home_t *home, FILE *f)
+{
+  msg_payload_t *pl;
+  int n;
+  char *buf;
+  off_t used, size;
+
+
+  if (f == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  pl = msg_payload_create(home, NULL, 0);
+
+  if (pl == NULL)
+    return NULL;
+
+  /* Read block by block */
+  used = 0;
+  size = 4096;
+  buf = malloc(size);
+
+  while (buf) {
+    n = fread(buf + used, 1, size - used, f);
+    used += n;
+    if (n < size - used) {
+      if (feof(f))
+	;
+      else if (ferror(f))
+	buf = NULL;
+      break;
+    }
+    buf = realloc(buf, size = 2 * size);
+  }
+  if (buf == NULL) {
+    perror("fread_payload: realloc");
+    return NULL;
+  }
+
+  if (used < size)
+    buf[used] = '\0';
+
+  pl->pl_common->h_data = pl->pl_data = buf;
+  pl->pl_common->h_len = pl->pl_len = used;
+
+  return pl;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nth" - HTTP Transactions Module
+ * 
+ * @section nth_meta Module Meta Information
+ *
+ * NTH provides interface to simple HTTP transaction engines for both HTTP
+ * servers and clients. The transaction interface for both client and server
+ * is available through <nth.h>, tags controlling the options in
+ * <nth_tag.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1268 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nth_client.c
+ * @brief HTTP Client implementhtion
+ * 
+ * Copyright (c) 2002 Nokia Research Center.  All rights reserved.
+ * 
+ * This source file has been divided into following sections:
+ * 1) engine
+ * 2) tport handling
+ * 3) client transactions
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sofia-sip/string0.h>
+
+/** @internal SU message argument structure type */
+#define SU_MSG_ARG_T   union sm_arg_u
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T struct nth_engine_s
+
+#define MSG_HDR_T union http_header_u
+#define MSG_PUB_T struct http_s
+
+#include "sofia-sip/nth.h"
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/auth_client.h>
+
+/* We are customer of tport_t */
+#define TP_STACK_T   nth_engine_t
+#define TP_MAGIC_T   void
+#define TP_CLIENT_T  nth_client_t
+
+#ifndef TPORT_H
+#include <sofia-sip/tport.h>
+#endif
+#include <sofia-sip/htable.h>
+
+#define HE_TIMER HE_TIMER
+enum { HE_TIMER = 1000 };
+
+/** @c http_flag telling that this message is internally generated. */
+#define NTH_INTERNAL_MSG (1<<16)
+
+HTABLE_DECLARE_WITH(hc_htable, hct, nth_client_t, uintptr_t, size_t);
+
+struct nth_engine_s {
+  su_home_t he_home[1];
+  su_root_t *he_root;
+  su_timer_t *he_timer;
+  int he_mflags;			/**< Message flags */
+  msg_mclass_t const *he_mclass;
+
+  tport_t *he_tports;
+
+  url_t *he_default_proxy;
+
+  unsigned he_now;
+  unsigned he_expires;
+
+  /* Attributes */
+  unsigned he_streaming:1;		/**< Enable streaming */
+  unsigned he_error_msg:1;
+  unsigned:0;
+
+  /* Statistics */
+  struct {
+    uint32_t st_requests;		/**< Sent requests */
+    uint32_t st_1xxresponses;		/**< Received 1XX responses */
+    uint32_t st_responses;		/**< Received responses */
+    uint32_t st_tp_errors;		/**< Transport errors */
+    uint32_t st_timeouts;		/**< Timeouts */
+    uint32_t st_bad;			/**< Bad responses*/
+  } he_stats[1];
+
+  /** Table for client transactions */
+  hc_htable_t he_clients[1];
+};
+
+struct nth_client_s {
+  nth_engine_t *hc_engine;
+  nth_response_f *hc_callback;
+  nth_client_magic_t *hc_magic;
+
+  http_method_t hc_method;
+  char const *hc_method_name;
+  url_t const *hc_url;			/**< Original RequestURI  */
+
+  unsigned hc_timeout;		        /**< Client timeout */
+  unsigned hc_expires;		        /**< Client expires */
+
+  /* Request state */
+  unsigned short hc_status;
+  unsigned hc_destroyed:1;
+  unsigned hc_completed:1;
+  unsigned hc_inserted:1;
+  unsigned hc_is_streaming:1;		/**< Currently streaming response */
+
+  /* Attributes */
+  unsigned hc_streaming:1;		/**< Enable streaming */
+  unsigned hc_error_msg:1;
+  unsigned /* pad */:0;				
+
+  url_string_t const *hc_route_url;
+  tp_name_t hc_tpn[1];			/**< Where to send requests */
+  tport_t *hc_tport;
+  int hc_pending;			/**< Request is pending in tport */
+  tagi_t *hc_tags;			/**< Transport tags */
+
+  auth_client_t **hc_auc;		/**< List of authenticators */
+
+  msg_t *hc_request;
+  msg_t *hc_response;
+};
+
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG   nth_client_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+
+/**@var NTH_DEBUG
+ *
+ * Environment variable determining the debug log level for @b nth
+ * module.
+ *
+ * The NTH_DEBUG environment variable is used to determine the debug
+ * logging level for @b nth module. The default level is 1.
+ *
+ * @sa <su_debug.h>, nth_client_log, #SOFIA_DEBUG
+ */
+extern char const NTH_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 1
+#endif
+
+/**Debug log for @b nth module.
+ *
+ * The nth_client_log is the log object used by @b nth client. The level of
+ * #nth_client_log is set using #NTH_DEBUG environment variable.
+ */
+su_log_t nth_client_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG) };
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nth";
+#endif
+
+/* ====================================================================== */
+/* Internal message passing */
+
+union sm_arg_u {
+  struct hc_recv_s {
+    nth_client_t *hc;
+    msg_t *msg;
+    http_t *http;
+  } hc_recv[1];
+};
+
+/* ====================================================================== */
+/* Internal prototypes */
+
+tagi_t nth_client_tags[] = {
+  {nthtag_mclass, 0},
+  {nthtag_message, 0},
+  {nthtag_mflags, 0},
+
+  {nthtag_proxy, 0},
+  {nthtag_error_msg, 0},
+  {nthtag_template, 0},
+  {nthtag_authentication, 0},
+
+  {TAG_NEXT(tport_tags)}
+};
+
+/* ====================================================================== */
+/* Internal prototypes */
+
+static int he_create_tports(nth_engine_t * he, tagi_t *tags);
+static int he_timer_init(nth_engine_t * he);
+static void he_timer(su_root_magic_t *, su_timer_t *, nth_engine_t * he);
+static void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now);
+static uint32_t he_now(nth_engine_t const *he);
+static void he_recv_message(nth_engine_t * he, tport_t * tport,
+			    msg_t *msg, void *arg, su_time_t now);
+static msg_t *he_msg_create(nth_engine_t * he, int flags,
+			    char const data[], usize_t dlen,
+			    tport_t const *tport, nth_client_t * hc);
+static void he_tp_error(nth_engine_t * he,
+			tport_t * tport, int errcode, char const *remote);
+static int hc_recv(nth_client_t * hc, msg_t *msg, http_t * http);
+
+HTABLE_PROTOS_WITH(hc_htable, hct, nth_client_t, uintptr_t, size_t);
+
+#define HTABLE_HASH_CLIENT(hc) ((uintptr_t)(hc)->hc_tport)
+HTABLE_BODIES_WITH(hc_htable, hct, nth_client_t, HTABLE_HASH_CLIENT,
+		   uintptr_t, size_t);
+
+static url_string_t const *hc_request_complete(nth_client_t * hc,
+					       msg_t *msg, http_t * http,
+					       http_method_t method,
+					       char const *name,
+					       url_string_t const *url,
+					       char const *version,
+					       url_t const *parent);
+static
+int hc_request_authenticate(nth_client_t * hc,
+			    msg_t *msg, http_t * http,
+			    url_string_t const *uri, auth_client_t **auc);
+static
+nth_client_t *hc_create(nth_engine_t * he,
+			nth_response_f * callback,
+			nth_client_magic_t * magic,
+			msg_t *msg, tag_type_t tag, tag_value_t value, ...);
+static int hc_resolve_and_send(nth_client_t * hc);
+static nth_client_t *hc_send(nth_client_t * hc);
+static void hc_insert(nth_engine_t * he, nth_client_t * hc);
+static void hc_free(nth_client_t * hc);
+static void hc_tport_error(nth_engine_t *, nth_client_t * hc,
+			   tport_t * tp, msg_t *msg, int error);
+static int hc_reply(nth_client_t * hc, int status, char const *phrase);
+static int hc_default_cb(nth_client_magic_t * magic,
+			 nth_client_t * request, http_t const *http);
+
+/* ---------------------------------------------------------------------- */
+
+char const *nth_engine_version(void)
+{
+  return "sofia-http-client/" NTH_CLIENT_VERSION;
+}
+
+/* ---------------------------------------------------------------------- */
+
+nth_engine_t *nth_engine_create(su_root_t *root,
+				tag_type_t tag, tag_value_t value, ...)
+{
+  nth_engine_t *he;
+  ta_list ta;
+
+  if ((he = su_home_new(sizeof(*he)))) {
+    he->he_root = root;
+    he->he_mflags = MSG_DO_CANONIC;
+    he->he_mclass = http_default_mclass();
+    he->he_expires = 32000;
+
+    ta_start(ta, tag, value);
+
+    if (hc_htable_resize(he->he_home, he->he_clients, 0) < 0 ||
+	he_create_tports(he, ta_args(ta)) < 0 ||
+	he_timer_init(he) < 0 || nth_engine_set_params(he, ta_tags(ta)) < 0) {
+      nth_engine_destroy(he), he = NULL;
+    }
+
+    ta_end(ta);
+  }
+
+  return he;
+}
+
+void nth_engine_destroy(nth_engine_t * he)
+{
+  if (he) {
+    size_t i;
+    hc_htable_t *hct = he->he_clients;
+
+    for (i = 0; i < hct->hct_size; i++)
+      hc_free(hct->hct_table[i]);
+
+    tport_destroy(he->he_tports);
+
+    su_timer_destroy(he->he_timer), he->he_timer = NULL;
+
+    su_home_unref(he->he_home);
+  }
+}
+
+int nth_engine_set_params(nth_engine_t * he,
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+  unsigned expires;
+  int error_msg;
+  msg_mclass_t const *mclass;
+  int mflags;
+  int streaming;
+  url_string_t const *proxy;
+
+  if (he == NULL)
+    return (errno = EINVAL), -1;
+
+  ta_start(ta, tag, value);
+
+  expires = he->he_expires;
+  error_msg = he->he_error_msg;
+  mclass = he->he_mclass;
+  mflags = he->he_mflags;
+  streaming = he->he_streaming;
+  proxy = (void *) he->he_default_proxy;
+
+  n = tl_gets(ta_args(ta),
+	      NTHTAG_EXPIRES_REF(expires),
+	      NTHTAG_ERROR_MSG_REF(error_msg),
+	      NTHTAG_MCLASS_REF(mclass),
+	      NTHTAG_MFLAGS_REF(mflags),
+	      NTHTAG_STREAMING_REF(streaming),
+	      NTHTAG_PROXY_REF(proxy), TAG_END());
+
+  if (n > 0) {
+    if (proxy->us_url != he->he_default_proxy) {
+      url_t *copy = url_hdup(he->he_home, proxy->us_url);
+
+      if (proxy && !copy) {
+	n = -1;
+      } else {
+	su_free(he->he_home, (void *) he->he_default_proxy);
+	he->he_default_proxy = copy;
+      }
+    }
+  }
+
+  if (n > 0) {
+    he->he_expires = expires;
+    he->he_error_msg = error_msg != 0;
+    if (mclass)
+      he->he_mclass = mclass;
+    else
+      he->he_mclass = http_default_mclass();
+    he->he_mflags = mflags;
+    he->he_streaming = streaming != 0;
+  }
+
+  ta_end(ta);
+
+  return n;
+}
+
+int nth_engine_get_params(nth_engine_t const *he,
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+  msg_mclass_t const *mclass;
+
+  if (he == NULL)
+    return (errno = EINVAL), -1;
+
+  if (he->he_mclass != http_default_mclass())
+    mclass = he->he_mclass;
+  else
+    mclass = NULL;
+
+  ta_start(ta, tag, value);
+
+  n = tl_tgets(ta_args(ta),
+	       NTHTAG_ERROR_MSG(he->he_error_msg),
+	       NTHTAG_MCLASS(mclass),
+	       NTHTAG_MFLAGS(he->he_mflags),
+	       NTHTAG_EXPIRES(he->he_expires),
+	       NTHTAG_STREAMING(he->he_streaming),
+	       NTHTAG_PROXY((url_string_t *) he->he_default_proxy),
+	       TAG_END());
+
+  ta_end(ta);
+
+  return n;
+}
+
+int nth_engine_get_stats(nth_engine_t const *he,
+			 tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+
+  if (he == NULL)
+    return (errno = EINVAL), -1;
+
+  ta_start(ta, tag, value);
+
+  n = tl_tgets(ta_args(ta), TAG_END());
+
+  ta_end(ta);
+
+  return n;
+}
+
+static tp_name_t he_name[1] = { {"*", "*", "*", "*"} };
+
+static char const *const he_tports[] = {
+  "tcp", "tls", NULL
+};
+
+static tp_stack_class_t http_client_class[1] = { {
+						  sizeof(http_client_class),
+						  he_recv_message,
+						  he_tp_error,
+						  he_msg_create}
+};
+
+/** Create transports for client engine */
+static
+int he_create_tports(nth_engine_t * he, tagi_t *tags)
+{
+  he->he_tports = tport_tcreate(he, http_client_class, he->he_root, TAG_END());
+
+  if (!he->he_tports)
+    return -1;
+
+  return tport_tbind(he->he_tports, he_name, he_tports,
+		     TPTAG_SERVER(0), TAG_NEXT(tags));
+}
+
+/** Initialize engine timer. */
+static
+int he_timer_init(nth_engine_t * he)
+{
+  he->he_timer = su_timer_create(su_root_task(he->he_root), HE_TIMER);
+  return su_timer_set(he->he_timer, he_timer, he);
+}
+
+/**
+ * Engine timer routine.
+ */
+static
+void he_timer(su_root_magic_t *rm, su_timer_t *timer, nth_engine_t * he)
+{
+  unsigned i;
+  uint32_t now;
+  hc_htable_t *hct = he->he_clients;
+
+  now = su_time_ms(su_now());
+  now += now == 0;
+  he->he_now = now;
+
+  if (hct)
+    for (i = hct->hct_size; i > 0;)
+      if (hct->hct_table[--i])
+	hc_timer(he, hct->hct_table[i], now);
+
+  su_timer_set(timer, he_timer, he);
+
+  he->he_now = 0;
+}
+
+/** Get current timestamp in milliseconds */
+static
+uint32_t he_now(nth_engine_t const *he)
+{
+  if (he->he_now)
+    return he->he_now;
+  else
+    return su_time_ms(su_now());
+}
+
+static
+void he_recv_message(nth_engine_t * he,
+		     tport_t * tport, msg_t *msg, void *arg, su_time_t now)
+{
+  nth_client_t *hc, **hcp;
+  tp_name_t const *tpn;
+
+  for (hcp = hc_htable_hash(he->he_clients, (hash_value_t)(uintptr_t) tport);
+       (hc = *hcp); hcp = hc_htable_next(he->he_clients, hcp)) {
+    if (hc->hc_tport == tport) {
+      if (hc_recv(hc, msg, http_object(msg)) < 0)
+	msg_destroy(msg);
+      return;
+    }
+  }
+
+  /* Extra response? Framing error? */
+
+  tpn = tport_name(tport);
+
+  if (msg_size(msg))
+    SU_DEBUG_3(("nth client: received extra data ("MOD_ZU" bytes) "
+		"from %s/%s:%s\n",
+		(size_t)msg_size(msg), 
+		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));
+  else
+    SU_DEBUG_3(("nth client: received extra data from %s/%s:%s\n",
+		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));
+
+  msg_destroy(msg);
+  tport_shutdown(tport, 2);
+}
+
+/** Report error from transport */
+static void he_tp_error(nth_engine_t * he,
+			tport_t * tport, int errcode, char const *remote)
+{
+  su_log("\nth: tport: %s%s%s\n",
+	 remote ? remote : "", remote ? ": " : "", su_strerror(errcode));
+}
+
+/** Create a new message. */
+msg_t *nth_engine_msg_create(nth_engine_t * he, int flags)
+{
+  if (he == NULL) {
+    errno = EINVAL;
+    return NULL;
+
+  }
+
+  flags |= he->he_mflags;
+
+  if (he->he_streaming)
+    flags |= MSG_FLG_STREAMING;
+  else
+    flags &= ~MSG_FLG_STREAMING;
+
+  return msg_create(he->he_mclass, flags);
+}
+
+
+/** Create a new message for transport */
+static
+msg_t *he_msg_create(nth_engine_t * he, int flags,
+		     char const data[], usize_t dlen,
+		     tport_t const *tport, nth_client_t * hc)
+{
+
+  flags |= he->he_mflags;
+
+  if (he->he_streaming)
+    flags |= MSG_FLG_STREAMING;
+  else
+    flags &= ~MSG_FLG_STREAMING;
+
+  if (hc == NULL) {
+    nth_client_t **slot;
+    for (slot = hc_htable_hash(he->he_clients, (hash_value_t)(uintptr_t) tport);
+	 (hc = *slot); slot = hc_htable_next(he->he_clients, slot))
+      if (hc->hc_tport == tport)
+	break;
+  }
+
+  if (hc) {
+    if (hc->hc_method == http_method_head) {
+      flags &= ~MSG_FLG_STREAMING;
+      flags |= HTTP_FLG_NO_BODY;
+    }
+  }
+
+  return msg_create(he->he_mclass, flags);
+}
+
+/** Get destination name from Host header and request URI. */
+static
+int tpn_by_host(tp_name_t * tpn, http_host_t const *h, url_t const *url)
+{
+  if (!h || !url)
+    return -1;
+
+  tpn->tpn_proto = url_tport_default(url->url_type);
+  tpn->tpn_canon = h->h_host;
+  tpn->tpn_host = h->h_host;
+  if (h->h_port)
+    tpn->tpn_port = h->h_port;
+  else
+    tpn->tpn_port = url_port_default(url->url_type);
+
+  return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+nth_client_t *nth_client_tcreate(nth_engine_t * engine,
+				 nth_response_f * callback,
+				 nth_client_magic_t * magic,
+				 http_method_t method, char const *name,
+				 url_string_t const *uri,
+				 tag_type_t tag, tag_value_t value, ...)
+{
+  nth_client_t *hc = NULL;
+  ta_list ta;
+
+  if (engine) {
+    void *none = &none;
+    msg_t *msg = none;
+    http_t *http;
+    char const *version = http_version_1_1;
+    nth_client_t const *template = NULL;
+    auth_client_t **auc = none;
+    unsigned expires = engine->he_expires;
+    int ok = 0;
+
+    ta_start(ta, tag, value);
+
+    tl_gets(ta_args(ta),
+	    NTHTAG_TEMPLATE_REF(template),
+	    NTHTAG_AUTHENTICATION_REF(auc),
+	    NTHTAG_MESSAGE_REF(msg),
+	    NTHTAG_EXPIRES_REF(expires),
+	    HTTPTAG_VERSION_REF(version), 
+	    TAG_END());
+
+    if (msg == none) {
+      if (template && template->hc_request)
+	msg = msg_copy(template->hc_request);
+      else
+	msg = msg_create(engine->he_mclass, engine->he_mflags);
+    }
+    http = http_object(msg);
+
+    if (template) {
+      if (callback == NULL)
+	callback = template->hc_callback;
+      if (magic == NULL)
+	magic = template->hc_magic;
+      if (name == NULL)
+	method = template->hc_method, name = template->hc_method_name;
+      if (uri == NULL)
+	uri = (url_string_t *) template->hc_url;
+
+      if (auc == none)
+	auc = template->hc_auc;
+    } else if (auc == none) {
+      auc = NULL;
+    }
+
+    hc = hc_create(engine, callback, magic, msg, ta_tags(ta));
+
+    if (hc)
+      hc->hc_expires = expires;
+
+    if (hc == NULL)
+      ;
+    else if (http_add_tl(msg, http, ta_tags(ta)) < 0)
+      ;
+    else if (!(uri = hc_request_complete(hc, msg, http,
+					 method, name, uri, version,
+					 nth_client_url(template))))
+      ;
+    else if (auc && hc_request_authenticate(hc, msg, http, uri, auc) <= 0)
+      ;
+    else if (hc_resolve_and_send(hc) < 0)
+      ;
+    else
+      ok = 1;
+
+    if (!ok) {
+      if (hc)
+	hc_free(hc);
+      else
+	msg_destroy(msg);
+      hc = NULL;
+    }
+
+    ta_end(ta);
+  }
+
+  return hc;
+}
+
+static
+url_string_t const *hc_request_complete(nth_client_t * hc,
+					msg_t *msg, http_t * http,
+					http_method_t method,
+					char const *name,
+					url_string_t const *uri,
+					char const *version,
+					url_t const *parent)
+{
+  su_home_t *home = msg_home(msg);
+  http_host_t *host = http->http_host;
+  void *tbf = NULL;
+  url_t const *url;
+  url_t u[1];
+
+  if (uri == NULL && http->http_request)
+    uri = (url_string_t *) http->http_request->rq_url;
+
+  if (uri == NULL)
+    uri = (url_string_t *) parent;
+
+  url = url_string_p(uri) ? (tbf = url_hdup(NULL, uri->us_url)) : uri->us_url;
+
+  if (!url)
+    return NULL;
+
+  *u = *url;
+
+  if (u->url_type == url_unknown && u->url_path && !u->url_host) {
+    if (parent) {
+      *u = *parent;
+      u->url_path = url->url_path;	/* XXX - relative URLs! */
+      u->url_params = url->url_params;
+      u->url_headers = url->url_headers;	/* Query */
+    }
+  }
+
+  if (!hc->hc_route_url && u->url_type != url_http
+      && u->url_type != url_https)
+    hc->hc_route_url = (url_string_t *) u;
+
+  if (host &&
+      (host_cmp(host->h_host, u->url_host) ||
+       str0cmp(host->h_port, u->url_port)))
+    host = NULL;
+
+  if (host == NULL && u->url_host) {
+    host = http_host_create(home, u->url_host, u->url_port);
+    msg_header_insert(msg, http, (http_header_t *) host);
+  }
+
+  if (u->url_host || hc->hc_route_url || host)
+    hc->hc_url = url_hdup(home, u);
+
+  if (hc->hc_route_url == (url_string_t *) u)
+    hc->hc_route_url = (url_string_t *) hc->hc_url;
+
+  if (hc->hc_url) {
+    http_request_t *rq = http->http_request;
+
+    if (rq && !method && !name)
+      method = rq->rq_method, name = rq->rq_method_name;
+    else if (rq && method && method != rq->rq_method)
+      rq = NULL;
+    else if (rq && name && strcmp(name, rq->rq_method_name))
+      rq = NULL;
+
+    if (rq && version && strcasecmp(version, rq->rq_version))
+      rq = NULL;
+
+    if (!hc->hc_route_url) {
+      u->url_type = url_unknown, u->url_scheme = NULL;
+      u->url_user = NULL, u->url_password = NULL;
+      u->url_host = NULL, u->url_port = NULL;
+      u->url_root = '/';
+      if (!u->url_path)
+	u->url_path = "";
+      u->url_fragment = NULL;
+    }
+
+    if (rq && http_url_cmp(u, rq->rq_url))
+      rq = NULL;
+
+    if (!rq) {
+      if (http->http_request)
+	msg_header_remove(msg, http, (msg_header_t *) http->http_request);
+
+      http->http_request =
+	http_request_create(home, method, name, (url_string_t *) u, version);
+
+      if (!http->http_request)
+	uri = NULL;
+    }
+  } else {
+    uri = NULL;
+  }
+
+  if (http_message_complete(msg, http) < 0)
+    uri = NULL;
+
+  if (tbf)
+    su_free(NULL, tbf);
+
+  if (uri) {
+    hc->hc_method = http->http_request->rq_method;
+    hc->hc_method_name = http->http_request->rq_method_name;
+  }
+
+  return uri;
+}
+
+static
+int hc_request_authenticate(nth_client_t * hc,
+			    msg_t *msg,
+			    http_t * http,
+			    url_string_t const *uri, auth_client_t **auc)
+{
+  return auc_authorization(auc, msg, http,
+			   http->http_request->rq_method_name,
+			   uri->us_url, http->http_payload);
+}
+
+static
+nth_client_t *hc_create(nth_engine_t * he,
+			nth_response_f * callback,
+			nth_client_magic_t * magic,
+			msg_t *msg, tag_type_t tag, tag_value_t value, ...)
+{
+  nth_client_t *hc;
+  su_home_t *home = msg_home(msg);
+
+  if (!(hc = su_zalloc(he->he_home, sizeof(*hc))))
+    return NULL;
+
+  if (!callback)
+    callback = hc_default_cb;
+
+  {
+    int error_msg = he->he_error_msg;
+    int streaming = he->he_streaming;
+    url_string_t const *route_url = NULL;
+
+    ta_list ta;
+    ta_start(ta, tag, value);
+
+    route_url = (url_string_t *) he->he_default_proxy;
+
+    tl_gets(ta_args(ta),
+	    NTHTAG_PROXY_REF(route_url),
+	    NTHTAG_ERROR_MSG_REF(error_msg),
+	    NTHTAG_STREAMING_REF(streaming), TAG_END());
+
+    hc->hc_engine = he;
+    hc->hc_callback = callback;
+    hc->hc_magic = magic;
+    hc->hc_tags = tl_afilter(home, tport_tags, ta_args(ta));
+    hc->hc_error_msg = error_msg;
+    hc->hc_streaming = streaming;
+    hc->hc_route_url = route_url;
+
+    ta_end(ta);
+  }
+
+  hc->hc_request = msg;
+
+  return hc;
+}
+
+
+static
+int hc_resolve_and_send(nth_client_t * hc)
+{
+  msg_t *msg = hc->hc_request;
+  http_t *http = http_object(msg);
+  su_home_t *home = msg_home(msg);
+  int resolved = -1;
+
+  if (hc->hc_route_url) {
+    resolved = tport_name_by_url(home, hc->hc_tpn, hc->hc_route_url);
+  } else {
+    resolved = tpn_by_host(hc->hc_tpn, http->http_host, hc->hc_url);
+  }
+
+  if (resolved < 0) {
+    SU_DEBUG_3(("nth client resolve: %s\n", "cannot resolve URL"));
+    return -1;
+  }
+
+  hc->hc_route_url = NULL;
+
+  hc->hc_tport = tport_by_name(hc->hc_engine->he_tports, hc->hc_tpn);
+
+  if (!hc->hc_tport) {
+    assert(hc->hc_tport);
+    SU_DEBUG_3(("nth client create: %s\n",
+		!hc->hc_tport ? "no transport" : "invalid message"));
+    return -1;
+  }
+
+  if (msg_serialize(msg, http) < 0) {
+    assert(hc->hc_tport);
+    SU_DEBUG_3(("nth client create: invalid message"));
+    return -1;
+  }
+
+  hc_send(hc);
+
+  hc_insert(hc->hc_engine, hc);
+
+  return 0;
+}
+
+/**@internal
+ * Insert client request to the hash table
+ */
+static
+void hc_insert(nth_engine_t * he, nth_client_t * hc)
+{
+  if (hc_htable_is_full(he->he_clients))
+    hc_htable_resize(he->he_home, he->he_clients, 0);
+  hc_htable_insert(he->he_clients, hc);
+  hc->hc_inserted = 1;
+}
+
+/**@internal
+ * Remove client request from the hash table
+ */
+static
+void hc_remove(nth_engine_t * he, nth_client_t * hc)
+{
+  if (hc->hc_inserted)
+    hc_htable_remove(he->he_clients, hc);
+  hc->hc_inserted = 0;
+}
+
+/** Destroy client request. */
+void nth_client_destroy(nth_client_t * hc)
+{
+  if (hc == NULL)
+    ;
+  else if (hc->hc_completed)
+    hc_free(hc);
+  else
+    hc->hc_callback = hc_default_cb;
+}
+
+/**@internal Free client request. */
+void hc_free(nth_client_t * hc)
+{
+  if (hc) {
+    if (hc->hc_pending)
+      tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
+		    0);
+    tport_decref(&hc->hc_tport);
+    msg_destroy(hc->hc_request);
+    msg_destroy(hc->hc_response);
+    su_free(hc->hc_engine->he_home, hc);
+  }
+}
+
+/**
+ * Gets client status.
+ *
+ * @param hc pointer to a nth client object
+ *
+ * @return
+ * Returns the status code from the response message if it has been
+ * received. A status code below 100 indicates that no response has been
+ * received. If request timeouts, the connection is closed and the status
+ * code is set to 408. If @a hc is NULL, returns 400 (Bad Request).
+ */
+int nth_client_status(nth_client_t const *hc)
+{
+  return hc ? hc->hc_status : 400;
+}
+
+/**
+ * Gets client method.
+ *
+ * @param hc pointer to a nth client object
+ *
+ * @return
+ * Returns the HTTP method from the request.
+ * If @a hc is NULL, returns #http_method_invalid.
+ */
+http_method_t nth_client_method(nth_client_t const *hc)
+{
+  return hc ? hc->hc_method : http_method_invalid;
+}
+
+/** Get original Request-URI */
+url_t const *nth_client_url(nth_client_t const *hc)
+{
+  return hc ? hc->hc_url : NULL;
+}
+
+/** Get request message. */
+msg_t *nth_client_request(nth_client_t * hc)
+{
+  msg_t *request = NULL;
+
+  if (hc)
+    request = hc->hc_request, hc->hc_request = NULL;
+
+  return request;
+}
+
+/** Get response message. */
+msg_t *nth_client_response(nth_client_t const *hc)
+{
+  if (hc)
+    return msg_ref_create(hc->hc_response);
+  else
+    return NULL;
+}
+
+/** Is client streaming response? */
+int nth_client_is_streaming(nth_client_t const *hc)
+{
+  return hc && hc->hc_is_streaming;
+}
+
+/** Send request. */
+static nth_client_t *hc_send(nth_client_t * hc)
+{
+  nth_engine_t *he = hc->hc_engine;
+  tport_t *tp;
+
+  he->he_stats->st_requests++;
+
+  tp = tport_tsend(hc->hc_tport, hc->hc_request, hc->hc_tpn,
+		   TAG_NEXT(hc->hc_tags));
+
+  if (tp == NULL) {
+    he->he_stats->st_tp_errors++;
+    hc_reply(hc, HTTP_503_NO_SERVICE);
+    return hc;
+  }
+
+  hc->hc_tport = tport_incref(tp);
+
+  hc->hc_pending = tport_pend(tp, hc->hc_request, hc_tport_error, hc);
+  if (hc->hc_pending == -1)
+    hc->hc_pending = 0;
+
+  if (hc->hc_expires) {
+    hc->hc_timeout = he_now(he) + hc->hc_expires;	/* XXX */
+    if (hc->hc_timeout == 0)
+      hc->hc_timeout++;
+  }
+
+  return hc;
+}
+
+/** @internal Report transport errors. */
+void hc_tport_error(nth_engine_t * he, nth_client_t * hc,
+		    tport_t * tp, msg_t *msg, int error)
+{
+  su_sockaddr_t const *su = msg_addr(msg);
+  tp_name_t const *tpn = tp ? tport_name(tp) : hc->hc_tpn;
+  char addr[SU_ADDRSIZE];
+  char const *errmsg;
+
+  if (error)
+    errmsg = su_strerror(error);
+  else
+    errmsg = "Remote end closed connection";
+  su_log("nth: %s: %s (%u) with %s@%s:%u\n",
+	 hc->hc_method_name,
+	 errmsg, error,
+	 tpn->tpn_proto,
+	 inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+	 htons(su->su_port));
+
+  he->he_stats->st_tp_errors++;
+  hc_reply(hc, HTTP_503_NO_SERVICE);
+}
+
+static
+void hc_delayed_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u);
+
+/** Respond internally to a transaction. */
+int hc_reply(nth_client_t * hc, int status, char const *phrase)
+{
+  nth_engine_t *he = hc->hc_engine;
+  msg_t *msg = NULL;
+  http_t *http = NULL;
+
+  assert(status >= 400);
+
+  SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", hc, status, phrase));
+
+  if (hc->hc_pending) {
+    tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
+		  status < 200);
+    if (status >= 200)
+      hc->hc_pending = 0;
+  }
+
+  tport_shutdown(hc->hc_tport, 2);
+
+  hc->hc_completed = 1;
+  hc->hc_timeout = 0;
+
+  if (hc->hc_callback == hc_default_cb) {
+    hc_free(hc);
+    return 0;
+  }
+
+  /* Create response message, if needed */
+  if (hc->hc_error_msg) {
+    msg = he_msg_create(he, NTH_INTERNAL_MSG, NULL, 0, NULL, hc);
+    http = http_object(msg);
+    http_complete_response(msg, status, phrase, http_object(hc->hc_request));
+  } else
+    hc->hc_status = status;
+
+  if (hc->hc_inserted) {
+    hc_recv(hc, msg, http);
+    return 0;
+  } else {
+    /*
+     * The thread creating outgoing transaction must return to application
+     * before transaction callback can be invoked. Processing an internally
+     * generated response message must be delayed until transaction creation
+     * is completed.
+     *
+     * The internally generated message is transmitted using su_msg_send()
+     * and it is delivered back to NTA when the application next time
+     * executes the su_root_t event loop.
+     */
+    su_root_t *root = he->he_root;
+    su_msg_r su_msg = SU_MSG_R_INIT;
+
+    if (su_msg_create(su_msg,
+		      su_root_task(root),
+		      su_root_task(root),
+		      hc_delayed_recv,
+		      sizeof(struct hc_recv_s)) == SU_SUCCESS) {
+      struct hc_recv_s *a = su_msg_data(su_msg)->hc_recv;
+
+      a->hc = hc;
+      a->msg = msg;
+      a->http = http;
+
+      if (su_msg_send(su_msg) == SU_SUCCESS)
+	return 0;
+    }
+  }
+
+  if (msg)
+    msg_destroy(msg);
+
+  return -1;
+}
+
+static
+void hc_delayed_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u)
+{
+  struct hc_recv_s *a = u->hc_recv;
+
+  if (hc_recv(a->hc, a->msg, a->http) < 0 && a->msg)
+    msg_destroy(a->msg);
+}
+
+/** Receive response to transaction. */
+int hc_recv(nth_client_t * hc, msg_t *msg, http_t * http)
+{
+  short status;
+  int streaming = msg_is_streaming(msg);
+  int shutdown = 0;
+
+  if (http && http->http_status) {
+    status = http->http_status->st_status;
+    if (status < 100)
+      status = 100;
+
+    if (streaming && !hc->hc_streaming) {
+      /* Disable streaming for this msg */
+      msg_set_streaming(msg, 0);
+
+      return 0;			/* Wait for complete message */
+    }
+
+    hc->hc_status = status;
+  } else if (http)
+    status = hc->hc_status = 500, streaming = 0, http = NULL;
+  else
+    status = hc->hc_status, streaming = 0;
+
+  if (status == 400 || (http && (http->http_flags & MSG_FLG_ERROR)))
+    shutdown = 2;
+
+  if (!streaming || shutdown)
+    msg_set_streaming(msg, 0);
+
+  if (hc->hc_pending) {
+    tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, msg, hc,
+		  streaming || status < 200);
+    if (!streaming && status >= 200)
+      hc->hc_pending = 0;
+  }
+
+  if (!streaming && status >= 200) {
+    /* Completed. */
+    hc->hc_completed = 1;
+    hc_remove(hc->hc_engine, hc);
+
+    if (shutdown ||
+	!http ||
+	(http->http_status->st_version == http_version_1_1 &&
+	 http->http_connection &&
+	 msg_params_find(http->http_connection->k_items, "close")) ||
+	(http->http_status->st_version == http_version_1_0))
+      shutdown = 2;
+  }
+
+  if (shutdown) {
+    if (status < 200)
+      status = 400;
+    tport_shutdown(hc->hc_tport, shutdown);
+  }
+
+  if (msg_is_complete(msg)) {
+    if (status < 200)
+      hc->hc_engine->he_stats->st_1xxresponses++;
+    else
+      hc->hc_engine->he_stats->st_responses++;
+  }
+
+  if (hc->hc_response)
+    msg_destroy(hc->hc_response);
+  hc->hc_response = msg;
+  hc->hc_is_streaming = streaming;
+
+  /* Call callback */
+  hc->hc_callback(hc->hc_magic, hc, http);
+
+  return 0;
+}
+
+/** @internal Default callback for request */
+int hc_default_cb(nth_client_magic_t * magic,
+		  nth_client_t * hc, http_t const *http)
+{
+  if (http == NULL || http->http_status->st_status >= 200)
+    hc_free(hc);
+  return 0;
+}
+
+/** @internal Client transaction timer routine. */
+static
+void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now)
+{
+  if (hc->hc_timeout == 0)
+    return;
+
+  if ((int)hc->hc_timeout - (int)now > 0)
+    return;
+
+  hc_reply(hc, HTTP_408_TIMEOUT);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1328 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nth_server.c
+ * @brief HTTP server.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Sat Oct 19 01:37:36 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/hostdomain.h>
+
+#if !defined(EALREADY) && defined(_WIN32)
+#define EALREADY WSAEALREADY
+#endif
+
+typedef struct server_s server_t;
+
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T server_t
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+#include <sofia-sip/http_tag.h>
+
+#include "sofia-sip/nth.h"
+
+#include <sofia-sip/msg_date.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/hostdomain.h>
+
+/* We are customer of tport_t */
+#define TP_STACK_T   server_t
+#define TP_MAGIC_T   void
+                                     
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+
+#include <sofia-sip/auth_module.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+enum { SERVER_TICK = 1000 };
+
+#define SERVER_VERSION "nth/" NTH_VERSION
+
+HTABLE_DECLARE(hc_htable, hct, nth_client_t);
+
+struct server_s 
+{
+  su_home_t          srv_home[1];
+  su_root_t         *srv_root;
+
+  su_timer_t        *srv_timer;
+  unsigned           srv_now;
+
+  msg_mclass_t const*srv_mclass;
+  int                srv_mflags;	/**< Message flags */
+
+  tport_t           *srv_tports;
+  unsigned           srv_queuesize;	/**< Maximum number of queued responses */
+
+  size_t             srv_max_bodylen;	/**< Maximum accepted length */
+
+  unsigned           srv_persistent:1;	/**< Allow persistent connections */
+
+  /** Sites */
+  nth_site_t        *srv_sites;
+
+  /* Statistics */
+  struct {
+    uint32_t           st_requests;     /**< Received requests */
+    uint32_t           st_responses;    /**< Sent responses */
+    uint32_t           st_bad;		/**< Bad requests */
+  }                  srv_stats[1];
+
+  http_server_t     *srv_server;      /**< Server header */
+};
+
+struct nth_site_s 
+{
+  nth_site_t          *site_next, **site_prev;
+
+  nth_site_t          *site_kids;
+
+  server_t            *site_server;
+  auth_mod_t          *site_auth;
+
+  url_t               *site_url;
+  char const          *site_path;
+  size_t               site_path_len;
+
+  nth_request_f       *site_callback;
+  nth_site_magic_t    *site_magic;
+
+  su_time_t            site_access; /**< Last request served */
+
+  /** Host header must match with server name */
+  unsigned             site_strict : 1;
+  /** Site can have kids */
+  unsigned             site_isdir : 1;
+  /** Site does not have domain name */
+  unsigned             site_wildcard : 1;
+};
+
+struct nth_request_s
+{
+  server_t              *req_server;
+
+  http_method_t        	req_method;
+  char const           *req_method_name;
+  url_t const          *req_url;         /**< RequestURI  */
+  char const           *req_version;
+  
+  tport_t              *req_tport;
+  msg_t		       *req_request;
+  msg_t                *req_response;
+
+  auth_status_t        *req_as;
+
+  unsigned short      	req_status;
+  unsigned              req_close : 1; /**< Client asked for close */
+  unsigned              req_in_callback : 1;
+  unsigned              req_destroyed : 1;
+};
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG   nth_server_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+
+/**Environment variable determining the debug log level for @b nth
+ * module.
+ *
+ * The NTH_DEBUG environment variable is used to determine the debug
+ * logging level for @b nth module. The default level is 1.
+ * 
+ * @sa <su_debug.h>, nth_server_log, SOFIA_DEBUG
+ */
+extern char const NTH_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 1
+#endif
+
+/**Debug log for @b nth module. 
+ * 
+ * The nth_server_log is the log object used by @b nth module. The level of
+ * #nth_server_log is set using #NTH_DEBUG environment variable.
+ */
+su_log_t nth_server_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG) };
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nth";
+#endif
+
+/* ====================================================================== */
+/** Server side
+ */
+static server_t *server_create(url_t const *url,
+			       tag_type_t tag, tag_value_t value, ...);
+void server_destroy(server_t *srv);
+static inline int server_timer_init(server_t *srv);
+static void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv);
+static inline uint32_t server_now(server_t const *srv);
+static void server_request(server_t *srv, tport_t *tport, msg_t *msg,
+				    void *arg, su_time_t now);
+static nth_site_t **site_get_host(nth_site_t **, char const *host, char const *port);
+static nth_site_t **site_get_rslot(nth_site_t *parent, char *path,
+				   char **return_rest);
+static nth_site_t *site_get_subdir(nth_site_t *parent, char const *path, char const **res);
+static void server_tport_error(server_t *srv, tport_t *tport,
+			       int errcode, char const *remote);
+static msg_t *server_msg_create(server_t *srv, int flags, 
+				char const data[], usize_t dlen,
+				tport_t const *tp, tp_client_t *tpc);
+
+static void server_reply(server_t *srv, tport_t *tport, 
+			 msg_t *request, msg_t *response,
+			 int status, char const *phrase);
+
+static
+void nth_site_request(server_t *srv,
+		      nth_site_t *site,
+		      tport_t *tport,
+		      msg_t *request,
+		      http_t *http,
+		      char const *path,
+		      msg_t *response);
+
+/* ----------------------------------------------------------------------
+ * 5) Site functions
+ */
+
+/** Create a http site object. 
+ *
+ * The function nth_site_create() allocates and initializes a web site
+ * object. A web site object can be either 
+ * - a primary http server (@a parent is NULL),
+ * - a virtual http server (@a address contains hostpart), or 
+ * - a site within a server 
+ *   (@a address does not have hostpart, only path part).
+ *
+ * @param parent pointer to parent site
+ *               (NULL when creating a primary server object)
+ * @param callback pointer to callback function called when
+ *                 a request is received
+ * @param magic    application context included in callback parameters
+ * @param address  absolute or relative URI specifying the address of
+ *                 site
+ * @param tag, value, ... list of tagged parameters
+ *
+ * @TAGS
+ * If the @a parent is NULL, the list of tagged parameters must contain
+ * NTHTAG_ROOT() used to create the server engine. Tags supported when @a
+ * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(),
+ * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to
+ * tport_tcreate() and tport_tbind(), too.
+ *
+ * @since Support for multiple sites was added to @VERSION_1_12_4
+ */
+nth_site_t *nth_site_create(nth_site_t *parent,  
+			    nth_request_f *callback,
+			    nth_site_magic_t *magic,
+			    url_string_t const *address,
+			    tag_type_t tag, tag_value_t value,
+			    ...)
+{
+  nth_site_t *site = NULL, **prev = NULL;
+  su_home_t home[SU_HOME_AUTO_SIZE(256)];
+  url_t *url, url0[1];
+  server_t *srv = NULL;
+  ta_list ta;
+  char *path = NULL;
+  size_t usize;
+  int is_host, is_path, wildcard = 0;
+
+  su_home_auto(home, sizeof home);
+
+  if (parent && url_is_string(address)) {
+    char const *s = (char const *)address;
+    size_t sep = strcspn(s, "/:");
+
+    if (parent->site_path) {
+      /* subpath */
+      url_init(url0, parent->site_url->url_type);
+      url0->url_path = s;
+      address = (url_string_t*)url0;
+    }
+    else if (s[sep] == ':')
+      /* absolute URL with scheme */;
+    else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) {
+      /* looks like a domain name */;
+      url_init(url0, parent->site_url->url_type);
+      url0->url_host = s;
+      address = (url_string_t*)url0;
+    }
+    else {
+      /* looks like a path */
+      url_init(url0, parent->site_url->url_type);
+      url0->url_path = s;
+      address = (url_string_t*)url0;
+    }
+  }
+
+  url = url_hdup(home, address->us_url);
+
+  if (!url || !callback)
+    return NULL;
+  
+  is_host = url->url_host != NULL;
+  is_path = url->url_path != NULL;
+
+  if (is_host && is_path) {
+    SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n"));
+    errno = EINVAL;
+    goto error;
+  }
+
+  if (!parent && !is_host) {
+    SU_DEBUG_3(("nth_site_create(): host is required\n"));
+    errno = EINVAL;
+    goto error;
+  }
+
+  if (parent) {
+    if (!parent->site_isdir) {
+      SU_DEBUG_3(("nth_site_create(): invalid parent resource \n"));
+      errno = EINVAL;
+      goto error;
+    }
+      
+    srv = parent->site_server; assert(srv);
+    if (is_host) {
+      prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port);
+
+      if (prev == NULL) {
+	SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n",
+		    url->url_host, url->url_port ? url->url_port : ""));
+	errno = EEXIST;
+	goto error;
+      }
+    } 
+    else {
+      size_t i, j;
+
+      path = (char *)url->url_path;
+      while (path[0] == '/')
+	path++;
+
+      /* Remove duplicate // */
+      for (i = j = 0; path[i];) {
+	while (path[i] == '/' && path[i + 1] == '/')
+	  i++;
+	path[j++] = path[i++];
+      }
+      path[j] = path[i];
+
+      url = url0, *url = *parent->site_url;
+
+      if (url->url_path) {
+	url->url_path = su_strcat(home, url->url_path, path);
+	if (!url->url_path)
+	  goto error;
+	path = (char *)url->url_path + strlen(parent->site_url->url_path);
+      }
+      else
+	url->url_path = path;
+
+      prev = site_get_rslot(parent, path, &path);
+
+      if (!prev || path[0] == '\0') {
+	SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n", 
+		    url->url_path));
+	errno = EEXIST;
+	goto error;
+      }
+    }
+  }
+
+  if (!parent) {
+    if (strcmp(url->url_host, "*") == 0 ||
+	host_cmp(url->url_host, "0.0.0.0") == 0 ||
+	host_cmp(url->url_host, "::") == 0)
+      wildcard = 1, url->url_host = "*";
+  }
+
+  usize = sizeof(*url) + url_xtra(url);
+
+  ta_start(ta, tag, value);
+
+  if (!parent) {
+    srv = server_create(url, ta_tags(ta));
+    prev = &srv->srv_sites;
+  }
+
+  if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) {
+    site->site_url = (url_t *)(site + 1);
+    url_dup((void *)(site->site_url + 1), usize - sizeof(*url), 
+	    site->site_url, url);
+
+    assert(prev);
+    if ((site->site_next = *prev))
+      site->site_next->site_prev = &site->site_next;
+    *prev = site, site->site_prev = prev;
+    site->site_server = srv;
+
+    if (path) {
+      size_t path_len;
+
+      site->site_path = site->site_url->url_path + (path - url->url_path);
+      path_len = strlen(site->site_path); assert(path_len > 0);
+      if (path_len > 0 && site->site_path[path_len - 1] == '/')
+	path_len--, site->site_isdir = 1;
+      site->site_path_len = path_len;
+    }
+    else {
+      site->site_isdir = is_host;
+      site->site_path = "";
+      site->site_path_len = 0;
+    }
+
+    site->site_wildcard = wildcard;
+    site->site_callback = callback;
+    site->site_magic = magic;
+    
+    if (parent)
+      site->site_auth = parent->site_auth;
+
+    nth_site_set_params(site, ta_tags(ta));
+  }
+
+  ta_end(ta);
+
+ error:
+  su_home_deinit(home);
+  return site;
+}
+
+void nth_site_destroy(nth_site_t *site)
+{
+  if (site == NULL)
+    return;
+
+  if (site->site_auth)
+    auth_mod_unref(site->site_auth), site->site_auth = NULL;
+
+  if (site->site_server->srv_sites == site) {
+    server_destroy(site->site_server);
+  }
+}
+
+
+nth_site_magic_t *nth_site_magic(nth_site_t const *site)
+{
+  return site ? site->site_magic : NULL;
+}
+
+
+void nth_site_bind(nth_site_t *site, 
+		   nth_request_f *callback, 
+		   nth_site_magic_t *magic)
+{
+  if (site) {
+    site->site_callback = callback;
+    site->site_magic = magic;
+  }
+}
+
+
+/** Get the site URL. @NEW_1_12_4. */
+url_t const *nth_site_url(nth_site_t const *site)
+{
+  return site ? site->site_url : NULL;
+}
+
+/** Return server name and version */
+char const *nth_site_server_version(void)
+{
+  return "nth/" NTH_VERSION;
+}
+
+/** Get the time last time served. @NEW_1_12_4. */
+su_time_t nth_site_access_time(nth_site_t const *site)
+{
+  su_time_t const never = { 0, 0 };
+
+  return site ? site->site_access : never;
+}
+
+int nth_site_set_params(nth_site_t *site,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+
+  server_t *server;
+  int master;
+  msg_mclass_t const *mclass;
+  int mflags;
+  auth_mod_t *am;
+
+  if (site == NULL)
+    return (errno = EINVAL), -1;
+
+  server = site->site_server;
+  master = site == server->srv_sites;
+  am = site->site_auth;
+
+  mclass = server->srv_mclass;
+  mflags = server->srv_mflags;
+
+  ta_start(ta, tag, value);
+
+  n = tl_gets(ta_args(ta),
+	      TAG_IF(master, NTHTAG_MCLASS_REF(mclass)),
+	      TAG_IF(master, NTHTAG_MFLAGS_REF(mflags)),
+	      NTHTAG_AUTH_MODULE_REF(am),
+	      TAG_END());
+  
+  if (n > 0) {
+    if (mclass)
+      server->srv_mclass = mclass;
+    else
+      server->srv_mclass = http_default_mclass();
+    server->srv_mflags = mflags;
+    auth_mod_ref(am), auth_mod_unref(site->site_auth), site->site_auth = am;
+  }
+
+  ta_end(ta);
+
+  return n;
+}
+
+int nth_site_get_params(nth_site_t const *site,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+  server_t *server;
+  int master;
+  msg_mclass_t const *mclass;
+
+  if (site == NULL)
+    return (errno = EINVAL), -1;
+
+  server = site->site_server;
+  master = site == server->srv_sites;
+
+  if (master && server->srv_mclass != http_default_mclass())
+    mclass = server->srv_mclass;
+  else
+    mclass = NULL;
+
+  ta_start(ta, tag, value);
+
+  n = tl_tgets(ta_args(ta),
+	       TAG_IF(master, NTHTAG_MCLASS(mclass)),
+	       TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags)),
+	       TAG_END());
+  
+  ta_end(ta);
+
+  return n;
+}
+
+int nth_site_get_stats(nth_site_t const *site, 
+		       tag_type_t tag, tag_value_t value, ...)
+{
+  int n;
+  ta_list ta;
+
+  if (site == NULL)
+    return (errno = EINVAL), -1;
+
+  ta_start(ta, tag, value);
+
+  n = tl_tgets(ta_args(ta),
+	       TAG_END());
+  
+  ta_end(ta);
+
+  return n;
+}
+
+static
+nth_site_t **site_get_host(nth_site_t **list, char const *host, char const *port)
+{
+  nth_site_t *site;
+
+  assert(host);
+
+  for (; (site = *list); list = &site->site_next) {
+    if (host_cmp(host, site->site_url->url_host) == 0 &&
+	str0cmp(port, site->site_url->url_port) == 0) {
+      break;
+    }
+  }
+
+  return list;
+}
+
+/** Find a place to insert site from the hierarchy.
+ *
+ * A resource can be either a 'dir' (name ends with '/') or 'file'.
+ * When a resource
+ */
+static
+nth_site_t **site_get_rslot(nth_site_t *parent, char *path, 
+			    char **return_rest)
+{
+  nth_site_t *site, **prev;
+  size_t len;
+  int cmp;
+
+  assert(path);
+
+  if (path[0] == '\0')
+    return errno = EEXIST, NULL;
+
+  for (prev = &parent->site_kids; (site = *prev); prev = &site->site_next) {
+    cmp = strncmp(path, site->site_path, len = site->site_path_len);
+    if (cmp > 0)
+      break;
+    if (cmp < 0)
+      continue;
+    if (path[len] == '\0') {
+      if (site->site_isdir)
+	return *return_rest = path, prev; 
+      return errno = EEXIST, NULL;
+    }
+    if (path[len] != '/' || site->site_path[len] != '/')
+      continue;
+
+    while (path[++len] == '/')
+      ;
+
+    return site_get_rslot(site, path + len, return_rest);
+  }
+
+  *return_rest = path;
+
+  return prev;
+}
+
+static char const site_nodir_match[] = "";
+
+/** Find a subdir from site hierarchy */
+static
+nth_site_t *site_get_subdir(nth_site_t *parent,
+			    char const *path,
+			    char const **return_rest)
+{
+  nth_site_t *site;
+  size_t len;
+  int cmp;
+
+  assert(path);
+
+  while (path[0] == '/')	/* Skip multiple slashes */
+    path++;
+
+  if (path[0] == '\0')
+    return *return_rest = path, parent;
+  
+  for (site = parent->site_kids; site; site = site->site_next) {
+    cmp = strncmp(path, site->site_path, len = site->site_path_len);
+    if (cmp > 0)
+      break;
+    if (cmp < 0)
+      continue;
+    if (path[len] == '\0')
+      return *return_rest = site_nodir_match, site;
+    if (site->site_path[len] == '/' && path[len] == '/')
+      return site_get_subdir(site, path + len + 1, return_rest);
+  }
+
+  return *return_rest = path, parent;
+}
+
+
+/* ----------------------------------------------------------------------
+ * Server functions
+ */
+
+static char const * const http_tports[] =
+  {
+    "tcp", "tls", NULL
+  };
+
+static tp_stack_class_t nth_server_class[1] =
+  {{
+    sizeof(nth_server_class),
+    server_request,
+    server_tport_error,
+    server_msg_create
+  }};
+
+server_t *server_create(url_t const *url,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  server_t *srv;
+  msg_mclass_t *mclass = NULL;
+  tp_name_t tpn[1] = {{ NULL }};
+  su_root_t *root = NULL;
+  http_server_t const *server = NULL;
+  int persistent = 0;
+  char const *server_str = SERVER_VERSION;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+  tl_gets(ta_args(ta), 
+	  NTHTAG_ROOT_REF(root),
+	  NTHTAG_MCLASS_REF(mclass),
+	  TPTAG_REUSE_REF(persistent),
+	  HTTPTAG_SERVER_REF(server),
+	  HTTPTAG_SERVER_STR_REF(server_str),
+	  TAG_END());
+
+  if (!root || !url || 
+      (url->url_type != url_http && url->url_type != url_https)
+      || !(srv = su_home_new(sizeof(*srv)))) {
+    ta_end(ta);
+    return NULL;
+  }
+
+  tpn->tpn_proto = url_tport_default(url->url_type);
+  tpn->tpn_canon = url->url_host;
+  tpn->tpn_host =  url->url_host;
+  tpn->tpn_port = url_port(url);
+
+  srv->srv_tports = tport_tcreate(srv, nth_server_class, root, 
+				  TPTAG_IDLE(600000),
+				  TPTAG_TIMEOUT(300000),
+				  ta_tags(ta));
+
+  srv->srv_persistent = persistent;
+  srv->srv_max_bodylen = 1 << 30; /* 1 GB */
+
+  if (tport_tbind(srv->srv_tports, tpn, http_tports,
+		  TAG_END()) >= 0) {
+    srv->srv_root = root;
+    srv->srv_mclass = mclass ? mclass : http_default_mclass();
+    srv->srv_mflags = MSG_DO_CANONIC;
+
+    if (server)
+      srv->srv_server = http_server_dup(srv->srv_home, server);
+    else
+      srv->srv_server = http_server_make(srv->srv_home, server_str);
+
+    tport_get_params(srv->srv_tports,
+		     TPTAG_QUEUESIZE_REF(srv->srv_queuesize),
+		     TAG_END());
+  }
+  else {
+    SU_DEBUG_1(("nth_server_create: cannot bind transports " 
+		URL_FORMAT_STRING "\n",
+		URL_PRINT_ARGS(url))); 
+    server_destroy(srv), srv = NULL;
+  }
+
+  ta_end(ta);
+
+  return srv;
+}
+
+void server_destroy(server_t *srv)
+{
+  tport_destroy(srv->srv_tports);
+  su_timer_destroy(srv->srv_timer);
+  su_home_unref(srv->srv_home);
+}
+
+/** Initialize server timer. */
+static inline
+int server_timer_init(server_t *srv)
+{
+  if (0) {
+    srv->srv_timer = su_timer_create(su_root_task(srv->srv_root), SERVER_TICK);
+    return su_timer_set(srv->srv_timer, server_timer, srv);
+  }
+  return 0;
+}
+
+/**
+ * Server timer routine.
+ */
+static
+void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv)
+{
+  uint32_t now;
+
+  su_timer_set(timer, server_timer, srv);
+
+  now = su_time_ms(su_now()); now += now == 0; srv->srv_now = now;
+
+  /* Xyzzy */
+
+  srv->srv_now = 0;
+}
+
+/** Get current timestamp in milliseconds */
+static inline
+uint32_t server_now(server_t const *srv)
+{
+  if (srv->srv_now)
+    return srv->srv_now;
+  else
+    return su_time_ms(su_now());
+}
+
+/** Process incoming request message */
+static
+void server_request(server_t *srv,
+		    tport_t *tport,
+		    msg_t *request,
+		    void *arg,
+		    su_time_t now)
+{
+  nth_site_t *site = NULL, *subsite = NULL;
+  msg_t *response;
+  http_t *http = http_object(request);
+  http_host_t *h;
+  char const *host, *port, *path, *subpath = NULL;
+
+  /* Disable streaming */
+  if (msg_is_streaming(request)) {
+    msg_set_streaming(request, 0);
+    return;
+  }
+
+  /* Create a response message */
+  response = server_msg_create(srv, 0, NULL, 0, NULL, NULL);
+  tport_tqueue(tport, response, TAG_END());
+
+  if (http && http->http_flags & MSG_FLG_TIMEOUT) {
+    server_reply(srv, tport, request, response, 400, "Request timeout");
+    return;
+  } else if (http && http->http_flags & MSG_FLG_TOOLARGE) {
+    server_reply(srv, tport, request, response, HTTP_413_ENTITY_TOO_LARGE);
+    return;
+  } else if (!http || !http->http_request || 
+	     (http->http_flags & MSG_FLG_ERROR)) {
+    server_reply(srv, tport, request, response, HTTP_400_BAD_REQUEST);
+    return;
+  }
+
+  if (http->http_request->rq_version != http_version_1_0 &&
+      http->http_request->rq_version != http_version_1_1) {
+    server_reply(srv, tport, request, response, HTTP_505_HTTP_VERSION);
+    return;
+  }
+
+  h = http->http_host;
+
+  if (h) {
+    host = h->h_host, port = h->h_port;
+  }
+  else if (http->http_request->rq_url->url_host) {
+    host = http->http_request->rq_url->url_host;
+    port = http->http_request->rq_url->url_port;
+  }
+  else
+    host = NULL, port = NULL;
+
+  path = http->http_request->rq_url->url_path;
+
+  if (host)
+    site = *site_get_host(&srv->srv_sites, host, port);
+
+  if (site == NULL && !srv->srv_sites->site_strict)
+    site = srv->srv_sites;
+
+  if (path == NULL)
+    path = "";
+
+  if (path[0])
+    subsite = site_get_subdir(site, path, &subpath);
+
+  if (subsite)
+    subsite->site_access = now;
+  else
+    site->site_access = now;
+
+  if (subsite && subsite->site_isdir && subpath == site_nodir_match) {
+    /* Answer with 301 */
+    http_location_t loc[1];
+    http_location_init(loc);
+
+    *loc->loc_url = *site->site_url;
+
+    if (site->site_wildcard) {
+      if (http->http_host) {
+	loc->loc_url->url_host = http->http_host->h_host;
+	loc->loc_url->url_port = http->http_host->h_port;
+      }
+      else {
+	tp_name_t const *tpn = tport_name(tport); assert(tpn);
+	loc->loc_url->url_host = tpn->tpn_canon;
+	if (strcmp(url_port_default(loc->loc_url->url_type), tpn->tpn_port))
+	  loc->loc_url->url_port = tpn->tpn_port;
+      }
+    }
+
+    loc->loc_url->url_root = 1;
+    loc->loc_url->url_path = subsite->site_url->url_path;
+
+    msg_header_add_dup(response, NULL, (msg_header_t *)loc);
+
+    server_reply(srv, tport, request, response, HTTP_301_MOVED_PERMANENTLY);
+  }
+  else if (subsite)
+    nth_site_request(srv, subsite, tport, request, http, subpath, response);
+  else if (site)
+    nth_site_request(srv, site, tport, request, http, path, response);
+  else
+    /* Answer with 404 */
+    server_reply(srv, tport, request, response, HTTP_404_NOT_FOUND);
+}
+
+static void server_tport_error(server_t *srv,
+				   tport_t *tport,
+				   int errcode,
+				   char const *remote)
+{
+  su_log("\nth: tport: %s%s%s\n",
+	 remote ? remote : "", remote ? ": " : "",
+	 su_strerror(errcode));
+}
+
+/** Respond without creating a request structure */
+static void server_reply(server_t *srv, tport_t *tport, 
+			 msg_t *request, msg_t *response,
+			 int status, char const *phrase)
+{
+  http_t *http;
+  http_payload_t *pl;
+  int close;
+  http_status_t st[1];
+  char const *req_version = NULL;
+
+  if (status < 200 || status >= 600)
+    status = 500, phrase = http_500_internal_server;
+
+  http = http_object(request);
+  
+  if (http && http->http_request)
+    req_version = http->http_request->rq_version;
+
+  close = status >= 200 && 
+    (!srv->srv_persistent
+     || status == 400
+     || (http && http->http_request && 
+	 http->http_request->rq_version != http_version_1_1)
+     || (http && http->http_connection && 
+	 msg_params_find(http->http_connection->k_items, "close")));
+
+  msg_destroy(request);
+
+  http = http_object(response);
+
+  pl = http_payload_format(msg_home(response), 
+			   "<html>\n"
+			   "<head><title>%u %s</title></head>\n"
+			   "<body><h2>%u %s</h2></body>\n"
+			   "</html>\n", status, phrase, status, phrase);
+
+  msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl);
+
+  if (req_version != http_version_0_9) {
+    http_status_init(st);
+    st->st_version = http_version_1_1;
+    st->st_status = status;
+    st->st_phrase = phrase;
+    
+    http_add_tl(response, http,
+		HTTPTAG_STATUS(st),
+		HTTPTAG_SERVER(srv->srv_server),
+		HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		HTTPTAG_SEPARATOR_STR("\r\n"),
+		TAG_IF(close, HTTPTAG_CONNECTION_STR("close")),
+		TAG_END());
+
+    msg_serialize(response, (msg_pub_t *)http);
+  } else {
+    /* Just send the response */
+    *msg_chain_head(response) = (msg_header_t *)pl;
+    close = 1;
+  }
+
+  if (tport_tqsend(tport, response, NULL, 
+		   TPTAG_CLOSE_AFTER(close), 
+		   TAG_END()) == -1) {
+    SU_DEBUG_3(("server_reply(): cannot queue response\n"));
+    tport_shutdown(tport, 2);
+  }
+
+  msg_destroy(response);
+}
+
+/** Create a new message for transport */
+static
+msg_t *server_msg_create(server_t *srv, int flags, 
+			 char const data[], usize_t dlen,
+			 tport_t const *tp, tp_client_t *tpc)
+{
+  msg_t *msg = msg_create(srv->srv_mclass, srv->srv_mflags | flags);
+
+  return msg;
+}
+
+/* ----------------------------------------------------------------------
+ * 6) Server transactions 
+ */
+
+struct auth_info
+{
+  nth_site_t *site;
+  nth_request_t *req;
+  http_t const *http;
+  char const *path;
+};
+
+static void nth_authentication_result(void *ai0, auth_status_t *as);
+
+static
+void nth_site_request(server_t *srv,
+		      nth_site_t *site,
+		      tport_t *tport,
+		      msg_t *request,
+		      http_t *http,
+		      char const *path,
+		      msg_t *response)
+{
+  auth_mod_t *am = site->site_auth;
+  nth_request_t *req;
+  auth_status_t *as;
+  struct auth_info *ai;
+  size_t size = (am ? (sizeof *as) + (sizeof *ai) : 0) + (sizeof *req);
+  int status;
+
+  req = su_zalloc(srv->srv_home, size);
+  
+  if (req == NULL) {
+    server_reply(srv, tport, request, response, HTTP_500_INTERNAL_SERVER);
+    return;
+  }
+  
+  if (am)
+    as = auth_status_init(req + 1, sizeof *as), ai = (void *)(as + 1);
+  else
+    as = NULL, ai = NULL;
+
+  req->req_server = srv;
+  req->req_method = http->http_request->rq_method;
+  req->req_method_name = http->http_request->rq_method_name;
+  req->req_url = http->http_request->rq_url;
+  req->req_version = http->http_request->rq_version;
+
+  req->req_tport = tport_incref(tport);
+  req->req_request = request;
+  req->req_response = response;
+
+  req->req_status = 100;
+  req->req_close = 
+    !srv->srv_persistent
+    || http->http_request->rq_version != http_version_1_1
+    || (http->http_connection && 
+	msg_params_find(http->http_connection->k_items, "close"));
+
+  if (am) {
+    static auth_challenger_t const http_server_challenger[] = 
+      {{ HTTP_401_UNAUTHORIZED, http_www_authenticate_class }};
+
+    req->req_as = as;
+
+    as->as_method = http->http_request->rq_method_name;
+    as->as_uri = path;
+    
+    if (http->http_payload) {
+      as->as_body = http->http_payload->pl_data;
+      as->as_bodylen = http->http_payload->pl_len;
+    }
+
+    auth_mod_check_client(am, as, 
+			  http->http_authorization,
+			  http_server_challenger);
+
+    if (as->as_status == 100) {
+      /* Stall transport - do not read more requests */
+      if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
+	tport_stall(tport);
+
+      as->as_callback = nth_authentication_result;
+      as->as_magic = ai;
+      ai->site = site;
+      ai->req = req;
+      ai->http = http;
+      ai->path = path;
+      return;
+    }
+    else if (as->as_status) {
+      assert(as->as_status >= 200);
+      nth_request_treply(req, as->as_status, as->as_phrase,
+			 HTTPTAG_HEADER((http_header_t *)as->as_response),
+			 HTTPTAG_HEADER((http_header_t *)as->as_info),
+			 TAG_END());
+      nth_request_destroy(req);
+      return;
+    }
+  }
+
+  req->req_in_callback = 1;
+  status = site->site_callback(site->site_magic, site, req, http, path);
+  req->req_in_callback = 0;
+
+  if (status != 0 && (status < 100 || status >= 600))
+    status = 500;
+
+  if (status != 0 && req->req_status < 200) {
+    nth_request_treply(req, status, NULL, TAG_END());
+  }
+
+  if (req->req_status < 100) {
+    /* Stall transport - do not read more requests */
+    if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
+      tport_stall(tport);
+  }
+
+  if (status >= 200 || req->req_destroyed)
+    nth_request_destroy(req);
+}
+
+static void nth_authentication_result(void *ai0, auth_status_t *as)
+{
+  struct auth_info *ai = ai0;
+  nth_request_t *req = ai->req;
+  int status;
+
+  if (as->as_status != 0) {
+    assert(as->as_status >= 300);
+    nth_request_treply(req, status = as->as_status, as->as_phrase, 
+		       HTTPTAG_HEADER((http_header_t *)as->as_response), 
+		       TAG_END());
+  }
+  else {
+    req->req_in_callback = 1;
+    status = ai->site->site_callback(ai->site->site_magic, 
+				     ai->site,
+				     ai->req,
+				     ai->http,
+				     ai->path);
+    req->req_in_callback = 0;
+
+    if (status != 0 && (status < 100 || status >= 600))
+      status = 500;
+
+    if (status != 0 && req->req_status < 200) {
+      nth_request_treply(req, status, NULL, TAG_END());
+    }
+  }
+
+  if (status >= 200 || req->req_destroyed)
+    nth_request_destroy(req);
+}
+
+void nth_request_destroy(nth_request_t *req)
+{
+  if (req == NULL)
+    return;
+
+  if (req->req_status < 200)
+    nth_request_treply(req, HTTP_500_INTERNAL_SERVER, TAG_END());
+
+  req->req_destroyed = 1;
+
+  if (req->req_in_callback) 
+    return;
+
+  if (req->req_as)
+    su_home_deinit(req->req_as->as_home);
+
+  tport_decref(&req->req_tport), req->req_tport = NULL;
+  msg_destroy(req->req_request), req->req_request = NULL;
+  msg_destroy(req->req_response), req->req_response = NULL;
+  su_free(req->req_server->srv_home, req);
+}
+
+/** Return request authentication status.
+ *
+ * @param req pointer to HTTP request object
+ * 
+ * @retval Status code
+ *
+ * @since New in @VERSION_1_12_4
+ */
+int nth_request_status(nth_request_t const *req)
+{
+  return req ? req->req_status : 400;
+}
+
+/** Return request authentication status.
+ *
+ * @param req pointer to HTTP request object
+ * 
+ * @retval Pointer to authentication status struct
+ *
+ * @note The authentication status struct is freed when the #nth_request_t
+ * object is destroyed.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa AUTH
+ */
+auth_status_t *nth_request_auth(nth_request_t const *req)
+{
+  return req ? req->req_as : NULL;
+}
+
+http_method_t nth_request_method(nth_request_t const *req)
+{
+  return req ? req->req_method : http_method_invalid;
+}
+
+msg_t *nth_request_message(nth_request_t *req)
+{
+  msg_t *retval = NULL;
+
+  if (req)
+    retval = msg_ref_create(req->req_request);
+
+  return retval;
+}
+
+int nth_request_treply(nth_request_t *req, 
+		       int status, char const *phrase, 
+		       tag_type_t tag, tag_value_t value, ...)
+{
+  msg_t *response, *next = NULL;
+  http_t *http;
+  int retval = -1;
+  int req_close, close;
+  ta_list ta;
+  http_header_t const *as_info = NULL;
+
+  if (req == NULL || status < 100 || status >= 600) {
+    return -1;
+  }
+
+  response = req->req_response;
+  http = http_object(response);
+
+  if (status >= 200 && req->req_as)
+    as_info = (http_header_t const *)req->req_as->as_info;
+
+  ta_start(ta, tag, value);
+
+  http_add_tl(response, http,
+	      HTTPTAG_SERVER(req->req_server->srv_server),
+	      HTTPTAG_HEADER(as_info), 
+	      ta_tags(ta));
+
+  if (http->http_payload && !http->http_content_length) {
+    http_content_length_t *l;
+    http_payload_t *pl;
+    size_t len = 0;
+    
+    for (pl = http->http_payload; pl; pl = pl->pl_next)
+      len += pl->pl_len;
+
+    if (len > UINT32_MAX)
+      goto fail;
+
+    l = http_content_length_create(msg_home(response), (uint32_t)len);
+
+    msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)l);
+  }
+
+  if (req->req_method == http_method_head && http->http_payload) {
+    http_payload_t *pl;
+    
+    for (pl = http->http_payload; pl; pl = pl->pl_next)
+      msg_header_remove(response, (msg_pub_t *)http, (msg_header_t *)pl);
+  }
+
+  http_complete_response(response, status, phrase, 
+			 http_object(req->req_request));
+
+  if (!http->http_date) {
+    http_date_t date[1];
+    http_date_init(date)->d_time = msg_now();
+    msg_header_add_dup(response, (msg_pub_t *)http, (msg_header_t*)date);
+  }
+
+  if (status < 200) {
+    close = 0;
+    next = server_msg_create(req->req_server, 0, NULL, 0, NULL, NULL);
+  }
+  else {
+    req_close = req->req_close;
+
+    close = (http->http_connection && 
+	     msg_params_find(http->http_connection->k_items, "close"));
+    
+    if (req_close && !close && status >= 200) {
+      close = 1;
+      http_add_tl(response, http, HTTPTAG_CONNECTION_STR("close"), TAG_END());
+    }
+  }
+
+  msg_serialize(response, (msg_pub_t *)http);
+
+  retval = tport_tqsend(req->req_tport, response, next, 
+			TAG_IF(close, TPTAG_CLOSE_AFTER(1)),
+			ta_tags(ta));
+
+ fail:
+  ta_end(ta);
+  
+  if (retval == 0)
+    req->req_status = status;
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nth_tag.c
+ * @brief Tags for HTTP Transaction API
+ *
+ * @note This file is used to automatically generate 
+ * nth_tag_ref.c and nth_tag_dll.c
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nth"
+
+#include "sofia-sip/nth_tag.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/http_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+#include <sofia-sip/http_protos.h>
+
+tag_typedef_t nthtag_any = NSTAG_TYPEDEF(*);
+
+/* Common */
+tag_typedef_t nthtag_mclass = PTRTAG_TYPEDEF(mclass);
+tag_typedef_t nthtag_message = PTRTAG_TYPEDEF(message);
+tag_typedef_t nthtag_mflags = INTTAG_TYPEDEF(mflags);
+tag_typedef_t nthtag_streaming = BOOLTAG_TYPEDEF(streaming);
+
+/* Client */
+tag_typedef_t nthtag_proxy = URLTAG_TYPEDEF(proxy);
+tag_typedef_t nthtag_expires = UINTTAG_TYPEDEF(expires);
+tag_typedef_t nthtag_error_msg = BOOLTAG_TYPEDEF(error_msg);
+tag_typedef_t nthtag_template = PTRTAG_TYPEDEF(template);
+tag_typedef_t nthtag_authentication = PTRTAG_TYPEDEF(authentication);
+
+/* Server */
+tag_typedef_t nthtag_root = PTRTAG_TYPEDEF(root);
+tag_typedef_t nthtag_strict_host = BOOLTAG_TYPEDEF(scrict_host);
+
+/**@def NTHTAG_AUTH_MODULE()
+ *
+ * Pointer to authentication module.
+ *
+ * A site requires authentication from the clients if passed an
+ * authentication module pointer with NTHTAG_AUTH_MODULE(). Incoming client
+ * request is challenged with 401, upon successful authentication the
+ * authenticated username is stored in the #auth_status_t structure
+ * associated with the #nth_request_t object. It is up to application to
+ * authorize the user.
+ *
+ * @sa nth_site_create(), nth_site_set_params(), nth_request_auth().
+ */
+tag_typedef_t nthtag_auth_module = PTRTAG_TYPEDEF(auth_module);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,202 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/nth.h
+ * @brief Transaction API for HTTP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Jun  5 19:25:18 2002 ppessi
+ */
+
+/* ----------------------------------------------------------------------
+ * 1) Types 
+ */
+
+#ifndef NTH_H_TYPES 
+#define NTH_H_TYPES
+
+/** NTH engine */
+typedef struct nth_engine_s   nth_engine_t;
+/** NTH client request */
+typedef struct nth_client_s   nth_client_t;
+
+/** NTH (virtual) hosts or site(s) */
+typedef struct nth_site_s   nth_site_t;
+/** Server transaction  */
+typedef struct nth_request_s nth_request_t;
+
+#ifndef NTH_CLIENT_MAGIC_T
+/** Default type of application context for client NTH requests.
+ * Application may define this to appropriate type before including
+ * <nth.h>. */
+#define NTH_CLIENT_MAGIC_T struct nth_client_magic_s
+#endif
+
+/** Application context for client requests */
+typedef NTH_CLIENT_MAGIC_T  nth_client_magic_t;
+
+#ifndef NTH_SITE_MAGIC_T
+/** Default type of application context for NTH servers.
+ * Application may define this to appropriate type before including
+ * <nth.h>. */
+#define NTH_SITE_MAGIC_T struct nth_site_magic_s
+#endif
+
+/** Application context for NTH servers */
+typedef NTH_SITE_MAGIC_T   nth_site_magic_t;
+
+#endif
+
+#ifndef NTH_H
+/** Defined when <sofia-sip/nth.h> has been included. */
+#define NTH_H
+
+/* ----------------------------------------------------------------------
+ * 2) Constants 
+ */
+
+/** Version number */
+#define NTH_VERSION "1.0"
+
+#define NTH_CLIENT_VERSION NTH_VERSION
+#define NTH_SERVER_VERSION NTH_VERSION
+
+/* ----------------------------------------------------------------------
+ * 3) Other include files
+ */
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_status.h>
+
+#ifndef NTH_TAG_H
+#include <sofia-sip/nth_tag.h>
+#endif
+
+/* ----------------------------------------------------------------------
+ * 3) Engine prototypes
+ */
+
+SOFIA_BEGIN_DECLS
+
+NTH_DLL char const *nth_engine_version(void);
+
+NTH_DLL nth_engine_t *nth_engine_create(su_root_t *root,
+					tag_type_t tag, tag_value_t value, ...);
+NTH_DLL void nth_engine_destroy(nth_engine_t *engine);
+
+NTH_DLL int nth_engine_set_params(nth_engine_t *engine, 
+				  tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_engine_get_params(nth_engine_t const *engine, 
+				  tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_engine_get_stats(nth_engine_t const *engine, 
+				 tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL msg_t *nth_engine_msg_create(nth_engine_t *he, int flags);
+
+/* ----------------------------------------------------------------------
+ * 4) Prototypes for client transactions
+ */
+typedef int nth_response_f(nth_client_magic_t *magic,
+			   nth_client_t *request,
+			   http_t const *http);
+
+NTH_DLL nth_client_t *nth_client_tcreate(nth_engine_t *engine,
+					 nth_response_f *callback,
+					 nth_client_magic_t *magic,
+					 http_method_t method,
+					 char const *method_name,
+					 url_string_t const *request_uri,
+					 tag_type_t tag, tag_value_t value,
+					 ...);
+
+NTH_DLL int nth_client_status(nth_client_t const *clnt);
+NTH_DLL http_method_t nth_client_method(nth_client_t const *cnlt);
+NTH_DLL int nth_client_is_streaming(nth_client_t const *hc);
+
+NTH_DLL url_t const *nth_client_url(nth_client_t const *clnt);
+
+NTH_DLL msg_t *nth_client_request(nth_client_t *clnt);
+NTH_DLL msg_t *nth_client_response(nth_client_t const *clnt);
+NTH_DLL void nth_client_destroy(nth_client_t *clnt);
+
+/* ----------------------------------------------------------------------
+ * 5) Server side prototypes
+ */
+
+typedef int nth_request_f(nth_site_magic_t *lmagic, 
+			  nth_site_t *server,
+			  nth_request_t *req, 
+			  http_t const *http,
+			  char const *path);
+
+char const *nth_site_server_version(void);
+
+NTH_DLL nth_site_t *nth_site_create(nth_site_t *parent,  
+				    nth_request_f *req_callback,
+				    nth_site_magic_t *magic,
+				    url_string_t const *address,
+				    tag_type_t tag, tag_value_t value,
+				    ...);
+
+NTH_DLL void nth_site_destroy(nth_site_t *site);
+
+NTH_DLL nth_site_magic_t *nth_site_magic(nth_site_t const *site);
+
+NTH_DLL void nth_site_bind(nth_site_t *site, 
+			   nth_request_f *callback, 
+			   nth_site_magic_t *);
+
+NTH_DLL su_time_t nth_site_access_time(nth_site_t const *site);
+
+NTH_DLL int nth_site_set_params(nth_site_t *site, 
+				tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_site_get_params(nth_site_t const *site,
+				tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_site_get_stats(nth_site_t const *site,
+			       tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL url_t const *nth_site_url(nth_site_t const *site);
+
+/* ----------------------------------------------------------------------
+ * 6) Prototypes for server transactions 
+ */
+
+NTH_DLL int nth_request_status(nth_request_t const *req);
+NTH_DLL http_method_t nth_request_method(nth_request_t const *req);
+NTH_DLL msg_t *nth_request_message(nth_request_t *req);
+
+NTH_DLL int nth_request_treply(nth_request_t *ireq, 
+			       int status, char const *phrase, 
+			       tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL void nth_request_destroy(nth_request_t *req);
+
+NTH_DLL struct auth_status_t *nth_request_auth(nth_request_t const *req);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTH_TAG_H
+/** Defined when <sofia-sip/nth_tag.h> has been included. */
+#define NTH_TAG_H
+
+/**@file sofia-sip/nth_tag.h
+ * @brief Tags for @b nth, HTTP engine module.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Sun Oct 13 22:23:48 2002 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+#ifndef HTTP_TAG_H
+#include <sofia-sip/http_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all nth tags */
+NTH_DLL extern tagi_t nth_client_tags[];
+
+/** Filter tag matching any nth tag. */
+#define NTHTAG_ANY()         nthtag_any, ((tag_value_t)0)
+NTH_DLL extern tag_typedef_t nthtag_any;
+
+/* Common tags */
+
+NTH_DLL extern tag_typedef_t nthtag_mclass;
+/** Pointer to a mclass, message factory object. @HI */
+#define NTHTAG_MCLASS(x) nthtag_mclass, tag_cptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_mclass_ref;
+#define NTHTAG_MCLASS_REF(x) nthtag_mclass_ref, tag_cptr_vr(&(x), (x))
+
+NTH_DLL extern tag_typedef_t nthtag_mflags;
+/** Message flags used by nth_engine_msg_create()/nth_site_msg(). @HI */
+#define NTHTAG_MFLAGS(x) nthtag_mflags, tag_int_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_mflags_ref;
+#define NTHTAG_MFLAGS_REF(x) nthtag_mflags_ref, tag_int_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_streaming;
+/** Enable streaming. @HI */
+#define NTHTAG_STREAMING(x) nthtag_streaming, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_streaming_ref;
+#define NTHTAG_STREAMING_REF(x) nthtag_streaming_ref, tag_bool_vr(&(x))
+
+/* Client-only tags */
+
+NTH_DLL extern tag_typedef_t nthtag_proxy;
+/** URL for (default) proxy. @HI */
+#define NTHTAG_PROXY(x) nthtag_proxy, urltag_url_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_proxy_ref;
+#define NTHTAG_PROXY_REF(x) nthtag_proxy_ref, urltag_url_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_expires;
+/** Expires in milliseconds for client transactions. @HI */
+#define NTHTAG_EXPIRES(x) nthtag_expires, tag_uint_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_expires_ref;
+#define NTHTAG_EXPIRES_REF(x) nthtag_expires_ref, tag_uint_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_error_msg;
+/** If true, nth engine generates complete error messages. @HI */
+#define NTHTAG_ERROR_MSG(x) nthtag_error_msg, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_error_msg_ref;
+#define NTHTAG_ERROR_MSG_REF(x) nthtag_error_msg_ref, tag_bool_vr(&(x))
+
+#if SU_HAVE_INLINE
+struct nth_client_s;
+su_inline tag_value_t nthtag_template_v(struct nth_client_s const *v)
+{ return (tag_value_t)v; }
+su_inline tag_value_t nthtag_template_vr(struct nth_client_s const **vp)
+{return(tag_value_t)vp;}
+#else
+#define nthtag_template_v(v) ((tag_value_t)(v))
+#define nthtag_template_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_template;
+/** Use existing client request as template. @HI */
+#define NTHTAG_TEMPLATE(x) nthtag_template, nthtag_template_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_template_ref;
+#define NTHTAG_TEMPLATE_REF(x) nthtag_template_ref, nthtag_template_vr(&(x))
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t nthtag_message_v(struct msg_s *v)
+{ return (tag_value_t)v; }
+su_inline tag_value_t nthtag_message_vr(struct msg_s **vp)
+{ return(tag_value_t)vp; }
+#else
+#define nthtag_message_v(v) ((tag_value_t)(v))
+#define nthtag_message_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_message;
+/** Use existing request message. @HI */
+#define NTHTAG_MESSAGE(x) nthtag_message, nthtag_message_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_message_ref;
+#define NTHTAG_MESSAGE_REF(x) nthtag_message_ref, nthtag_message_vr(&(x))
+
+#if SU_HAVE_INLINE
+struct auth_client_s;
+su_inline tag_value_t nthtag_authentication_v(struct auth_client_s **v) { return (tag_value_t)v; }
+su_inline tag_value_t nthtag_authentication_vr(struct auth_client_s ***vp) {return(tag_value_t)vp;}
+#else
+#define nthtag_authentication_v(v) ((tag_value_t)(v))
+#define nthtag_authentication_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_authentication;
+/** Use stack of authenticators. @HI */
+#define NTHTAG_AUTHENTICATION(x) \
+nthtag_authentication, nthtag_authentication_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_authentication_ref;
+#define NTHTAG_AUTHENTICATION_REF(x) \
+nthtag_authentication_ref, nthtag_authentication_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_max_retry_after;
+/** Maximum value for retry interval. @HI */
+#define NTHTAG_MAX_RETRY_AFTER(x) nthtag_max_retry_after, tag_int_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_max_retry_after_ref;
+#define NTHTAG_MAX_RETRY_AFTER_REF(x) \
+nthtag_max_retry_after_ref, tag_int_vr(&(x))
+
+/* Server-side tags */
+
+NTH_DLL extern tag_typedef_t nthtag_root;
+/** Pointer to root reactor object. @HI */
+#define NTHTAG_ROOT(x) nthtag_root, tag_ptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_root_ref;
+#define NTHTAG_ROOT_REF(x) nthtag_root_ref, tag_ptr_vr(&(x), (x))
+
+NTH_DLL extern tag_typedef_t nthtag_strict_host;
+/** Do not serve requests to mismatching hosts by default host. @HI */
+#define NTHTAG_STRICT_HOST(x) nthtag_strict_host, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_strict_host_ref;
+#define NTHTAG_STRICT_HOST_REF(x) nthtag_strict_host_ref, tag_bool_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_auth_module;
+/** Pointer to authentication module. @HI. @NEW_1_12_4. */
+#define NTHTAG_AUTH_MODULE(x) nthtag_auth_module, tag_ptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_auth_module_ref;
+#define NTHTAG_AUTH_MODULE_REF(x) nthtag_auth_module_ref, tag_ptr_vr(&(x), (x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined NTH_TAG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,960 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file test_nth.c
+ * @brief Tests for nth module
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Oct 22 20:52:37 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <assert.h>
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+typedef struct tester tester_t;
+typedef struct site site_t;
+typedef struct client client_t;
+
+#define SU_ROOT_MAGIC_T tester_t
+
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_wait.h>
+
+#define NTH_CLIENT_MAGIC_T client_t
+#define NTH_SITE_MAGIC_T site_t
+
+#include "sofia-sip/nth.h"
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/auth_module.h>
+
+int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+char const name[] = "test_nth";
+
+static int init_test(tester_t *t);
+static int deinit_test(tester_t *t);
+static int test_nth_client_api(tester_t *t);
+static int test_nth_server_api(tester_t *t);
+static int init_server(tester_t *t);
+static int test_requests(tester_t *t);
+static int init_engine(tester_t *t);
+
+struct site 
+{
+  site_t       *s_next, *s_parent;
+  tester_t     *s_tester;
+  url_string_t *s_url;
+  nth_site_t   *s_ns;
+  int           s_called;
+  int           s_status;
+  char const   *s_phrase;
+  tagi_t       *s_tags;
+};
+
+struct client
+{
+  unsigned      c_status;
+};
+
+struct tester
+{
+  su_home_t     t_home[1];
+  su_root_t    *t_root;
+  msg_mclass_t *t_mclass;
+  url_string_t *t_proxy;
+  nth_engine_t *t_engine;
+
+  char const   *t_srcdir;
+  char const   *t_pem;
+
+  su_sockaddr_t t_addr[1];
+  socklen_t     t_addrlen;
+
+  su_socket_t   t_sink;
+  url_string_t *t_sinkuri;
+  su_sockaddr_t t_sinkaddr[1];
+  socklen_t     t_sinkaddrlen;
+
+  site_t       *t_sites;
+  site_t       *t_master;
+};
+
+static int test_site(site_t *t, 
+		     nth_site_t *server,
+		     nth_request_t *req, 
+		     http_t const *http,
+		     char const *path);
+
+static site_t *site_create(tester_t *t, site_t *parent,
+			   char const *url,
+			   int status, char const *phrase,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  nth_site_t *pns = parent ? parent->s_ns : NULL;
+  site_t *s;
+  ta_list ta;
+
+  if (url == NULL)
+    return NULL;
+
+  s = su_zalloc(t->t_home, sizeof *s);
+  if (s == NULL)
+    return NULL;
+
+  s->s_url = URL_STRING_MAKE(url);
+  s->s_tester = t;
+  s->s_next = t->t_sites;
+  s->s_status = status;
+  s->s_phrase = phrase;
+
+  ta_start(ta, tag, value);
+
+  s->s_tags = tl_adup(t->t_home, ta_args(ta)); 
+  if (s->s_tags)
+    s->s_ns = nth_site_create(pns, test_site, s,
+			      (url_string_t *)s->s_url, 
+			      NTHTAG_ROOT(t->t_root),
+			      ta_tags(ta));
+
+  ta_end(ta);
+  
+  if (s->s_ns == NULL)
+    return NULL;
+
+  t->t_sites = s;
+
+  return s;
+}
+
+static int init_test(tester_t *t)
+{
+  su_socket_t s;
+
+  BEGIN();
+
+  t->t_root = su_root_create(t); TEST_1(t->t_root);
+  t->t_mclass = msg_mclass_clone(http_default_mclass(), 0, 0); 
+  TEST_1(t->t_mclass);
+
+  t->t_addr->su_len = (sizeof t->t_addr->su_sin);
+  s = su_socket(t->t_addr->su_family = AF_INET, SOCK_STREAM, 0);
+  TEST_1(s != INVALID_SOCKET);
+  TEST_1(inet_pton(AF_INET, "127.0.0.1", &t->t_addr->su_sin.sin_addr) >= 0);
+  TEST_1(bind(s, &t->t_addr->su_sa, 
+	      t->t_addrlen = (sizeof t->t_addr->su_sin)) != -1);
+  TEST_1(getsockname(s, &t->t_addr->su_sa, &t->t_addrlen) != -1);
+  TEST_1(t->t_addr->su_port != 0);
+  TEST_1(su_close(s) != -1);
+
+  t->t_pem = su_sprintf(t->t_home, "%s/agent.pem", t->t_srcdir);
+
+  END();
+}
+
+static int deinit_test(tester_t *t)
+{
+  site_t *s, *s_next;
+
+  BEGIN();
+
+  nth_engine_destroy(t->t_engine);
+
+  for (s = t->t_sites; s; s = s_next) {
+    s_next = s->s_next;
+    nth_site_destroy(s->s_ns), s->s_ns = NULL;
+    su_free(t->t_home, s);
+  }
+
+  su_root_destroy(t->t_root);
+
+  su_home_deinit(t->t_home);
+
+  memset(t, 0, sizeof t);
+
+  END();
+}
+
+
+static int test_nth_client_api(tester_t *t)
+{
+  char const *s;
+
+  BEGIN();
+
+  s = nth_engine_version(); 
+  TEST_1(s); TEST_1(strlen(s)); TEST_S(s, "sofia-http-client/" NTH_CLIENT_VERSION);
+
+  TEST_1(nth_engine_create(NULL, TAG_END()) == NULL);
+  TEST(errno, EINVAL);
+  TEST_VOID(nth_engine_destroy(NULL));
+  TEST_1(nth_engine_get_params(NULL, TAG_END()) == -1);
+  TEST_1(nth_engine_set_params(NULL, TAG_END()) == -1);
+  TEST_1(!nth_client_tcreate(NULL, NULL, NULL, 
+			     HTTP_METHOD_OPTIONS, 
+			     URL_STRING_MAKE("*"), 
+			     TAG_END()));
+  TEST(nth_client_status(NULL), 400);
+  TEST(nth_client_method(NULL), http_method_invalid);
+  TEST(nth_client_is_streaming(NULL), 0);
+  TEST_P(nth_client_url(NULL), NULL);
+  TEST_P(nth_client_request(NULL), NULL);
+  TEST_P(nth_client_response(NULL), NULL);
+  TEST_VOID(nth_client_destroy(NULL));
+
+  t->t_engine = nth_engine_create(t->t_root, 
+				  NTHTAG_ERROR_MSG(2),
+				  NTHTAG_MCLASS(t->t_mclass),
+				  NTHTAG_MFLAGS(MSG_DO_CANONIC|MSG_DO_COMPACT),
+				  NTHTAG_STREAMING(0),
+				  NTHTAG_PROXY("http://localhost:8888"),
+				  TAG_END());
+  TEST_1(t->t_engine);
+  
+  {
+    int error_msg = -1;
+    msg_mclass_t const *mclass = (void *)-1;
+    int mflags = -1;
+    unsigned expires = -1;
+    int streaming = -1;
+    url_string_t const *proxy = (void *)-1;
+
+    char *proxy_str;
+
+    TEST(nth_engine_get_params(t->t_engine, 
+			       NTHTAG_ERROR_MSG_REF(error_msg),
+			       NTHTAG_MCLASS_REF(mclass),
+			       NTHTAG_MFLAGS_REF(mflags),
+			       NTHTAG_EXPIRES_REF(expires),
+			       NTHTAG_STREAMING_REF(streaming),
+			       NTHTAG_PROXY_REF(proxy),
+			       TAG_END()), 
+	 6);
+
+    TEST(error_msg, 1);
+    TEST_P(mclass, t->t_mclass);
+    TEST(mflags, MSG_DO_CANONIC|MSG_DO_COMPACT);
+    TEST(expires, 32000);
+    TEST(streaming, 0);
+    TEST_1(proxy != NULL);
+    TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
+    TEST_S(proxy_str, "http://localhost:8888");
+
+    proxy = URL_STRING_MAKE("http://127.0.0.1:80");
+
+    TEST(nth_engine_set_params(t->t_engine, 
+			       NTHTAG_ERROR_MSG(0),
+			       NTHTAG_MCLASS(http_default_mclass()),
+			       NTHTAG_MFLAGS(0),
+			       NTHTAG_EXPIRES(10000),
+			       NTHTAG_STREAMING(2),
+			       NTHTAG_PROXY(proxy),
+			       TAG_END()), 
+	 6);
+
+    error_msg = -1;
+    mclass = (void *)-1;
+    mflags = -1;
+    expires = (unsigned)-1;
+    streaming = -1;
+    proxy = (void *)-1;
+
+    TEST(nth_engine_get_params(t->t_engine, 
+			       NTHTAG_ERROR_MSG_REF(error_msg),
+			       NTHTAG_MCLASS_REF(mclass),
+			       NTHTAG_MFLAGS_REF(mflags),
+			       NTHTAG_EXPIRES_REF(expires),
+			       NTHTAG_STREAMING_REF(streaming),
+			       NTHTAG_PROXY_REF(proxy),
+			       TAG_END()), 
+	 6);
+
+    TEST(error_msg, 0);
+    TEST_P(mclass, NULL);
+    TEST(mflags, 0);
+    TEST(expires, 10000);
+    TEST(streaming, 1);
+    TEST_1(proxy != NULL); 
+    TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
+    TEST_S(proxy_str, "http://127.0.0.1:80");
+  }
+
+  TEST_1(nth_engine_get_stats(NULL, TAG_END()) == -1);
+  
+  {
+    msg_t *msg;
+    http_t *http;
+
+    TEST_1(nth_engine_msg_create(NULL, -1) == NULL);
+    TEST_1(msg = nth_engine_msg_create(t->t_engine, -1));
+    TEST_1(http = http_object(msg));
+    TEST(http->http_flags, MSG_FLG_USERMASK);
+    msg_destroy(msg);
+
+    /* Use mflags set by set_params (+ streaming flag) */
+    TEST_1(msg = nth_engine_msg_create(t->t_engine, 0));
+    TEST_1(http = http_object(msg));
+    TEST(http->http_flags, MSG_FLG_STREAMING | t->t_mclass->mc_flags);
+    msg_destroy(msg);
+  }
+
+  TEST_VOID(nth_engine_destroy(t->t_engine));
+  t->t_engine = NULL;
+
+  END();
+}
+
+static int site_check_all(site_t *t, 
+			  nth_site_t *server,
+			  nth_request_t *req, 
+			  http_t const *http,
+			  char const *path);
+
+static int test_nth_server_api(tester_t *t)
+
+{
+  char const *v;
+  site_t s[1];
+  
+  BEGIN();
+
+  memset(s, 0, sizeof s);
+
+  v = nth_site_server_version(); 
+  TEST_1(v); TEST_1(strlen(v)); TEST_S(v, "nth/" NTH_SERVER_VERSION);
+
+  /* Fails because no parent site, no root */
+  TEST_1(!nth_site_create(NULL, test_site, s,
+			  URL_STRING_MAKE("http://127.0.0.1:8888"),
+			  TAG_END()));
+
+  /* Fails because url specifies both host and path */
+  TEST_1(!nth_site_create(NULL, site_check_all, s, 
+			  URL_STRING_MAKE("http://127.0.0.1:8888/foo/"), 
+			  NTHTAG_ROOT(t->t_root), TAG_END()));
+
+  TEST_VOID(nth_site_destroy(NULL));
+  TEST_P(nth_site_magic(NULL), NULL);
+  TEST_VOID(nth_site_bind(NULL, test_site, s));
+  TEST_1(nth_site_set_params(NULL, TAG_END()) == -1);
+  TEST_1(nth_site_get_params(NULL, TAG_END()) == -1);
+  TEST_1(nth_site_get_stats(NULL, TAG_END()) == -1);
+  TEST(nth_request_status(NULL), 400);
+  TEST(nth_request_method(NULL), http_method_invalid);
+  TEST_P(nth_request_message(NULL), NULL);
+  TEST_1(nth_request_treply(NULL, HTTP_200_OK, TAG_END()) == -1);
+  TEST_VOID(nth_request_destroy(NULL));
+
+  END();
+}
+
+static int test_site(site_t *s, 
+		     nth_site_t *ns,
+		     nth_request_t *req, 
+		     http_t const *http,
+		     char const *path)
+{
+  if (s == NULL || ns == NULL || req == NULL)
+    return 500;
+
+  TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
+			    TAG_NEXT(s->s_tags)) != -1);
+
+  TEST_VOID(nth_request_destroy(req));
+
+  return s->s_status;
+}
+
+
+static int site_check_all(site_t *s, 
+			  nth_site_t *ns,
+			  nth_request_t *req, 
+			  http_t const *http,
+			  char const *path)
+{
+  msg_t *msg;
+  auth_status_t *as;
+
+  TEST_1(s); TEST_1(ns); TEST_1(req); TEST_1(http); TEST_1(path);
+
+  if (s == NULL || ns == NULL || req == NULL)
+    return 500;
+
+  TEST(nth_request_status(req), 0);
+  TEST(nth_request_method(req), http_method_get);
+  TEST_1(msg = nth_request_message(req));
+
+  msg_destroy(msg);
+
+  as = nth_request_auth(req);
+
+  TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
+			    TAG_NEXT(s->s_tags)) != -1);
+
+  TEST_VOID(nth_request_destroy(req));
+
+  return s->s_status;
+}
+
+static char passwd_name[] = "tmp_sippasswd.XXXXXX";
+
+static void remove_tmp(void)
+{
+  if (passwd_name[0])
+    unlink(passwd_name);
+}
+
+static char const passwd[] =
+  "alice:secret:\n"
+  "bob:secret:\n"
+  "charlie:secret:\n";
+
+static int init_server(tester_t *t)
+{
+  BEGIN();
+
+  site_t *m = t->t_master, *sub2;
+  auth_mod_t *am;
+  int temp;
+
+  TEST_1(t->t_master = m = 
+	 site_create(t, NULL,
+		     su_sprintf(t->t_home, "HTTP://127.0.0.1:%u", 
+				htons(t->t_addr->su_port)),
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR("<html><body>Hello</body></html>\n"),
+		     TPTAG_CERTIFICATE(t->t_pem),
+		     TAG_END()));
+
+  TEST_1(site_create(t, m, "/sub/sub",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR
+		     ("<html><body>sub/sub</body></html>\n"),
+		     TAG_END()));
+
+  TEST_1(site_create(t, m, "/sub/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR("<html><body>sub/</body></html>\n"),
+		     TAG_END()));
+
+  TEST_1(site_create(t, m, "/sub/sub/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR
+		     ("<html><body>sub/sub/</body></html>\n"),
+		     TAG_END()));
+
+  TEST_1(sub2 = 
+	 site_create(t, m, "/sub2/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR("<html><body>sub2/</body></html>\n"),
+		     TAG_END()));
+
+  TEST_1(site_create(t, sub2, "sub/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR
+		     ("<html><body>sub2/sub/</body></html>\n"),
+		     TAG_END()));
+
+
+#ifndef _WIN32
+  temp = mkstemp(passwd_name);
+#else
+  temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
+#endif
+  TEST_1(temp != -1);
+  atexit(remove_tmp);		/* Make sure temp file is unlinked */
+
+  TEST_SIZE(write(temp, passwd, strlen(passwd)), strlen(passwd));
+
+  TEST_1(close(temp) == 0);
+
+  am = auth_mod_create(t->t_root, 
+		       AUTHTAG_METHOD("Digest"), 
+		       AUTHTAG_REALM("auth"),
+		       AUTHTAG_DB(passwd_name),
+		       TAG_END());
+  TEST_1(am);
+
+  TEST_1(site_create(t, m, "auth/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR
+		     ("<html><body>auth/</body></html>\n"),
+		     NTHTAG_AUTH_MODULE(am),
+		     TAG_END()));
+
+  auth_mod_unref(am);
+
+
+  am = auth_mod_create(t->t_root, 
+		       AUTHTAG_METHOD("Delayed+Basic"), 
+		       AUTHTAG_REALM("auth2"),
+		       AUTHTAG_DB(passwd_name),
+		       TAG_END());
+  TEST_1(am);
+
+  TEST_1(site_create(t, m, "auth2/",
+		     HTTP_200_OK, 
+		     HTTPTAG_CONTENT_TYPE_STR("text/html"),
+		     HTTPTAG_PAYLOAD_STR
+		     ("<html><body>auth/</body></html>\n"),
+		     NTHTAG_AUTH_MODULE(am),
+		     TAG_END()));
+
+  auth_mod_unref(am);
+
+  END();
+}
+
+static int send_request(tester_t *t, char const *req, size_t reqlen,
+			int close_socket,
+			char reply[], int rlen,
+			int *return_len)
+{
+  static su_socket_t c = INVALID_SOCKET;
+  int m, r;
+  su_wait_t w[1];
+
+  BEGIN();
+
+  if (c == INVALID_SOCKET) {
+    c = su_socket(t->t_addr->su_family, SOCK_STREAM, 0); TEST_1(c != SOCK_STREAM);
+    TEST_1(connect(c, &t->t_addr->su_sa, t->t_addrlen) != -1);
+
+    while (su_root_step(t->t_root, 1) == 0);
+  }
+
+  if (reqlen == (size_t)-1)
+    reqlen = strlen(req);
+
+  TEST_SIZE(su_send(c, req, reqlen, 0), reqlen);
+
+  if (close_socket == 1)
+    shutdown(c, 1);
+
+  TEST(su_wait_create(w, c, SU_WAIT_IN), 0);
+
+  while (su_root_step(t->t_root, 1) == 0 || su_wait(w, 1, 0) < 0);
+
+  for (r = 0;;) {
+    TEST_1((m = recv(c, reply, rlen - r - 1, 0)) != -1);
+    r += m;
+    if (m == 0 || r == rlen - 1)
+      break;
+  }
+  reply[r] = '\0';
+
+  if (close_socket != -1)
+    su_close(c), c = -1;
+
+  *return_len = r;
+
+  END();
+}
+
+int sspace(char const *buffer) 
+{
+  int m = strcspn(buffer, " "); 
+
+  if (buffer[m]) 
+    m += 1 + strcspn(buffer + m + 1, " "); 
+
+  return m;
+}
+
+#define CRLF "\r\n"
+
+static int test_requests(tester_t *t)
+{
+  char buffer[4096 + 1];
+  int m;
+
+  BEGIN();
+
+  {
+    static char const get[] = 
+      "GET / HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      CRLF;
+
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200");
+  }
+
+  {
+    static char const get[] = 
+      "GET / HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      CRLF;
+
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+    m = strcspn(buffer, CRLF); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+  }
+
+  {
+    static char const request[] = 
+      "GET %s HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      CRLF;
+    char *get;
+
+    get = su_sprintf(NULL, request, "/sub");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 301");
+    m += strcspn(buffer + m, CRLF) + 1;
+    free(get);
+
+    get = su_sprintf(NULL, request, "/sub/");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+    TEST_1(strstr(buffer + m, "<body>sub/</body>"));
+    free(get);
+
+    get = su_sprintf(NULL, request, "/sub2/");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+    TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
+    free(get);
+
+    get = su_sprintf(NULL, request, "/sub2/hub");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+    TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
+    free(get);
+
+    /* Test that absolute path for subdir site is calculated correctly */
+    get = su_sprintf(NULL, request, "/sub2/sub");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 301");
+    TEST_1(strstr(buffer + m, "/sub2/sub/" CRLF));
+    free(get);
+
+    get = su_sprintf(NULL, request, "/sub2/sub/");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+    TEST_1(strstr(buffer + m, "<body>sub2/sub/</body>"));
+    free(get);
+
+    get = su_sprintf(NULL, request, "/sub/sub");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200 OK");
+    TEST_1(strstr(buffer + m, "<body>sub/sub</body>"));
+    free(get);
+
+    get = su_sprintf(NULL, request, "/auth/");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 401");
+    free(get);
+
+    get = su_sprintf(NULL, request, "/auth2/");
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 401");
+    free(get);
+  }
+
+  {
+    static char const get[] = 
+      "GET /auth2/ HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      /* alice:secret in base64 */
+      "Authorization: Basic YWxpY2U6c2VjcmV0" CRLF
+      CRLF;
+
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m++] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200");
+  }
+
+  {
+    static char const kuik[] = 
+      "kuik" CRLF CRLF;
+
+    TEST(send_request(t, kuik, -1, 0, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 400");
+  }
+
+  {
+    static char const kuik[] = 
+      "POST / HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "Content-Length: 4294967296" CRLF
+      CRLF;
+
+    TEST(send_request(t, kuik, -1, 1, buffer, sizeof(buffer), &m), 0);
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 400");
+  }
+
+  {
+    static char const get[] = 
+      "GET / HTTP/10.10" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      CRLF;
+
+    TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 505");
+  }
+
+  {
+    static char const get[] = 
+      "GET /" CRLF;
+
+    TEST(send_request(t, get, -1, 1, buffer, sizeof(buffer) - 1, &m), 0);
+
+    buffer[6] = '\0';
+    TEST_S(buffer, "<html>");
+  }
+
+  if (0)
+  {
+    static char const post[] = 
+      "POST /foo HTTP/1.1" CRLF
+      "Host: 127.0.0.1" CRLF
+      "User-Agent: Test-Tool" CRLF
+      "Connection: close" CRLF
+      "Content-Length: 7" CRLF
+      "Expect: 100-continue" CRLF
+      CRLF;
+    static char const body[] =
+      "<html/>";
+
+    TEST(send_request(t, post, -1, -1, buffer, sizeof(buffer) - 1, &m), 0);
+
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 100");
+
+    TEST(send_request(t, body, -1, 0, buffer, sizeof(buffer) - 1, &m), 0);
+
+    m = sspace(buffer); buffer[m] = '\0';
+    TEST_S(buffer, "HTTP/1.1 200");
+  }
+
+  END();
+}
+
+
+static int init_engine(tester_t *t)
+{
+  BEGIN();
+  su_socket_t s;
+
+  t->t_engine = nth_engine_create(t->t_root, 
+				  NTHTAG_STREAMING(0),
+				  TAG_END());
+  TEST_1(t->t_engine);
+
+  t->t_sink = s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+  TEST(bind(s, &t->t_sinkaddr->su_sa, 
+	    t->t_sinkaddrlen = (sizeof t->t_sinkaddr->su_sin)),
+       0);
+  TEST_1(getsockname(s, &t->t_sinkaddr->su_sa, &t->t_sinkaddrlen) != -1);
+  TEST(listen(t->t_sink, 5), 0);
+  
+  TEST_1(t->t_sinkuri = (url_string_t *)
+	 su_sprintf(t->t_home, "HTTP://127.0.0.1:%u", 
+		    htons(t->t_sinkaddr->su_port)));
+
+  END();
+}
+
+
+static int response_to_client(client_t *c,
+			      nth_client_t *hc,
+			      http_t const *http)
+{
+  if (http) {
+    c->c_status = http->http_status->st_status;
+  }
+  else {
+    c->c_status = nth_client_status(hc);
+  }
+
+  return 0;
+}
+
+
+static int test_client(tester_t *t)
+{
+  BEGIN();
+
+  nth_client_t *hc;
+  char *uri;
+  client_t client[1];
+
+  memset(client, 0, sizeof client);
+
+  TEST_1(uri = su_strcat(NULL, t->t_master->s_url->us_str, "/"));
+  TEST_1(hc = nth_client_tcreate(t->t_engine,
+				 response_to_client, client,
+				 HTTP_METHOD_GET,
+				 URL_STRING_MAKE(uri),
+				 TAG_END()));
+  while (client->c_status == 0) su_root_step(t->t_root, 1);
+  TEST(client->c_status, 200);
+  nth_client_destroy(hc);
+  su_free(NULL, uri);
+
+  memset(client, 0, sizeof client);
+
+  TEST_1(hc = nth_client_tcreate(t->t_engine,
+				 response_to_client, client,
+				 HTTP_METHOD_GET,
+				 URL_STRING_MAKE(t->t_sinkuri),
+				 NTHTAG_EXPIRES(1000),
+				 TAG_END()));
+  while (client->c_status == 0) su_root_step(t->t_root, 1);
+  TEST(client->c_status, 408);
+  nth_client_destroy(hc);
+	 
+  END();
+}
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v|-q] [-p proxy-uri]\n", name);
+  exit(1);
+}
+
+int main(int argc, char **argv)
+{
+  int i;
+  int retval = 0;
+  int o_alarm = 1;
+
+  tester_t t[1] = {{{ SU_HOME_INIT(t) }}};
+
+  char const *srcdir = getenv("srcdir");
+
+  if (srcdir == NULL)
+    srcdir = ".";
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-q") == 0)
+      tstflags &= ~tst_verbatim;
+    else if (strcmp(argv[i], "-p") == 0 && argv[i + 1])
+      t->t_proxy = (url_string_t *)argv[++i];
+    else if (strcmp(argv[i], "-s") == 0 && argv[i + 1])
+      srcdir = argv[++i];
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (argv[i][0] != '-') {
+      break;
+    }
+    else
+      usage();
+  }
+
+  t->t_srcdir = srcdir;
+
+#if HAVE_ALARM
+  if (o_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  su_init();
+
+  retval |= init_test(t);
+  retval |= test_nth_client_api(t);
+  retval |= test_nth_server_api(t);
+  retval |= init_server(t);
+  retval |= test_requests(t);
+  retval |= init_engine(t);
+  retval |= test_client(t);
+  retval |= deinit_test(t);
+ 
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,480 @@
+2005-11-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Removed obsolete NUTAG_MEDIA* tags.
+
+2005-11-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Indicate the response status with the nua_i_<method>.
+
+	Now returning the status of the returned response in
+	nua_i_<method> events. The application can determine from status
+	code if it has to respond.
+
+	* Added NUTAG_ALLOW() and NUTAG_ALLOW_REF() to nua.
+
+	* Try to catch more errors when responding to invite in nua.
+
+	* Fixed call state events with UPDATE in nua.
+
+	Fixed the order the nua_i_update and nua_i_state events are sent. 
+	Now we are using session-timer headers in responses, too.
+
+	* Added NUTAG_ALLOW() and NUTAG_ALLOW_REF() to nua.
+
+	* Renamed NUTAG_USE_LEG() as NUTAG_USE_DIALOG() in nua.
+
+2005-10-21  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed challenge header checking in nua/nua_stack.c when receiving 401/407.
+  Now checking for Proxy-Authenticate header when receiving 407 and
+  WWW-Authenticate header when receiving 401.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * Added test case for 407 followed by 401.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -3 +53
+
+2005-10-18  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Test case numbering.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -1 +1
+
+  * Log level setting.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -1 +2
+
+  * Added a basic session timer test.
+
+    M ./libsofia-sip-ua/nua/test_nua.c +121
+
+  * Fixed session-timer role selection at uas end.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -10 +13
+
+  * Added -s option.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -2 +10
+
+  * Simplified test_basic_call().
+
+    M ./libsofia-sip-ua/nua/test_nua.c -18 +1
+
+  * Added test case for nua_authenticate.
+
+    M ./libsofia-sip-ua/nua/test_nua.c +187
+
+  * Fixed response to 401.
+  We are now not terminating call when application is expected to authenticate
+  request. Should we add 
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -10 +28
+
+  * Renumbered test cases. Split reject tests into separate functions.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -135 +159
+
+  * Added aliases for SOATAG_MSS_POINTER and SOATAG_MSS_SESSION.
+
+    M ./libsofia-sip-ua/nua/nua_tag.h -27 +9
+
+2005-10-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Using port 5060 by default.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -7 +13
+
+  * Fixed race condition in 302 test.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+  * Silenced some gcc4 warnings.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -10 +11
+    M ./libsofia-sip-ua/nua/test_nua.c -10 +10
+
+2005-10-15  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Relay real CANCEL response to application.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -8 +31
+
+  * Added CANCEL and early BYE tests. Added headings for test cases.
+  Added more command-line options, too.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -26 +476
+
+  * Fixed process_bye().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +15
+
+  * Fixed ua_bye().
+
+  Not mark session as terminated if we have an ongoing INVITE (just as
+  terminating). Instead of sending BYE, send CANCEL, if we have no dialog.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -24 +34
+
+  * Let nh_init() call soa_set_params() in ua_update().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -3
+    M ./libsofia-sip-ua/nua/nua_stack.c -7 +4
+
+  * Using new soa API in signal_call_state_change().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -17 +11
+
+  * Cleaned indentation.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -4 +11
+
+  * Replaced ancient nta_msg_discard() with msg_destroy().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+
+  * Refactored nh_create_from_incoming().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -15 +14
+
+  * Made ua_set_params() and nh_init() to return -1 upon an error.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -18 +27
+
+  * Updated soa_get_local_sdp() API.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * Zapped annoying last modified.
+
+    M ./libsofia-sip-ua/nua/nua.c -1
+    M ./libsofia-sip-ua/nua/nua.h -1
+    M ./libsofia-sip-ua/nua/nua_common.c -1
+    M ./libsofia-sip-ua/nua/nua_stack.c -1
+    M ./libsofia-sip-ua/nua/nua_stack.h -1
+    M ./libsofia-sip-ua/nua/nua_tag.c -1
+    M ./libsofia-sip-ua/nua/nua_tag.h -1
+
+  * Fixed logging options. Allow multithreaded, unsynchronised execution.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -115 +162
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed logging options. Allow multithreaded, unsynchronised execution.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -115 +162
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added test for call hold.
+
+    M ./libsofia-sip-ua/nua/test_nua.c +241
+
+  * Added better logging functions.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -77 +149
+
+  * LDADD now have dependencies.
+
+    M ./libsofia-sip-ua/nua/Makefile.am -15 +15
+
+  * Added call reject cases.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -62 +461
+
+  * When call is retried or terminated, always send nua_i_state after
+  nua_r_invite().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -53 +55
+
+  * Fixed reference counting bug in process_ack().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -6 +2
+
+2005-10-11  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Used picture-mode (cleaned up whitespace at eol).
+
+    M ./libsofia-sip-ua/nua/test_nua.c -23 +23
+
+  * Testing call flow on client side, too.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -17 +94
+
+  * Transitions terminating call. Added letter C, S, and T to transitions.
+
+    M ./libsofia-sip-ua/nua/nua.docs -72 +159
+
+2005-10-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed basic call test run. 
+
+    M ./libsofia-sip-ua/nua/test_nua.c -8 +11
+
+  * It is nua_callstate_completed, not nua_callstate_complete.
+
+    M ./libsofia-sip-ua/nua/nua_common.c -1 +1
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+    M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+	
+  * Running a basic call test case.
+
+    M ./libsofia-sip-ua/nua/test_nua.c -24 +109
+
+  * Added separate nua_i_ack event. Generating it after ACK is received.
+
+    M ./libsofia-sip-ua/nua/nua.h -1 +2
+    M ./libsofia-sip-ua/nua/nua_common.c -1 +3
+    M ./libsofia-sip-ua/nua/nua_stack.c -11 +24
+    M ./libsofia-sip-ua/nua/nua_stack.h -1 +4
+
+  * ua_invite2() crashed if there was problem creating SIP message.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+  * Fixed indenting in nua_stack.c.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -3 +6
+
+  * Including nua_callstate_terminated in the NUTAG_CALLSTATE always when call
+  is terminated.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * nua_handle_has_streaming() is obsolete.
+
+    M ./libsofia-sip-ua/nua/nua.h -2 +3
+
+  * Using nua_callstate_complete.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -8 +10
+
+  * Added nua_callstate_completing and nua_callstate_completed.
+
+    M ./libsofia-sip-ua/nua/nua_common.c +2
+    M ./libsofia-sip-ua/nua/nua_tag.h -1 +3
+
+  * Added nua_call_model @page.
+
+    M ./libsofia-sip-ua/nua/nua.docs -1 +355
+
+  * Used picture-mode here. 
+
+    M ./libsofia-sip-ua/nua/nua.docs -227 +227
+
+  * Fixed nua_set_hparams() documentation. 
+
+    M ./libsofia-sip-ua/nua/nua.c -1 +1
+
+  * Exposed struct event_s as nua_event_data_t.
+  Replaced clumsy nua_info_event() with nua_event_data(). Added tests for new
+  function.
+
+    M ./libsofia-sip-ua/nua/nua.c -31 +6
+    M ./libsofia-sip-ua/nua/nua.h -10 +14
+    M ./libsofia-sip-ua/nua/nua_stack.h -10
+    M ./libsofia-sip-ua/nua/test_nua.c -60 +182
+
+  * Fixed nua_set_hparams()/nua_get_hparams().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -4 +6
+    M ./libsofia-sip-ua/nua/test_nua.c -6 +5
+
+  * nua_set_(h)params() now also returns an event.
+
+    M ./libsofia-sip-ua/nua/nua.h -1 +1
+    M ./libsofia-sip-ua/nua/nua_stack.c -13 +33
+
+  * Removed superfluous tags from nua_tag.h and from documentation.
+
+    M ./libsofia-sip-ua/nua/nua.c -21 +19
+    M ./libsofia-sip-ua/nua/nua_tag.c -1
+    M ./libsofia-sip-ua/nua/nua_tag.h -19
+
+  * Renamed nua_set/get_handle_params() as nua_set/get_hparams().
+
+    M ./libsofia-sip-ua/nua/nua.c -4 +2
+    M ./libsofia-sip-ua/nua/nua.h -3 +3
+    M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+  * Added test for nua_set_params() and nua_get_params().
+
+    M ./libsofia-sip-ua/nua/test_nua.c -75 +420
+
+  * Fixed ua_set_params(), added SIPTAG_FROM_STR() to ua_get_params().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -19 +23
+
+  * Fixed prototypes of nua_save_event() and nua_info_event().
+
+    M ./libsofia-sip-ua/nua/nua.c -1 +1
+    M ./libsofia-sip-ua/nua/nua.h -2 +2
+
+  * Using nua_any_refresher.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -7 +9
+
+  * Fixed user_agent handling in ua_set_params()
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * Added NUTAG_RETRY_COUNT() and NUTAG_MAX_SUBSCRIPTIONS().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -4 +4
+    M ./libsofia-sip-ua/nua/nua_tag.c -1 +4
+    M ./libsofia-sip-ua/nua/nua_tag.h -4 +54
+
+  * Added nua_set_handle_params() and nua_get_handle_params().
+  Revised the internal handling of parameters. They can be now set at handle
+  or user agent level. Once a parameter is set at handle level, changes at
+  user agent level does modify its value within a handle.
+
+    M ./libsofia-sip-ua/nua/nua.c -7 +90
+    M ./libsofia-sip-ua/nua/nua.h -1 +8
+    M ./libsofia-sip-ua/nua/nua_common.c +2
+    M ./libsofia-sip-ua/nua/nua_stack.c -378 +486
+    M ./libsofia-sip-ua/nua/nua_stack.h -64 +113
+
+  * Silenced test run.
+  Disabled debug output from nua functions getting invalid input during test
+  run.
+
+    M ./libsofia-sip-ua/nua/nua.c -2 +2
+    M ./libsofia-sip-ua/nua/test_nua.c -5 +10
+
+2005-10-04  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua.h (nua_invite_respond): Removed, no implementation
+	available.
+
+2005-10-04  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed soa_set_params() in respond_to_invite().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+2005-10-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added soa_set_params() to respond_to_invite().
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +3
+
+  * Added API for saving nua events.
+
+    M ./libsofia-sip-ua/nua/nua.c -4 +80
+    M ./libsofia-sip-ua/nua/nua.h +20
+    M ./libsofia-sip-ua/nua/nua_stack.h +2
+
+2005-09-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added nua_callstate_name().
+
+    M ./libsofia-sip-ua/nua/nua_common.c +17
+    M ./libsofia-sip-ua/nua/nua_tag.h +3
+
+  * Responding with 504 if 100rel times out.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+  * Using SOATAG_ACTIVE_*.
+
+    M ./libsofia-sip-ua/nua/nua_stack.h -8 +8
+
+  * Using offer/answer tags.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +11
+
+  * Commenting.
+
+    M ./libsofia-sip-ua/nua/nua_tag.h +9
+
+  * Added NUTAG_OFFER_RECV(), NUTAG_ANSWER_SENT(), NUTAG_OFFER_SENT(),
+    NUTAG_ANSWER_RECV().
+
+    M ./libsofia-sip-ua/nua/nua_tag.c +4
+    M ./libsofia-sip-ua/nua/nua_tag.h +64
+
+  * Using SOATAG_ACTIVE_*().
+
+    M ./libsofia-sip-ua/nua/nua_tag.c -3
+    M ./libsofia-sip-ua/nua/nua_tag.h -91 +32
+
+  * Updated signal_call_state_change() to take more versatile args.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -302 +375
+
+  * Added NUTAG_CALLSTATE(), enum nua_callstate.
+
+    M ./libsofia-sip-ua/nua/nua_stack.h -20 +8
+    M ./libsofia-sip-ua/nua/nua_tag.c +1
+    M ./libsofia-sip-ua/nua/nua_tag.h -1 +38
+
+  * Added sdp_session_t and SDP_MIME_TYPE.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c +9
+
+  * Moved nua_event_name() to nua_common.c
+
+    M ./libsofia-sip-ua/nua/nua.h +1
+    M ./libsofia-sip-ua/nua/nua_common.c +62
+    M ./libsofia-sip-ua/nua/nua_stack.c -58
+
+  * Removed SRTP things (they are in soa).
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -10
+    M ./libsofia-sip-ua/nua/nua_stack.h -3
+
+  * Added nua_unpublish()
+
+    M ./libsofia-sip-ua/nua/nua.c -4 +28
+    M ./libsofia-sip-ua/nua/nua.h +1
+    M ./libsofia-sip-ua/nua/nua_stack.c +1
+
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Including <soa_tag.h> in <nua_tag.h>.
+
+    M ./libsofia-sip-ua/nua/nua_tag.h -3 +3
+
+  * Compiled with new soa.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -63 +61
+
+  * Do not pass soa handle to application.
+
+    M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+	
+2005-09-23  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua_stack.c: Fix delivering nua_i_active.
+
+2005-09-22  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua.docs: Updated event documentation.
+
+	* nua_stack.c: Unused nua_i_terminate event removed.
+
+	* nua_tag.h: Removed NUTAG_MEDIA_SUBSYSTEM.
+
+	* nua.h: Added nua_i_state_change event. Removed 
+	nua_i_media_update (replaced by nua_i_state_change).
+
+2005-09-21  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua_stack.h, nua_common.c, nua.c: Removed obsolete
+	code related to old media subsystem interface (HAVE_MSS).
+	Added nua_i_media_update event. Removed code related
+	to ring-tone generation (HAVE_HERBIE).
+	
+2005-09-20  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua.h, nua.c: Removed implementation for obsolete media
+	param functions. Added dummy implementations that print 
+	a warning to users of the removed interfaces.
+
+	* nua_stack.c: Removed obsolete media param code.
+	
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+PROJECT_NAME         = "nua"
+OUTPUT_DIRECTORY     = ../docs/html/nua
+
+INPUT 		     = nua.docs . sofia-sip
+
+ at INCLUDE             = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/docs.doxytags=../docs
+TAGFILES            += ../docs/su.doxytags=../su
+TAGFILES            += ../docs/ipt.doxytags=../ipt
+TAGFILES            += ../docs/bnf.doxytags=../bnf
+TAGFILES            += ../docs/url.doxytags=../url
+TAGFILES            += ../docs/msg.doxytags=../msg
+TAGFILES            += ../docs/sip.doxytags=../sip
+TAGFILES            += ../docs/sresolv.doxytags=../sresolv
+TAGFILES            += ../docs/tport.doxytags=../tport
+TAGFILES            += ../docs/nta.doxytags=../nta
+TAGFILES            += ../docs/soa.doxytags=../soa
+TAGFILES            += ../docs/nea.doxytags=../nea
+TAGFILES            += ../docs/sdp.doxytags=../sdp
+
+GENERATE_TAGFILE     = ../docs/nua.doxytags
+
+ALIASES             += CFILE="@internal @file" IFILE="@internal @file"
+
+ALIASES 	    += nua="@ref index \"nua\""
+# When GENERATE_TAGFILE=YES, we should use \ref main
+#ALIASES 	    += nua="@ref main \"nua\""
+
+ALIASES		    += NUA_EVENT="@var nua_event_e::"
+ALIASES		    += END_NUA_EVENT="@par &nbsp;"
+
+VERBATIM_HEADERS     = NO
+
+ at INCLUDE             = ../sip/sip.doxyaliases

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,101 @@
+#
+# Makefile.am for nua module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../bnf -I../bnf \
+	 		-I$(srcdir)/../ipt -I../ipt \
+	 		-I$(srcdir)/../iptsec -I../iptsec \
+	 		-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../nea -I../nea \
+			-I$(srcdir)/../nta -I../nta \
+			-I$(srcdir)/../nth -I../nth \
+			-I$(srcdir)/../sdp -I../sdp \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../soa -I../soa \
+			-I$(srcdir)/../tport -I../tport \
+			-I$(srcdir)/../stun -I../stun \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libnua.la
+
+check_PROGRAMS =	test_nua
+
+TESTS = 		test_nua
+
+CLEANFILES =           tmp_sippasswd.??????
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		nua_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nua.h sofia-sip/nua_tag.h
+
+libnua_la_SOURCES = 	nua.c nua_stack.h nua_common.c nua_stack.c \
+			nua_extension.c \
+			nua_dialog.c nua_dialog.h \
+			outbound.c outbound.h \
+			nua_params.c nua_params.h \
+			nua_register.c nua_registrar.c \
+			nua_session.c nua_options.c \
+			nua_message.c nua_publish.c nua_subnotref.c \
+			nua_notifier.c \
+			nua_event_server.c \
+			nua_tag.c nua_tag_ref.c
+
+COVERAGE_INPUT = 	$(libnua_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libnua.la \
+			../iptsec/libiptsec.la \
+			../ipt/libipt.la \
+			../nea/libnea.la \
+			../nta/libnta.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../soa/libsoa.la \
+			../sdp/libsdp.la \
+			../sip/libsip.la \
+			../http/libhttp.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nua_LDFLAGS = 	-static
+
+test_nua_SOURCES = 	test_nua.c test_nua.h test_ops.c \
+			test_init.c \
+			test_nua_api.c test_nua_params.c \
+			test_register.c test_basic_call.c \
+			test_call_reject.c test_cancel_bye.c \
+			test_call_hold.c test_session_timer.c \
+			test_refer.c test_100rel.c \
+			test_simple.c test_sip_events.c \
+			test_extension.c \
+			test_proxy.h test_proxy.c \
+			test_nat.h test_nat.c test_nat_tags.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile nua.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS =		LIST=nua_tag_list

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,799 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nua module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_nua$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nua
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnua_la_LIBADD =
+am_libnua_la_OBJECTS = nua.lo nua_common.lo nua_stack.lo \
+	nua_extension.lo nua_dialog.lo outbound.lo nua_params.lo \
+	nua_register.lo nua_registrar.lo nua_session.lo nua_options.lo \
+	nua_message.lo nua_publish.lo nua_subnotref.lo nua_notifier.lo \
+	nua_event_server.lo nua_tag.lo nua_tag_ref.lo
+libnua_la_OBJECTS = $(am_libnua_la_OBJECTS)
+am_test_nua_OBJECTS = test_nua.$(OBJEXT) test_ops.$(OBJEXT) \
+	test_init.$(OBJEXT) test_nua_api.$(OBJEXT) \
+	test_nua_params.$(OBJEXT) test_register.$(OBJEXT) \
+	test_basic_call.$(OBJEXT) test_call_reject.$(OBJEXT) \
+	test_cancel_bye.$(OBJEXT) test_call_hold.$(OBJEXT) \
+	test_session_timer.$(OBJEXT) test_refer.$(OBJEXT) \
+	test_100rel.$(OBJEXT) test_simple.$(OBJEXT) \
+	test_sip_events.$(OBJEXT) test_extension.$(OBJEXT) \
+	test_proxy.$(OBJEXT) test_nat.$(OBJEXT) \
+	test_nat_tags.$(OBJEXT)
+test_nua_OBJECTS = $(am_test_nua_OBJECTS)
+test_nua_LDADD = $(LDADD)
+test_nua_DEPENDENCIES = libnua.la ../iptsec/libiptsec.la \
+	../ipt/libipt.la ../nea/libnea.la ../nta/libnta.la \
+	../sresolv/libsresolv.la ../tport/libtport.la \
+	../stun/libstun.la ../soa/libsoa.la ../sdp/libsdp.la \
+	../sip/libsip.la ../http/libhttp.la ../msg/libmsg.la \
+	../url/liburl.la ../bnf/libbnf.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+DIST_SOURCES = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+	 		-I$(srcdir)/../ipt -I../ipt \
+	 		-I$(srcdir)/../iptsec -I../iptsec \
+	 		-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../nea -I../nea \
+			-I$(srcdir)/../nta -I../nta \
+			-I$(srcdir)/../nth -I../nth \
+			-I$(srcdir)/../sdp -I../sdp \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../soa -I../soa \
+			-I$(srcdir)/../tport -I../tport \
+			-I$(srcdir)/../stun -I../stun \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnua.la
+TESTS = test_nua
+CLEANFILES = tmp_sippasswd.??????
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nua_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/nua.h sofia-sip/nua_tag.h
+
+libnua_la_SOURCES = nua.c nua_stack.h nua_common.c nua_stack.c \
+			nua_extension.c \
+			nua_dialog.c nua_dialog.h \
+			outbound.c outbound.h \
+			nua_params.c nua_params.h \
+			nua_register.c nua_registrar.c \
+			nua_session.c nua_options.c \
+			nua_message.c nua_publish.c nua_subnotref.c \
+			nua_notifier.c \
+			nua_event_server.c \
+			nua_tag.c nua_tag_ref.c
+
+COVERAGE_INPUT = $(libnua_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnua.la \
+			../iptsec/libiptsec.la \
+			../ipt/libipt.la \
+			../nea/libnea.la \
+			../nta/libnta.la \
+			../sresolv/libsresolv.la \
+			../tport/libtport.la \
+			../stun/libstun.la \
+			../soa/libsoa.la \
+			../sdp/libsdp.la \
+			../sip/libsip.la \
+			../http/libhttp.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_nua_LDFLAGS = -static
+test_nua_SOURCES = test_nua.c test_nua.h test_ops.c \
+			test_init.c \
+			test_nua_api.c test_nua_params.c \
+			test_register.c test_basic_call.c \
+			test_call_reject.c test_cancel_bye.c \
+			test_call_hold.c test_session_timer.c \
+			test_refer.c test_100rel.c \
+			test_simple.c test_sip_events.c \
+			test_extension.c \
+			test_proxy.h test_proxy.c \
+			test_nat.h test_nat.c test_nat_tags.c
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nua.docs $(BUILT_SOURCES)
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+TAG_DLL_FLAGS = LIST=nua_tag_list
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/nua/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/nua/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnua.la: $(libnua_la_OBJECTS) $(libnua_la_DEPENDENCIES) 
+	$(LINK)  $(libnua_la_LDFLAGS) $(libnua_la_OBJECTS) $(libnua_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_nua$(EXEEXT): $(test_nua_OBJECTS) $(test_nua_DEPENDENCIES) 
+	@rm -f test_nua$(EXEEXT)
+	$(LINK) $(test_nua_LDFLAGS) $(test_nua_OBJECTS) $(test_nua_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_dialog.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_event_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_extension.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_message.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_notifier.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_options.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_params.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_publish.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_register.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_registrar.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_session.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_stack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_subnotref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/outbound.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_100rel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_basic_call.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_call_hold.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_call_reject.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_cancel_bye.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_extension.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_init.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nat.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nat_tags.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua_api.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua_params.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_ops.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_proxy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_refer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_register.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_session_timer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_simple.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sip_events.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1159 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nua.c High-Level User Agent Library - "nua" Implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Pasi Rinne-Rahkola
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#define SU_ROOT_MAGIC_T   struct nua_s
+#define SU_MSG_ARG_T      struct event_s
+#define NUA_SAVED_EVENT_T su_msg_t *
+
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/nta.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* From AM_INIT/AC_INIT in our "config.h" */
+char const nua_version[] = VERSION;
+
+/**Environment variable determining the debug log level for @nua module.
+ *
+ * The NUA_DEBUG environment variable is used to determine the debug logging
+ * level for @nua module. The default level is 3.
+ * 
+ * @sa <sofia-sip/su_debug.h>, nua_log, SOFIA_DEBUG
+ */
+extern char const NUA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @nua module. 
+ * 
+ * The nua_log is the log object used by @nua module. The level of
+ * #nua_log is set using #NUA_DEBUG environment variable.
+ */
+su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };
+
+/**Create a @nua agent.
+ *
+ * This function creates a Sofia-SIP User Agent stack object (@nua) and
+ * initializes its parameters by given tagged values.
+ *
+ * @param root            Pointer to a root object
+ * @param callback        Pointer to event callback function
+ * @param magic           Pointer to callback context
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @retval !=NULL a pointer to a @nua stack object \n
+ * @retval NULL upon an error
+ *
+ * @par Related tags:
+ *     NUTAG_PROXY()            \n
+ *     NUTAG_URL()              \n
+ *     NUTAG_SIPS_URL()         \n
+ *     NUTAG_SIP_PARSER()       \n
+ *     NUTAG_UICC()             \n
+ *     NUTAG_CERTIFICATE_DIR()  \n
+ *     and all tags listed in nua_set_params(), \n
+ *     and all relevant NTATAG_* are passed to NTA.
+ *
+ * @note
+ * From the @VERSION_1_12_2 all the nua_set_params() tags are processed. 
+ * Previously all nutags except NUTAG_SOA_NAME() and NUTAG_MEDIA_ENABLE()
+ * were ignored.
+ *
+ * @note
+ * Both the NUTAG_URL() and NUTAG_SIPS_URL() are used to pass arguments to
+ * nta_agent_add_tport(). 
+ *
+ * @par Events:
+ *     none
+ *
+ * @sa nua_shutdown(), nua_destroy(), nua_handle()
+ */
+nua_t *nua_create(su_root_t *root,
+		  nua_callback_f callback,
+		  nua_magic_t *magic,
+		  tag_type_t tag, tag_value_t value, ...)
+{
+  nua_t *nua = NULL;
+
+  enter;
+
+  if (callback == NULL)
+    return (void)(errno = EFAULT), NULL;
+
+  if (root == NULL)
+    return (void)(errno = EFAULT), NULL;
+
+  if ((nua = su_home_new(sizeof(*nua)))) {
+    ta_list ta;
+
+    su_home_threadsafe(nua->nua_home);
+    nua->nua_api_root = root;
+
+    ta_start(ta, tag, value);
+
+    nua->nua_args = tl_adup(nua->nua_home, ta_args(ta));
+
+    su_task_copy(nua->nua_client, su_root_task(root));
+
+    /* XXX: where to put this in the nua_server case? */
+#if HAVE_SMIME		/* Start NRC Boston */
+      nua->sm = sm_create();
+#endif                  /* End NRC Boston */
+
+#ifndef NUA_SERVER
+    if (su_clone_start(root,
+		       nua->nua_clone,
+		       nua,
+		       nua_stack_init,
+		       nua_stack_deinit) == SU_SUCCESS) {
+      su_task_copy(nua->nua_server, su_clone_task(nua->nua_clone));
+      nua->nua_callback = callback;
+      nua->nua_magic = magic;
+    }
+    else {
+      su_home_unref(nua->nua_home);
+      nua = NULL;
+    }
+#endif
+
+    ta_end(ta);
+  }
+
+  return nua;
+}
+
+/* nua_shutdown() is documented with nua_stack_shutdown() */
+
+void nua_shutdown(nua_t *nua)
+{
+  enter;
+
+  if (nua)
+    nua->nua_shutdown_started = 1;
+  nua_signal(nua, NULL, NULL, 1, nua_r_shutdown, 0, NULL, TAG_END());
+}
+
+/** Destroy the @nua stack.
+ *
+ * Before calling nua_destroy() the application 
+ * should call nua_shutdown and wait for successful #nua_r_shutdown event.
+ * Shuts down and destroys the @nua stack. Ongoing calls, registrations, 
+ * and subscriptions are left as they are.
+ *
+ * @param nua         Pointer to @nua stack object
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ *
+ * @sa nua_shutdown(), nua_create(), nua_handle_destroy(), nua_handle_unref()
+ */
+void nua_destroy(nua_t *nua)
+{
+  enter;
+
+  if (nua) {
+    if (!nua->nua_shutdown_final) {
+      SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n", nua));
+      assert(nua->nua_shutdown);
+      return;
+    }
+
+    su_task_deinit(nua->nua_server);
+    su_task_deinit(nua->nua_client);
+
+    su_clone_wait(nua->nua_api_root, nua->nua_clone);
+#if HAVE_SMIME		/* Start NRC Boston */
+    sm_destroy(nua->sm);
+#endif			/* End NRC Boston */
+    su_home_unref(nua->nua_home);
+  }
+}
+
+/** Fetch callback context from nua.
+ *
+ * @param nua         Pointer to @nua stack object
+ *
+ * @return Callback context pointer.
+ *
+ * @NEW_1_12_4.
+ */
+nua_magic_t *nua_magic(nua_t *nua)
+{
+  return nua ? nua->nua_magic : NULL;
+}
+
+/** Obtain default operation handle of the @nua stack object.
+ *
+ * A default operation can be used for operations where the 
+ * ultimate result is not important or can be discarded.
+ *
+ * @param nua         Pointer to @nua stack object
+ *
+ * @retval !=NULL Pointer to @nua operation handle
+ * @retval NULL   No default operation exists
+ *
+ * @par Related tags:
+ *    none
+ *
+ * @par Events:
+ *    none
+ *
+ */
+nua_handle_t *nua_default(nua_t *nua)
+{
+  return nua ? nua->nua_handles : NULL;
+}
+
+/** Create an operation handle 
+ *
+ * Allocates a new operation handle and associated storage.
+ *
+ * @param nua         Pointer to @nua stack object
+ * @param hmagic      Pointer to callback context
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @retval !=NULL  Pointer to operation handle
+ * @retval NULL    Creation failed
+ *
+ * @par Related tags:
+ *     Duplicates the provided tags for use with every operation. Note that
+ *     NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO(). 
+ *     And also vice versa, request-URI is taken from SIPTAG_TO() if there
+ *     is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
+ *     the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
+ *     @Timestamp.
+ *
+ * @par
+ *     nua_handle() accepts all the tags accepted by nua_set_hparams(), too.
+ *
+ *
+ * @par Events:
+ *     none
+ *
+ * @sa nua_handle_bind(), nua_handle_destroy(), nua_handle_ref(),
+ * nua_handle_unref().
+ */
+nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
+			 tag_type_t tag, tag_value_t value, ...)
+{
+  nua_handle_t *nh = NULL;
+
+  if (nua) {
+    ta_list ta;
+
+    ta_start(ta, tag, value);
+
+    nh = nh_create_handle(nua, hmagic, ta_args(ta));
+    
+    if (nh)
+      nh->nh_ref_by_user = 1;
+
+    ta_end(ta);
+  }
+
+  return nh;
+}
+
+/** Bind a callback context to an operation handle. 
+ *
+ * @param nh          Pointer to operation handle
+ * @param hmagic      Pointer to callback context
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
+{
+  enter;
+
+  if (NH_IS_VALID(nh))
+    nh->nh_magic = hmagic;
+}
+
+/** Fetch a callback context from an operation handle. 
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @return
+ *     Pointer to callback context
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ *
+ * @NEW_1_12_4.
+ */
+nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
+{
+  nua_hmagic_t *magic = NULL;
+  enter;
+
+  if (NH_IS_VALID(nh))
+    magic = nh->nh_magic;
+  
+  return magic;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Check if operation handle is used for INVITE
+ *
+ * Check if operation handle has been used with either outgoing or incoming
+ * INVITE request.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0 no invite in operation or operation handle is invalid 
+ * @retval 1 operation has invite 
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_invite(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_has_invite : 0;
+}
+
+/**Check if operation handle has active event subscriptions. 
+ *
+ * Active subscription can be established either by nua_subscribe() or
+ * nua_refer() calls.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0    no event subscriptions in operation or 
+ *              operation handle is invalid 
+ * @retval !=0  operation has event subscriptions
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_events(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_ds->ds_has_events : 0;
+}
+
+/** Check if operation handle has active registrations
+ *
+ * A registration is active when either when a REGISTER operation is going
+ * on or when it has successfully completed so that @nua stack is expected to
+ * refresh the registration in the future. Normally, a handle has active
+ * registration after nua_register() until nua_unregister() completes,
+ * unless the initial nua_register() had either expiration time of 0 or it
+ * had SIPTAG_CONTACT(NULL) as an argument.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0 no active registration in operation or 
+ *           operation handle is invalid
+ * @retval 1 operation has registration
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ *
+ * @sa nua_register(), nua_unregister(), #nua_r_register, #nua_r_unregister
+ */
+int nua_handle_has_registrations(nua_handle_t const *nh)
+{
+  return nh && nh->nh_ds->ds_has_register;
+}
+
+/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request. 
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0 no active subscription in operation or 
+ *           operation handle is invalid 
+ * @retval 1 operation has subscription.
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_subscribe(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_has_subscribe : 0;
+}
+
+/** Check if operation handle has been used with nua_register() or nua_unregister().
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0 no active register in operation or operation handle is invalid
+ * @retval 1 operation has been used with nua_register() or nua-unregister()
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_register(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_has_register : 0;
+}
+
+/** Check if operation handle has an active call 
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0 no active call in operation or operation handle is invalid
+ * @retval 1 operation has established call or pending call request.
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_active_call(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_active_call : 0;
+}
+
+/** Check if operation handle has a call on hold 
+ *
+ * Please note that this status is not affected by remote end putting 
+ * this end on hold. Remote end can put each media separately on hold 
+ * and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO() 
+ * and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval 0  if no call on hold in operation or operation handle is invalid 
+ * @retval 1  if operation has call on hold, for example nua_invite() or 
+ *            nua_update() has been called with SOATAG_HOLD() with non-NULL
+ *            argument.
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+int nua_handle_has_call_on_hold(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_hold_remote : 0;
+}
+
+/** Get the remote address (From/To header) of operation handle
+ *
+ * Remote address is used as To header in outgoing operations and 
+ * derived from From: header in incoming operations.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval NULL   no remote address for operation or operation handle invalid
+ * @retval !=NULL pointer to remote address for operation
+ *     
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_ds->ds_remote : NULL;
+}
+
+/** Get the local address (From/To header) of operation handle
+ *
+ * Local address is used as From header in outgoing operations and 
+ * derived from To: header in incoming operations.
+ *
+ * @param nh          Pointer to operation handle
+ *
+ * @retval NULL   no local address for operation or operation handle invalid
+ * @retval !=NULL pointer to local address for operation
+ *     
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     none
+ */
+sip_to_t const *nua_handle_local(nua_handle_t const *nh)
+{
+  return nh ? nh->nh_ds->ds_local : NULL;
+}
+
+/* Documented with nua_stack_set_params() */
+void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  ta_start(ta, tag, value);
+
+  enter;
+
+  nua_signal(nua, NULL, NULL, 0, nua_r_set_params, 0, NULL, ta_tags(ta));
+
+  ta_end(ta);
+}
+
+/* Documented with nua_stack_get_params() */
+void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  ta_start(ta, tag, value);
+
+  enter;
+
+  nua_signal(nua, NULL, NULL, 0, nua_r_get_params, 0, NULL, ta_tags(ta));
+
+  ta_end(ta);
+}
+
+#define NUA_SIGNAL(nh, event, tag, value) \
+  enter; \
+  if (NH_IS_VALID((nh))) { \
+    ta_list ta; \
+    ta_start(ta, tag, value); \
+    nua_signal((nh)->nh_nua, nh, NULL, 0, event, 0, NULL, ta_tags(ta));	\
+    ta_end(ta); \
+  } \
+  else { \
+    SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", nh));	\
+  }
+
+/* Documented with nua_stack_set_params() */
+void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_set_params, tag, value);
+}
+
+/* Documented with nua_stack_get_params() */
+void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_get_params, tag, value);
+}
+
+/* Documented with nua_stack_register() */
+void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_register, tag, value);
+}
+
+void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_unregister, tag, value);
+}
+
+/* Documented with nua_stack_invite() */
+void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_invite, tag, value);
+}
+
+/* Documented with nua_stack_ack() */
+void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_ack, tag, value);
+}
+
+/* Documented with nua_stack_bye() */
+void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_bye, tag, value);
+}
+
+/* Documented with nua_stack_cancel() */
+void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_cancel, tag, value);
+}
+
+/* Documented with nua_stack_options() */
+void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_options, tag, value);
+}
+
+/* Documented with nua_stack_message() */
+void nua_message(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_message, tag, value);
+}
+
+/* Documented with nua_stack_method() */
+void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_method, tag, value);
+}
+
+/** Send a chat message. 
+ *
+ * A chat channel can be established during call setup using "message" media. 
+ * An active chat channel is indicated using #nua_i_state event containing 
+ * SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with 
+ * nua_chat() function. Currently this is implemented using SIP MESSAGE 
+ * requests but in future MSRP (message session protocol) will replace it.
+*
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    SIPTAG_CONTENT_TYPE() \n
+ *    SIPTAG_PAYLOAD()      \n
+ *    SIPTAG_FROM()         \n
+ *    SIPTAG_TO()           \n
+ *    Use of other SIP tags is deprecated
+ *
+ * @par Events:
+ *    #nua_r_chat
+ */
+void nua_chat(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_chat, tag, value);
+}
+
+/* Documented with nua_stack_subscribe() */
+void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_subscribe, tag, value);
+}
+
+/* Documented with nua_stack_subscribe() */
+void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_unsubscribe, tag, value);
+}
+
+/* Documented with nua_stack_notify() */
+void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_notify, tag, value);
+}
+
+/* nua_r_notify is documented with process_response_to_notify() */
+
+/** Create an event server. 
+ *
+ * This function create an event server taking care of sending NOTIFY 
+ * requests and responding to further SUBSCRIBE requests. The event 
+ * server can accept multiple subscriptions from several sources and 
+ * takes care for distributing the notifications. Unlike other functions 
+ * this call only accepts the SIP tags listed below.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
+ *    SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR() \n
+ *    SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() \n
+ *    SIPTAG_ACCEPT() or SIPTAG_ACCEPT_STR() \n
+ *
+ * @par Events:
+ *    #nua_r_notify
+ */
+void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_notifier, tag, value);
+}
+
+/** Terminate an event server. 
+ *
+ * Terminate an event server with matching event and content type. The event
+ * server was created earlier with nua_notifier() function.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    SIPTAG_EVENT() \n
+ *    SIPTAG_CONTENT_TYPE() \n
+ *    SIPTAG_PAYLOAD() \n
+ *    NEATAG_REASON()
+ *
+ * @par Events:
+ *    #nua_r_terminate
+ *
+ * @sa nua_notifier(), nua_authorize().
+ */
+void nua_terminate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_terminate, tag, value);
+}
+
+/* Documented with nua_stack_refer() */
+void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_refer, tag, value);
+}
+
+/* Documented with nua_stack_publish() */
+void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_publish, tag, value);
+}
+
+/* Documented with nua_stack_publish() */
+void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_unpublish, tag, value);
+}
+
+/* Documented with nua_stack_info() */
+void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_info, tag, value);
+}
+
+/* Documented with nua_stack_prack() */
+void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_prack, tag, value);
+}
+
+/* Documented with nua_stack_update() */
+void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_update, tag, value);
+}
+
+/** Authenticate an operation.
+ *
+ * - 401 / 407 response with www-authenticate header/ proxy-authenticate header
+ * - application should provide stack with username&password for each realm
+ *   with NUTAG_AUTH() tag
+ * - restarts operation
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_AUTH()
+ *
+ * @par Events:
+ *    (any operation events)
+ */
+void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_authenticate, tag, value);
+}
+
+/** Authorize a subscriber.
+ *
+ * After creating a local presence server by nua_notifier(), an incoming
+ * SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
+ * identified with NEATAG_SUB() tag in the #nua_i_subscription event. 
+ * Application can either authorize the subscriber with
+ * NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
+ * NUTAG_SUBSTATE(#nua_substate_terminated).
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NEATAG_SUB() \n
+ *    NUTAG_SUBSTATE()
+ *
+ * @par Events:
+ *    #nua_i_subscription
+ *
+ * @sa nua_notifier(), nua_terminate()
+ */
+void nua_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_authorize, tag, value);
+}
+
+/*# Redirect an operation. */
+void nua_redirect(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  NUA_SIGNAL(nh, nua_r_redirect, tag, value);
+}
+
+/* Documented with nua_stack_respond() */
+
+void nua_respond(nua_handle_t *nh,
+		 int status, char const *phrase,
+		 tag_type_t tag, tag_value_t value,
+		 ...)
+{
+  enter;
+
+  if (NH_IS_VALID(nh)) {
+    ta_list ta;
+    ta_start(ta, tag, value);
+    nua_signal(nh->nh_nua, nh, NULL, 0, nua_r_respond,
+	       status, phrase, ta_tags(ta));
+    ta_end(ta);
+  }
+  else {
+    SU_DEBUG_1(("nua: respond with invalid handle %p\n", nh));
+  }
+}
+
+/** Destroy a handle 
+ *
+ * Terminate the protocol state associated with an operation handle. The
+ * stack discards resources and terminates the ongoing dialog usage,
+ * sessions and transactions associated with this handle. For example, calls
+ * are terminated with BYE request. Also, the reference count for the handle
+ * is also decremented.
+ *
+ * The handles use reference counting for memory management. In order to
+ * make it more convenient for programmer, nua_handle_destroy() decreases
+ * the reference count, too.
+ *
+ * @param nh              Pointer to operation handle
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    none
+ *
+ * @par Events:
+ *    none
+ *
+ * @sa nua_handle(), nua_handle_bind(), nua_handle_ref(), nua_handle_unref(),
+ * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_bye().
+ */
+void nua_handle_destroy(nua_handle_t *nh)
+{
+  enter;
+
+  if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
+    nh->nh_valid = NULL;	/* Events are no more delivered to appl. */
+    nua_signal(nh->nh_nua, nh, NULL, 1, nua_r_destroy, 0, NULL, TAG_END());
+  }
+}
+
+/*# Send a request to the protocol thread */
+void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
+		nua_event_t event,
+		int status, char const *phrase,
+		tag_type_t tag, tag_value_t value, ...)
+{
+  su_msg_r sumsg = SU_MSG_R_INIT;
+  size_t len, xtra, e_len, l_len = 0, l_xtra = 0;
+  ta_list ta;
+
+  if (nua == NULL || (nua->nua_shutdown_started && event != nua_r_shutdown))
+    return;
+
+  ta_start(ta, tag, value);
+
+  e_len = offsetof(event_t, e_tags);
+  len = tl_len(ta_args(ta));
+  xtra = tl_xtra(ta_args(ta), len);
+
+  if (su_msg_create(sumsg, nua->nua_server, su_task_null,
+		    nua_stack_signal,
+		    e_len + len + l_len + xtra + l_xtra) == 0) {
+    event_t *e = su_msg_data(sumsg);
+    tagi_t *t = e->e_tags;
+    void *b = (char *)t + len + l_len;
+
+    tagi_t *tend = (tagi_t *)b;
+    char *bend = (char *)b + xtra + l_xtra;
+
+    t = tl_dup(t, ta_args(ta), &b);
+
+    assert(tend == t); (void)tend; assert(b == bend); (void)bend;
+
+    e->e_always = always;
+    e->e_event = event;
+    e->e_nh = event == nua_r_destroy ? nh : nua_handle_ref(nh);
+    e->e_status = status;
+    e->e_phrase = phrase;
+
+    if (su_msg_send(sumsg) != 0)
+      nua_handle_unref(nh);
+  } 
+  else {
+    /* XXX  - we should return error code to application */
+    assert(ENOMEM == 0);
+  }
+
+  ta_end(ta);
+}
+
+/*# Receive event from protocol machine and hand it over to application */
+void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
+{
+  nua_t *nua;
+  nua_handle_t *nh = e->e_nh;
+
+  enter;
+
+  if (nh) {
+    if (!nh->nh_ref_by_user && nh->nh_valid) {
+      nh->nh_ref_by_user = 1;
+      nua_handle_ref(nh);
+    }
+  }
+
+  if (!nh || !nh->nh_valid) {	/* Handle has been destroyed */
+    if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+      SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+    }
+    if (e->e_msg)
+      msg_destroy(e->e_msg), e->e_msg = NULL;
+    return;
+  }
+
+  nua = nh->nh_nua; assert(nua);
+
+  if (e->e_event == nua_r_shutdown && e->e_status >= 200)
+    nua->nua_shutdown_final = 1;
+
+  if (!nua->nua_callback)
+    return;
+
+  if (NH_IS_DEFAULT(nh))
+    nh = NULL;
+
+  su_msg_save(nua->nua_current, sumsg);
+
+  e->e_nh = NULL;
+
+  nua->nua_callback(e->e_event, e->e_status, e->e_phrase,
+		    nua, nua->nua_magic,
+		    nh, nh ? nh->nh_magic : NULL,
+		    e->e_msg ? sip_object(e->e_msg) : NULL,
+		    e->e_tags);
+
+  if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+    SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+  }
+
+  if (!su_msg_is_non_null(nua->nua_current))
+    return;
+
+  if (e->e_msg)
+    msg_destroy(e->e_msg), e->e_msg = NULL;
+
+  su_msg_destroy(nua->nua_current);
+}
+
+/** Get current request message. @NEW_1_12_4. */
+msg_t *nua_current_request(nua_t const *nua)
+{
+  return nua && nua->nua_current ? su_msg_data(nua->nua_current)->e_msg : NULL;
+}
+
+/** Get request message from saved nua event. @NEW_1_12_4. */
+msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
+{
+  return saved ? su_msg_data(saved)->e_msg : NULL;
+}
+
+/** Save nua event and its arguments */
+int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
+{
+  if (nua && return_saved) {
+    su_msg_save(return_saved, nua->nua_current);
+    if (su_msg_is_non_null(return_saved)) {
+      /* Remove references to tasks */
+      su_msg_remove_refs(return_saved);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/** Get event data */
+nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
+{
+  return saved ? su_msg_data(saved) : NULL;
+}
+
+/** Destroy saved event */
+void nua_destroy_event(nua_saved_event_t saved[1])
+{
+  if (su_msg_is_non_null(saved)) {
+    event_t *e = su_msg_data(saved);
+    nua_handle_t *nh = e->e_nh;
+
+    if (e->e_msg)
+      msg_destroy(e->e_msg), e->e_msg = NULL;
+
+    if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+      SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+    }
+
+    su_msg_destroy(saved);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct nua_stack_handle_make_replaces_args {
+  sip_replaces_t *retval;
+  nua_handle_t *nh;
+  su_home_t *home;
+  int early_only;
+};
+
+static int nua_stack_handle_make_replaces_call(void *arg)
+{
+  struct nua_stack_handle_make_replaces_args *a = arg;
+
+  a->retval = nua_stack_handle_make_replaces(a->nh, a->home, a->early_only);
+
+  return 0;
+}
+
+
+/**Generate a @Replaces header for handle.
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, nua_refer(),
+ * #nua_i_refer, @ReferTo, nta_leg_make_replaces()
+ */
+sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh, 
+					 su_home_t *home,
+					 int early_only)
+{
+  if (nh && nh->nh_valid && nh->nh_nua) {
+    struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
+
+    if (su_task_execute(nh->nh_nua->nua_server, 
+			nua_stack_handle_make_replaces_call, (void *)&a, 
+			NULL) == 0) {
+      return a.retval;
+    }
+  }
+  return NULL;
+}
+
+struct nua_stack_handle_by_replaces_args {
+  nua_handle_t *retval;
+  nua_t *nua;
+  sip_replaces_t const *r;
+};
+
+static int nua_stack_handle_by_replaces_call(void *arg)
+{
+  struct nua_stack_handle_by_replaces_args *a = arg;
+
+  a->retval = nua_stack_handle_by_replaces(a->nua, a->r);
+
+  return 0;
+}
+
+/** Obtain a new reference to an existing handle based on @Replaces header.
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @note 
+ * You should release the reference with nua_handle_unref() when you are
+ * done with handle.
+ *
+ * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
+ * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
+ */
+nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
+{
+  if (nua) {
+    struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
+
+    if (su_task_execute(nua->nua_server, 
+			nua_stack_handle_by_replaces_call, (void *)&a, 
+			NULL) == 0) {
+      nua_handle_t *nh = a.retval;
+
+      if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
+	return nua_handle_ref(nh);
+    }
+  }
+  return NULL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2279 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "nua" - High-Level User Agent Module
+
+ at section nua_meta Module Meta Information
+
+The @b nua module contains the user-agent library taking care of basic
+SIP User Agent functions. Its functionality includes call management,
+messaging and event retrieval.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+- Pasi Rinne-Rahkola <Pasi.Rinne-Rahkola at nokia.com>
+- Kai Vehmanen <Kai.Vehmanen at nokia.com>
+- Martti Mela <Martti.Mela at nokia.com>
+
+ at section nua_overview Overview
+
+The NUA API gives the high-level application programmer transparent and
+full control to the SIP protocol engine below it. NUA provides the call
+semantics on top of existing transaction semantics found in
+<a href="../nta/index.html"><b>nta</b></a> module.
+API makes it possible to create different kind of User Agents,
+like terminals, gateways or MCUs.
+
+The @b nua engine hides many low-level signaling and media management
+aspects from the application programmer. It is possible to use different
+kind of media interfaces - even remote ones - in a fully transparent way.
+
+The application and the protocol engine within User Agent library can be
+run in separate threads. Communications from the protocol engine is
+conveyed through a callback function. The callback function is called
+within context of the application, so the application must provide
+appropriate handle to a #su_root_t object.
+
+ at section nua_concepts_user Sofia Concepts for NUA User
+
+ at subsection nua_intro Introduction
+
+The Sofia software suite is based on certain basic ideas and concepts that
+are used in all levels of Sofia software. Many of those are implemented in
+Sofia utility library (<a href="../su/index.html"><b>su</b></a>) providing
+unified interface to the most important OS services and utilities .
+
+The following sections contain descriptions of the concepts that a user of
+NUA library must understand to create a working application. The other
+utilities (in the SU library and other libraries of Sofia software suite)
+might also be useful for an application developer but one must be careful
+when using them because they might change the behavior of the Sofia
+software suite in a way that causes NUA library to work incorrectly.
+See [<a href="../su/index.html"><b>su</b></a>] for more detailed
+description of the SU services.
+
+ at subsection nua_root Event loop - root object
+
+The NUA uses the reactor pattern (also known as dispatcher pattern and
+notifier pattern) for event driven systems (see [Using Design Patterns
+to Develop Reusable Object-oriented Communication Software, D.C. Schmidt,
+CACM October '95, 38(10): 65-74]). Sofia uses a task as basic execution
+unit for the programming model. According to the model, the program can
+ask that the event loop invokes a callback function when a certain event
+occurs. Such events include I/O activity, timers or a asynchronously
+delivered messages from other task.
+
+The root object is a handle representing the task in the application.
+Another way of seeing the same thing is that the root object represents
+the main event loop of the task. Through the root object the task code
+can access its context information (magic) and thread-synchronization
+features like wait objects, timers, and messages.
+
+An application using NUA services must create a root object and the
+callback routine to handle events. The root object is created with
+su_root_create() function and the callback routine is registered with
+nua_create() function.
+
+Root object has type #su_root_t.
+
+See documentation of <su_wait.h> and <su_root.c> for more information
+of root object.
+
+See section #nua_event_e for more information of the callback function.
+
+ at subsection nua_magic Magic
+
+The magic is a term used for the context pointer that can be bound
+to various objects in Sofia stack (for example root object and operation
+handle) by the application code. This context pointer is passed back
+to the application code when a registered callback function is called by
+the main event loop. The Sofia stack retains the context information between
+calls to the callback function. An application can use the context information
+to store any information it needs for processing the events.
+
+ at subsection nua_memmgmt Memory Handling
+
+The home-based memory management is useful when a lot of memory blocks are
+allocated for given task. The allocations are done via the memory home,
+which keeps a reference to each allocated memory block. When the memory
+home is then freed, it will free all memory blocks to which it has
+reference. This simplifies application logic because application code does
+not need to keep track of the allocated memory and free every allocated block
+separately.
+
+An application using NUA services can use the memory management services
+provided by the SU library but it is not mandatory.
+
+See documentation of <su_alloc.h> for more information of memory management
+services.
+
+ at subsection nua_tags Tags
+
+Tagging is the mechanism used in Sofia software for packing parameters to
+functions. It enables passing a variable number of parameters having
+non-fixed types. For an application programmer the tagging is visible as
+macros that are used to encapsulate the passed parameters. When evaluated a
+tagging macro creates a structure that contains a tag (telling what is the
+type of a parameter) and a value (pointer to opaque data). By checking the
+tag the layers of Sofia software check whether they can handle the parameter
+or should it just be passed to lower layers for processing.
+
+There are some tags with special meaning:
+- TAG_NULL() (synonymous to TAG_END()) end of tag list
+- TAG_SKIP()  empty tag item
+- TAG_NEXT()  tag item pointing to another tag list, ends the current tag list
+- TAG_ANY() filter tag accepting any tag
+- TAG_IF() conditional inclusion of tag item
+
+The NUA functions can be called with a list of tagged values if they have
+following parameters at the end of parameter list:
+
+ at code
+tag_type_t   tag,
+tag_value_t  value,
+...);
+ at endcode
+
+The last tagged value on the parameter list must be TAG_NULL()
+(or TAG_END(), synonym for TAG_NULL()).
+
+Every tag has two versions: \n
+NUTAG_<tagname> \n
+which takes a value parameter and \n
+NUTAG_<tagname>_REF \n
+which takes a reference parameter. The latter is used with
+tl_gets() function to retrieve tag values from tag list.
+
+For SIP headers there exists also additional
+version of tags: \n
+SIPTAG_<tagname>_STR \n
+This tag version takes a C-language character string as parameter.
+The corresponding tag without _STR suffix takes a parsed value structure
+as parameter.
+
+The following is an example of call to NUA function containing tagged values:
+ at code
+nua_unregister(op->op_handle,
+               TAG_IF(use_registrar, NUTAG_REGISTRAR(registrar)),
+               SIPTAG_CONTACT_STR("*"),
+               SIPTAG_EXPIRES_STR("0"),
+               TAG_NULL());
+ at endcode
+
+An application using NUA services must use tagged arguments for passing the
+parameters to functions. See nua_invite() for discussion on how a SIP
+message is constructed from the tags.
+
+See documentation of <su_tag.h> for more information of tags and the
+module-specific documentation of each Sofia module for information of
+tags specific for that module.
+
+ at subsection nua_debugandlogging Debugging and Logging
+
+The modules of Sofia stack contain configurable debugging and logging
+functionality based on the services defined in <su_log.h>. The debugging
+and logging details (for example level of details on output and output
+file name) can be configured by environment variables, directives in
+configuration files and compilation directives in the source files.
+
+Examples of useful directives/ environment variables are:
+- #SOFIA_DEBUG	Default debug level (0..9)
+- #NUA_DEBUG	NUA debug level (0..9)
+- #NTA_DEBUG	Transaction engine debug level (0..9)
+- #TPORT_DEBUG	Transport event debug level (0..9)
+- #TPORT_LOG	If set, print out all parsed SIP messages on transport layer
+- #TPORT_DUMP	Filename for dumping unparsed messages from transport
+
+The defined debug output levels are:
+- 0 fatal errors, panic
+- 1 critical errors, minimal progress at subsystem level
+- 2 non-critical errors
+- 3 warnings, progress messages
+- 5 signaling protocol actions (incoming packets, ...)
+- 7 media protocol actions (incoming packets, ...)
+- 9 entering/exiting functions, very verbatim progress
+
+An application using NUA services can also use the debugging and
+logging services provided by the Sofia stack but it is not mandatory.
+
+See documentation of <su_log.h> for more information of debugging and
+logging services.
+
+ at section nua_concepts NUA Concepts
+
+ at subsection nua_stackobject NUA Stack Object
+
+Stack object represents an instance of SIP stack and media engine. It
+contains reference to root object of that stack, user-agent-specific
+settings, and reference to the SIP transaction engine, for example.
+
+A NUA stack object is created by nua_create() function and deleted by
+nua_destroy() function. The nua_shutdown() function is used to gracefully
+release active the sessions by @b nua engine.
+
+NUA stack object has type nua_t.
+
+ at subsection nua_operationhandle NUA Operation Handle
+
+Operation handle represents an abstract SIP call/session. It contains
+information of SIP dialog and media session, and state machine that
+takes care of the call, high-level SDP offer-answer protocol, registration,
+subscriptions, publications and simple SIP transactions. An operation
+handle may contain list of tags used when SIP messages are created by
+NUA (e.g. From and To headers).
+
+An operation handle is created explicitly by the application using NUA
+for sending messages (function nua_handle()) and by stack for incoming
+calls/sessions (starting with INVITE or MESSAGE). The handle is destroyed
+by the application using NUA (function nua_handle_destroy()).
+
+Indication and response events are associated with an operation handle.
+
+NUA operation handle has type nua_handle_t.
+
+ at subsection nua_stacktread Stack Thread and Message Passing Concepts
+
+The stack thread is a separate thread from application that provides the
+real-time protocol stack operations so that application thread can for
+example block or redraw UI as it likes.
+
+The communication between stack thread and application thread is asynchronous.
+Most of the NUA API functions cause a send of a message to the stack thread
+for processing and similarly when something happens in the stack thread it
+sends a message to the application thread. The messages to the application
+thread are delivered as invokes of the application callback function when
+the application calls su_root_run() or su_root_step() function.
+
+ at subsection nua_sip_message SIP Message and Header Manipulation
+
+SIP messages are manipulated with typesafe SIPTAG_ tags. There are
+three versions of each SIP tag:
+- SIPTAG_<tagname>() takes a parsed value as parameter.
+- SIPTAG_<tagname>_STR() takes an unparsed string as parameter.
+- SIPTAG_<tagname>_REF() takes a reference as parameter, is used
+        with tl_gets() function to retrieve tag values from tag list.
+- SIPTAG_<tagname>__STR_REF() takes a reference as parameter, is used
+        with tl_gets() function to retrieve string tag values from tag list.
+
+For example a header named "Example" would have tags names SIPTAG_EXAMPLE(),
+SIPTAG_EXAMPLE_STR(), and SIPTAG_EXAMPLE_REF().
+
+When tags are used in NUA calls the corresponding headers are added to
+the message. In case the header can be present only once in a message
+and there already exists a value for the header the value given by
+tag replaces the existing header value. Passing tag value NULL has no
+effect on headers. Passing tag value (void *)-1 removes corresponding
+headers from the message.
+
+For example:
+
+- sending a SUBSCRIBE with @b Event: header and two @b Accept: headers:
+
+ at code
+	nua_subscribe(nh,
+                      SIPTAG_EVENT_STR("presence"),
+                      SIPTAG_ACCEPT(accept1),
+                      SIPTAG_ACCEPT(accept2),
+                      TAG_END());
+ at endcode
+
+- fetching tag values when processing nua_r_subscribe event:
+
+ at code
+           sip_accept_t *ac = NULL;
+           sip_event_t  *o  = NULL;
+
+           tl_gets(tl,
+                   SIPTAG_EVENT_REF(o),   /* _REF takes a reference! */
+                   SIPTAG_ACCEPT_REF(ac),
+                   TAG_END());
+ at endcode
+
+ at section nua_tutorial SIP/NUA tutorial
+
+This section describes basic usage scenarios of NUA/Sofia stack using
+message sequence charts.
+
+ at subsection nua_outgoingcall Outgoing Call
+
+ at image latex SIP_outgoing_call.eps
+
+ at image html SIP_outgoing_call.gif
+
+
+ at subsection nua_incomingcall Incoming Call
+
+ at image latex SIP_incoming_call.eps
+
+ at image html SIP_incoming_call.gif
+
+ at subsection nua_basicoutgoingoperation Basic Outgoing Operation
+
+ at image latex SIP_basic_outgoing_operation.eps
+
+ at image html SIP_basic_outgoing_operation.gif
+
+
+ at subsection nua_basicincomingoperation Basic Incoming Operation
+
+ at image latex SIP_basic_incoming_operation.eps
+
+ at image html SIP_basic_incoming_operation.gif
+
+
+ at subsection nua_outgoingoperationwithauth Outgoing Operation with Authentication
+
+ at image latex SIP_outgoing_operation_with_auth.eps
+
+ at image html SIP_outgoing_operation_with_auth.gif
+
+
+ at section nua_simpleapplication Simple Application
+
+The following sections will present code examples from a simple application
+that uses services of NUA. The example is not complete but should present
+all relevant details of the basic use of NUA.
+
+The source distribution of Sofia stack contains in directory nua an example
+application nua_cli.c that can be studied for more complete example.
+
+ at subsection nua_datastructures Data Structures & Defines
+
+An application using services of NUA normally defines data areas that are
+used to store context information (i.e., "magic"). The types of pointers to
+these context information areas are passed to NUA by defines.
+
+ at code
+/* type for application context data */
+typedef struct application application;
+#define NUA_MAGIC_T   application
+
+/* type for operation context data */
+typedef union oper_ctx_u oper_ctx_t;
+#define NUA_HMAGIC_T  oper_ctx_t
+ at endcode
+
+The information area contents themselves can be defined as
+C structures or unions:
+
+ at code
+/* example of application context information structure */
+typedef struct application
+{
+  su_home_t       home[1];  /* memory home */
+  su_root_t      *root;     /* root object */
+  nua_t          *nua;      /* NUA stack object */
+
+  /* other data as needed ... */
+} application;
+
+/* Example of operation handle context information structure */
+typedef union operation
+{
+  nua_handle_t    *handle;  /* operation handle /
+
+  struct
+  {
+    nua_handle_t  *handle;  /* operation handle /
+    ...                     /* call-related information */
+  } call;
+
+  struct
+  {
+    nua_handle_t  *handle;  /* operation handle /
+    ...                     /* subscription-related information */
+  } subscription;
+
+  /* other data as needed ... */
+
+} operation;
+ at endcode
+
+NUA stack object and handle are opaque to the application programmer.
+Likewise, the application context is completely opaque to the NUA stack
+module. NUA functions are passed a pointer, and that pointer is then
+given back to the application within the callback parameters. In this
+case the application context information structure is also used to
+store a root object and memory home for memory handling. The application
+context information also contains the NUA stack object information.
+
+ at subsection nua_initanddeinit Initialization and deinitialization
+
+The following code is an example of application function that initializes
+the system, enters the main loop for processing the messages, and, after
+message processing is ended, deinitalizes the system.
+
+If the application is not just responding to incoming SIP messages there must
+also be means to send messages to NUA. This can be handled for example by
+having a separate thread that calls NUA functions to send messages or by
+having a socket connection to the application for sending commands to the
+application (see documentation of su_wait_create() and su_root_register()).
+
+ at code
+/* Application context structure */
+application appl[1] = {{{{(sizeof appl)}}}};
+
+/* initialize system utilities */
+su_init();
+
+/* initialize memory handling */
+su_home_init(appl->home);
+
+/* initialize root object */
+appl->root = su_root_create(appl);
+
+if (appl->root != NULL) {
+  /* create NUA stack */
+  appl->nua = nua_create(appl->root,
+                             app_callback,
+                             appl,
+                             /* tags as necessary ...*/
+                             TAG_NULL());
+
+  if (appl->nua != NULL) {
+    /* set necessary parameters */
+    nua_set_params(appl->nua,
+                    /* tags as necessary ... */
+                    TAG_NULL());
+
+    /* enter main loop for processing of messages */
+    su_root_run(appl->root);
+
+    /* destroy NUA stack */
+    nua_destroy(appl->nua);
+  }
+
+  /* deinit root object */
+  su_root_destroy(appl->root);
+  appl->root = NULL;
+}
+
+/* deinitialize memory handling */
+su_home_deinit(appl->home);
+
+/* deinitialize system utilities */
+su_deinit();
+ at endcode
+
+ at subsection nua_handlingevents Handling events
+
+Handling of the events coming from NUA stack is done in the callback
+function that is registered for NUA stack with the nua_create() function
+when the application is initialized. The content of callback function is
+in its simplest form just a switch/case statement that dispatches the
+incoming events for processing to separate functions.
+
+ at code
+void app_callback(nua_event_t   event,
+                  int           status,
+                  char const   *phrase,
+                  nua_t        *nua,
+                  nua_magic_t  *magic,
+                  nua_handle_t *nh,
+                  nua_hmagic_t *hmagic,
+                  sip_t const  *sip,
+                  tagi_t        tags[])
+{
+  switch (event) {
+  case nua_i_invite:
+    app_i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
+    break;
+
+  case nua_r_invite:
+    app_r_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
+    break;
+
+  /* and so on ... */
+
+  default:
+    /* unknown event -> print out error message */
+    if (status > 100) {
+      printf("unknown event %d: %03d %s\n",
+             event,
+             status,
+             phrase);
+    }
+    else {
+      printf("unknown event %d\n", event);
+    }
+    tl_print(stdout, "", tags);
+    break;
+  }
+} /* app_callback */
+ at endcode
+
+ at subsection nua_placeacall Place a call
+
+The following three functions show an example of how a basic SIP
+call is created.
+
+The place_a_call() function creates an operation handle and invokes the
+SIP INVITE method.
+
+ at code
+operation *place_a_call(char const *name, url_t const *url)
+{
+  operation *op;
+  sip_to_t *to;
+
+  /* create operation context information */
+  op = su_zalloc(appl->home, (sizeof *op));
+  if (!op)
+     return NULL;
+
+  /* Destination address */
+  to = sip_to_create(NULL, url);
+  if (!to)
+     return NULL;
+
+  to->a_display = name;
+
+  /* create operation handle */
+  op->handle = nua_handle(appl->nua, op, SIPTAG_TO(to), TAG_END());
+
+  if (op->handle == NULL) {
+    printf("cannot create operation handle\n");
+    return NULL;
+  }
+
+  nua_invite(op->handle,
+              /* other tags as needed ... */
+              TAG_END());
+
+} /* place_a_call */
+ at endcode
+
+The app_r_invite() function is called by callback function when response to
+INVITE message is received. Here it is assumed that automatic acknowledge
+is not enabled so ACK response must be sent explicitly.
+
+ at code
+void app_r_invite(int           status,
+                  char const   *phrase,
+                  nua_t        *nua,
+                  nua_magic_t  *magic,
+                  nua_handle_t *nh,
+                  nua_hmagic_t *hmagic,
+                  sip_t const  *sip,
+                  tagi_t        tags[])
+{
+  if (status == 200) {
+    nua_ack(nh, TAG_END());
+  }
+  else {
+    printf("response to INVITE: %03d %s\n", status, phrase);
+  }
+} /* app_r_invite */
+ at endcode
+
+The nua_i_state event is sent (and app_i_state() function called by callback
+function) when the call state changes (see @ref nua_uac_call_model
+"client-side call model").
+
+ at code
+void app_i_state(int           status,
+		 char const   *phrase,
+		 nua_t        *nua,
+		 nua_magic_t  *magic,
+		 nua_handle_t *nh,
+		 nua_hmagic_t *hmagic,
+		 sip_t const  *sip,
+		 tagi_t        tags[])
+{
+  nua_callstate_t state = nua_callstate_init;
+
+  tl_gets(tags,
+          NUTAG_CALLSTATE_REF(state),
+          NUTAG__REF(state),
+
+  
+    state = (nua_callstate_t)t->t_value;
+
+  printf("call %s\n", nua_callstate_name(state));
+
+} /* app_i_state */
+ at endcode
+
+ at subsection nua_receiveacall Receive a call
+
+The app_i_invite() function is called by callback function when incoming
+INVITE message is received. This example assumes that autoanswer is
+not enabled so the response must be sent explicitly.
+
+ at code
+void app_i_invite(int           status,
+                  char const   *phrase,
+                  nua_t        *nua,
+                  nua_magic_t  *magic,
+                  nua_handle_t *nh,
+                  nua_hmagic_t *hmagic,
+                  sip_t const  *sip,
+                  tagi_t        tags[])
+{
+  printf("incoming call\n");
+
+  nua_respond(nh, 200, "OK", SOA_USER_SDP(magic->sdp), TAG_END());
+
+} /* app_i_invite */
+ at endcode
+
+The app_i_state() function is called by the callback function when call has
+been successfully set up and the media has been activated.
+
+ at code
+void app_i_active(int           status,
+                   char const   *phrase,
+                   nua_t        *nua,
+                   nua_magic_t  *magic,
+                   nua_handle_t *nh,
+                   nua_hmagic_t *hmagic,
+                   sip_t const  *sip,
+                   tagi_t        tags[])
+{
+  printf("call active\n");
+
+} /* app_i_active */
+ at endcode
+
+ at subsection nua_terminatingcall Terminating a call
+
+The following three functions show an example of how a basic SIP
+call is terminated.
+
+The terminate_call() function sends the SIP BYE message.
+
+ at code
+void terminate_call(void)
+{
+  nua_bye(op->handle, TAG_END());
+
+} /* terminate call */
+ at endcode
+
+The app_r_bye() function is called by the callback function when answer to
+the BYE message is received. The function destroys the call handle and
+releases the memory allocated to operation context information.
+
+ at code
+void app_r_bye(int           status,
+               char const   *phrase,
+               nua_t        *nua,
+               nua_magic_t  *magic,
+               nua_handle_t *nh,
+               nua_hmagic_t *hmagic,
+               sip_t const  *sip,
+               tagi_t        tags[])
+{
+  if (status < 200)
+     return;
+
+  printf("call released\n");
+
+  /* release operation handle */
+  nua_handle_destroy(hmagic->handle);
+  op->handle = NULL;
+
+  /* release operation context information */
+  su_free(appl->home, hmagic);
+
+} /* app_r_bye */
+ at endcode
+
+The app_i_bye() function is called by the callback function when an incoming
+BYE message is received. The function destroys the call handle and releases
+the memory allocated to operation context information.
+
+ at code
+void app_i_bye(int           status,
+               char const   *phrase,
+               nua_t        *nua,
+               nua_magic_t  *magic,
+               nua_handle_t *nh,
+               nua_hmagic_t *hmagic,
+               sip_t const  *sip,
+               tagi_t        tags[])
+{
+  printf("call released\n");
+
+  /* release operation handle */
+  nua_handle_destroy(hmagic->handle);
+  op->handle = NULL;
+
+  /* release operation context information */
+  su_free(appl->home, hmagic);
+
+} /* app_i_bye */
+ at endcode
+
+ at subsection nua_sendamessage Sending a message
+
+The following functions show an example of how a SIP MESSAGE is sent.
+
+The send_message() function sends the SIP MESSAGE.
+
+ at code
+void send_message(void)
+{
+  op_t *op;
+
+  /* create operation context information */
+  op = su_zalloc(appl->home, sizeof(op_t));
+  if (op = NULL) {
+    printf("cannot create operation context information\n");
+    return;
+  }
+
+  /* how we create destination_address? */
+
+  /* create operation handle */
+  op->handle = nua_handle(appl->nua,
+                                op,
+                                NUTAG_URL(destination_address),
+                                TAG_END());
+
+  if (op->handle == NULL) {
+    printf("cannot create operation handle\n");
+    return;
+  }
+
+  /* send MESSAGE */
+  nua_message(op->handle,
+               SIPTAG_CONTENT_TYPE_STR("text/plain"),
+               SIPTAG_PAYLOAD_STR("Hello, world!"),
+               /* other tags as needed ... */
+               TAG_END());
+
+} /* send_message */
+ at endcode
+
+The app_r_message() function is called by the callback function when
+answer to the MESSAGE is received.
+
+ at code
+void app_r_message(int           status,
+                    char const   *phrase,
+                    nua_t        *nua,
+                    nua_magic_t  *magic,
+                    nua_handle_t *nh,
+                    nua_hmagic_t *hmagic,
+                    sip_t const  *sip,
+                    tagi_t        tags[])
+{
+  printf("response to MESSAGE: %03d %s\n", status, phrase);
+} /* app_r_message */
+ at endcode
+
+ at subsection nua_receivemessage Receiving a message
+
+The following function shows an example of how a SIP MESSAGE is received.
+
+The app_i_message() function is called by the callback function when
+a SIP MESSAGE is received.
+
+ at code
+void app_i_message(int           status,
+                   char const   *phrase,
+                   nua_t        *nua,
+                   nua_magic_t  *magic,
+                   nua_handle_t *nh,
+                   nua_hmagic_t *hmagic,
+                   sip_t const  *sip,
+                   tagi_t        tags[])
+{
+  printf("received MESSAGE: %03d %s\n", status, phrase);
+
+  printf("From: %s%s" URL_PRINT_FORMAT "\n",
+         sip->sip_from->a_display ? sip->sip_from->a_display : "",
+         sip->sip_from->a_display ? " " : "",
+         URL_PRINT_ARGS(sip->sip_from->a_url));
+
+  if (sip->sip_subject) {
+    printf("Subject: %s\n", sip->sip_subject->g_value);
+  }
+
+  if (sip->sip_payload) {
+    fwrite(sip->sip_payload->pl_data, sip->sip_payload->pl_len, 1, stdout);
+    fputs("\n", stdout);
+  }
+} /* app_i_message */
+ at endcode
+
+ at subsection nua_notifier Creating a Presence Server
+
+ at code
+
+...
+  application_t *app;
+  operation_t   *oper;
+
+...
+
+  oper->app = app;
+
+
+  app->nua = nua_create(ssip->s_root,
+                        app_callback,
+                        app,
+                        TAG_NULL());
+...
+
+  oper->handle = nua_handle(app->nua, app,
+                            NUTAG_URL(to->a_url),
+                            SIPTAG_TO(to),
+                            ta_tags(ta));
+...
+
+    nua_notifier(oper->handle,
+		 SIPTAG_EXPIRES_STR("3600"),
+		 SIPTAG_EVENT_STR("presence"),
+		 SIPTAG_CONTENT_TYPE_STR("application/pidf-partial+xml"),
+		 NUTAG_SUBSTATE(nua_substate_pending),
+		 TAG_END());
+ at endcode
+
+After the nua_notifier object -- the presence server -- is created, an
+event nua_r_notifier is returned. Status and phrase values of the
+app_callback function indicate the success of the creation.
+
+Authorization of an incoming subscription (to the local presence
+server) can be handled in the callback function.
+
+ at code
+void app_callback(nua_event_t event,
+                  int status, char const *phrase,
+                  nua_t *nua, application_t *app,
+                  nua_handle_t *nh, oper_t *op,
+                  sip_t const *sip, tagi_t tags[])
+{
+  nea_sub_t *subscriber = NULL;
+
+  switch (event) {
+  case nua_i_subscription:
+    tl_gets(tags,
+	    NEATAG_SUB_REF(subscriber),
+	    TAG_END());
+
+
+    nua_authorize(nua_substate_active);
+
+
+  default:
+    break;
+}
+
+
+ at endcode
+
+
+ at subsection nua_shutting_down Shutdown
+
+The following functions show an example of how application terminates
+the NUA stack.
+
+The shutdown() function starts the termination.
+
+ at code
+void shutdown(void)
+{
+  nua_shutdown(appl->nua);
+
+} /* shutdown */
+ at endcode
+
+The app_r_shutdown() function is called by the callback function when NUA
+stack termination is either finished or failed.
+
+ at code
+void app_r_shutdown(int           status,
+                    char const   *phrase,
+                    nua_t        *nua,
+                    nua_magic_t  *magic,
+                    nua_handle_t *nh,
+                    nua_hmagic_t *hmagic,
+                    sip_t const  *sip,
+                    tagi_t        tags[])
+{
+  printf("shutdown: %d %s\n", status, phrase);
+
+  if (status < 200) {
+    /* shutdown in progress -> return */
+    return;
+  }
+
+  /* end the event loop. su_root_run() will return */
+  su_root_break(magic->root);
+
+} /* app_r_shutdown */
+ at endcode
+
+*/
+
+/** @page nua_call_model NUA Call Model
+
+The NUA call follows a relatively simple state model presented below. The call
+model is used to present changes in call: when media starts to flow, when
+call is considered established, when call is terminated.
+
+In the figure below, a simplified state diagram for a SIP call is presented.
+After the call state has changes the application will receive an
+#nua_i_state event indicating the change. The states in NUA call model are
+represented by @e enum #nua_callstate, and the current value of state is
+included as the tag NUTAG_CALLSTATE() with the #nua_i_state event.
+
+The @RFC3264 SDP Offer/Answer negotiation status is also included in the
+#nua_i_state event. The negotiation status includes the local SDP (in
+SOATAG_LOCAL_SDP()) sent and flags indicating whether the local SDP was an
+offer or answer (NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT()). Likewise, the
+received remote SDP is included in tag SOATAG_REMOTE_SDP() and flags
+indicating whether the remote SDP was an offer or an answer in tags
+NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV(). SOATAG_ACTIVE_AUDIO() and
+SOATAG_ACTIVE_VIDEO() are informational tags used to indicate what is the
+status of these media.
+
+The #nua_i_state event is not sent, however, if the change is invoked by 
+application calling API functions like nua_bye() and there is no change in
+SDP offer/answer status.
+
+ at code
+                    +---------------+
+             +------|     INIT      |-----+
+    INVITE/- |      +---------------+     | INVITE/100
+             V                            |
+       +------------+               +------------+
+  +----|  CALLING   |--+        +---|  RECEIVED  |--+
+  |    +------------+  |        |   +------------+  |
+  |          |         |        |         |         |
+  |          | 18X/-   |        |         | -/18X   |
+  |          V         |        |         V         |
+  |    +------------+  |        |   +------------+  |
+  |<---| PROCEEDING |  |        |   |   EARLY    |->|
+  |    +------------+  |        |   +------------+  |  -/[3456]XX
+  |          |         |        |         |         |
+  |          | 2XX/-   | 2XX/-  | -/2XX   | -/2XX   |    or
+  |          V         |        |         V         |
+  |    + - - - - - -+  |        |   +------------+  |  CANCEL/200,487
+  |    : COMPLETING :<-+        +-->|  COMPLETE  |  |
+  |    + - - - - - -+               +------------+  |
+  |          |                            |         |
+  |          | -/ACK                ACK/- |         |
+  |          |                            |         |
+  |          |                            |         |
+  |          |      +---------------+     |         |
+  |          +----->|     READY     |<----+         |
+  |                 +---------------+               |
+  |                   |           |                 |
+  |          BYE/200  |           | -/BYE           |
+  |                   |           |                 |
+  |                   |           V                 |
+  |                   |   +--------------+          |
+  | [3456]XX/ACK      |   | TERMINATING  |          |
+  |                   |   +--------------+          |
+  |                   |           |                 |
+  |                   |           | [23456]XX/-     |
+  |                   V           V                 |
+  |                 +---------------+               |
+  +---------------->|  TERMINATED   |<--------------+
+                    +---------------+
+ at endcode
+
+The labels "input/output" along each transition indicates SIP messages
+received from and sent to network, for instance, state transition
+"INVITE/100" occurs when a SIP @b INVITE request is received, and it is
+immediately returned a 100 (<i>Trying</i>) response. Label "2XX" means any
+200-series response, e.g., <i>200 OK</i> or <i>202 Accepted</i>). Notation
+"[3456]XX" means any final error response in 300, 400, 500, or 600
+series. Label "18X" means any provisional response from 101 to 199, most
+typically 180 (<i>Ringing</i>) or 183 (<i>Session Progress</i>).
+
+ at section nua_uac_call_model Detailed Client Call Model
+
+The detailed call model at client side is presented below. This model does
+not include the extensions like @b 100rel or @b UPDATE.
+
+ at code
+            +------------+
+            |    INIT    |
+            +------------+
+                  |
+                 (1) nua_invite/INVITE
+                  |
+                  V
+            +------------+
+            |            |-----------------------------(6a)-----+
+            |            |----+  nua_cancel                     |
+     +------|  CALLING   |  (7a)  /CANCEL                       |
+     |      |            |<---+                                 |
+     |      |            |----------------------+               |
+     |      +------------+                      |               |
+     |            |                           (8a) nua_bye      |
+     |           (2) 18X/-                      |   /CANCEL     |
+     |            |                             |               |
+     |            V                             |               |
+     |      +------------+                      |               |
+     |      |            |-----------------------------(6b)---->|
+     |      |            |----+  nua_cancel     |               |
+     |      | PROCEEDING |  (7b)  /CANCEL       |               |
+     |      |            |<---+                 |               |
+     |      |            |----------------------+               |
+     |      +------------+                      |               |
+     |            |                             |               |
+   (3a) 2XX/-   (3b) 2XX/-                      |              (6) [3456]XX/ACK
+     |            |                             |               |
+     |            V                             |               |
+     |      + - - - - - -+                      |               |
+     +----->:            :                      |               |
+            : COMPLETING :-------+              |               |
+     + - - -:            :       |              |               |
+     :      + - - - - - -+       |              |               |
+     :     	  |         	 |              |               |
+     :<auto_ack>  |         	 |              |               |
+     :or nua_ack  | <auto_ack>   |              |               |
+     :and media   | or nua_ack   | nua_bye      |               |
+    (5) error 	 (4) /ACK   	(9) /ACK+BYE  (8b) nua_bye/BYE  |
+     : /ACK+BYE	  |         	 |              |               |
+     :     	  V         	 |              V               |
+     :      +------------+       |       +-------------+        |
+     :      |            |       |       |             |        |
+     :      |   READY    |       |       | TERMINATING*|        |
+     :      |            |       |       |             |        |
+     :      +------------+       |       +-------------+        |
+     :                           |        |	     |		|
+     :                           |      (10) 2XX   (11) 3XX 4XX |
+     :      +-------------+      |        |   /BYE   |	5XX 6XX |
+     :      |             |      V        V          |   /-     |
+     + - - >| TERMINATING |<-------------------------+	        |
+            |             |                                     |
+            +-------------+			      	        |
+                  |        			      		|
+                (12) [23456]XX to BYE/-		      		|
+                  |             		      		|
+                  V             		      		|
+            +------------+             		      		|
+            | TERMINATED |<-------------------------------------+
+            +------------+
+ at endcode
+
+The detailed description of state transitions on the client side is as
+follows:
+
+<table>
+<tr><th>#</th>
+    <th>Previous state</th>
+    <th>Input</th>
+    <th>Output</th>
+    <th>Next state</th>
+    <th>Offer/ Answer</th>
+    <th align="left">Description</th>
+</tr>
+<tr><td>C1</td>			<!-- transition -->
+    <td>init</td>		<!-- previous state -->
+    <td>nua_invite()</td>	<!-- input -->
+    <td>INVITE</td>		<!-- output -->
+    <td>calling</td>		<!-- next state -->
+    <td>Generate offer</td>	<!-- offer/answer -->
+    <td>
+   Client application starts call be invoking nua_invite(). By default, stack runs
+   the initial offer/answer step and sends @b INVITE request with the SDP
+   offer.
+</td></tr>
+<tr><td>C2</td>
+    <td>calling</td><td>18X</td><td>-</td><td>proceeding</td>
+    <td>(Save answer)</td>
+  <td>
+   Stack receives a 18X response (a provisional response between 101
+   and 199). It establishes an early dialog with server.  If the provisional
+   response contains an SDP answer, a session with early media is
+   established. The caller can be listen to, for instance, ring tone or
+   announcements about call progress using the early media session.
+</td></tr>
+<tr><td>C3a</td>
+    <td>calling</td><td rowspan="2">2XX</td>
+    <td rowspan="2">-</td><td rowspan="2">completing</td>
+    <td rowspan="2">Save answer</td>
+  <td rowspan="2">
+   Client receives a 2XX response (usually <i>200 OK</i>) indicating that
+   call has been accepted by the server. If there is an SDP session
+   description included with response, it is stored.
+
+   Unless the @ref NUTAG_AUTOACK() "auto-ack" mode is explicitly turned off
+   by application the client does not stay in @b completing state, but
+   proceeds immediately to next state transition.
+</td></tr>
+<tr><td>C3b</td>
+    <td>proceeding</td></tr>
+<tr><td>C4</td>
+    <td>completing</td>
+    <td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" </td>
+    <td>ACK</td><td>ready</td>
+    <td>Process answer</td>
+    <td>
+   Client sends an ACK request in this state transition. If the initial
+   offer was sent with INVITE, the answer must have been received by this
+   time, usually in the 2XX response. Client now completes the SDP
+   offer-answer exchange and activates the media.
+</td></tr>
+<tr><td>C5</td>
+    <td>completing</td>
+    <td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" and<br> media error</td>
+    <td>ACK<br>BYE</td>
+    <td>terminating</td>
+    <td>Process answer</td>
+    <td>
+   If there was an failure in SDP negotiation or other failure with media,
+   the stack will automatically terminate the call. The BYE follows
+   immediatelhy after the ACK.
+</td></tr>
+<tr><td>C6a</td>
+    <td>calling</td>
+    <td rowspan=2>3XX 4XX <br> 5XX 6XX</td>
+    <td rowspan=2>ACK*</td>
+    <td rowspan=2>terminated</td>
+    <td rowspan=2>-</td>
+    <td rowspan=2>
+   Call is terminated when client receives a final error response (from 300
+   to 699) to its INVITE request. In this case, the underlying transaction
+   engine takes care of sending ACK even when application-driven-ack mode is
+   requested by application.
+</td></tr>
+<tr><td>C6b</td>
+    <td>proceeding</td>
+</tr>
+
+<tr><td>C7a</td>
+    <td>calling</td>
+    <td rowspan=2>nua_cancel()</td>
+    <td rowspan=2>CANCEL</td>
+    <td>calling</td>
+    <td rowspan=2>-</td>
+    <td rowspan=2>
+   Client can ask server to cancel the call attempt while in @b calling or
+   @b proceeding state. There is no direct call state transition caused by
+   nua_cancel(). The call state changes when the server returns a response.
+   After receiving a CANCEL request the server will usually return a <i>487
+   Request Terminated</i> response and call is terminated as in previous
+   item.
+
+   However, there is a race condition and the server can respond with a
+   succesful 2XX response before receiving CANCEL. In that case, the call is
+   established as usual. It is up to application to terminate the call with
+   nua_bye().
+</td></tr>
+<tr><td>C7b</td>
+    <td>proceeding</td>
+    <td>proceeding</td>
+</tr>
+<tr><td>C8a</td>
+    <td>proceeding</td>
+    <td>nua_bye()</td>
+    <td>CANCEL</td>
+    <td rowspan=2>terminating*</td>
+    <td rowspan=2>-</td>
+    <td>
+   The cannot be terminated with BYE before the dialog is established with a
+   non-100 preliminary response. So, instead of @b BYE, stack sends a @b
+   CANCEL request, and enters terminating state.
+
+   However, there is a race condition and the server can respond with a
+   succesful 2XX response before receiving CANCEL. If the server responds with
+   a 2XX response, the nua will automatically send a BYE request asking server
+   to terminate the call.
+</td></tr>
+<tr><td>C8b</td>
+    <td>proceeding</td>
+    <td>nua_bye()</td>
+    <td>BYE</td>
+<td>
+   Even an early session can be terminated after entering @b proceeding
+   state with nua_bye(). Stack sends a @b BYE request, and enters
+   terminating state. Unlike @b CANCEL, @b BYE affects only one fork.
+
+   However, there is a race condition and the server can respond with a
+   succesful 2XX response before receiving BYE. If the server responds with
+   a 2XX response, the nua will automatically send a BYE request asking server
+   to terminate the call.
+</td></tr>
+<tr><td>C9</td>
+    <td>completing</td><td>nua_bye()</td><td>ACK<br>BYE</td><td>terminating</td>
+    <td>-</td>
+    <td>
+   If the stack is in @b completing state (it has already
+   received 2XX response), it will have to @b ACK the final response, too.
+</td></tr>
+
+<tr><td>C10</td>
+    <td>terminating*</td>
+    <td>2XX<br>to INVITE</td>
+    <td>BYE</td>
+    <td>terminating</td>
+    <td>-</td>
+    <td>
+   There is a race condition between @b BYE and @b INVITE. The call may have
+   been re-established with @b INVITE after @b BYE was processed. @b BYE is
+   re-sent and call state transitions to normal terminating state.
+</td></tr>
+
+<tr><td>C11</td>
+    <td>terminating*</td>
+    <td>3XX 4XX<br>5XX 6XX<br>to INVITE</td>
+    <td>BYE</td>
+    <td>terminating</td>
+    <td>-</td>
+    <td>
+   The @b INVITE transaction is completed without a call being created. The
+   call state transitions to normal terminating state.
+</td></tr>
+
+<tr><td>C12</td>
+    <td>terminating</td>
+    <td>3XX 4XX<br>5XX 6XX<br>to BYE</td>
+    <td>-</td>
+    <td>terminated</td>
+    <td>-</td>
+    <td>
+   Call is terminated when the final response to the BYE is received.
+</td></tr>
+
+</table>
+
+ at section nua_uas_call_model Detailed Server-Side Call Model
+
+The detailed call model at server side (UAS) is presented below. This model
+does not include the extensions like @b 100rel or @b UPDATE.
+
+ at code
+
+                           +----------------------------------+
+                           |                INIT              |
+                           +----------------------------------+
+                             |              :               :
+                             |              :               :
+                            (1) INVITE/100 (2b) INVITE/18X (3c) INVITE/2XX
+                             |              :               :
+                             |              :               :
+                             V              :               :
+                          +------------+    :               :
+     +--------------------|            |    :               :
+     |                    |  RECEIVED  |--------------+     :
+     |    +---------------|            |    :         |     :
+     |    |               +------------+    :         |     :
+     |    |                           |     :         |     :
+     |    |          nua_respond/18X (2)    :         |     :
+     |    |                           |     :         |     :
+     |    |                           V     V         |     :
+     |    |                          +------------+   |     :
+     |<------------------------------|            |   |     :
+     |    |<-------------------------|    EARLY   |   |     :
+     |    |               +----------|            |   |     :
+     |    |               |          +------------+   |     :
+     | nua_respond/       |                     |     |     :
+    (6) /[3456]XX         |    nua_respond/2XX (3b)  (3a)   :
+     |    |               |                     |     |     :
+     |    |               |                     V     V     V
+     |    |               |                    +-------------+
+     |    |               |                    |             |
+     |    |               |              +-----|  COMPLETED  |- - +
+     |    |               |              |     |             |    :
+     |    |               |              |     +-------------+    :
+     |    |               |              |            |           :
+     |    |               |              |           (4) ACK/-    :
+     |    |               |              |            |           :
+     |    |               |              |            V           :
+     |    |               |              |     +-------------+    :
+     |    |               |              |     |             |    :
+     |    |               |              |     |    READY    |    :
+     |    |               |              |     |             |    :
+     |    |               |              |     +-------------+    :
+     |    |               |              |                        :
+     |   (7) CANCEL/487  (8) BYE/487    (9) BYE/200              (5) timeout
+     |    |               |              |                        :     /BYE
+     |    |               |              |     +-------------+    :
+     |    |               |              |     | TERMINATING |<- -+
+     |    |               |              |     +-------------+
+     |    |               |              |            |
+     |    |               |              |            | [23456]XX/-
+     |    |               |              |            |
+     |    |               |              |            V
+     |    V               V              V     +-------------+
+     +---------------------------------------->| TERMINATED  |
+                                               +-------------+
+ at endcode
+
+The detailed description of state transitions on the server side is as
+follows:
+<table>
+<tr><th>#</th>
+    <th>Previous state</th>
+    <th>Input</th>
+    <th>Output</th>
+    <th>Next state</th>
+    <th>Offer/ Answer</th>
+    <th align="left">Description</th>
+</tr>
+<tr><td>S1</td>				<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE</td>			<!-- input -->
+    <td>100 Trying</td>			<!-- output -->
+    <td>received</td>			<!-- next state -->
+    <td>Save offer</td>			<!-- offer/answer -->
+    <td>
+   When a @b INVITE request for a new call is received, the server creates a
+   fresh call handle for it, responds to the client with <i>100 Trying</i>
+   and enters in the @b received state by default. It saves the possible SDP
+   offer included in @b INVITE and passes it to the application.
+</td></tr>
+<tr><td>S2a</td>			<!-- transition -->
+    <td>received</td>			<!-- previous state -->
+    <td>nua_respond()</td>		<!-- input -->
+    <td>18X</td>			<!-- output -->
+    <td rowspan=2>early</td>		<!-- next state -->
+    <td>(Generate early answer)</td>	<!-- offer/answer -->
+    <td>
+   When server returns a preliminary response for the initial @b INVITE request,
+   a early dialog is created. The server can also send an SDP answer with
+   the preliminary answer and establish an early session, too. It can use
+   the early session to send early media, e.g., ringing tone and
+   announcements towards the client.
+</td></tr>
+<tr><td>S2b</td>			<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE and			<!-- input -->
+        @ref NUTAG_AUTOALERT() "auto-alert"</td>
+    <td>180 Ringing</td>		<!-- output -->
+    <td>Save offer (and
+        generate early answer)</td>	<!-- offer/answer -->
+    <td>
+    When @ref NUTAG_AUTOALERT() "auto-alert" option is enabled, stack sends
+    180 Ringing immediately after receiving INVITE and enters @b early state.
+</td></tr>
+<tr><td>S3a</td>			<!-- transition -->
+    <td>received</td>			<!-- previous state -->
+    <td rowspan=2>nua_respond()</td>	<!-- input -->
+    <td rowspan=2>2XX</td>		<!-- output -->
+    <td rowspan=3>completed</td>	<!-- next state -->
+    <td rowspan=2>Generate answer</td>	<!-- offer/answer -->
+    <td rowspan=2>
+   When the server sends a 2XX response towards the client, it accepts the
+   call. The @b INVITE transaction is now considered complete but unconfirmed
+   at the server side. If the offer was sent in @b INVITE request, the answer
+   should be included in the 2XX response.
+</td></tr>
+<tr><td>S3b</td>			<!-- transition -->
+    <td>early</td>			<!-- previous state -->
+</td></tr>
+<tr><td>S3c</td>			<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE and @ref NUTAG_AUTOANSWER() "auto-answer"
+    </td>				<!-- input -->
+    <td>200 OK</td>			<!-- output -->
+    <td>Save offer and
+    <br>generate answer</td>		<!-- offer/answer -->
+    <td>
+    When @ref NUTAG_AUTOANSWER() "auto-answer" option is enabled, stack send
+    200 OK immediately after receiving INVITE and enters @b completed state.
+</td></tr>
+</td></tr>
+<tr><td>S4</td>				<!-- transition -->
+    <td>completed</td>			<!-- previous state -->
+    <td>ACK</td>			<!-- input -->
+    <td>-</td>				<!-- output -->
+    <td>ready</td>			<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+   The ready state is entered at server side after receiving @b ACK request
+   from client, indicating that the client have received server's 2XX
+   response. The call is ready, the @b INVITE transaction is confirmed.
+</td></tr>
+<tr><td>S5td>				<!-- transition -->
+    <td>completed</td>			<!-- previous state -->
+    <td>timeout</td>			<!-- input -->
+    <td>BYE</td>			<!-- output -->
+    <td>terminating</td>		<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+   If the server does not receive an @b ACK request in timely fashion, it will
+   terminate the call by sending a @b BYE request to client.
+</td></tr>
+<tr><td>S6a</td>			<!-- transition -->
+    <td>received</td>			<!-- previous state -->
+    <td rowspan=2>nua_respond()</td>	<!-- input -->
+    <td rowspan=2>3XX 4XX<br>5XX 6XX</td><!-- output -->
+    <td rowspan=2>terminated</td>	<!-- next state -->
+    <td rowspan=2>-</td>		<!-- offer/answer -->
+    <td rowspan=2>
+   The server can reject the call by sending a 3XX, 4XX, 5XX, or 6XX response
+   towards the client. The underlying transaction engine takes care of
+   retransmitting the response when needed. It consumes the ACK response
+   sent by the client, too.
+</td></tr>
+<tr><td>S6b</td>			<!-- transition -->
+    <td>early</td>			<!-- previous state -->
+</td></tr>
+<tr><td>S7a</td>			<!-- transition -->
+    <td>received</td>			<!-- previous state -->
+    <td rowspan=2>CANCEL</td>		<!-- input -->
+    <td rowspan=2>487 Request terminated</td><!-- output -->
+    <td rowspan=2>terminated</td>	<!-- next state -->
+    <td rowspan=2>-</td>		<!-- offer/answer -->
+    <td rowspan=2>
+   The client can cancel the call attempt before it is completed with a @b
+   CANCEL request. Server returns a <i>200 OK</i> response to @b CANCEL and
+   a <i>487 Request Terminated</i> response to the @b INVITE transaction and
+   the call is terminated.
+</td></tr>
+<tr><td>S7b</td>			<!-- transition -->
+    <td>early</td>			<!-- previous state -->
+</td></tr>
+<tr><td>S8</td>				<!-- transition -->
+    <td>early</td>			<!-- previous state -->
+    <td>BYE</td>			<!-- input -->
+    <td>487 to INVITE<br>
+        200 to BYE</td>			<!-- output -->
+    <td>terminated</td>			<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+   The client can terminate an early session with a @b BYE request, too. Like
+   in the @b CANCEL case above, the server will terminate call immediately,
+   return a <i>200 OK</i> response to @b BYE and a <i>487 Request
+   Terminated</i> response to the @b INVITE transaction.
+</td></tr>
+<tr><td>S9</td>				<!-- transition -->
+    <td>completed</td>			<!-- previous state -->
+    <td>BYE</td>			<!-- input -->
+    <td>200 to BYE</td>			<!-- output -->
+    <td>terminated</td>			<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+   The client can terminate a completed dialog with a @b BYE request. Server
+   terminates call immediately, returns a <i>200 OK</i> response to @b BYE
+   and lets the underlying transaction engine to take care of consuming @b
+   ACK.
+</td></tr>
+</table>
+
+ at section nua_3pcc_call_model Third Party Call Control
+
+There is an alternative offer-answer model for third party call control
+(3pcc).  The call setup involves a 3rd party, client C, which sends initial
+INVITE to server A without SDP. The call setup looks perfectly ordinary to
+server B, however.
+
+ at code
+	A		        C		        B
+	|			|			|
+	|<-------INVITE---------|			|
+	|			|			|
+	|			|			|
+	|------200 (offer)----->|  	  		|
+	|			|----INVITE (offer)---->|
+	|			|			|
+	|			|			|
+	|			|<-----200 (answer)-----|
+	|<-----ACK (answer)-----|			|
+	|			|     			|
+	|			|----------ACK--------->|
+	|			|			|
+ at endcode
+
+The modifications to the call model affect mainly offer-answer model.
+The detailed description of state transitions for 3pcc on the server side is as
+follows:
+
+<table>
+<tr><th>#</th>
+    <th>Previous state</th>
+    <th>Input</th>
+    <th>Output</th>
+    <th>Next state</th>
+    <th>Offer/ Answer</th>
+    <th align="left">Description</th>
+</tr>
+<tr><td>S1'</td>			<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE</td>			<!-- input -->
+    <td>100 Trying</td>			<!-- output -->
+    <td>received</td>			<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+    There is no SDP to save.
+</td></tr>
+<tr><td>S2b'</td>			<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE and			<!-- input -->
+        @ref NUTAG_AUTOALERT() "auto-alert"</td>
+    <td>180 Ringing</td>		<!-- output -->
+    <td>early</td>			<!-- next state -->
+    <td>-</td>				<!-- offer/answer -->
+    <td>
+    There is no SDP to save.
+</td></tr>
+<tr><td>S3a'</td>			<!-- transition -->
+    <td>early</td>			<!-- previous state -->
+    <td rowspan=2>nua_respond()</td>	<!-- input -->
+    <td rowspan=2>2XX</td>		<!-- output -->
+    <td rowspan=3>completed</td>	<!-- next state -->
+    <td rowspan=3>Generate offer</td>	<!-- offer/answer -->
+    <td rowspan=3>
+    The offer is sent in 200 OK.
+</td></tr>
+<tr><td>S3b'</td>			<!-- transition -->
+    <td>received</td>			<!-- previous state -->
+</td></tr>
+<tr><td>S3c'</td>			<!-- transition -->
+    <td>init</td>			<!-- previous state -->
+    <td>INVITE and			<!-- input -->
+        @ref NUTAG_AUTOANSWER() "auto-answer"</td>
+    <td>200 OK</td>			<!-- output -->
+</td></tr>
+<tr><td>S4'</td>			<!-- transition -->
+    <td>completed</td>			<!-- previous state -->
+    <td>ACK</td>			<!-- input -->
+    <td>-</td>				<!-- output -->
+    <td>ready</td>			<!-- next state -->
+    <td>Save and process answer</td>	<!-- offer/answer -->
+    <td>
+    The answer is processed and media activated after receiving @b ACK.
+</td></tr>
+<tr><td>S9b'</td>			<!-- transition -->
+    <td>completed</td>			<!-- previous state -->
+    <td>ACK and O/A error</td>		<!-- input -->
+    <td>BYE</td>			<!-- output -->
+    <td>terminating</td>		<!-- next state -->
+    <td>Save and process answer</td>	<!-- offer/answer -->
+    <td>
+    If the offer/answer negotiation ends in error after the server receives
+    answer in @b ACK request, the server will have to terminate call by
+    sending a @b BYE request.
+</td></tr>
+</table>
+
+
+ at section nua_terminate_call_model Model for Modifying and Terminating Call
+
+After the SIP session has been established, it can be further modified by @b
+INVITE transactions, initiated by either the original client or the original
+server. These so-called re-INVITE transactions can be used to upgrade
+session (add new media to it), put the session on hold or resume a held
+call.
+
+A session can be terminated with a @b BYE request at any time.
+
+If any in-dialog request (including re-INVITE) fails with certain response
+code, the session can be considered terminated, too. These response codes
+are documented with sip_response_terminates_dialog(). In some cases, the
+session should be terminated gracefully by sending a @b BYE request after
+the failed requests.
+
+ at code
+    +-------------------------------------------------------------+
+    |                            READY                            |
+    +-------------------------------------------------------------+
+      |           |                |		    |
+      |           |                |		    |
+     (1) BYE/200 (2) nua_bye/BYE  (4) graceful/BYE (5) fatal/-
+      |           |		   |     	    |
+      |           V		   V     	    |
+      |     +-----------------------------+         |
+      |     |         TERMINATING         |         |
+      |     +-----------------------------+	    |
+      |                    |			    |
+      |                   (3) [23456]XX/-	    |
+      |                    |			    |
+      V                    V			    V
+    +-------------------------------------------------------------+
+    |                         TERMINATED                          |
+    +-------------------------------------------------------------+
+ at endcode
+
+The detailed description of state transitions while call is terminated is as
+follows:
+<table>
+<tr><th>#</th>
+    <th>Previous state</th>
+    <th>Input</th>
+    <th>Output</th>
+    <th>Next state</th>
+    <th align="left">Description</th>
+</tr>
+<tr><td>T1</td>				<!-- transition -->
+    <td>ready</td>			<!-- previous state -->
+    <td>BYE</td>			<!-- input -->
+    <td>200 OK</td>			<!-- output -->
+    <td>terminated</td>			<!-- next state -->
+    <td>
+    	When the @b BYE request is received, the recipient terminates the
+    	currently ongoing @b INVITE transaction, the session and its dialog
+    	usage (if there is another dialog usage active, e.g., a subscription
+    	creted by @b REFER.)
+</td></tr>
+<tr><td>T2</td>				<!-- transition -->
+    <td>ready</td>			<!-- previous state -->
+    <td>nua_bye</td>			<!-- input -->
+    <td>BYE</td>			<!-- output -->
+    <td>terminating</td>		<!-- next state -->
+    <td>
+        The application terminates the session by calling nua_bye(). All the
+    	call-related requests on the dialog are rejected while in
+    	terminating state with <i>487 No Such Call</i> response.
+</td></tr>
+<tr><td>T3</td>				<!-- transition -->
+    <td>terminating</td>		<!-- previous state -->
+    <td>2XX 3XX 4XX 5XX 6XX</td>	<!-- input -->
+    <td>-</td>				<!-- output -->
+    <td>terminated</td>			<!-- next state -->
+    <td>
+        The session is finally terminated when a final response to @b BYE is
+    	received. Note that nua stack does retry @b BYE requests.
+</td></tr>
+<tr><td>T4</td>				<!-- transition -->
+    <td>ready</td>			<!-- previous state -->
+    <td>"graceful" response</td>	<!-- input -->
+    <td>BYE</td>			<!-- output -->
+    <td>terminating</td>		<!-- next state -->
+    <td>
+        A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
+    	@b REFER) fails with a response code indicating that the client
+    	should gracefully terminate the call.
+</td></tr>
+<tr><td>T5</td>				<!-- transition -->
+    <td>ready</td>			<!-- previous state -->
+    <td>"fatal" response</td>		<!-- input -->
+    <td>-</td>				<!-- output -->
+    <td>terminated</td>			<!-- next state -->
+    <td>
+        A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
+    	@b REFER) fails with a response code indicating that the call has
+    	been terminated.
+</td></tr>
+</table>
+
+ at sa http://www.ietf.org/internet-drafts/draft-sparks-sipping-dialogusage-01.txt
+ at sa sip_response_terminates_dialog()
+
+*/
+
+/*
+For reference:
+
+                    +---------------+
+             +-(1)--|     INIT      |-----+
+    INVITE/- |      +---------------+    (A) INVITE/100
+             V                            |
+       +------------+               +------------+
+  +----|  CALLING   |           +---|  RECEIVED  |--+
+  |    +------------+           |   +------------+  |
+  |          |                  |         |         |
+  |         (2) 18X/-           |        (B) -/18X  |
+  |          V                  |         V         |
+  |    +------------+           |   +------------+  |
+  |<---| PROCEEDING |--+        |   |   EARLY    |->|
+  |    +------------+  |        |   +------------+ (F) -/[3456]XX
+  |          :         |        |         |         |
+  |         (4) 2XX/-  |       (E) -/2XX (C) -/2XX  |    or
+  |          V         |        |         V         |
+  |    + - - - - - -+  |        |   +------------+ (G) CANCEL/200,487
+  |    : COMPLETING :  |        +-->|  COMPLETE  |  |
+  |    + - - - - - -+  |            +------------+  |
+  |          :         |                  |    :    |
+  |         (5)-/ACK  (3) 2XX/ACK   ACK/-(D)   :    |
+  |          :         |                  |    :    |
+  |          :         V                  |    :    |
+  |          :      +---------------+     |    :    |
+  |          + - - >|     READY     |<----+    :    |
+  |                 +---------------+          :    |
+  |                   |     |                  :    |
+  |          BYE/200 (i)  (ii) -/BYE  timeout/ :    |
+  |                   |     |             BYE (H)   |
+  |                   |     V                  :    |
+  |                   |   +--------------+     :    |
+ (6) [3456]XX/ACK     |   | TERMINATING  |<- - +    |
+  |                   |   +--------------+          |
+  |                   |           |                 |
+  |                   |         (iii) [23456]XX/-   |
+  |                   V           V                 |
+  |                 +---------------+               |
+  +---------------->|  TERMINATED   |<--------------+
+                    +---------------+
+                            |
+                            V
+                           INIT
+
+*/
+
+/**@page nua_event_diagrams NUA Event Diagrams
+
+The example diagrams below try to present how to use NUA API with different
+SIP use cases.
+
+ at section nua_event_diagram_call Basic Call
+
+The SIP following event diagram shows a pretty simple, succesful call case.
+The nua events and nua function calls are show in the diagram below as well
+as the SIP messages.
+
+The call setup above assumes parameters NUTAG_AUTOALERT(0),
+NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
+
+ at code
+
+                   Alice           Proxy            Bob
+ 0                  |                |                |
+ 1  nua_handle()    |                |                |
+ 2  nua_invite() -> |-----INVITE---->|                |
+ 3   nua_i_state <- |                |                |
+ 4                  |                |-----INVITE---->| -> nua_i_invite
+ 5                  |<--100 Trying---|                | -> nua_i_state
+ 6                  |                |                |
+ 7                  |                |                |
+ 8                  |                |                |
+ 9                  |                |<--180 Ringing--| <- nua_respond(180)
+10  nua_i_invite <- |<--180 Ringing--|                | -> nua_i_state
+11   nua_i_state <- |                |                |
+12                  |                |<--200 OK-------| <- nua_respond(200)
+13  nua_i_invite <- |<---200 OK------|                | -> nua_i_state
+14   nua_i_state <- |                |                |
+15     nua_ack() -> |-----ACK------->|                |
+16   nua_i_state <- |                |-----ACK------->| -> nua_i_ack
+17                  |                |                | -> nua_i_state
+18                  |                |                |
+19               <<====== SIP Session Established =======>>
+20                  |                |                |
+21                  |                |                |
+22     nua_bye() -> |-----BYE------->|                |
+23                  |                |-----BYE------->| -> nua_i_bye
+24                  |                |<----200 OK-----| -> nua_i_state
+25     nua_r_bye <- |<---200 OK------|                |
+26   nua_i_state <- |                |                |
+                    |                |                |
+ at endcode
+
+ at section nua_event_diagram_call_hold Holding Call
+
+The media (audio, video) can be put on hold. In SIP system this means that
+application can indicate to the remote end that it is engaged in other
+activity (another call, for instance) and does not wish to receive media
+from the remove end.
+
+The call hold is usully implemented using re-INVITE. Re-INVITE is an INVITE
+request sent on existing SIP session. Both original caller and callee can
+send re-INVITEs. The main use of re-INVITE is modifying sessions: adding
+media lines to the session, changing codecs on existing media, and, as you
+might expect, putting existing media on hold as well as resuming media from
+hold.
+
+A re-INVITE is sent by calling nua_invite() on handle with existing call.
+When putting call on hold, the application can include SOATAG_HOLD("audio")
+or SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
+as parameters to re-INVITE nua_invite(). (Note that last SOATAG_HOLD() in
+the tag list will override the SOATAG_HOLD() tags before it.)
+
+Another feature where nua tries to be helpful is autoanswer and auto-ACK on
+existing sessions: the re-INVITE is automatically responded with <i>200 OK</i>
+and ACK is automatically sent. (If the application wants to respond and ACK
+by itself, it should explicitly set NUTAG_AUTOANSWER(0) and/or
+NUTAG_AUTOACK(0) in the handle; either include them in nua_invite() or
+nua_respond() parameters or call nua_set_hparams() explicitly.
+
+ at code
+                   Alice           Proxy            Bob
+ 0     nua_handle() |                |                |
+ 1                  |                |                |
+ 2  nua_invite() -> |-----INVITE---->|                |
+ 3   nua_i_state <- |                |                |
+ 4                  |                |-----INVITE---->| -> nua_i_invite
+ 5                  |<--100 Trying---|                | -> nua_i_state
+ 6                  |                |                |
+ 7                  |                |                |
+ 8                  |                |                |
+ 9                  |                |<--180 Ringing--| <- nua_respond(180)
+10  nua_i_invite <- |<--180 Ringing--|                | -> nua_i_state
+11   nua_i_state <- |                |                |
+12                  |                |<--200 OK-------| <- nua_respond(200)
+13  nua_i_invite <- |<---200 OK------|                | -> nua_i_state
+14   nua_i_state <- |                |                |
+15     nua_ack() -> |-----ACK------->|                |
+16   nua_i_state <- |                |-----ACK------->| -> nua_i_ack
+17                  |                |                | -> nua_i_state
+18                  |                |                |
+19               <<== Bi-Directional RTP Established ==>>
+20                  |                |                |
+21                  |                |                |
+22                  |                |<--INVITE(hold)-| <- nua_invite(..
+21                  |                |                |       NUTAG_HOLD("*")..)
+23  nua_i_invite <- |<-INVITE(hold)--|                | -> nua_i_state
+25   nua_i_state <- |----200 OK----->|    	      |
+26                  |                |----200 OK----->| -> nua_i_invite
+28                  |                |<-----ACK-------| -> nua_i_state
+29     nua_i_ack <- |<----ACK--------|                |
+24                  |                |                |
+30               <<== Uni-Directional RTP Established ==>>
+24                  |                |                |
+31                  |                |                |
+32                  |                |<--INVITE-------| <- nua_invite(..
+21                  |                |                |      NUTAG_HOLD(NULL)..)
+33  nua_i_invite <- |<--INVITE-------|                | -> nua_i_state
+35   nua_i_state <- |---200 OK------>|                |
+36                  |                |---200 OK------>| -> nua_i_invite
+38                  |                |<----ACK--------| -> nua_i_state
+39     nua_i_ack <- |<----ACK--------|                |
+40   nua_i_state <- |                |                |
+19               <<== Bi-Directional RTP Established ==>>
+42                  |                |                |
+43     nua_bye() -> |-----BYE------->|                |
+44   nua_i_state <- |                |-----BYE------->| -> nua_i_bye
+46                  |                |<----200 OK-----| -> nua_i_state
+47                  |<---200 OK------|                |
+                    |                |                |
+ at endcode
+
+
+
+ at section nua_event_diagram_call_transfer  Call Transfer
+
+This is the unattended call transfer case.
+
+1st MSC showing Alice's end:
+
+ at code
+           Alice                      Bob                 Carol
+ 0                     |                    |                    |
+ 1     nua_i_invite <- |<-----INVITE--------|                    |
+ 2      nua_i_state <- |                    |                    |
+ 2                     |                    |                    |
+ 3 nua_respond(180) -> |----180 Ringing---->|                    |
+ 2      nua_i_state <- |                    |                    |
+ 4                     |                    |                    |
+ 5 nua_respond(200) -> |------200 OK------->|                    |
+ 6      nua_i_state <- |                    |                    |
+ 8                     |                    |                    |
+ 7        nua_i_ack <- |<-------ACK---------|                    |
+ 8      nua_i_state <- |                    |                    |
+ 9                     |<========RTP=======>|                    |
+10                     |                    |                    |
+11             << Alice performs unattended transfer >>          |
+12                     |                    |                    |
+13                     |                    |                    |
+14      nua_refer() -> |---REFER("r: C")--->|                    |
+15                     |                    |                    |
+16      nua_r_refer <- |<---202 Accepted----|                    |
+17                     |                    |                    |
+18     nua_i_notify <- |<-----NOTIFY--------|                    |
+19                     |                    |                    |
+20                     |------200 OK------->|                    |
+21                     |                    |---INVITE("b: A")-->|
+23                     |                    |                    |
+22        nua_bye() -> |-------BYE--------->|                    |
+23                     |                    |                    |
+24        nua_r_bye <- |<----200 OK---------|                    |
+25      nua_i_state <- |   No RTP Session   |                    |
+28                     |                    |<----180 Ringing----|
+26     nua_i_notify <- |<- - -NOTIFY - - - -|                    |
+27                     |                    |                    |
+20                     |- - - 200 OK- - - ->|                    |
+29                     |                    |                    |
+30                     |                    |<------200 OK-------|
+31                     |                    |                    |
+32                     |                    |---------ACK------->|
+33                     |                    |        RTP         |
+34                     |                    |<==================>|
+35                     |                    |                    |
+36                     |<-----NOTIFY--------|                    |
+37                     |                    |                    |
+38                     |------200 OK------->|                    |
+                       |                    |                    |
+ at endcode
+
+2nd MSC showing Bobs's end:
+
+ at code
+   Alice               Bob (nh1)            Bob (nh2)             Carol
+ 0   |      	          |                    |                    |
+ 1   |<-----INVITE--------|                    |                    |
+ 2   |   	          |                    |                    |
+ 3   |---180 Ringing----->|                    |                    |
+ 4   |      	          |                    |                    |
+ 5   |------200 OK------->|                    |                    |
+ 6   |        	          |                    |                    |
+ 7   |<-------ACK---------|                    |                    |
+ 8   |        RTP         |                    |                    |
+ 9   |<==================>|                    |                    |
+10   |                    |                    |                    |
+11<< Alice performs unattended transfer >>     |                    |
+12   |                    |                    |                    |
+13   | 	     Refer-To:C F5|                    |                    |
+14   |-REFER------------->| -> nua_i_refer     |                    |
+15   |  	          |                    |                    |
+16   |<-202 Accepted------|                    |                    |
+17   |      	          |                    |                    |
+18   |<-----NOTIFY--------|                    |                    |
+19   |      	          |                    |                    |
+20   |------200 OK------->| -> nua_r_notify    |                    |
+21   |       	          |                    |                    |
+22   |-------BYE--------->| -> nua_i_bye       |                    |
+23   |     	          | -> nua_i_state     |                    |
+24   |<----200 OK---------|    nua_handle() -> |                    |
+25   |   No RTP Session   |    nua_invite() -> |                    |
+26   |                    |                    |--INVITE("b: A")--->|
+27   |                    |                    |   	            |
+28   |                    |    nua_i_invite <- |<--180 Ringing------|
+29   |                    |     nua_i_state <- |     	            |
+30   |                    |    nua_i_invite <- |<----200 OK---------|
+31   |                    |     nua_i_state <- |       	            |
+32   |                    |         nua_ack -> |-------ACK--------->|
+33   |                    |                    |                    |
+34   |                    |                    |<=======RTP========>|
+35   |      	          |                    |                    |
+36   |<-----NOTIFY--------|                    |                    |
+37   |      	          |
+38   |------200 OK------->| -> nua_r_notify
+39   |                    | <- nua_handle_destroy
+     |                    |
+ at endcode
+
+Bob includes nh1 in nua_invite()/25 as NUTAG_NOTIFY_REFER() parameter.
+
+Open Issue 1:
+
+- how Bob know when to destroy nh1?
+
+
+ at section nua_event_diagram_3gpp_call 3GPP Call Model
+
+The 3GPP call model is defined in 3GPP TS 24.229. In order to select only a
+single codec and ensure that the QoS reservationa are made before the call
+is alerting, the 3GPP call model employs multiple offer/answer exchanges. It
+uses 100rel and PRACK (@RFC3262), UPDATE (@RFC3311) and preconditions
+(@RFC3312) extensions specified by IETF.
+
+The call setup below assumes parameters NUTAG_AUTOALERT(0),
+NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
+
+ at code
+                      A                       B
+ 0    nua_handle()    |                       |
+ 1    nua_invite() -> |                       |
+ 2     nua_i_state <- |----INVITE (offer)---->|
+ 3                    |                       | -> nua_i_invite
+ 4                    |                       | -> nua_i_state
+ 5                    |                       |
+ 6                    |                       | <- nua_respond(183)
+ 7    nua_i_invite <- |<----183 (answer)------| -> nua_i_state
+ 8     nua_i_state <- |                       |
+ 9                << single codec is selected now >>
+10                    |-----PRACK(offer2)---->| -> nua_i_prack
+11                    |                       | -> nua_i_state
+12    nua_r_prack  <- |<--200/PRACK(answer2)--|
+13                    |                       |
+14                    |                       |
+15            << resource reservations are done now >>
+16                    |                       |
+17    nua_update() -> |----UPDATE (offer3)--->|
+18    nua_i_state  <- |                       |
+19    nua_i_state  <- |<-200/UPDATE (answer3)-| -> nua_i_update
+20                    |                       | -> nua_i_state
+21                    |                       |
+22                    |                       |    << B rings >>
+23                    |                       |
+24                    |                       | <- nua_respond(180)
+25    nua_i_invite <- |<---------180----------|
+26    nua_i_state  <- |                       |
+27                    |--------PRACK--------->| -> nua_i_prack
+28    nua_r_prack  <- |<-----200/PRACK------->| -> nua_i_state
+29                    |                       |
+30                    |                       | <- nua_respond(200)
+31    nua_i_invite <- |<---------200----------| -> nua_i_state
+32    nua_i_state  <- |                       |
+33    nua_ack()    -> |                       |
+34    nua_i_state  <- |----------ACK--------->| -> nua_i_ack
+35                    |                       | -> nua_i_state
+                      |                       |
+ at endcode
+
+*/
+
+/**@var nua_event_e
+ *
+ * @brief Events
+ *
+ * The NUA event loop calls an event callback function when an application
+ * needs to act on something that happened in the Sofia stack. The callback
+ * function is registered when nua_create() function call is used to create
+ * the NUA stack object.
+ *
+ * The prototype of the event callback function is:
+ * @code
+ * void nua_callback_f(nua_event_t   event,
+ *                     int           status,
+ *                     char const   *phrase,
+ *                     nua_t        *nua,
+ *                     nua_magic_t  *magic,
+ *                     nua_handle_t *nh,
+ *                     nua_hmagic_t *hmagic,
+ *                     sip_t const  *sip,
+ *                     tagi_t        tags[]);
+ * @endcode
+ *
+ * @param event  Callback event identification. \n
+ *               Always present
+ * @param status Protocol status code. \n
+ *               Always present
+ * @param phrase Text corresponding to status code. \n
+ *               Always present
+ * @param nua    Pointer to NUA stack object. \n
+ *               Always present
+ * @param magic  Pointer to callback context from nua_create(). \n
+ *               Always present
+ * @param nh     Pointer to operation handle.
+ * @param hmagic Pointer to callback context from nua_handle().
+ * @param sip    Parsed incoming message. May be NULL.
+ * @param tags   Tag list containing more information about the state of NUA.
+ *               May be empty.
+ *
+ * Note that the contents of the last four parameters vary depending on
+ * the event. The descriptions can be found from the description of the
+ * individual event.
+ *
+ * The events can be divided into the following categories: \n
+ * @par Indications:
+ * #nua_i_active           \n
+ * #nua_i_ack              \n
+ * #nua_i_bye              \n
+ * #nua_i_cancel           \n
+ * #nua_i_chat             \n
+ * #nua_i_error            \n
+ * #nua_i_fork             \n
+ * #nua_i_info             \n
+ * #nua_i_invite           \n
+ * #nua_i_media_error      \n
+ * #nua_i_message          \n
+ * #nua_i_method           \n
+ * #nua_i_notify           \n
+ * #nua_i_options          \n
+ * #nua_i_prack            \n
+ * #nua_i_publish          \n
+ * #nua_i_refer            \n
+ * #nua_i_register         \n
+ * #nua_i_subscribe        \n
+ * #nua_i_subscription     \n
+ * #nua_i_state            \n
+ * #nua_i_terminated       \n
+ * #nua_i_update
+ *
+ * @par Responses:
+ * #nua_r_get_params       \n
+ * #nua_r_notifier         \n
+ * #nua_r_shutdown         \n
+ * #nua_r_terminate
+ *
+ * @par SIP responses:
+ * #nua_r_bye         \n
+ * #nua_r_cancel      \n
+ * #nua_r_info        \n
+ * #nua_r_invite      \n
+ * #nua_r_message     \n
+ * #nua_r_notify      \n
+ * #nua_r_options     \n
+ * #nua_r_prack       \n
+ * #nua_r_publish     \n
+ * #nua_r_refer       \n
+ * #nua_r_register    \n
+ * #nua_r_subscribe   \n
+ * #nua_r_unpublish   \n
+ * #nua_r_unregister  \n
+ * #nua_r_unsubscribe \n
+ * #nua_r_update
+ */
+
+/** @NUA_EVENT nua_i_chat
+ *
+ * Incoming chat message.
+ *
+ * @param nh     operation handle associated with the message
+ * @param hmagic operation magic associated with the handle
+ * @param sip    incoming chat message
+ * @param tags   empty
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_error
+ *
+ * Error indication.
+ *
+ * Will be sent when an internal error happened or
+ * an error occurred while responding a request.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ *               describing the problem
+ * @param phrase a short textual description of @a status code
+ * @param nh     NULL or operation handle associated with the call
+ * @param hmagic NULL or operation magic associated with the call
+ * @param sip    NULL
+ * @param tags   empty or error specific information
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_fork
+ *
+ * Outgoing call has been forked.
+ *
+ * This is sent when an INVITE request is answered with multiple 200 responses.
+ *
+ * @param status response status code
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the original call
+ * @param hmagic operation magic associated with the original call
+ * @param sip    preliminary or 2XX response to INVITE
+ * @param tags   NUTAG_HANDLE() of the new forked call
+ *
+ * @sa #nua_r_invite, #nua_i_state, @ref nua_call_model
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_media_error
+ *
+ * Media error indication.
+ *
+ * This may be sent after an SOA operation has failed while processing
+ * incoming or outgoing call.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ *               describing the problem
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic operation magic associated with this handle
+ *               (maybe NULL if call handle was created for this call)
+ * @param sip    NULL
+ * @param tags   empty
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_message is documented with nua_stack_process_message() */
+
+/* nua_i_method is documented with nua_stack_process_method() */
+
+/** @NUA_EVENT nua_i_network_changed
+ *
+ * Local IP(v6) address has changed.
+ *
+ * @param nh     default operation handle
+ * @param hmagic operation magic associated with the default operation handle
+ * @param sip    NULL
+ * @param tags   empty
+ *
+ * @since Experimental in @VERSION_1_12_2.
+ * 
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_notify is documented with nua_stack_process_notify() */
+
+/* nua_i_options is documented with nua_stack_process_options() */
+
+/* nua_i_publish is documented with nua_stack_process_publish() */
+
+/* nua_i_refer is documented with nua_stack_process_refer() */
+
+/* nua_i_subscribe is documented with nua_stack_process_subscribe() */
+
+/** @NUA_EVENT nua_i_subscription
+ *
+ * Incoming subscription to be authorized.
+ *
+ * This event is launched by nua_notifier() to inform application of the
+ * current state of the subscriber. The subscriber state is included in the
+ * NUTAG_SUBSTATE() tag. If the state is #nua_substate_pending or
+ * #nua_substate_embryonic, application should to authorize the subscriber
+ * with nua_authorize().
+ *
+ * @param nh     operation handle associated with the notifier
+ * @param hmagic operation magic
+ * @param status statuscode of response sent automatically by stack
+ * @param sip    incoming SUBSCRIBE request
+ * @param tags   NEATAG_SUB(),
+ *               NUTAG_SUBSTATE()
+ *
+ * @sa nua_notifier(), #nua_i_subscribe, nua_authorize(), nua_terminate()
+ * @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_update is documented with nua_stack_process_update() */
+
+/* nua_r_bye is documented with process_response_to_bye() */
+
+/* nua_r_cancel is documented with process_response_to_cancel() */
+
+/** @NUA_EVENT nua_r_chat
+ *
+ * Answer to outgoing chat message.
+ *
+ * @param nh     operation handle associated with the notifier
+ * @param hmagic operation magic associated with the notifier
+ * @param sip    response to MESSAGE request or NULL upon an error
+ *               (error code and message are in status an phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_chat(), #nua_r_message
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_info is documented with process_response_to_info() */
+
+/* nua_r_invite is documented with process_response_to_invite() */
+
+/* nua_r_message is documented with process_response_to_message() */
+
+/** @NUA_EVENT nua_r_notifier
+ *
+ * Answer to nua_notitier()
+ *
+ * @param nh     operation handle associated with the call
+ * @param hmagic operation magic associated with the call
+ * @param sip    NULL
+ * @param tags   SIPTAG_EVENT() \n
+ *               SIPTAG_CONTENT_TYPE()
+ *
+ * @sa nua_notitier(), #nua_i_subscription, @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_notify is documented with process_response_to_notify() */
+
+/* nua_r_options is documented with process_response_to_options() */
+
+/* nua_r_prack is documented with process_response_to_prack() */
+
+/* nua_r_publish is documented with process_response_to_publish() */
+
+/* nua_r_refer is documented with process_response_to_refer() */
+
+/* nua_r_shutdown is documented with nua_stack_shutdown() */
+
+/* nua_r_subscribe is documented with process_response_to_subscribe() */
+
+/** @NUA_EVENT nua_r_terminate
+ *
+ * Answer to nua_terminate().
+ *
+ * @param nh     operation handle associated with the notifier
+ * @param hmagic operation magic associated with the notifier
+ * @param sip    NULL
+ * @param tags   empty
+ * 
+ * @sa nua_terminate(), nua_handle_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_unsubscribe is documented with process_response_to_subscribe() */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,303 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_common.c
+ * @brief Function common to both stack and application side.  
+ * 
+ * @author Pekka.Pessi at nokia.com
+ * 
+ * @date Created: Tue Apr 26 13:23:17 2005 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <stdio.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#define SU_ROOT_MAGIC_T   struct nua_s
+#define SU_MSG_ARG_T      struct event_s
+
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_strlst.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nea.h>
+
+#include <sofia-sip/auth_client.h>
+#if HAVE_SMIME 		/* Start NRC Boston */
+#include "smimec.h"
+#endif                  /* End NRC Boston */
+
+#include <sofia-sip/sdp.h>
+
+#include "nua_stack.h"
+
+static void nh_destructor(void *arg);
+
+/**@internal
+ * Create an operation handle 
+ *
+ * Allocates a new operation handle and associated storage.
+ *
+ * @param nua         Pointer to NUA stack object
+ * @param hmagic      Pointer to callback context
+ * @param tags        List of tagged parameters
+ *
+ * @retval non-NULL  Pointer to operation handle
+ * @retval NULL    Creation failed
+ *
+ * @par Related tags:
+ *     Creates a copy of the provided tags which will 
+ *     be used with every operation.
+ *
+ * @par Events:
+ *     none
+ *
+ * @note
+ * This function is called by both stack and application sides.
+ */
+nua_handle_t *nh_create_handle(nua_t *nua,
+			       nua_hmagic_t *hmagic,
+			       tagi_t *tags)
+{
+  nua_handle_t *nh;
+  static int8_t _handle_lifetime = 1;
+
+  enter;
+
+  assert(nua->nua_home);
+
+  if ((nh = su_home_clone(nua->nua_home, sizeof(*nh)))) {
+    nh->nh_valid = nua_handle;
+    nh->nh_nua = nua;
+    nh->nh_magic = hmagic;
+    nh->nh_prefs = nua->nua_dhandle->nh_prefs;
+
+    if (nua_handle_save_tags(nh, tags) < 0) {
+      SU_DEBUG_5(("nua(%p): creating handle %p failed\n", nua, nh));
+      su_home_unref(nh->nh_home), nh = NULL;
+    }
+    
+    if (nh && su_home_is_threadsafe(nua->nua_home)) {
+      if (su_home_threadsafe(nh->nh_home) < 0) {
+	su_home_unref(nh->nh_home);
+	nh = NULL;
+      }
+    }
+
+    if (nh && _handle_lifetime) {      
+      /* This far, we have nothing real to destruct but
+       * when _NUA_HANDLE_DEBUG is set, we add destructor 
+       * and get more entertaining debugging output */
+      if (_handle_lifetime == 1 && !getenv("_NUA_HANDLE_DEBUG")) {
+	_handle_lifetime = 0;
+      } 
+      else {
+	_handle_lifetime = 2;
+	SU_DEBUG_0(("nh_handle_create(%p)\n", nh));
+	su_home_destructor(nh->nh_home, nh_destructor);
+      }
+    }
+  }
+
+  return nh;
+}
+
+/**@var _NUA_HANDLE_DEBUG
+ *
+ * If this environment variable is set, nua stack logs a message whenever a
+ * handle is created and when it is destroyed. This is mainly useful when
+ * debugging #nua_handle_t leaks.
+ *
+ * @sa nua_handle(), nua_handle_destroy()
+ */
+extern char const _NUA_HANDLE_DEBUG[];
+
+/* nua handle destructor. It does nothing. */
+static void nh_destructor(void *arg)
+{
+  nua_handle_t *nh = arg;
+
+  SU_DEBUG_0(("nh_destructor(%p)\n", nh));
+}
+
+/** Make a new reference to handle.
+ *
+ * The handles use reference counting for memory management. In addition to
+ * the memory management, there is protocol state associated with the
+ * handles. The protocol state is terminated with nua_handle_destroy(). In
+ * order to make it more convenient for programmer, nua_handle_destroy()
+ * decreases the reference count, too.
+ *
+ * @note All handle references are destroyed when the nua object is destroyed.
+ *
+ * @sa nua_handle_unref(), nua_handle(), nua_handle_destroy().
+ */
+nua_handle_t *nua_handle_ref(nua_handle_t *nh)
+{
+  return (nua_handle_t *)su_home_ref(nh->nh_home);
+}
+
+
+/** Destroy reference to handle. 
+ *
+ * The handles use reference counting for memory management. In addition to
+ * the memory management, there is protocol state associated with the
+ * handles. The protocol state is terminated with nua_handle_destroy(). In
+ * order to make it more convenient for programmer, nua_handle_destroy()
+ * decreases the reference count, too.
+ *
+ * @sa nua_handle_ref(), nua_handle(), nua_handle_destroy().
+ */
+int nua_handle_unref(nua_handle_t *nh)
+{
+  return su_home_unref(nh->nh_home);
+}
+
+/** Generate an instance identifier. */
+char const *nua_generate_instance_identifier(su_home_t *home)
+{
+  char str[su_guid_strlen + 1];
+  su_guid_t guid[1];
+
+  su_guid_generate(guid);
+  /*
+   * Guid looks like "NNNNNNNN-NNNN-NNNN-NNNN-XXXXXXXXXXXX"
+   * where NNNNNNNN-NNNN-NNNN-NNNN is timestamp and XX is MAC address
+   * (but we use usually random ID for MAC because we do not have
+   *  guid generator available for all processes within node)
+   */
+  su_guid_sprintf(str, su_guid_strlen + 1, guid);
+
+  return su_strdup(home, str);
+}
+
+/** Get name for a NUA event. */
+char const *nua_event_name(nua_event_t event)
+{
+  switch (event) {
+  case nua_i_error: return "nua_i_error";
+  case nua_i_invite: return "nua_i_invite";
+  case nua_i_cancel: return "nua_i_cancel";
+  case nua_i_ack: return "nua_i_ack";
+
+  case nua_i_register: return "nua_i_register";
+  case nua_i_fork: return "nua_i_fork";
+  case nua_i_active: return "nua_i_active";
+  case nua_i_terminated: return "nua_i_terminated";
+  case nua_i_state: return "nua_i_state";
+  case nua_i_outbound: return "nua_i_outbound";
+
+  case nua_i_bye: return "nua_i_bye";
+  case nua_i_options: return "nua_i_options";
+  case nua_i_refer: return "nua_i_refer";
+  case nua_i_publish: return "nua_i_publish";
+  case nua_i_prack: return "nua_i_prack";
+  case nua_i_info: return "nua_i_info";
+  case nua_i_update: return "nua_i_update";
+  case nua_i_message: return "nua_i_message";
+  case nua_i_chat: return "nua_i_chat";
+  case nua_i_subscribe: return "nua_i_subscribe";
+  case nua_i_subscription: return "nua_i_subscription";
+  case nua_i_notify: return "nua_i_notify";
+  case nua_i_method: return "nua_i_method";
+
+  case nua_i_media_error: return "nua_i_media_error";
+
+  /* Responses */
+  case nua_r_get_params: return "nua_r_get_params";
+  case nua_r_shutdown: return "nua_r_shutdown";
+  case nua_r_notifier: return "nua_r_notifier";
+  case nua_r_terminate: return "nua_r_terminate";
+
+  case nua_r_register: return "nua_r_register";
+  case nua_r_unregister: return "nua_r_unregister";
+  case nua_r_invite: return "nua_r_invite";
+  case nua_r_bye: return "nua_r_bye";
+  case nua_r_options: return "nua_r_options";
+  case nua_r_refer: return "nua_r_refer";
+  case nua_r_publish: return "nua_r_publish";
+  case nua_r_unpublish: return "nua_r_unpublish";
+  case nua_r_info: return "nua_r_info";
+  case nua_r_prack: return "nua_r_prack";
+  case nua_r_update: return "nua_r_update";
+  case nua_r_message: return "nua_r_message";
+  case nua_r_chat: return "nua_r_chat";
+  case nua_r_subscribe: return "nua_r_subscribe";
+  case nua_r_unsubscribe: return "nua_r_unsubscribe";
+  case nua_r_notify: return "nua_r_notify";
+  case nua_r_method: return "nua_r_method";
+
+  case nua_r_cancel: return "nua_r_cancel";
+  case nua_r_authenticate: return "nua_r_authenticate";
+  case nua_r_authorize: return "nua_r_authorize";
+  case nua_r_redirect: return "nua_r_redirect";
+  case nua_r_destroy: return "nua_r_destroy";
+  case nua_r_respond: return "nua_r_respond";
+  case nua_r_nit_respond: return "nua_r_nit_respond";
+  case nua_r_set_params: return "nua_r_set_params";
+  case nua_r_ack: return "nua_r_ack";
+  default: return "NUA_UNKNOWN";
+  }
+}
+
+/** Return name of call state */
+char const *nua_callstate_name(enum nua_callstate state)
+{
+  switch (state) {
+  case nua_callstate_init: return "init";
+  case nua_callstate_authenticating: return "authenticating";
+  case nua_callstate_calling: return "calling";
+  case nua_callstate_proceeding: return "proceeding";
+  case nua_callstate_completing: return "completing";
+  case nua_callstate_received: return "received";
+  case nua_callstate_early: return "early";
+  case nua_callstate_completed: return "completed";
+  case nua_callstate_ready: return "ready";
+  case nua_callstate_terminating: return "terminating";
+  case nua_callstate_terminated: return "terminated";
+  default: return "UNKNOWN";
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,554 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_dialog.c
+ * @brief Dialog and dialog usage handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/sip_protos.h>
+
+#define NUA_OWNER_T su_home_t
+
+#include "nua_dialog.h"
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#ifndef NONE
+#define NONE ((void *)-1)
+#endif
+
+/* ======================================================================== */
+/* Dialog handling */
+
+static void nua_dialog_usage_remove_at(nua_owner_t*, nua_dialog_state_t*, 
+				       nua_dialog_usage_t**);
+static void nua_dialog_log_usage(nua_owner_t *, nua_dialog_state_t *);
+
+/**@internal
+ * UAS tag and route.
+ *
+ * Update dialog tags and route on the UAS side.
+ *
+ * @param own  dialog owner
+ * @param ds   dialog state
+ * @param sip  SIP message containing response used to update dialog
+ * @param rtag if true, set remote tag within the leg
+ */
+void nua_dialog_uas_route(nua_owner_t *own, 
+			  nua_dialog_state_t *ds,
+			  sip_t const *sip, 
+			  int rtag)
+{
+  int established = nua_dialog_is_established(ds);
+
+  if (!established && sip->sip_from->a_tag)
+    ds->ds_remote_tag = su_strdup(own, sip->sip_from->a_tag);
+
+  if (ds->ds_leg == NULL)
+    return;
+
+  nta_leg_server_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact);
+  ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact;
+
+  if (rtag && !established && sip->sip_from->a_tag)
+    nta_leg_rtag(ds->ds_leg, sip->sip_from->a_tag);
+}
+
+/**@internal
+ * UAC tag and route.
+ *
+ * Update dialog tags and route on the UAC side.
+ *
+ * @param own  dialog owner
+ * @param ds   dialog state
+ * @param sip  SIP message containing response used to update dialog
+ * @param rtag if true, set remote tag within the leg
+ */
+void nua_dialog_uac_route(nua_owner_t *own, 
+			  nua_dialog_state_t *ds,
+			  sip_t const *sip,
+			  int rtag)
+{
+  int established = nua_dialog_is_established(ds);
+
+  if (!established && sip->sip_to->a_tag)
+    ds->ds_remote_tag = su_strdup(own, sip->sip_to->a_tag);
+
+  if (ds->ds_leg == NULL)
+    return;
+
+  nta_leg_client_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact);
+  ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact;
+
+  if (rtag && !established && sip->sip_to->a_tag)
+    nta_leg_rtag(ds->ds_leg, sip->sip_to->a_tag);
+}
+
+/**@internal Store information from remote endpoint. */
+void nua_dialog_store_peer_info(nua_owner_t *own, 
+				nua_dialog_state_t *ds,
+				sip_t const *sip)
+{
+  nua_remote_t *nr = ds->ds_remote_ua;
+  nua_dialog_usage_t *du;
+  nua_remote_t old[1];
+
+  *old = *nr;
+
+  if (sip && sip->sip_status &&
+      sip->sip_status->st_status >= 300 &&
+      sip->sip_status->st_status <= 399)
+    sip = NULL;			/* Redirected */
+
+  if (sip == NULL) {
+    nr->nr_allow = NULL, su_free(own, old->nr_allow);
+    nr->nr_accept = NULL, su_free(own, old->nr_accept);
+    nr->nr_require = NULL, su_free(own, old->nr_require);
+    nr->nr_supported = NULL, su_free(own, old->nr_supported);
+    nr->nr_user_agent = NULL, su_free(own, old->nr_user_agent);
+    return;
+  }
+
+  if (sip->sip_allow) {
+    nr->nr_allow = sip_allow_dup(own, sip->sip_allow);
+    su_free(own, old->nr_allow);
+  }
+
+  if (sip->sip_accept) {
+    nr->nr_accept = sip_accept_dup(own, sip->sip_accept);
+    su_free(own, old->nr_accept);
+  }
+
+  if (sip->sip_require) {
+    nr->nr_require = sip_require_dup(own, sip->sip_require);
+    su_free(own, old->nr_require);
+  }
+
+  if (sip->sip_supported) {
+    nr->nr_supported = sip_supported_dup(own, sip->sip_supported);
+    su_free(own, old->nr_supported);
+  }
+
+  if (sip->sip_user_agent) {
+    nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_user_agent);
+    su_free(own, old->nr_user_agent);
+  }
+  else if (sip->sip_server) {
+    nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_server);
+    su_free(own, old->nr_user_agent);
+  }
+
+  for (du = ds->ds_usage; du; du = du->du_next) {
+    if (du->du_class->usage_peer_info)
+      du->du_class->usage_peer_info(du, ds, sip);
+  }
+}
+
+/** Remove dialog (if there is no other usages). */
+int nua_dialog_remove(nua_owner_t *own,
+		      nua_dialog_state_t *ds,
+		      nua_dialog_usage_t *usage)
+{
+  if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) {
+    nua_dialog_store_peer_info(own, ds, NULL); /* zap peer info */
+    nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
+    su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
+    ds->ds_route = 0;
+  }
+  return 0;
+}
+
+
+/** @internal Get dialog usage slot. */
+nua_dialog_usage_t **
+nua_dialog_usage_at(nua_dialog_state_t const *ds, 
+		    nua_usage_class const *kind,
+		    sip_event_t const *event)
+{
+  static nua_dialog_usage_t *none = NULL;
+
+  if (ds) {
+    nua_dialog_usage_t *du, * const * prev;
+    sip_event_t const *o;
+
+    for (prev = &ds->ds_usage; (du = *prev); prev = &du->du_next) {
+      if (du->du_class != kind)
+	continue;
+
+      if (event == NONE)
+	return (nua_dialog_usage_t **)prev;
+
+      o = du->du_event;
+
+      if (!event && !o)
+	return (nua_dialog_usage_t **)prev;
+
+      if (event != o) {
+	if (event == NULL || o == NULL)
+	  continue;
+	if (strcmp(event->o_type, o->o_type))
+	  continue;
+	if (str0casecmp(event->o_id, o->o_id)) {
+	  if (event->o_id || strcmp(event->o_type, "refer"))
+	    continue;
+	}
+      }
+
+      return (nua_dialog_usage_t **)prev;
+    }
+  }
+
+  return &none;
+}
+
+/** @internal Get a dialog usage */
+nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds, 
+					 nua_usage_class const *kind,
+					 sip_event_t const *event)
+{
+  return *nua_dialog_usage_at(ds, kind, event);
+}
+
+/** @internal Get dialog usage name */
+char const *nua_dialog_usage_name(nua_dialog_usage_t const *du)
+{
+  if (du == NULL)
+    return "<NULL>";
+  return du->du_class->usage_name(du);
+} 
+
+/** @internal Add dialog usage */
+nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own, 
+					 struct nua_dialog_state *ds, 
+					 nua_usage_class const *uclass,
+					 sip_event_t const *event)
+{
+  if (ds) {
+    sip_event_t *o;
+    nua_dialog_usage_t *du, **prev_du;
+
+    prev_du = nua_dialog_usage_at(ds, uclass, event);
+    du = *prev_du;
+    if (du) {		/* Already exists */
+      SU_DEBUG_5(("nua(%p): adding already existing %s usage%s%s\n",
+		  own, nua_dialog_usage_name(du), 
+		  event ? "  with event " : "", event ? event->o_type : ""));
+      
+      if (prev_du != &ds->ds_usage) {
+	/* Move as a first usage in the list */
+	*prev_du = du->du_next;
+	du->du_next = ds->ds_usage;
+	ds->ds_usage = du;
+      }
+      return du;
+    }
+
+    o = event ? sip_event_dup(own, event) : NULL;
+
+    if (o != NULL || event == NULL)
+      du = su_zalloc(own, sizeof *du + uclass->usage_size);
+
+    if (du) {
+      du->du_class = uclass;
+      du->du_event = o;
+
+      if (uclass->usage_add(own, ds, du) < 0) {
+	su_free(own, o);
+	su_free(own, du);
+	return NULL;
+      }
+	
+      SU_DEBUG_5(("nua(%p): adding %s usage%s%s\n",
+		  own, nua_dialog_usage_name(du), 
+		  o ? " with event " : "", o ? o->o_type :""));
+
+      su_home_ref(own);
+      du->du_next = ds->ds_usage, ds->ds_usage = du;
+
+      return du;
+    }
+
+    su_free(own, o);
+  }
+
+  return NULL;
+}
+
+/** @internal Remove dialog usage. */
+void nua_dialog_usage_remove(nua_owner_t *own, 
+			     nua_dialog_state_t *ds,
+			     nua_dialog_usage_t *du)
+{
+  nua_dialog_usage_t **at;
+
+  assert(own); assert(ds); assert(du);
+
+  for (at = &ds->ds_usage; *at; at = &(*at)->du_next)
+    if (du == *at)
+      break;
+
+  assert(*at);
+
+  nua_dialog_usage_remove_at(own, ds, at);
+}
+
+/** @internal Remove dialog usage. 
+ *
+ * Zap dialog state (leg, tag and route) if no usages remain. 
+*/
+static 
+void nua_dialog_usage_remove_at(nua_owner_t *own, 
+				nua_dialog_state_t *ds,
+				nua_dialog_usage_t **at)
+{
+  if (*at) {
+    nua_dialog_usage_t *du = *at;
+    sip_event_t const *o = NULL;
+    nua_client_request_t *cr, *cr_next;
+    nua_server_request_t *sr, *sr_next;
+
+    for (cr = ds->ds_cr; cr; cr = cr_next) {
+      cr_next = cr->cr_next;
+      if (cr->cr_usage == du)
+	cr->cr_usage = NULL;
+    }
+
+    for (sr = ds->ds_sr; sr; sr = sr_next) {
+      sr_next = sr->sr_next;
+      if (sr->sr_usage == du)
+	nua_server_request_destroy(sr);
+    }
+
+    *at = du->du_next;
+
+    o = du->du_event;
+
+    SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
+		own, nua_dialog_usage_name(du), 
+		o ? " with event " : "", o ? o->o_type :""));
+    du->du_class->usage_remove(own, ds, du);
+    msg_destroy(du->du_msg), du->du_msg = NULL;
+    su_home_unref(own);
+    su_free(own, du);
+  }
+
+  /* Zap dialog if there is no more usages */
+  if (ds->ds_usage == NULL) {
+    nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
+    su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
+    ds->ds_route = 0;
+    ds->ds_has_events = 0;
+    ds->ds_terminated = 0;
+    return;
+  }
+  else if (!ds->ds_terminated) {
+    nua_dialog_log_usage(own, ds);
+  }
+}
+
+static
+void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
+{
+  nua_dialog_usage_t *du;
+
+  if (SU_LOG->log_level >= 3) {
+    char buffer[160];
+    size_t l = 0, N = sizeof buffer;
+    ssize_t n;
+    
+    buffer[0] = '\0';
+
+    for (du = ds->ds_usage; du; du = du->du_next) {
+      msg_header_t const *h = (void *)du->du_event;
+
+      if (!h)
+	continue;
+
+      n = sip_event_e(buffer + l, N - l, h, 0);
+      if (n == -1)
+	break;
+      l += (size_t)n;
+      if (du->du_next && l + 2 < sizeof(buffer)) {
+	strcpy(buffer + l, ", ");
+	l += 2;
+      }
+    }
+    
+    SU_DEBUG_3(("nua(%p): handle with %s%s%s\n", own,
+		ds->ds_has_session ? "session and " : "", 
+		ds->ds_has_events ? "events " : "",
+		buffer));
+  }
+}
+
+/** Deinitialize dialog and its usage. @internal */
+void nua_dialog_deinit(nua_owner_t *own,
+		       nua_dialog_state_t *ds)
+{
+  while (ds->ds_usage) {
+    nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
+  }
+}
+
+
+/** @internal Dialog has been terminated. Remove all usages. */
+void nua_dialog_terminated(nua_owner_t *own,
+			   struct nua_dialog_state *ds,
+			   int status,
+			   char const *phrase)
+{
+
+  ds->ds_terminated = 1;
+
+  while (ds->ds_usage) {
+#if 0
+    int call = 0;
+
+    if (ds->ds_usage->du_kind == nua_session_usage)
+      call = 1;			/* Delay sending the event */
+    else
+      /* XXX */;
+#endif
+    nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
+  }
+}
+
+/**@internal
+ * Set expiration time. 
+ */
+void nua_dialog_usage_set_expires(nua_dialog_usage_t *du,
+				  unsigned delta)
+{
+  if (delta) {
+    sip_time_t now = sip_now(), expires = now + delta;
+    if (expires < now)
+      expires = SIP_TIME_MAX;
+    du->du_expires = expires;
+    nua_dialog_usage_set_refresh(du, delta);
+  }
+  else
+    du->du_expires = 0, du->du_refresh = 0;
+}
+
+/**@internal
+ * Set refresh value suitably. 
+ *
+ * The refresh time is set either around half of the @a delta interval or,
+ * if @a delta is less than 5 minutes but longer than 90 seconds, 30..60
+ * seconds before end of interval.
+ *
+ * If @a delta is 0, the refresh time is set at the end of the world
+ * (maximum time, for 32-bit systems sometimes during 2036).
+ */
+void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta)
+{
+  if (delta == 0)
+    du->du_refresh = 0;
+  else if (delta > 90 && delta < 5 * 60)
+    /* refresh 30..60 seconds before deadline */
+    nua_dialog_usage_refresh_range(du, delta - 60, delta - 30);
+  else {
+    /* By default, refresh around half time before deadline */
+    unsigned min = (delta + 2) / 4;
+    unsigned max = (delta + 2) / 4 + (delta + 1) / 2;
+    if (min == 0)
+      min = 1;
+    nua_dialog_usage_refresh_range(du, min, max);
+  }
+}
+
+/**@internal Set refresh in range min..max seconds in the future. */
+void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du, 
+				    unsigned min, unsigned max)
+{
+  sip_time_t now = sip_now(), target;
+  unsigned delta;
+
+  if (max < min)
+    max = min;
+
+  if (min != max)
+    delta = su_randint(min, max);
+  else
+    delta = min;
+
+  if (now + delta >= now)
+    target = now + delta;
+  else
+    target = SIP_TIME_MAX;
+
+  SU_DEBUG_7(("nua(): refresh %s after %lu seconds (in [%u..%u])\n",
+	      nua_dialog_usage_name(du), target - now, min, max));
+
+  du->du_refresh = target;
+}
+
+/**@internal Do not refresh. */
+void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du)
+{
+  du->du_refresh = 0;
+}
+
+/** @internal Refresh usage or shutdown usage if @a now is 0. */
+void nua_dialog_usage_refresh(nua_owner_t *owner,
+			      nua_dialog_state_t *ds,
+			      nua_dialog_usage_t *du, 
+			      sip_time_t now)
+{
+  if (du) {
+    du->du_refresh = 0;
+
+    if (now > 0) {
+      if (du->du_class->usage_refresh) {
+	du->du_class->usage_refresh(owner, ds, du, now);
+	return;
+      }
+    }
+    else {
+      du->du_shutdown = 1;
+      if (du->du_class->usage_shutdown) {
+	du->du_class->usage_shutdown(owner, ds, du);
+	return;
+      }
+    }
+  }
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,304 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_DIALOG_H
+/** Defined when <nua_dialog.h> has been included. */
+#define NUA_DIALOG_H
+
+/**@IFILE nua_dialog.h 
+ * @brief Dialog and dialog usage handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:38:18 EET 2006  ppessi
+ */
+
+typedef struct nua_dialog_state nua_dialog_state_t;
+typedef struct nua_dialog_usage nua_dialog_usage_t;
+typedef struct nua_remote_s nua_remote_t;
+
+#ifndef NUA_OWNER_T
+#define NUA_OWNER_T struct nua_owner_s
+#endif
+typedef NUA_OWNER_T nua_owner_t;
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+typedef struct nua_server_request nua_server_request_t; 
+typedef struct nua_client_request nua_client_request_t; 
+
+/** Respond to an incoming request. */
+typedef int nua_server_respond_f(nua_server_request_t *, tagi_t const *);
+
+/** Restart an outgoing request. */
+typedef void nua_creq_restart_f(nua_owner_t *, tagi_t *tags);
+
+/** Server side transaction */
+struct nua_server_request {
+  struct nua_server_request *sr_next, **sr_prev;
+
+  nua_owner_t *sr_owner;	/**< Backpointer to handle */
+  nua_dialog_usage_t *sr_usage;	/**< Backpointer to usage */
+
+  /** When the application responds to an request with
+   * nua_respond(), the sr_respond() is called
+   */
+  nua_server_respond_f *sr_respond;
+  
+  nta_incoming_t *sr_irq;	/**< Server transaction object */
+  msg_t *sr_msg;		/**< Request message */
+
+  sip_method_t sr_method;	/**< Request method */
+  int sr_status;		/**< Status code */
+  char const *sr_phrase;	/**< Status phrase */
+
+  unsigned sr_auto:1;		/**< Autoresponse - no event has been sent */
+  unsigned sr_initial:1;	/**< Handle was created by this request */
+
+  /* Flags used with offer-answer */
+  unsigned sr_offer_recv:1;	/**< We have received an offer */
+  unsigned sr_answer_sent:2;	/**< We have answered (reliably, if >1) */
+
+  unsigned sr_offer_sent:1;	/**< We have offered SDP */
+  unsigned sr_answer_recv:1;	/**< We have received SDP answer */
+};
+
+#define SR_INIT(sr)			     \
+  ((void)memset((sr), 0, sizeof (sr)[0]),    \
+   (void)(SR_STATUS1((sr), SIP_100_TRYING)), \
+   sr)
+
+#define SR_STATUS(sr, status, phrase) \
+  ((sr)->sr_phrase = (phrase), (sr)->sr_status = (status))
+
+#define SR_STATUS1(sr, statusphrase)					\
+  sr_status(sr, statusphrase)
+
+su_inline 
+int sr_status(nua_server_request_t *sr, int status, char const *phrase)
+{
+  return (void)(sr->sr_phrase = phrase), (sr->sr_status = status);
+}
+
+struct nua_client_request
+{
+  nua_client_request_t *cr_next;        /**< Linked list of requests */
+  /*nua_event_t*/ int cr_event;		/**< Request event */
+  nua_creq_restart_f *cr_restart;
+  nta_outgoing_t     *cr_orq;
+  msg_t              *cr_msg;
+  nua_dialog_usage_t *cr_usage;
+  unsigned short      cr_retry_count;   /**< Retry count for this request */
+
+  /* Flags used with offer-answer */
+  unsigned short      cr_answer_recv;   /**< Recv answer in response 
+					 *  with this status.
+					 */
+  unsigned            cr_offer_sent:1;  /**< Sent offer in this request */
+
+  unsigned            cr_offer_recv:1;  /**< Recv offer in a response */
+  unsigned            cr_answer_sent:1; /**< Sent answer in (PR)ACK */
+
+  unsigned            cr_has_contact:1; /**< Request has application contact */
+};
+
+
+struct nua_dialog_state
+{
+  nua_client_request_t ds_cr[1];
+  nua_server_request_t *ds_sr;
+
+  /** Dialog usages. */
+  nua_dialog_usage_t     *ds_usage;
+
+  /* Dialog and subscription state */
+  unsigned ds_route:1;		/**< We have route */
+  unsigned ds_terminated:1;	/**< Being terminated */
+
+  unsigned ds_has_session:1;	/**< We have session */
+  unsigned ds_has_register:1;	/**< We have registration */
+  unsigned ds_has_publish:1;	/**< We have publish */
+
+  unsigned ds_has_referrals:1;	/**< We have (or have had) referrals */
+
+  unsigned :0;
+
+  unsigned ds_has_events;	/**< We have events */
+  unsigned ds_has_subscribes;   /**< We have subscriptions */
+  unsigned ds_has_notifys;	/**< We have notifiers */
+
+  sip_from_t const *ds_local;		/**< Local address */
+  sip_to_t const *ds_remote;		/**< Remote address */
+  nta_leg_t      *ds_leg;
+  char const     *ds_remote_tag;	/**< Remote tag (if any). 
+					 * Should be non-NULL 
+					 * if dialog is established.
+					 */
+
+  struct nua_remote_s {
+    sip_allow_t      *nr_allow;
+    sip_accept_t     *nr_accept;
+    sip_require_t    *nr_require;
+    sip_supported_t  *nr_supported;
+    sip_user_agent_t *nr_user_agent;
+  } ds_remote_ua[1];
+};
+
+typedef void nh_pending_f(nua_owner_t *, 
+			  nua_dialog_usage_t *du,
+			  sip_time_t now);
+
+/** Virtual function pointer table for dialog usage. */
+typedef struct {
+  unsigned usage_size, usage_class_size;
+  int (*usage_add)(nua_owner_t *, 
+		   nua_dialog_state_t *ds,
+		   nua_dialog_usage_t *du);
+  void (*usage_remove)(nua_owner_t *, 
+		       nua_dialog_state_t *ds,
+		       nua_dialog_usage_t *du);
+  char const *(*usage_name)(nua_dialog_usage_t const *du);
+  void (*usage_peer_info)(nua_dialog_usage_t *du,
+			  nua_dialog_state_t const *ds,
+			  sip_t const *sip);
+  void (*usage_refresh)(nua_owner_t *, nua_dialog_state_t *ds,
+			nua_dialog_usage_t *, sip_time_t now);
+  int (*usage_shutdown)(nua_owner_t *, nua_dialog_state_t *ds, 
+			nua_dialog_usage_t *);
+} nua_usage_class;
+
+
+/** Base structure for dialog usage. */
+struct nua_dialog_usage {
+  nua_dialog_usage_t *du_next;
+  nua_usage_class const *du_class;
+
+  unsigned     du_terminating:1;	/**< Now trying to terminate usage */
+  unsigned     du_ready:1;	        /**< Established usage */
+  unsigned     du_shutdown:1;	        /**< Shutdown in progress */
+  unsigned:0;
+
+  /** When usage expires.
+   * Non-zero if the usage is established, SIP_TIME_MAX if there no
+   * expiration time.
+   */
+  sip_time_t      du_expires;		
+
+  sip_time_t      du_refresh;		/**< When to refresh */
+
+  sip_event_t const *du_event;		/**< Event of usage */
+
+  msg_t *du_msg;			/**< Template message */
+};
+
+void nua_dialog_uac_route(nua_owner_t *, nua_dialog_state_t *ds,
+			  sip_t const *sip, int rtag);
+void nua_dialog_uas_route(nua_owner_t *, nua_dialog_state_t *ds,
+			  sip_t const *sip, int rtag);
+void nua_dialog_store_peer_info(nua_owner_t *, nua_dialog_state_t *ds,
+				sip_t const *sip);
+int nua_dialog_remove(nua_owner_t *own,
+		      nua_dialog_state_t *ds,
+		      nua_dialog_usage_t *usage);
+
+char const *nua_dialog_usage_name(nua_dialog_usage_t const *du);
+
+nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *, 
+					 struct nua_dialog_state *ds,
+					 nua_usage_class const *uclass,
+					 sip_event_t const *event);
+
+nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds, 
+					 nua_usage_class const *uclass,
+					 sip_event_t const *event);
+
+void nua_dialog_usage_remove(nua_owner_t *, 
+			     nua_dialog_state_t *ds,
+			     nua_dialog_usage_t *du);
+
+void nua_dialog_deinit(nua_owner_t *own,
+		       nua_dialog_state_t *ds);
+
+void nua_dialog_terminated(nua_owner_t *,
+			   struct nua_dialog_state *ds,
+			   int status,
+			   char const *phrase);
+
+void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
+
+void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
+
+void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du, 
+				    unsigned min, unsigned max);
+
+void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du);
+
+void nua_dialog_usage_refresh(nua_owner_t *owner,
+			      nua_dialog_state_t *ds,
+			      nua_dialog_usage_t *du, 
+			      sip_time_t now);
+
+static inline
+int nua_dialog_is_established(nua_dialog_state_t const *ds)
+{
+  return ds->ds_remote_tag != NULL;
+}
+
+#if 0
+static inline
+void *nua_dialog_usage_private(nua_dialog_usage_t const *du)
+{
+  return du ? (void *)(du + 1) : NULL;
+}
+
+static inline
+nua_dialog_usage_t *nua_dialog_usage_public(void const *p)
+{
+  return p ? (nua_dialog_usage_t *)p - 1 : NULL;
+}
+#else
+#define nua_dialog_usage_private(du) ((du) ? (void*)((du) + 1) : NULL)
+#define nua_dialog_usage_public(p) ((p) ? (nua_dialog_usage_t*)(p) - 1 : NULL)
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+void nua_server_request_destroy(nua_server_request_t *sr);
+
+int nua_server_respond(nua_server_request_t *sr,
+		       int status, char const *phrase,
+		       tag_type_t tag, tag_value_t value, ...);
+
+msg_t *nua_server_response(nua_server_request_t *sr,
+			   int status, char const *phrase,
+			   tag_type_t tag, tag_value_t value, ...);
+
+int nua_default_respond(nua_server_request_t *sr,
+			tagi_t const *tags);
+
+
+#endif /* NUA_DIALOG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_event_server.c
+ * @brief Easy event server
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#define NEA_SMAGIC_T         struct nua_handle_s
+#define NEA_EMAGIC_T         struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* Event server */
+
+static
+nea_event_t *nh_notifier_event(nua_handle_t *nh, 
+			       su_home_t *home, 
+			       sip_event_t const *event,
+			       tagi_t const *tags);
+
+static
+void authorize_watcher(nea_server_t *nes,
+		       nua_handle_t *nh,
+		       nea_event_t *ev,
+		       nea_subnode_t *sn,
+		       sip_t const *sip);
+
+void
+nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  sip_event_t const *event = NULL;
+  sip_content_type_t const *ct = NULL;
+  sip_payload_t const *pl = NULL;
+  url_string_t const *url = NULL;
+  char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
+  nea_event_t *ev;
+  int status = 900;
+  char const *phrase = nua_internal_error;
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  tl_gets(tags, 
+	  NUTAG_URL_REF(url), 
+	  SIPTAG_EVENT_REF(event),
+	  SIPTAG_EVENT_STR_REF(event_s),
+	  SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+	  SIPTAG_PAYLOAD_REF(pl),
+	  SIPTAG_PAYLOAD_STR_REF(pl_s),
+	  TAG_END());
+
+  if (!event && !event_s)
+    status = 400, phrase = "Missing Event";
+
+  else if (!ct && !ct_s) 
+    status = 400, phrase = "Missing Content-Type";
+
+  else if (!nh->nh_notifier &&
+	   !(nh->nh_notifier = 
+	     nea_server_create(nua->nua_nta, nua->nua_root,
+			       url->us_url,
+			       NH_PGET(nh, max_subscriptions), 
+			       NULL, nh,
+			       TAG_NEXT(tags)))) 
+    status = 900, phrase = nua_internal_error;
+
+  else if (!event && !(event = sip_event_make(home, event_s)))
+    status = 900, phrase = "Could not create an event header";
+
+  else if (!(ev = nh_notifier_event(nh, home, event, tags)))
+    status = 900, phrase = "Could not create an event view";
+
+  else if (nea_server_update(nh->nh_notifier, ev,  TAG_NEXT(tags)) < 0)
+    status = 900, phrase = "No content for event";
+
+  else if (nea_server_notify(nh->nh_notifier, ev) < 0)
+    status = 900, phrase = "Error when notifying watchers";
+
+  else 
+    nua_stack_event(nua, nh, NULL, e, status = SIP_200_OK, 
+		    SIPTAG_EVENT(event),
+		    SIPTAG_CONTENT_TYPE(ct),
+		    TAG_END());
+	     
+  if (status != 200)
+    nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END());
+
+  su_home_deinit(home);
+}
+
+
+/* Create a event view for notifier */
+static
+nea_event_t *nh_notifier_event(nua_handle_t *nh, 
+			       su_home_t *home, 
+			       sip_event_t const *event,
+			       tagi_t const *tags)
+{
+  nea_event_t *ev = nea_event_get(nh->nh_notifier, event->o_type);
+  sip_accept_t const *accept = NULL;
+  char const  *accept_s = NULL;
+  sip_content_type_t const *ct = NULL;
+  char const *ct_s = NULL;
+
+  if (ev == NULL) {
+    char *o_type = su_strdup(home, event->o_type);
+    char *o_subtype = strchr(o_type, '.');
+
+    if (o_subtype)
+      *o_subtype++ = '\0';
+
+    tl_gets(tags, 
+	    SIPTAG_ACCEPT_REF(accept),
+	    SIPTAG_ACCEPT_STR_REF(accept_s),
+	    SIPTAG_CONTENT_TYPE_REF(ct),
+	    SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+	    TAG_END());
+      
+    /*
+     * XXX - We really should build accept header when we add new content
+     * types
+     */
+    if (accept_s == NULL && accept)
+      accept_s = sip_header_as_string(home, (sip_header_t *)accept);
+    if (accept_s == NULL && ct)
+      accept_s = ct->c_type;
+    if (accept_s == NULL && ct_s)
+      accept_s = ct_s;
+
+    ev = nea_event_create(nh->nh_notifier, 
+			  authorize_watcher, nh,
+			  o_type, o_subtype,
+			  ct ? ct->c_type : ct_s,
+			  accept_s);
+  }
+
+  return ev;
+}
+
+/* Callback from nea_server asking nua to authorize subscription */
+static
+void authorize_watcher(nea_server_t *nes,
+		       nua_handle_t *nh,
+		       nea_event_t *ev,
+		       nea_subnode_t *sn,
+		       sip_t const *sip)
+{
+  nua_t *nua = nh->nh_nua;
+  msg_t *msg = NULL;
+  nta_incoming_t *irq = NULL;
+  int substate = sn->sn_state;
+  int status; char const *phrase;
+
+  SET_STATUS1(SIP_200_OK);
+
+  /* OK. In nhp (nua_handle_preferences_t) structure we have the
+     current default action (or state) for incoming
+     subscriptions. 
+     Action can now be modified by the application with NUTAG_SUBSTATE(). 
+  */
+  irq = nea_sub_get_request(sn->sn_subscriber);
+  msg = nta_incoming_getrequest(irq);
+
+  if (sn->sn_state == nea_embryonic) {
+    char const *what;
+
+    substate = NH_PGET(nh, substate);
+
+    if (substate == nua_substate_embryonic)
+      substate = nua_substate_pending;
+
+    if (substate == nua_substate_terminated) {
+      what = "rejected"; SET_STATUS1(SIP_403_FORBIDDEN);
+    }
+    else if (substate == nua_substate_pending) {
+      what = "pending"; SET_STATUS1(SIP_202_ACCEPTED);
+    }
+    else {
+      what = "active";
+    }
+
+    SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", nh, what)); 
+    nea_sub_auth(sn->sn_subscriber, substate,
+		 TAG_IF(substate == nua_substate_pending,
+			NEATAG_FAKE(1)),
+		 TAG_IF(substate == nua_substate_terminated,
+			NEATAG_REASON("rejected")),
+		 TAG_END());
+  }
+  else if (sn->sn_state == nea_terminated || sn->sn_expires == 0) {
+    substate = nua_substate_terminated;
+    nea_server_flush(nes, NULL);
+    SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", 
+		nh, "watcher is removed")); 
+  }
+
+  nua_stack_event(nua, nh, msg, nua_i_subscription, status, phrase,
+	   NUTAG_SUBSTATE(substate),
+	   NEATAG_SUB(sn->sn_subscriber),
+	   TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* Authorization of watchers by application */
+
+void nua_stack_authorize(nua_t *nua,
+			 nua_handle_t *nh,
+			 nua_event_t e,
+			 tagi_t const *tags)
+{
+  nea_sub_t *sub = NULL;
+  int state = nea_extended;
+
+  tl_gets(tags,
+	  NEATAG_SUB_REF(sub),
+	  NUTAG_SUBSTATE_REF(state),
+	  TAG_END());
+
+  if (sub && state > 0) {
+    nea_sub_auth(sub, state, TAG_NEXT(tags));
+    nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
+  }
+  else {
+    nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, TAG_END());
+  }
+  return;
+}
+
+/** @internal Shutdown notifier object */
+int nh_notifier_shutdown(nua_handle_t *nh,
+			 nea_event_t *ev,
+			 tag_type_t t, 
+			 tag_value_t v, ...)
+{
+  nea_server_t *nes = nh->nh_notifier;
+  nea_subnode_t const **subs;
+  int busy = 0;
+
+  if (nes == NULL)
+    return 0;
+
+  subs = nea_server_get_subscribers(nes, ev);
+
+  if (subs) {
+    int i;
+    ta_list ta;
+
+    ta_start(ta, t, v);
+    
+    for (i = 0; subs[i]; i++)
+      nea_sub_auth(subs[i]->sn_subscriber, nea_terminated, ta_tags(ta));
+    
+    ta_end(ta);
+
+    busy++;
+  }
+
+  nea_server_free_subscribers(nes, subs);
+  
+  nea_server_flush(nh->nh_notifier, NULL);
+
+  if (ev == NULL)
+    nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
+
+  return busy;
+}
+
+
+/** @internal Terminate notifier. */
+void nua_stack_terminate(nua_t *nua,
+			 nua_handle_t *nh,
+			 nua_event_t e,
+			 tagi_t const *tags)
+{
+  sip_event_t const *event = NULL;
+  sip_content_type_t const *ct = NULL;
+  sip_payload_t const *pl = NULL;
+  char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
+  nea_event_t *nev = NULL;
+
+  if (nh->nh_notifier == NULL) {
+    UA_EVENT2(e, 900, "No event server to terminate");
+    return;
+  }
+
+  tl_gets(tags, 
+	  SIPTAG_EVENT_REF(event),
+	  SIPTAG_EVENT_STR_REF(event_s),
+	  SIPTAG_CONTENT_TYPE_REF(ct),
+	  SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+	  SIPTAG_PAYLOAD_REF(pl),
+	  SIPTAG_PAYLOAD_STR_REF(pl_s),
+	  TAG_END());
+
+  nev = nea_event_get(nh->nh_notifier, 
+		      event ? event->o_type : event_s);
+
+  if (nev && (pl || pl_s) && (ct || ct_s)) {
+    nea_server_update(nh->nh_notifier, nev, TAG_NEXT(tags));
+  }
+
+  nh_notifier_shutdown(nh, NULL, 
+		       NEATAG_REASON("noresource"), 
+		       TAG_NEXT(tags));
+
+  nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_extension.c
+ * @brief Extension method
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Nov 13 15:18:54 EET 2006
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+static int process_response_to_method(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+static void restart_method(nua_handle_t *nh, tagi_t *tags);
+static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
+
+/** Send an extension request. 
+ *
+ * Send an entension request message.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_METHOD() \n
+ *    NUTAG_URL() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_method
+ *
+ * @sa SIP_METHOD_UNKNOWN(), #nua_r_method, #nua_i_method
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+
+int 
+nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{ 
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+
+  if (cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+		     SIP_METHOD_UNKNOWN,
+		     TAG_NEXT(tags));
+  if (msg)
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_method, nh, NULL,
+				      msg,
+				      SIPTAG_END(),
+				      TAG_NEXT(tags));
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  return cr->cr_event = e;
+}
+
+/** @NUA_EVENT nua_r_method
+ *
+ * Response to an outgoing extension request.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response method, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the method
+ * @param hmagic application context associated with the handle
+ * @param sip    response to the extension request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive method in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_method(), #nua_i_method, @RFC3428
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_method(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip)
+{
+  if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_method))
+    return 0;
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+void restart_method(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_method, tags);
+}
+
+/** @NUA_EVENT nua_i_method
+ *
+ * @brief Incoming extension request.
+ *
+ * The extension request does not create a dialog. If the incoming request
+ * was not assiciated with an existing dialog the stack creates a new handle
+ * for it. If the handle @a nh is not bound, you should probably destroy it
+ * after responding to the request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the method
+ * @param hmagic application context associated with the handle
+ *               (maybe NULL if outside session)
+ * @param sip    incoming request
+ * @param tags   NUTAG_METHOD()
+ *
+ * The extension name is in sip->sip_request->rq_method_name, too.
+ *
+ * @sa nua_method(), #nua_r_method
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_method(nua_t *nua,
+			      nua_handle_t *nh,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+  
+  sr = SR_INIT(sr0);
+  
+  sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+			  respond_to_method, 0);
+
+  return nua_stack_server_event(nua, sr, nua_i_method, TAG_END());
+}
+
+static
+int respond_to_method(nua_server_request_t *sr, tagi_t const *tags)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_t *nua = nh->nh_nua;
+  msg_t *msg;
+
+  msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
+
+  if (msg) {
+    nta_incoming_mreply(sr->sr_irq, msg);
+  }
+  else {
+    SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+    nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+    nua_stack_event(nua, nh, NULL,
+		    nua_i_error, 900, "Response to Extension Method Fails",
+		    TAG_END());
+  }
+  
+  return sr->sr_status >= 200 ? sr->sr_status : 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_message.c
+ * @brief MESSAGE method
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 17:01:22 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* MESSAGE */
+
+/** Send an instant message. 
+ *
+ * Send an instant message using SIP MESSAGE method.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_message
+ *
+ * @sa #nua_i_message, @RFC3428
+ */
+
+static int process_response_to_message(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+
+int 
+nua_stack_message(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{ 
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+  sip_t *sip;
+
+  if (nh_is_special(nh)) {
+    return UA_EVENT2(e, 900, "Invalid handle for MESSAGE");
+  }
+  else if (cr->cr_orq) {
+    return UA_EVENT2(e, 900, "Request already in progress");
+  }
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+			 SIP_METHOD_MESSAGE,
+			 NUTAG_ADD_CONTACT(NH_PGET(nh, win_messenger_enable)),
+			 TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (sip)
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_message, nh, NULL,
+				      msg,
+				      SIPTAG_END(), TAG_NEXT(tags));
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  return cr->cr_event = e;
+}
+
+void restart_message(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_message, tags);
+}
+
+/** @NUA_EVENT nua_r_message
+ *
+ * Response to an outgoing @b MESSAGE request.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the message
+ * @param hmagic application context associated with the handle
+ * @param sip    response to MESSAGE request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_message(), #nua_i_message, @RFC3428
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_message(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip)
+{
+  if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_message))
+    return 0;
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/** @NUA_EVENT nua_i_message
+ *
+ * @brief Incoming @b MESSAGE request.
+ *
+ * The @b MESSAGE request does not create a dialog. If the incoming @b
+ * MESSAGE request is not assiciated with an existing dialog the stack
+ * creates a new handle for it. If the handle @a nh is not bound, you should
+ * probably destroy it after responding to the MESSAGE request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the message
+ * @param hmagic application context associated with the handle
+ *               (maybe NULL if outside session)
+ * @param sip    incoming MESSAGE request
+ * @param tags   empty
+ *
+ * @sa nua_message(), #nua_r_message, @RFC3428, @RFC3862
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_message(nua_t *nua,
+			      nua_handle_t *nh,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  msg_t *msg;
+
+  if (nh
+      ? !NH_PGET(nh, message_enable)
+      : !DNH_PGET(nua->nua_dhandle, message_enable))
+    return 403;
+
+  if (nh == NULL)
+    if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 0)))
+      return 500;		/* respond with 500 Internal Server Error */
+
+  msg = nta_incoming_getrequest(irq);
+
+  nua_stack_event(nh->nh_nua, nh, msg, nua_i_message, SIP_200_OK, TAG_END());
+
+#if 0 /* XXX */
+  if (nh->nh_nua->nua_messageRespond) {	
+    nh->nh_irq = irq;
+    return 0;
+  }
+#endif
+
+  return 200;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,722 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_notifier.c
+ * @brief SUBSCRIBE server, NOTIFY client and REFER server
+ *
+ * Simpler event server. See nua_event_server.c for more complex event
+ * server.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 15:10:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ---------------------------------------------------------------------- */
+/* Notifier event usage */
+
+struct notifier_usage
+{
+  enum nua_substate  nu_substate;	/**< Subscription state */
+  sip_time_t         nu_expires;
+};
+
+static char const *nua_notify_usage_name(nua_dialog_usage_t const *du);
+static int nua_notify_usage_add(nua_handle_t *nh, 
+				   nua_dialog_state_t *ds,
+				   nua_dialog_usage_t *du);
+static void nua_notify_usage_remove(nua_handle_t *nh, 
+				       nua_dialog_state_t *ds,
+				       nua_dialog_usage_t *du);
+static void nua_notify_usage_refresh(nua_handle_t *nh,
+				     nua_dialog_state_t *ds,
+				     nua_dialog_usage_t *du,
+				     sip_time_t now);
+static int nua_notify_usage_shutdown(nua_handle_t *nh,
+				     nua_dialog_state_t *ds,
+				     nua_dialog_usage_t *du);
+
+static nua_usage_class const nua_notify_usage[1] = {
+  {
+    sizeof (struct notifier_usage), (sizeof nua_notify_usage),
+    nua_notify_usage_add,
+    nua_notify_usage_remove,
+    nua_notify_usage_name,
+    NULL,
+    nua_notify_usage_refresh,
+    nua_notify_usage_shutdown,
+  }};
+
+static char const *nua_notify_usage_name(nua_dialog_usage_t const *du)
+{
+  return "notify";
+}
+
+static 
+int nua_notify_usage_add(nua_handle_t *nh, 
+			   nua_dialog_state_t *ds,
+			   nua_dialog_usage_t *du)
+{
+  ds->ds_has_events++;
+  ds->ds_has_notifys++;
+  return 0;
+}
+
+static 
+void nua_notify_usage_remove(nua_handle_t *nh, 
+			       nua_dialog_state_t *ds,
+			       nua_dialog_usage_t *du)
+{
+  ds->ds_has_events--;	
+  ds->ds_has_notifys--;	
+}
+
+/* ====================================================================== */
+/* SUBSCRIBE server */
+
+static int respond_to_subscribe(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_subscribe
+ *
+ * Incoming @b SUBSCRIBE request.
+ *
+ * @b SUBSCRIBE request is used to query SIP event state or establish a SIP
+ * event subscription.
+ *
+ * Initial SUBSCRIBE requests are dropped with <i>489 Bad Event</i>
+ * response, unless the application has explicitly included the @Event in
+ * the list of allowed events with nua_set_params() tag NUTAG_ALLOW_EVENTS()
+ * (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). The application
+ * can decide whether to accept the SUBSCRIBE request or reject it. The
+ * nua_response() call responding to a SUBSCRIBE request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag.
+ *
+ * If the application accepts the SUBSCRIBE request, it must immediately
+ * send an initial NOTIFY establishing the dialog. This is because the
+ * response to the SUBSCRIBE request may be lost because the SUBSCRIBE
+ * request was forked by an intermediate proxy. 
+ *
+ * SUBSCRIBE requests modifying (usually refreshing or terminating) an
+ * existing event subscription are accepted by default and a <i>200 OK</i>
+ * response along with a copy of previously sent NOTIFY is sent
+ * automatically.
+ *
+ * By default, only event subscriptions accepted are those created
+ * implicitly by REFER request. See #nua_i_refer how the application must
+ * handle the REFER requests.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase response phrase sent automatically by stack
+ * @param nh     operation handle associated with the incoming request
+ * @param hmagic application context associated with the handle
+ *               (NULL when handle is created by the stack)
+ * @param sip    SUBSCRIBE request headers
+ * @param tags   NUTAG_SUBSTATE()
+ *
+ * @sa @RFC3265, nua_notify(), NUTAG_SUBSTATE(), @SubscriptionState,
+ * @Event, nua_subscribe(), #nua_r_subscribe, #nua_i_refer, nua_refer()
+ *
+ * @END_NUA_EVENT
+ */
+
+
+/** @internal Process incoming SUBSCRIBE. */
+int nua_stack_process_subscribe(nua_t *nua,
+				nua_handle_t *nh,
+				nta_incoming_t *irq,
+				sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+  nua_dialog_state_t *ds;
+  nua_dialog_usage_t *du = NULL;
+  sip_event_t *o = sip->sip_event;
+  char const *event = o ? o->o_type : NULL;
+  
+  enum nua_substate substate = nua_substate_terminated;
+
+  enter;
+
+  if (nh)
+    du = nua_dialog_usage_get(ds = nh->nh_ds, nua_notify_usage, o);
+
+  sr = SR_INIT(sr0);
+  
+  if (nh == NULL || du == NULL) {
+    sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+
+    if (event && str0cmp(event, "refer") == 0)
+      /* refer event subscription should be initiated with REFER */
+      SR_STATUS1(sr, SIP_403_FORBIDDEN);
+    else if (!event || !msg_header_find_param(allow_events->k_common, event))
+      SR_STATUS1(sr, SIP_489_BAD_EVENT);
+    else
+      substate = nua_substate_embryonic;
+  }
+  else {
+    /* Refresh existing subscription */
+    struct notifier_usage *nu = nua_dialog_usage_private(du);
+    unsigned long expires;
+
+    assert(nh && du && nu);
+
+    expires = str0cmp(event, "refer") ? 3600 : NH_PGET(nh, refer_expires);
+
+    if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+      expires = sip->sip_expires->ex_delta;
+
+    if (expires == 0)
+      nu->nu_substate = nua_substate_terminated;
+
+    nu->nu_expires = sip_now() + expires;
+    substate = nu->nu_substate;
+
+    /* XXX - send notify */
+
+    SR_STATUS1(sr, SIP_200_OK);
+  }
+
+  sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+			  respond_to_subscribe, 1);
+
+  if (!du && substate == nua_substate_embryonic && sr->sr_status < 300) {
+    nh = sr->sr_owner; assert(nh && nh != nua->nua_dhandle);
+    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, sip->sip_event);
+    if (du) {
+      struct notifier_usage *nu = nua_dialog_usage_private(du);
+      unsigned long expires = 3600; /* XXX */
+      
+      if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+	expires = sip->sip_expires->ex_delta;
+
+      nu->nu_expires = sip_now() + expires;
+      nu->nu_substate = substate;
+    }
+    else 
+      SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+  }
+
+  if (substate == nua_substate_embryonic && sr->sr_status >= 300)
+    substate = nua_substate_terminated;
+
+  sr->sr_usage = du;
+
+  return nua_stack_server_event(nua, sr, nua_i_subscribe,
+				NUTAG_SUBSTATE(substate), TAG_END());
+}
+
+/** @internal Respond to an SUBSCRIBE request.
+ *
+ */
+static
+int respond_to_subscribe(nua_server_request_t *sr, tagi_t const *tags)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_t *nua = nh->nh_nua;
+  struct notifier_usage *nu;
+  sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+  sip_expires_t ex[1]; 
+  sip_time_t now = sip_now();
+  msg_t *msg;
+
+  sip_expires_init(ex);
+
+  nu = nua_dialog_usage_private(sr->sr_usage);
+  if (nu && nu->nu_expires > now)
+    ex->ex_delta = nu->nu_expires - now;
+
+  msg = nua_server_response(sr,
+			    sr->sr_status, sr->sr_phrase,
+			    NUTAG_ADD_CONTACT(sr->sr_status < 300),
+			    TAG_IF(nu, SIPTAG_EXPIRES(ex)),
+			    SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+			    SIPTAG_ALLOW_EVENTS(allow_events),
+			    TAG_NEXT(tags));
+
+  if (msg) {
+    sip_t *sip = sip_object(msg);
+
+    if (nu && sip->sip_expires && sr->sr_status < 300)
+      nu->nu_expires = now + sip->sip_expires->ex_delta;
+
+    nta_incoming_mreply(sr->sr_irq, msg);
+
+    if (nu && nu->nu_substate != nua_substate_embryonic)
+      /* Send NOTIFY (and terminate subscription, when needed) */
+      nua_dialog_usage_refresh(nh, ds, sr->sr_usage, sip_now());
+  }
+  else {
+    /* XXX - send nua_i_error */
+    SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+    nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+  }
+  
+  return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
+
+/* ======================================================================== */
+/* NOTIFY */
+
+static int process_response_to_notify(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip);
+
+static int nua_stack_notify2(nua_t *, nua_handle_t *, nua_event_t, 
+			     nua_dialog_usage_t *du,
+			     tagi_t const *tags);
+
+
+/**@fn void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send a SIP NOTIFY request message.
+ *
+ * This function is used when the application implements itself the
+ * notifier. The application must provide valid @SubscriptionState and
+ * @Event headers using SIP tags. If there is no @SubscriptionState header,
+ * the subscription state can be modified with NUTAG_SUBSTATE().
+ *
+ * @bug If the @Event is not given by application, stack uses the @Event
+ * header from the first subscription usage on handle.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_SUBSTATE() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_notify
+ *
+ * @sa @RFC3265, #nua_i_subscribe, #nua_i_refer, NUTAG_ALLOW_EVENTS()
+ */
+
+/**@internal Send NOTIFY. */
+int nua_stack_notify(nua_t *nua,
+		     nua_handle_t *nh,
+		     nua_event_t e,
+		     tagi_t const *tags)
+{
+  return nua_stack_notify2(nua, nh, e, NULL, tags);
+}
+
+
+int nua_stack_notify2(nua_t *nua,
+		      nua_handle_t *nh,
+		      nua_event_t e,
+		      nua_dialog_usage_t *du,
+		      tagi_t const *tags)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  struct notifier_usage *nu;
+  msg_t *msg;
+  sip_t *sip;
+  sip_event_t const *o;
+  sip_time_t now;
+  int refresh = du != NULL;
+
+  if (cr->cr_orq) {
+    return UA_EVENT2(e, 900, "Request already in progress");
+  }
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  if (refresh) {
+    assert(!cr->cr_msg);
+    if (cr->cr_msg)
+      msg_destroy(cr->cr_msg);
+    cr->cr_msg = msg_copy(du->du_msg);
+  }
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
+		     SIP_METHOD_NOTIFY,
+		     NUTAG_ADD_CONTACT(1),
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+  if (!sip)
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+
+  if (nh->nh_ds->ds_has_notifys == 1 && !sip->sip_event)
+    o = NONE;
+  else
+    o = sip->sip_event;
+
+  du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o);
+  nu = nua_dialog_usage_private(du);
+
+  if (du && du->du_event && !sip->sip_event)
+    sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
+
+  now = sip_now();
+
+  if (!du)
+    ;
+  else if (sip->sip_subscription_state) {
+    /* SIPTAG_SUBSCRIPTION_STATE() overrides NUTAG_SUBSTATE() */
+    char const *ss_substate = sip->sip_subscription_state->ss_substate;
+
+    if (strcasecmp(ss_substate, "terminated") == 0)
+      nu->nu_substate = nua_substate_terminated;
+    else if (strcasecmp(ss_substate, "pending") == 0)
+      nu->nu_substate = nua_substate_pending;
+    else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ 
+      nu->nu_substate = nua_substate_active;
+
+    if (sip->sip_subscription_state->ss_expires) {
+      unsigned long expires;
+      expires = strtoul(sip->sip_subscription_state->ss_expires, NULL, 10);
+      if (expires > 3600)
+        expires = 3600;
+      nu->nu_expires = now + expires;
+    }
+    else if (nu->nu_substate != nua_substate_terminated) {
+      sip_subscription_state_t *ss = sip->sip_subscription_state;
+      char *param;
+
+      if (now < nu->nu_expires)
+        param = su_sprintf(msg_home(msg), "expires=%lu", nu->nu_expires - now);
+      else
+        param = "expires=0";
+
+      msg_header_add_param(msg_home(msg), ss->ss_common, param);
+    }
+  }
+  else {
+    sip_subscription_state_t *ss;
+    enum nua_substate substate;
+    char const *name;
+
+    substate = nu->nu_substate;
+
+    if (nu->nu_expires <= now)
+      substate = nua_substate_terminated;
+
+    if (substate != nua_substate_terminated) {
+      tagi_t const *t = tl_find_last(tags, nutag_substate);
+      if (t)
+	substate = (enum nua_substate)t->t_value;
+    }
+
+    switch (substate) {
+    case nua_substate_embryonic:
+      /*FALLTHROUGH*/
+    case nua_substate_pending:
+      name = "pending";
+      nu->nu_substate = nua_substate_pending;
+      break;
+    case nua_substate_active:
+    default:
+      name = "active";
+      nu->nu_substate = nua_substate_active;
+      break;
+    case nua_substate_terminated:
+      name = "terminated";
+      nu->nu_substate = nua_substate_terminated;
+      break;
+    }
+
+    if (nu->nu_substate != nua_substate_terminated) {
+      unsigned long expires = nu->nu_expires - now;
+      ss = sip_subscription_state_format(msg_home(msg), "%s;expires=%lu",
+					 name, expires);
+    }
+    else {
+      ss = sip_subscription_state_make(msg_home(msg), "terminated; "
+				       "reason=noresource");
+    }
+
+    msg_header_insert(msg, (void *)sip, (void *)ss);
+  }
+
+  if (du) {
+    if (nu->nu_substate == nua_substate_terminated)
+      du->du_terminating = 1;
+
+    if (!du->du_terminating && !refresh) {
+      /* Save template */
+      if (du->du_msg)
+        msg_destroy(du->du_msg);
+      du->du_msg = msg_ref_create(cr->cr_msg);
+    }
+  }
+
+  /* NOTIFY outside a dialog */
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_notify, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(tags));
+
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  cr->cr_usage = du;
+
+  return cr->cr_event = e;
+}
+
+static
+void restart_notify(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_notify, tags);
+}
+
+/** @NUA_EVENT nua_r_notify
+ *
+ * Response to an outgoing @b NOTIFY request.
+ *
+ * The @b NOTIFY may be sent explicitly by nua_notify() or implicitly by NUA
+ * state machine. Implicit @b NOTIFY is sent when an established dialog is
+ * refreshed by client or it is terminated (either by client or because of a
+ * timeout)
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip    response to @b NOTIFY request or NULL upon an error 
+ *               (status code is in @a status and 
+ *               descriptive message in @a phrase parameters)
+ * @param tags   NUTAG_SUBSTATE() indicating subscription state
+ *
+ * @sa nua_notify(), @RFC3265, #nua_i_subscribe, #nua_i_refer
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_notify(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip)
+{
+  enum nua_substate substate = nua_substate_terminated;
+
+  if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_notify))
+    return 0;
+
+  if (nh->nh_ds->ds_cr->cr_usage) {
+    struct notifier_usage *nu = nua_dialog_usage_private(nh->nh_ds->ds_cr->cr_usage);
+    substate = nu->nu_substate;
+    assert(substate != nua_substate_embryonic);
+  }
+
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, 
+				    NUTAG_SUBSTATE(substate),
+				    TAG_END());
+}
+
+
+static void nua_notify_usage_refresh(nua_handle_t *nh,
+				     nua_dialog_state_t *ds,
+				     nua_dialog_usage_t *du,
+				     sip_time_t now)
+{
+  struct notifier_usage *nu = nua_dialog_usage_private(du);
+
+  if (nh->nh_ds->ds_cr->cr_usage == du) /* Already notifying. */
+    return;
+
+  if (now >= nu->nu_expires) {
+    sip_subscription_state_t ss[1];
+    char const *params[] = { NULL, NULL };
+    tagi_t tags[2] = {
+      { SIPTAG_SUBSCRIPTION_STATE(ss) }, { TAG_END() }
+    };
+
+    sip_subscription_state_init(ss);
+
+    ss->ss_substate = "terminated";
+    ss->ss_params = params;
+    params[0] = "reason=timeout";
+    ss->ss_reason = "timeout";
+
+    nua_stack_notify2(nh->nh_nua, nh, nua_r_notify, du, tags);
+  }
+  else {
+    nua_stack_notify2(nh->nh_nua, nh, nua_r_notify, du, NULL);
+  }
+}
+
+/** @interal Shut down NOTIFY usage. 
+ *
+ * @retval >0  shutdown done
+ * @retval 0   shutdown in progress
+ * @retval <0  try again later
+ */
+static int nua_notify_usage_shutdown(nua_handle_t *nh,
+				     nua_dialog_state_t *ds,
+				     nua_dialog_usage_t *du)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+
+  if (!cr->cr_usage) {
+    /* Unnotify */
+    nua_stack_notify2(nh->nh_nua, nh, nua_r_destroy, du, NULL);
+    return cr->cr_usage != du;
+  }
+
+  if (!du->du_ready && !cr->cr_orq)
+    return 1;			/* Unauthenticated NOTIFY? */
+
+  return -1;  /* Request in progress */
+}
+
+
+/* ======================================================================== */
+/* REFER */
+/* RFC 3515 */
+
+/** @NUA_EVENT nua_i_refer
+ *
+ * Incoming @b REFER request used to transfer calls.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the incoming request
+ * @param hmagic application context associated with the handle
+ *               (NULL if outside of an already established session)
+ * @param sip    incoming REFER request
+ * @param tags   NUTAG_REFER_EVENT() \n
+ *               SIPTAG_REFERRED_BY()
+ *  
+ * @sa nua_refer(), #nua_r_refer, @ReferTo, NUTAG_REFER_EVENT(), 
+ * SIPTAG_REFERRED_BY(), @ReferredBy, NUTAG_NOTIFY_REFER(),
+ * NUTAG_REFER_WITH_ID(), @RFC3515.
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming REFER. */
+int nua_stack_process_refer(nua_t *nua,
+			    nua_handle_t *nh,
+			    nta_incoming_t *irq,
+			    sip_t const *sip)
+{
+  nua_dialog_usage_t *du = NULL;
+  struct notifier_usage *nu;
+  sip_event_t *event;
+  sip_referred_by_t *by = NULL, default_by[1];
+  msg_t *response;
+  sip_time_t expires;
+  int created = 0;
+
+  if (nh == NULL) {
+    if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 1)))
+      return 500;
+    created = 1;
+  }
+
+  if (nh->nh_ds->ds_has_referrals || NH_PGET(nh, refer_with_id))
+    event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq);
+  else
+    event = sip_event_make(nh->nh_home, "refer");
+
+  if (event)
+    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, event);
+
+  if (!du || du->du_ready) {
+    if (du->du_ready) {
+      SU_DEBUG_1(("nua(%p): REFER with existing refer;id=%u\n", nh,
+		  sip->sip_cseq->cs_seq));
+    }
+    if (created) 
+      nh_destroy(nua, nh);
+    return 500;
+  }
+
+  nu = nua_dialog_usage_private(du);
+  du->du_ready = 1;
+  nh->nh_ds->ds_has_referrals = 1;
+
+  nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);	/* Set route and tags */
+
+  if (!sip->sip_referred_by) {
+    sip_from_t *a = sip->sip_from;
+
+    sip_referred_by_init(by = default_by);
+
+    *by->b_url = *a->a_url;
+    by->b_display = a->a_display;
+  }
+
+  response = nh_make_response(nua, nh, irq, 
+			      SIP_202_ACCEPTED, 
+			      NUTAG_ADD_CONTACT(1),
+			      TAG_END());
+
+  nta_incoming_mreply(irq, response);
+
+  expires = NH_PGET(nh, refer_expires);
+
+  if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+    expires = sip->sip_expires->ex_delta;
+  nu->nu_substate = nua_substate_pending;
+  nu->nu_expires = sip_now() + expires;
+
+  /* Immediate notify in order to establish the dialog */
+  if (!sip->sip_to->a_tag)
+    nua_stack_post_signal(nh,
+			  nua_r_notify,
+			  SIPTAG_EVENT(event),
+			  SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+			  SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"),
+			  TAG_END());
+  
+  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+		  nua_i_refer, SIP_202_ACCEPTED, 
+		  NUTAG_REFER_EVENT(event),
+		  TAG_IF(by, SIPTAG_REFERRED_BY(by)),
+		  TAG_END());
+  
+  su_free(nh->nh_home, event);
+
+  return 500;   
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_options.c
+ * @brief Implementation of OPTIONS client.
+ *
+ * OPTIONS server is in nua_session.c.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 17:02:19 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/**@fn void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Query capabilities from server with OPTIONS request.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_options
+ *
+ * @sa #nua_i_options, @RFC3261 section 10
+ */
+
+static int process_response_to_options(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+
+int
+nua_stack_options(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+
+  if (nh_is_special(nh)) {
+    return UA_EVENT2(e, 900, "Invalid handle for OPTIONS");
+  }
+  else if (cr->cr_orq) {
+    return UA_EVENT2(e, 900, "Request already in progress");
+  }
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+			 SIP_METHOD_OPTIONS, 
+			 TAG_NEXT(tags));
+
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_options, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(tags));
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  return cr->cr_event = e;
+}
+
+void restart_options(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_options, tags);
+}
+
+/** @NUA_EVENT nua_r_options
+ *
+ * Answer to outgoing OPTIONS.
+ *
+ * @param status response status code
+ *               (if the request is retried the @a status is 100 and the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the incoming OPTIONS request
+ * @param hmagic application context associated with the handle
+ * @param sip    response to OPTIONS request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_options(), @RFC3261 section 11, #nua_i_options
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_options(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip)
+{
+  if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_options))
+    return 0;
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1617 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_register.c
+ * @brief REGISTER and registrations
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/token64.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_tag_inline.h>
+
+#include <sofia-sip/bnf.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/msg_parser.h>
+
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#if !HAVE_STRCASESTR
+char *strcasestr(char const *haystack, char const *needle);
+#endif
+
+/* ====================================================================== */
+/* Helper macros and functions for handling #nua_handle_preferences_t. */
+
+#define NHP_IS_ANY_SET(nhp) nhp_is_any_set((nhp))
+
+/** Check if any preference is set in @a nhp. */
+su_inline int nhp_is_any_set(nua_handle_preferences_t const *nhp)
+{
+  char nhp_zero[sizeof nhp->nhp_set] = { 0 };
+  return memcmp(&nhp->nhp_set, nhp_zero, sizeof nhp->nhp_set) != 0;
+}
+
+/** Copy set parameters from @a b to @a a.
+ *
+ * If preference is set in @a b, mark it set also in @a a.
+ */
+su_inline void nhp_or_set(nua_handle_preferences_t *a,
+			  nua_handle_preferences_t const *b)
+{
+  unsigned *ap = a->nhp_set_.set_unsigned;
+  unsigned const *bp = b->nhp_set_.set_unsigned;
+  size_t i;
+
+  memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set));
+
+  for (i = 0; i < (sizeof a->nhp_set); i += (sizeof *ap))
+    *ap++ |= *bp++;
+}
+
+static int nhp_set_tags(su_home_t *home, 
+			nua_handle_preferences_t *nhp,
+			int global,
+			tagi_t const *tags);
+
+static int nhp_merge_lists(su_home_t *home,
+			   msg_hclass_t *hc,
+			   msg_list_t **return_new_list,
+			   msg_list_t const *old_list,
+			   int already_set,
+			   int already_parsed,
+			   int always_merge,
+			   tag_value_t value);
+
+static
+nua_handle_preferences_t *nhp_move_params(su_home_t *home,
+					  nua_handle_preferences_t *dst,
+					  su_home_t *tmphome,
+					  nua_handle_preferences_t const *src);
+
+/* ====================================================================== */
+/* Magical NUTAG_USER_AGENT() - add NHP_USER_AGENT there if it is not there */
+
+#define NHP_USER_AGENT PACKAGE_NAME "/" PACKAGE_VERSION
+
+static int already_contains_package_name(char const *s)
+{
+  char const pn[] = " " PACKAGE_NAME "/";
+  size_t pnlen = strlen(pn + 1);
+
+  return strncasecmp(s, pn + 1, pnlen) == 0 || strcasestr(s, pn);
+}
+
+/* ====================================================================== */
+/* Stack and handle parameters */
+
+static int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags);
+
+/** @internal Methods allowed by default. */
+static char const nua_allow_str[] =
+"INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, "
+"MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE";
+
+/** @internal Set default parameters */
+int nua_stack_set_defaults(nua_handle_t *nh, 
+			   nua_handle_preferences_t *nhp)
+{
+  su_home_t *home = (su_home_t *)nh;
+
+  /* Set some defaults */
+  NHP_SET(nhp, retry_count, 3);
+  NHP_SET(nhp, max_subscriptions, 20);
+
+  NHP_SET(nhp, media_enable, 1);
+  NHP_SET(nhp, invite_enable, 1);
+  NHP_SET(nhp, auto_alert, 0);
+  NHP_SET(nhp, early_media, 0);
+  NHP_SET(nhp, only183_100rel, 0);
+  NHP_SET(nhp, auto_answer, 0);
+  NHP_SET(nhp, auto_ack, 1);
+  NHP_SET(nhp, invite_timeout, 120);
+
+  NHP_SET(nhp, session_timer, 1800);
+  NHP_SET(nhp, min_se, 120);
+  NHP_SET(nhp, refresher, nua_no_refresher);
+  NHP_SET(nhp, update_refresh, 0);
+
+  NHP_SET(nhp, message_enable, 1);
+  NHP_SET(nhp, win_messenger_enable, 0);
+  if (getenv("PIMIW_HACK") != 0)
+    NHP_SET(nhp, message_auto_respond, 1);
+
+  NHP_SET(nhp, media_features,  0);
+  NHP_SET(nhp, callee_caps, 0);
+  NHP_SET(nhp, service_route_enable, 1);
+  NHP_SET(nhp, path_enable, 1);
+
+  NHP_SET(nhp, refer_expires, 300);
+  NHP_SET(nhp, refer_with_id, 1);
+
+  NHP_SET(nhp, substate, nua_substate_active);
+
+  NHP_SET(nhp, allow, sip_allow_make(home, nua_allow_str));
+  NHP_SET(nhp, supported, sip_supported_make(home, "timer, 100rel"));
+  NHP_SET(nhp, user_agent, su_strdup(home, NHP_USER_AGENT));
+
+  NHP_SET(nhp, outbound, su_strdup(home, "natify"));
+
+  NHP_SET(nhp, keepalive, 120000);
+
+  NHP_SET(nhp, appl_method,
+	  sip_allow_make(home, "INVITE, REGISTER, PUBLISH, SUBSCRIBE"));
+
+  if (!nhp->nhp_allow ||
+      !nhp->nhp_supported ||
+      !nhp->nhp_user_agent ||
+      !nhp->nhp_outbound)
+    return -1;
+
+  return 0;
+}
+
+/** @internal Set the default from field */
+int nua_stack_set_from(nua_t *nua, int initial, tagi_t const *tags)
+{
+  sip_from_t const *from = NONE;
+  char const *str = NONE;
+  sip_from_t *f = NULL,  f0[1];
+
+  char const *uicc_name = "default";
+
+  tl_gets(tags,
+	  /* By nua_stack_set_from() */
+	  SIPTAG_FROM_REF(from),
+	  SIPTAG_FROM_STR_REF(str),
+	  NUTAG_UICC_REF(uicc_name),
+	  TAG_END());
+
+#if HAVE_UICC_H
+  if (initial && uicc_name)
+    nua->nua_uicc = uicc_create(root, uicc_name);
+#endif
+
+  if (!initial && from == NONE && str == NONE)
+    return 0;
+
+  sip_from_init(f0);
+
+  if (from && from != NONE) {
+    f0->a_display = from->a_display;
+    *f0->a_url = *from->a_url;
+    f = sip_from_dup(nua->nua_home, f0);
+  }
+  else if (str && str != NONE) {
+    f = sip_from_make(nua->nua_home, str);
+    if (f)
+      *f0 = *f, f = f0, f->a_params = NULL;
+  }
+  else {
+    sip_contact_t const *m;
+
+    m = nua_stack_get_contact(nua->nua_registrations);
+    
+    if (m) {
+      f0->a_display = m->m_display;
+      *f0->a_url = *m->m_url;
+      f = sip_from_dup(nua->nua_home, f0);
+    }
+  }
+
+  if (!f)
+    return -1;
+
+  *nua->nua_from = *f;
+  return 0;
+}
+
+/** @internal Initialize instance ID. */
+int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
+{
+  nua_handle_preferences_t *nhp = nh->nh_prefs;
+
+  char const *instance = NONE;
+
+  tl_gets(tags, NUTAG_INSTANCE_REF(instance), TAG_END());
+
+  if (instance != NONE) {
+    NHP_SET(nhp, instance, su_strdup(nh->nh_home, instance));
+    if (instance && !nhp->nhp_instance)
+      return -1;
+  }
+
+  return 0;
+}
+
+/**@fn void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+ *
+ * Set @nua parameters, shared by all handles.
+ *
+ * @param nua             Pointer to NUA stack object
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *   NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
+ *   NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and 
+ *                         SIPTAG_ALLOW_EVENTS_STR() \n
+ *   NUTAG_AUTOACK() \n
+ *   NUTAG_AUTOALERT() \n
+ *   NUTAG_AUTOANSWER() \n
+ *   NUTAG_CALLEE_CAPS() \n
+ *   NUTAG_DETECT_NETWORK_UPDATES() \n
+ *   NUTAG_EARLY_ANSWER() \n
+ *   NUTAG_EARLY_MEDIA() \n
+ *   NUTAG_ENABLEINVITE() \n
+ *   NUTAG_ENABLEMESSAGE() \n
+ *   NUTAG_ENABLEMESSENGER() \n
+ *   NUTAG_INSTANCE() \n
+ *   NUTAG_INVITE_TIMER() \n
+ *   NUTAG_KEEPALIVE() \n
+ *   NUTAG_KEEPALIVE_STREAM() \n
+ *   NUTAG_MAX_SUBSCRIPTIONS() \n
+ *   NUTAG_MEDIA_ENABLE() \n
+ *   NUTAG_MEDIA_FEATURES() \n
+ *   NUTAG_MIN_SE() \n
+ *   NUTAG_M_DISPLAY() \n
+ *   NUTAG_M_FEATURES() \n
+ *   NUTAG_M_PARAMS() \n
+ *   NUTAG_M_USERNAME() \n
+ *   NUTAG_ONLY183_100REL() \n
+ *   NUTAG_OUTBOUND() \n
+ *   NUTAG_PATH_ENABLE() \n
+ *   NUTAG_REFER_EXPIRES() \n
+ *   NUTAG_REFER_WITH_ID() \n
+ *   NUTAG_REGISTRAR() \n
+ *   NUTAG_RETRY_COUNT() \n
+ *   NUTAG_SERVICE_ROUTE_ENABLE() \n
+ *   NUTAG_SESSION_REFRESHER() \n
+ *   NUTAG_SESSION_TIMER() \n
+ *   NUTAG_SMIME_ENABLE() \n
+ *   NUTAG_SMIME_KEY_ENCRYPTION() \n
+ *   NUTAG_SMIME_MESSAGE_DIGEST() \n
+ *   NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
+ *   NUTAG_SMIME_OPT() \n
+ *   NUTAG_SMIME_PROTECTION_MODE() \n
+ *   NUTAG_SMIME_SIGNATURE() \n
+ *   NUTAG_SOA_NAME() \n
+ *   NUTAG_SUBSTATE() \n
+ *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
+ *   NUTAG_UPDATE_REFRESH() \n
+ *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
+ *   SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
+ *
+ * nua_set_params() also accepts any soa tags, defined in
+ * <sofia-sip/soa_tag.h>, and nta tags, defined in <sofia-sip/nta_tag.h>.
+ * 
+ * @par Events:
+ *     #nua_r_set_params
+ *
+ * @par SIP Header as NUA Parameters
+ * The @nua parameters include SIP headers @Allow, @Supported, @Organization,
+ * @UserAgent and @From. They are included in most of the SIP messages sent
+ * by @nua. They are set in the same way as the tagged arguments are
+ * used to populate a SIP message.
+ * @par
+ * When multiple tags for the same header are specified, the behaviour
+ * depends on the header type. If only a single header field can be included
+ * in a SIP message, the latest non-NULL value is used, e.g., @Organization. 
+ * However, if the SIP header can consist of multiple lines or header fields
+ * separated by comma, in this case, @Allow and @Supported, all the tagged
+ * values are concatenated.
+ * @par
+ * However, if the tag value is #SIP_NONE (-1 casted as a void pointer), the
+ * values from previous tags are ignored.
+ *
+ * For example, the nua_set_params() call like this:
+ * @code
+ * nua_set_params(nua,
+ *                SIPTAG_USER_AGENT_STR("tester/1.0"),
+ *                SIPTAG_ALLOW_STR("INVITE,CANCEL,BYE,ACK"),
+ *                SIPTAG_ORGANIZATION(NULL),
+ *                SIPTAG_USER_AGENT(NULL),
+ *                SIPTAG_ALLOW(SIP_NONE),
+ *                TAG_END());
+ * @endcode
+ * will leave @Allow and @Organization headers empty. The @UserAgent header
+ * will contain value "tester/1.0".
+ * @code
+ * nua_set_params(nua,
+ *                SIPTAG_ORGANIZATION_STR("Malevolent Microwavers"),
+ *                SIPTAG_ALLOW_STR("OPTIONS"),
+ *                SIPTAG_ALLOW(SIP_NONE),
+ *                SIPTAG_ORGANIZATION_STR("The Phone Company"),
+ *                SIPTAG_ALLOW_STR("SUBSCRIBE"),
+ *                SIPTAG_ALLOW(NULL),
+ *                SIPTAG_ORGANIZATION_STR(NULL),
+ *                TAG_END());
+ * @endcode
+ * sets the header @Allow with value <code>SUBSCRIBE</code> and the
+ * header @Organization will have value <code>The Phone Company</code>.
+ *
+ */
+
+/**@fn void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Set the handle-specific parameters.
+ *
+ * The handle-specific parameters override default or global parameters set
+ * by nua_set_params(). The handle-specific parameters are set by several
+ * other operations: nua_invite(), nua_respond(), nua_ack(),
+ * nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(),
+ * nua_message(), nua_register(), nua_publish(), nua_refer(),
+ * nua_subscribe(), nua_notify(), nua_refer(), and nua_notifier().
+ *
+ * @param nh              Pointer to a NUA handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *     nothing
+ *
+ * @par Tags Used to Set Handle-Specific Parameters:
+ *   NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
+ *   NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and 
+ *                         SIPTAG_ALLOW_EVENTS_STR() \n
+ *   NUTAG_AUTOACK() \n
+ *   NUTAG_AUTOALERT() \n
+ *   NUTAG_AUTOANSWER() \n
+ *   NUTAG_CALLEE_CAPS() \n
+ *   NUTAG_EARLY_ANSWER() \n
+ *   NUTAG_EARLY_MEDIA() \n
+ *   NUTAG_ENABLEINVITE() \n
+ *   NUTAG_ENABLEMESSAGE() \n
+ *   NUTAG_ENABLEMESSENGER() \n
+ *   NUTAG_INSTANCE() \n
+ *   NUTAG_INVITE_TIMER() \n
+ *   NUTAG_KEEPALIVE() \n
+ *   NUTAG_KEEPALIVE_STREAM() \n
+ *   NUTAG_MAX_SUBSCRIPTIONS() \n
+ *   NUTAG_MEDIA_ENABLE() \n
+ *   NUTAG_MEDIA_FEATURES() \n
+ *   NUTAG_MIN_SE() \n
+ *   NUTAG_M_DISPLAY() \n
+ *   NUTAG_M_FEATURES() \n
+ *   NUTAG_M_PARAMS() \n
+ *   NUTAG_M_USERNAME() \n
+ *   NUTAG_ONLY183_100REL() \n
+ *   NUTAG_OUTBOUND() \n
+ *   NUTAG_PATH_ENABLE() \n
+ *   NUTAG_REFER_EXPIRES() \n
+ *   NUTAG_REFER_WITH_ID() \n
+ *   NUTAG_REGISTRAR() \n
+ *   NUTAG_RETRY_COUNT() \n
+ *   NUTAG_SERVICE_ROUTE_ENABLE() \n
+ *   NUTAG_SESSION_REFRESHER() \n
+ *   NUTAG_SESSION_TIMER() \n
+ *   NUTAG_SOA_NAME() \n
+ *   NUTAG_SUBSTATE() \n
+ *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
+ *   NUTAG_UPDATE_REFRESH() \n
+ *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
+ *   SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
+ * Any soa tags are also considered as handle-specific parameters. They are
+ * defined in <sofia-sip/soa_tag.h>.
+ *
+ * The global parameters that can not be set by nua_set_hparams() include 
+ * NUTAG_DETECT_NETWORK_UPDATES(), NUTAG_SMIME_* tags, and all NTA tags.
+ * 
+ * @par Events:
+ *     #nua_r_set_params
+ */
+
+/** @NUA_EVENT nua_r_set_params
+ *
+ * Response to nua_set_params() or nua_set_hparams().
+ *
+ * @param status 200 when successful, error code otherwise
+ * @param phrase a short textual description of @a status code
+ * @param nh     NULL when responding to nua_set_params(),
+ *               operation handle when responding to nua_set_hparams()
+ * @param hmagic NULL when responding to nua_set_params(),
+ *               application contact associated with the operation handle 
+ *               when responding to nua_set_hparams()
+ * @param sip    NULL
+ * @param tags   None
+ *
+ * @sa nua_set_params(), nua_set_hparams(), 
+ * #nua_r_get_params, nua_get_params(), nua_get_hparams()
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_set_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+			 tagi_t const *tags)
+{
+  nua_handle_t *dnh = nua->nua_dhandle;
+  nua_handle_preferences_t tmp[1], *nhp = nh->nh_prefs;
+  nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
+
+  su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
+
+  tagi_t const *ptags;
+
+  int error, global;
+  int status = 900;
+  char const *phrase = "Error storing parameters";
+  sip_supported_t const *supported = NULL;
+  sip_allow_t const *allow = NULL;
+  sip_allow_events_t const *allow_events = NULL;
+  sip_allow_t const *appl_method = NULL;
+
+  enter;
+
+  ptags = !nh->nh_used_ptags ? nh->nh_ptags : NULL;
+
+  *tmp = *nhp; NHP_UNSET_ALL(tmp);
+
+  /* Supported features, allowed methods and events are merged 
+     with previous ones */
+  if (!NHP_ISSET(nhp, supported)) 
+    supported = tmp->nhp_supported = dnhp->nhp_supported;
+  if (!NHP_ISSET(nhp, allow)) 
+    allow = tmp->nhp_allow = dnhp->nhp_allow;
+  if (!NHP_ISSET(nhp, allow_events)) 
+    allow_events = tmp->nhp_allow_events = dnhp->nhp_allow_events;
+  if (!NHP_ISSET(nhp, appl_method)) 
+    appl_method = tmp->nhp_appl_method = dnhp->nhp_appl_method;
+
+  error = 0;
+  global = nh == dnh;			/* save also stack-specific params */
+    
+  /* Set and save parameters to tmp */
+  if (nhp_set_tags(tmphome, tmp, global, ptags) < 0)
+    error = 1, phrase = "Error storing default handle parameters";
+  else if (nhp_set_tags(tmphome, tmp, global, tags) < 0)
+    error = 1, phrase = "Error storing parameters";
+  else {
+    if (NHP_IS_ANY_SET(tmp)) {
+      if (tmp->nhp_supported == supported)
+	tmp->nhp_supported = NULL;
+
+      if (tmp->nhp_allow == allow)
+	tmp->nhp_allow = NULL;
+
+      if (tmp->nhp_allow_events == allow_events)
+	tmp->nhp_allow_events = NULL;
+
+      if (tmp->nhp_appl_method == appl_method)
+	tmp->nhp_appl_method = NULL;
+
+      /* Move parameters from tmp to nhp (or allocate new nhp) */
+      if (nh != dnh && nhp == dnh->nh_prefs)
+	nhp = NULL;
+      nhp = nhp_move_params(nh->nh_home, nhp, tmphome, tmp);
+
+      if (nhp)
+	nh->nh_prefs = nhp;
+      else
+	/* Fail miserably with ENOMEM */
+	error = 1, status = 900, phrase = su_strerror(ENOMEM);
+    }
+
+    if (!error)
+      nh->nh_used_ptags = 1;
+  }
+
+  su_home_deinit(tmphome);
+
+  if (error)
+    ;
+  else if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
+    /* Create soa when needed */
+    char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
+
+    if (dnh->nh_soa)
+      nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
+    else  
+      nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
+
+    ptags = nh->nh_ptags;
+
+    if (!nh->nh_soa)
+      error = 1, status = 900, phrase = "Error Creating SOA Object";
+  }
+  else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
+    /* ... destroy soa when not needed */
+    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+  }
+
+  if (!error && nh->nh_soa) {
+    if ((ptags && soa_set_params(nh->nh_soa, TAG_NEXT(ptags)) < 0) ||
+	(tags && soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0))
+      error = 1, status = 900, phrase = "Error Setting SOA Parameters";
+  }
+
+  if (error || nh != dnh) {
+    ;
+  }
+  else if (nua_stack_set_smime_params(nua, tags) < 0) {
+    error = 1, status = 900, phrase = "Error setting S/MIME parameters";
+  }
+  else if (!nua->nua_nta) {
+  }
+  /* Set stack-specific things below */
+  else if (nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
+    status = 900, phrase = "Error setting NTA parameters";
+    error = 1;
+  }
+  else {
+    nua_stack_set_from(nua, 0, tags);
+    if (NHP_ISSET(nhp, detect_network_updates))
+      nua_stack_launch_network_change_detector(nua);
+  }
+
+  if (error) {
+    if (e == nua_i_none)
+      SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase));
+    return UA_EVENT2(e, status, phrase), -1;
+  }
+
+  if (e == nua_r_set_params)
+    UA_EVENT2(e, 200, "OK");
+
+  return 0;
+}
+
+/** Parse parameters from tags to @a nhp.
+ *
+ * @param home allocate new values from @a home
+ * @param nhp  structure to store handle preferences
+ * @param global  if true, save also global parameters
+ * @param tags list of tags to parse
+ */
+static int nhp_set_tags(su_home_t *home, 
+			nua_handle_preferences_t *nhp,
+			int global,
+			tagi_t const *tags)
+{
+
+/* Set copy of string to handle pref structure */
+#define NHP_SET_STR(nhp, name, v)				 \
+  if ((v) != (tag_value_t)0) {					 \
+    char const *_value = (char const *)v;			 \
+    char *_new = _value ? su_strdup(home, _value) : NULL;	 \
+    if (NHP_ISSET(nhp, name))					 \
+      su_free(home, (void *)nhp->nhp_##name);			 \
+    NHP_SET(nhp, name, _new);					 \
+    if (_new == NULL && _value != NULL)				 \
+      return -1;						 \
+  }
+
+/* Set copy of string from url to handle pref structure */
+#define NHP_SET_STR_BY_URL(nhp, name, v)			 \
+  if ((v) != (tag_value_t)-1) {					 \
+    url_t const *_value = (url_t const *)(v);			 \
+    char *_new;							 \
+    _new = url_as_string(home, (void *)_value);			 \
+    if (NHP_ISSET(nhp, name))					 \
+      su_free(home, (void *)nhp->nhp_##name);			 \
+    NHP_SET(nhp, name, _new);					 \
+    if (_new == NULL && _value != NULL)				 \
+      return -1;						 \
+  }
+
+/* Set copy of header to handle pref structure */
+#define NHP_SET_HEADER(nhp, name, v)				 \
+  if ((v) != 0) {						 \
+    sip_##name##_t const *_value = (sip_##name##_t const *)(v);	 \
+    sip_##name##_t *_new = NULL;				 \
+    if (_value != SIP_NONE)					 \
+      _new = sip_##name##_dup(home, _value);			 \
+    if (NHP_ISSET(nhp, name))					 \
+      msg_header_free_all(home, (void *)nhp->nhp_##name);	 \
+    NHP_SET(nhp, name, _new);					 \
+    if (_new == NULL && _value != SIP_NONE)			 \
+      return -1;						 \
+  }
+
+/* Set header made of string to handle pref structure */
+#define NHP_SET_HEADER_STR(nhp, name, v)			 \
+  if ((v) != 0) {						 \
+    char const *_value = (char const *)(v);			 \
+    sip_##name##_t *_new = NULL;				 \
+    if (_value != SIP_NONE)					 \
+      _new = sip_##name##_make(home, _value);			 \
+    if (NHP_ISSET(nhp, name))					 \
+      msg_header_free_all(home, (void *)nhp->nhp_##name);	 \
+    NHP_SET(nhp, name, _new);					 \
+    if (_new == NULL && _value != SIP_NONE)			 \
+      return -1;						 \
+  }
+
+/* Set copy of string from header to handle pref structure */
+#define NHP_SET_STR_BY_HEADER(nhp, name, v)			 \
+  if ((v) != 0) {					 \
+    sip_##name##_t const *_value = (sip_##name##_t const *)(v);	 \
+    char *_new = NULL;						 \
+    if (_value != SIP_NONE)					 \
+      _new = sip_header_as_string(home, (void *)_value);	 \
+    if (NHP_ISSET(nhp, name))					 \
+      su_free(home, (void *)nhp->nhp_##name);			 \
+    NHP_SET(nhp, name, _new);					 \
+    if (_new == NULL && _value != SIP_NONE)			 \
+      return -1;						 \
+  }
+
+
+  tagi_t const *t;
+
+  for (t = tags; t; t = tl_next(t)) {
+    tag_type_t tag = t->t_tag;
+    tag_value_t value = t->t_value;
+
+    if (tag == NULL)
+      break;
+    /* NUTAG_RETRY_COUNT(retry_count) */
+    else if (tag == nutag_retry_count) {
+      NHP_SET(nhp, retry_count, (unsigned)value);
+    }
+    /* NUTAG_MAX_SUBSCRIPTIONS(max_subscriptions) */
+    else if (tag == nutag_max_subscriptions) {
+      NHP_SET(nhp, max_subscriptions, (unsigned)value);
+    }
+    /* NUTAG_SOA_NAME(soa_name) */
+    else if (tag == nutag_soa_name) {
+      NHP_SET_STR(nhp, soa_name, value);
+    }
+    /* NUTAG_MEDIA_ENABLE(media_enable) */
+    else if (tag == nutag_media_enable) {
+      NHP_SET(nhp, media_enable, value != 0);
+    }
+    /* NUTAG_ENABLEINVITE(invite_enable) */
+    else if (tag == nutag_enableinvite) {
+      NHP_SET(nhp, invite_enable, value != 0);
+    }
+    /* NUTAG_AUTOALERT(auto_alert) */
+    else if (tag == nutag_autoalert) {
+      NHP_SET(nhp, auto_alert, value != 0);
+    }
+    /* NUTAG_EARLY_ANSWER(early_answer) */
+    else if (tag == nutag_early_answer) {
+      NHP_SET(nhp, early_answer, value != 0);
+    }
+    /* NUTAG_EARLY_MEDIA(early_media) */
+    else if (tag == nutag_early_media) {
+      NHP_SET(nhp, early_media, value != 0);
+    }
+    /* NUTAG_ONLY183_100REL(only183_100rel) */
+    else if (tag == nutag_only183_100rel) {
+      NHP_SET(nhp, only183_100rel, value != 0);
+    }
+    /* NUTAG_AUTOANSWER(auto_answer) */
+    else if (tag == nutag_autoanswer) {
+      NHP_SET(nhp, auto_answer, value != 0);
+    }
+    /* NUTAG_AUTOACK(auto_ack) */
+    else if (tag == nutag_autoack) {
+      NHP_SET(nhp, auto_ack, value != 0);
+    }
+    /* NUTAG_INVITE_TIMER(invite_timeout) */
+    else if (tag == nutag_invite_timer) {
+      NHP_SET(nhp, invite_timeout, (unsigned)value);
+    }
+    /* NUTAG_SESSION_TIMER(session_timer) */
+    else if (tag == nutag_session_timer) {
+      NHP_SET(nhp, session_timer, (unsigned)value);
+    }
+    /* NUTAG_MIN_SE(min_se) */
+    else if (tag == nutag_min_se) {
+      NHP_SET(nhp, min_se, (unsigned)value);
+    }
+    /* NUTAG_SESSION_REFRESHER(refresher) */
+    else if (tag == nutag_session_refresher) {
+      int refresher = value;
+
+      if (refresher >= nua_remote_refresher)
+	refresher = nua_remote_refresher;
+      else if (refresher <= nua_no_refresher)
+	refresher = nua_no_refresher;
+
+      NHP_SET(nhp, refresher, refresher);
+    }
+    /* NUTAG_UPDATE_REFRESH(update_refresh) */
+    else if (tag == nutag_update_refresh) {
+      NHP_SET(nhp, update_refresh, value != 0);
+    }
+    /* NUTAG_ENABLEMESSAGE(message_enable) */
+    else if (tag == nutag_enablemessage) {
+      NHP_SET(nhp, message_enable, value != 0);
+    }
+    /* NUTAG_ENABLEMESSENGER(win_messenger_enable) */
+    else if (tag == nutag_enablemessenger) {
+      NHP_SET(nhp, win_messenger_enable, value != 0);
+    }
+#if 0
+    /* NUTAG_AUTORESPOND(autorespond) */
+    else if (tag == nutag_autorespond) {
+      NHP_SET(nhp, autorespond, value);
+    }
+#endif
+    /* NUTAG_CALLEE_CAPS(callee_caps) */
+    else if (tag == nutag_callee_caps) {
+      NHP_SET(nhp, callee_caps, value != 0);
+    }
+    /* NUTAG_MEDIA_FEATURES(media_features) */
+    else if (tag == nutag_media_features) {
+      NHP_SET(nhp, media_features, value != 0);
+    }
+    /* NUTAG_SERVICE_ROUTE_ENABLE(service_route_enable) */
+    else if (tag == nutag_service_route_enable) {
+      NHP_SET(nhp, service_route_enable, value != 0);
+    }
+    /* NUTAG_PATH_ENABLE(path_enable) */
+    else if (tag == nutag_path_enable) {
+      NHP_SET(nhp, path_enable, value != 0);
+    }
+    /* NUTAG_REFER_EXPIRES(refer_expires) */
+    else if (tag == nutag_refer_expires) {
+      NHP_SET(nhp, refer_expires, value);
+    }
+    /* NUTAG_REFER_WITH_ID(refer_with_id) */
+    else if (tag == nutag_refer_with_id) {
+      NHP_SET(nhp, refer_with_id, value != 0);
+    }
+    /* NUTAG_SUBSTATE(substate) */
+    else if (tag == nutag_substate) {
+      NHP_SET(nhp, substate, (int)value);
+    }
+    /* NUTAG_KEEPALIVE(keepalive) */
+    else if (tag == nutag_keepalive) {
+      NHP_SET(nhp, keepalive, (unsigned)value);
+    }
+    /* NUTAG_KEEPALIVE_STREAM(keepalive_stream) */
+    else if (tag == nutag_keepalive_stream) {
+      NHP_SET(nhp, keepalive_stream, (unsigned)value);
+    }
+
+    /* NUTAG_SUPPORTED(feature) */
+    /* SIPTAG_SUPPORTED_STR(supported_str) */
+    /* SIPTAG_SUPPORTED(supported) */
+    else if (tag == nutag_supported ||
+	     tag == siptag_supported || 
+	     tag == siptag_supported_str) {
+      int ok;
+      sip_supported_t *supported = NULL;
+
+      ok = nhp_merge_lists(home, 
+			   sip_supported_class, &supported, nhp->nhp_supported,
+			   NHP_ISSET(nhp, supported), /* already set by tags */
+			   tag == siptag_supported, /* dup it, don't make */
+			   tag == nutag_supported, /* merge with old value */
+			   t->t_value);
+      if (ok < 0)
+	return -1;
+      else if (ok)
+	NHP_SET(nhp, supported, supported);
+    }
+    /* NUTAG_ALLOW(allowing) */
+    /* SIPTAG_ALLOW_STR(allow_str) */
+    /* SIPTAG_ALLOW(allow) */
+    else if (tag == nutag_allow ||
+	     tag == siptag_allow_str ||
+	     tag == siptag_allow) {
+      int ok;
+      msg_list_t *allow = NULL;
+
+      ok = nhp_merge_lists(home, 
+			   sip_allow_class,
+			   &allow,
+			   (msg_list_t const *)nhp->nhp_allow,
+			   NHP_ISSET(nhp, allow), /* already set by tags */
+			   tag == siptag_allow, /* dup it, don't make */
+			   tag == nutag_allow, /* merge with old value */
+			   t->t_value);
+      if (ok < 0)
+	return -1;
+      else if (ok)
+	NHP_SET(nhp, allow, (sip_allow_t *)allow);
+    }
+    /* NUTAG_ALLOW_EVENTS(allow_events) */
+    /* SIPTAG_ALLOW_EVENTS_STR(allow_events) */
+    /* SIPTAG_ALLOW_EVENTS(allow_events) */
+    else if (tag == nutag_allow_events ||
+	     tag == siptag_allow_events_str ||
+	     tag == siptag_allow_events) {
+      int ok;
+      sip_allow_events_t *allow_events = NULL;
+
+      ok = nhp_merge_lists(home, 
+			   sip_allow_events_class,
+			   &allow_events, 
+			   nhp->nhp_allow_events,
+			   NHP_ISSET(nhp, allow_events), /* already set */
+			   tag == siptag_allow_events, /* dup it, don't make */
+			   tag == nutag_allow_events, /* merge with old value */
+			   t->t_value);
+      if (ok < 0)
+	return -1;
+      else if (ok)
+	NHP_SET(nhp, allow_events, allow_events);
+    }
+    /* NUTAG_APPL_METHOD(appl_method) */
+    else if (tag == nutag_appl_method) {
+      if (t->t_value == 0) {
+	NHP_SET(nhp, appl_method, NULL);
+      }
+      else {
+	int ok;
+	msg_list_t *appl_method = NULL;
+
+	ok = nhp_merge_lists(home,
+			     sip_allow_class,
+			     &appl_method,
+			     (msg_list_t const *)nhp->nhp_appl_method,
+			     NHP_ISSET(nhp, allow), /* already set by tags */
+			     0, /* dup it, don't make */
+			     1, /* merge with old value */
+			     t->t_value);
+	if (ok < 0)
+	  return -1;
+	else if (ok)
+	  NHP_SET(nhp, appl_method, (sip_allow_t *)appl_method);
+      }
+    }
+    /* SIPTAG_USER_AGENT(user_agent) */
+    else if (tag == siptag_user_agent) {
+      NHP_SET_STR_BY_HEADER(nhp, user_agent, value);
+    }
+    /* SIPTAG_USER_AGENT_STR(user_agent_str) */
+    else if (tag == siptag_user_agent_str && value != 0) {
+      if (value == -1)
+	value = 0;
+      NHP_SET_STR(nhp, user_agent, value);
+    }
+    /* NUTAG_USER_AGENT(ua_name) */
+    else if (tag == nutag_user_agent) {
+      /* Add contents of NUTAG_USER_AGENT() to our distribution name */
+      char const *str = (void *)value, *ua;
+
+      if (str && !already_contains_package_name(str))
+	ua = su_sprintf(home, "%s %s", str, NHP_USER_AGENT);
+      else if (str)
+	ua = su_strdup(home, str);
+      else
+	ua = su_strdup(home, NHP_USER_AGENT);
+
+      NHP_SET(nhp, user_agent, ua);
+    }
+    /* SIPTAG_ORGANIZATION(organization) */
+    else if (tag == siptag_organization) {
+      NHP_SET_STR_BY_HEADER(nhp, organization, value);
+    }
+    /* SIPTAG_ORGANIZATION_STR(organization_str) */
+    else if (tag == siptag_organization_str) {
+      if (value == -1)
+	value = 0;
+      NHP_SET_STR(nhp, organization, value);
+    }
+    /* NUTAG_REGISTRAR(registrar) */
+    else if (tag == nutag_registrar) {
+      NHP_SET_STR_BY_URL(nhp, registrar, value);
+      if (NHP_ISSET(nhp, registrar) && !str0cmp(nhp->nhp_registrar, "*"))
+	NHP_SET_STR(nhp, registrar, 0);
+    }
+    /* NUTAG_INSTANCE(instance) */
+    else if (tag == nutag_instance) {
+      NHP_SET_STR(nhp, instance, value);
+    }
+    /* NUTAG_M_DISPLAY(m_display) */
+    else if (tag == nutag_m_display) {
+      NHP_SET_STR(nhp, m_display, value);
+    }
+    /* NUTAG_M_USERNAME(m_username) */
+    else if (tag == nutag_m_username) {
+      NHP_SET_STR(nhp, m_username, value);
+    }
+    /* NUTAG_M_PARAMS(m_params) */
+    else if (tag == nutag_m_params) {
+      NHP_SET_STR(nhp, m_params, value);
+    }
+    /* NUTAG_M_FEATURES(m_features) */
+    else if (tag == nutag_m_features) {
+      NHP_SET_STR(nhp, m_features, value);
+    }
+    /* NUTAG_OUTBOUND(outbound) */
+    else if (tag == nutag_outbound) {
+      NHP_SET_STR(nhp, outbound, value);
+    }
+    /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
+    else if (global && tag == nutag_detect_network_updates) {
+      int detector = (int)value;
+
+      if (detector < NUA_NW_DETECT_NOTHING)
+	detector = NUA_NW_DETECT_NOTHING;
+      else if (detector > NUA_NW_DETECT_TRY_FULL)
+	detector = NUA_NW_DETECT_TRY_FULL;
+
+      NHP_SET(nhp, detect_network_updates, detector);
+    }
+  }
+
+  return 0;
+}
+
+/** Merge (when needed) new values with old values. */
+static int nhp_merge_lists(su_home_t *home,
+			   msg_hclass_t *hc,
+			   msg_list_t **return_new_list,
+			   msg_list_t const *old_list,
+			   int already_set,
+			   int already_parsed,
+			   int always_merge,
+			   tag_value_t value)
+{
+  msg_list_t *list, *elems;
+
+  if (value == -1) {
+    *return_new_list = NULL;
+    return 1;
+  }
+
+  if (value == 0) {
+    if (!already_set && !always_merge) {
+      *return_new_list = NULL;
+      return 1;
+    }
+    return 0;
+  }
+
+  if (already_parsed) 
+    elems = (void *)msg_header_dup_as(home, hc, (msg_header_t *)value);
+  else
+    elems = (void *)msg_header_make(home, hc, (char const *)value);
+
+  if (!elems)
+    return -1;
+
+  list = (msg_list_t *)old_list;
+
+  if (!already_set) {
+    if (always_merge && list) {
+      list = (void *)msg_header_dup_as(home, hc, (void *)old_list);
+      if (!list)
+	return -1;
+    }
+    else
+      list = NULL;
+  }
+
+  if (!list) {
+    *return_new_list = elems;
+    return 1;
+  }
+
+  /* Add contents to the new list to the old list */
+  if (msg_params_join(home, (msg_param_t **)&list->k_items, elems->k_items,
+		      2 /* prune */, 0 /* don't dup */) < 0)
+    return -1;
+  
+  *return_new_list = 
+    (msg_list_t *)msg_header_dup_as(home, hc, (msg_header_t *)list);
+  if (!*return_new_list)
+    return -1;
+
+  msg_header_free(home, (msg_header_t *)list);
+  msg_header_free(home, (msg_header_t *)elems);
+
+  return 1;
+}
+
+static
+nua_handle_preferences_t *nhp_move_params(su_home_t *home,
+					  nua_handle_preferences_t *dst,
+					  su_home_t *tmphome,
+					  nua_handle_preferences_t const *src)
+{
+  /* Update prefs structure */
+  nua_handle_preferences_t tbf[1];
+
+  if (dst == NULL)
+    dst = su_zalloc(home, sizeof *dst);
+  if (dst == NULL)
+    return NULL;
+  if (su_home_move(home, tmphome) < 0)
+    return NULL;
+
+  *tbf = *dst;
+  nhp_or_set(dst, src);
+
+  /* Handle pointer items. Free changed ones and zap unset ones. */
+#define NHP_ZAP_OVERRIDEN(tbf, nhp, pref)				\
+  (((tbf)->nhp_set.nhb_##pref						\
+    && (tbf)->nhp_##pref != (nhp)->nhp_##pref				\
+    ? su_free(home, (void *)(tbf)->nhp_##pref) : (void)0),		\
+   (void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
+
+  NHP_ZAP_OVERRIDEN(tbf, dst, soa_name);
+  NHP_ZAP_OVERRIDEN(tbf, dst, registrar);
+  NHP_ZAP_OVERRIDEN(tbf, dst, supported);
+  NHP_ZAP_OVERRIDEN(tbf, dst, allow);
+  NHP_ZAP_OVERRIDEN(tbf, dst, user_agent);
+  NHP_ZAP_OVERRIDEN(tbf, dst, organization);
+  NHP_ZAP_OVERRIDEN(tbf, dst, instance);
+  NHP_ZAP_OVERRIDEN(tbf, dst, m_display);
+  NHP_ZAP_OVERRIDEN(tbf, dst, m_username);
+  NHP_ZAP_OVERRIDEN(tbf, dst, m_params);
+  NHP_ZAP_OVERRIDEN(tbf, dst, m_features);
+  NHP_ZAP_OVERRIDEN(tbf, dst, outbound);
+
+  return dst;
+}
+
+static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t);
+static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t);
+
+/** Save taglist to a handle */
+int nua_handle_save_tags(nua_handle_t *nh, tagi_t *tags)
+{
+  tagi_t const tagfilter[] = {
+    { TAG_FILTER(nua_handle_tags_filter) },
+    { TAG_NULL() }
+  };
+  tagi_t const paramfilter[] = {
+    { TAG_FILTER(nua_handle_param_filter) },
+    { TAG_NULL() }
+  };
+
+  /* Initialization parameters */
+  url_string_t const *url = NULL;
+  sip_to_t const *p_to = NULL;
+  char const *to_str = NULL;
+  sip_from_t from[1];
+  sip_from_t const *p_from = NULL;
+  char const *from_str = NULL;
+  nua_handle_t *identity = NULL;
+
+  tagi_t const *t;
+
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(1024)];
+
+  int error;
+
+  for (t = tags; t; t = tl_next(t)) {
+    if (t->t_tag == NULL)
+      break;
+    /* SIPTAG_FROM_REF(p_from) */
+    else if (t->t_tag == siptag_from) {
+      p_from = (sip_from_t *)t->t_value, from_str = NULL;
+    }
+    /* SIPTAG_FROM_STR_REF(from_str) */
+    else if (t->t_tag == siptag_from_str) {
+      from_str = (char const *)t->t_value, p_from = NULL;
+    }
+    /* SIPTAG_TO_REF(p_to) */
+    else if (t->t_tag == siptag_to) {
+      p_to = (sip_to_t *)t->t_value, to_str = NULL;
+    }
+    /* SIPTAG_TO_STR_REF(to_str) */
+    else if (t->t_tag == siptag_to_str) {
+      to_str = (char const *)t->t_value, p_to = NULL;
+    }
+    /* NUTAG_IDENTITY_REF(identity) */
+    else if (t->t_tag == nutag_identity) {
+      identity = (nua_handle_t *)t->t_value;
+    }
+    /* NUTAG_URL_REF(url) */
+    else if (t->t_tag == nutag_url) {
+      url = (url_string_t *)t->t_value;
+    }
+    /* NUTAG_SIPS_URL_REF(url) */
+    else if (t->t_tag == nutag_url) {
+      url = (url_string_t *)t->t_value;
+    }
+  }
+
+  su_home_auto(tmphome, sizeof tmphome);
+
+  if (p_from)
+    ;
+  else if (from_str)
+    p_from = sip_from_make(tmphome, from_str);
+  else if (!p_from && nh->nh_nua->nua_from)
+    *from = *nh->nh_nua->nua_from, from->a_params = NULL, p_from = from;
+  else
+    p_from = SIP_NONE;    /* XXX - why? */
+
+  if (p_to)
+    ;
+  else if (to_str)
+    p_to = sip_to_make(tmphome, to_str);
+  else if (url)
+    p_to = sip_to_create(tmphome, url), 
+      p_to ? sip_aor_strip((url_t*)p_to->a_url) : 0;
+  else
+    p_to = SIP_NONE;
+  
+  if (p_to == NULL || p_from == NULL) {
+    su_home_deinit(tmphome);
+    return -1;
+  }
+
+  nh->nh_tags = 
+    tl_filtered_tlist(nh->nh_home, tagfilter,
+		      SIPTAG_FROM(p_from),
+		      TAG_FILTER(nua_handle_tags_filter),
+		      SIPTAG_TO(p_to),
+		      TAG_FILTER(nua_handle_tags_filter),
+		      TAG_NEXT(tags));
+
+  nh->nh_ptags = 
+    tl_filtered_tlist(nh->nh_home, paramfilter, TAG_NEXT(tags));
+
+  error = nh->nh_tags == NULL || nh->nh_ptags == NULL;
+
+  if (!error)
+    tl_gets(nh->nh_tags,	/* These does not change while nh lives */
+	    SIPTAG_FROM_REF(nh->nh_ds->ds_local),
+	    SIPTAG_TO_REF(nh->nh_ds->ds_remote),
+	    TAG_END());
+
+  if (nh->nh_ptags && nh->nh_ptags->t_tag == NULL)
+    su_free(nh->nh_home, nh->nh_ptags), nh->nh_ptags = NULL;
+    
+  if (identity)
+    nh->nh_identity = nua_handle_ref(identity);
+
+  su_home_deinit(tmphome);
+
+  return -error;
+}
+
+/** Filter tags used for settings. */
+static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t)
+{
+  char const *ns;
+
+  if (!t || !t->t_tag)
+    return 0;
+
+  if (t->t_tag == nutag_url || 
+      t->t_tag == nutag_sips_url ||
+      t->t_tag == nutag_identity)
+    return 0;
+
+  ns = t->t_tag->tt_ns; 
+  if (!ns)
+    return 0;
+
+  return strcmp(ns, "nua") == 0 || strcmp(ns, "soa") == 0;
+}
+
+/** Filter tags stored permanently as taglist. */
+static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t)
+{
+  tag_type_t tag;
+
+  if (!t || !t->t_tag)
+    return 0;
+
+  tag = t->t_tag;
+
+  if (tag == tag_filter)
+    return 0;
+  
+  /* Accept @From or @To only when they are followed by
+     TAG_FILTER(nua_handle_tags_filter) */
+  if (tag == siptag_from || tag == siptag_to) {
+    t = tl_next(t);
+    return t && t->t_tag == tag_filter && 
+      t->t_value == (tag_value_t)nua_handle_tags_filter;
+  }
+
+  if (tag == nutag_identity)
+    return 0;
+  if (tag == siptag_from_str)
+    return 0;
+  if (tag == siptag_to_str)
+    return 0;
+
+  /** Ignore @CSeq, @RSeq, @RAck, @Timestamp, and @ContentLength */
+  if (tag == siptag_cseq || tag == siptag_cseq_str)
+    return 0;
+  if (tag == siptag_rseq || tag == siptag_rseq_str)
+    return 0;
+  if (tag == siptag_rack || tag == siptag_rack_str)
+    return 0;
+  if (tag == siptag_timestamp || tag == siptag_timestamp_str)
+    return 0;
+  if (tag == siptag_content_length || tag == siptag_content_length_str)
+    return 0;
+
+  return ! nua_handle_param_filter(f, t);
+}
+
+static
+int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
+{
+#if HAVE_SOFIA_SMIME
+  int           smime_enable = nua->sm->sm_enable;
+  int           smime_opt = nua->sm->sm_opt;
+  int           smime_protection_mode = nua->sm->sm_protection_mode;
+  char const   *smime_message_digest = NONE;
+  char const   *smime_signature = NONE;
+  char const   *smime_key_encryption = NONE;
+  char const   *smime_message_encryption = NONE;
+  char const   *smime_path = NONE;
+
+  int n;
+
+  n = tl_gets(tags,
+	      NUTAG_SMIME_ENABLE_REF(smime_enable),
+	      NUTAG_SMIME_OPT_REF(smime_opt),
+	      NUTAG_SMIME_PROTECTION_MODE_REF(smime_protection_mode),
+	      NUTAG_SMIME_MESSAGE_DIGEST_REF(smime_message_digest),
+	      NUTAG_SMIME_SIGNATURE_REF(smime_signature),
+	      NUTAG_SMIME_KEY_ENCRYPTION_REF(smime_key_encryption),
+	      NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(smime_message_encryption),
+	      NUTAG_CERTIFICATE_DIR_REF(smime_path),
+	      TAG_NULL());
+  if (n <= 0)
+    return n;
+
+  /* XXX - all other S/MIME parameters? */
+  return sm_set_params(nua->sm, smime_enable, smime_opt, 
+		       smime_protection_mode, smime_path);
+#endif
+
+  return 0;
+}
+
+/**@fn void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+ *
+ * Get NUA parameters matching with the given filter.
+ * The values of NUA parameters is returned in #nua_r_get_params event.
+ *
+ * @param nua             Pointer to NUA stack object
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     TAG_ANY() \n
+ *     otherwise same tags as nua_set_params()
+ *
+ * @par Events:
+ *     #nua_r_get_params
+ *
+ * @par Examples
+ * Find out default values of all parameters:
+ * @code
+ *    nua_get_params(nua, TAG_ANY(), TAG_END());
+ * @endcode
+ */
+
+/**@fn void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+ * 
+ * Get values of handle-specific parameters in #nua_r_get_params event.
+ *
+ * Application will specify either expilicit list of tags it is interested
+ * in, or a filter (at the moment, TAG_ANY()). The values are returned as a
+ * list of tags in the #nua_r_get_params event.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * The handle-specific parameters will contain only the parameters actually
+ * modified by application, either by nua_set_hparams() or some other
+ * handle-specific call. Currently, no NTA parameters are returned. They are
+ * returned only when application asks for user-agent-level parameters using
+ * either nua_get_params() or using default handle, eg.
+ * @code
+ * nua_get_hparams(nua_default(nua), TAG_ANY())
+ * @endcode
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     #TAG_ANY \n
+ *     othervise same tags as nua_set_hparams()
+ *
+ * @par Events:
+ *     #nua_r_get_params
+ */
+
+/** @NUA_EVENT nua_r_get_params
+ *
+ * Answer to nua_get_params() or nua_get_hparams().
+ *
+ * @param status 200 when succesful, error code otherwise
+ * @param phrase a short textual description of @a status code
+ * @param nh     NULL when responding to nua_get_params(),
+ *               operation handle when responding to nua_get_hparams()
+ * @param hmagic NULL when responding to nua_get_params(),
+ *               application contact associated with the operation handle 
+ *               when responding to nua_get_hparams()
+ * @param sip    NULL
+ * @param tags   
+ *   NUTAG_AUTOACK() \n
+ *   NUTAG_AUTOALERT() \n
+ *   NUTAG_AUTOANSWER() \n
+ *   NUTAG_CALLEE_CAPS() \n
+ *   NUTAG_DETECT_NETWORK_UPDATES() \n
+ *   NUTAG_EARLY_ANSWER() \n
+ *   NUTAG_EARLY_MEDIA() \n
+ *   NUTAG_ENABLEINVITE() \n
+ *   NUTAG_ENABLEMESSAGE() \n
+ *   NUTAG_ENABLEMESSENGER() \n
+ *   NUTAG_INSTANCE() \n
+ *   NUTAG_INVITE_TIMER() \n
+ *   NUTAG_KEEPALIVE() \n
+ *   NUTAG_KEEPALIVE_STREAM() \n
+ *   NUTAG_MAX_SUBSCRIPTIONS() \n
+ *   NUTAG_MEDIA_ENABLE() \n
+ *   NUTAG_MEDIA_FEATURES() \n
+ *   NUTAG_MIN_SE() \n
+ *   NUTAG_M_DISPLAY() \n
+ *   NUTAG_M_FEATURES() \n
+ *   NUTAG_M_PARAMS() \n
+ *   NUTAG_M_USERNAME() \n
+ *   NUTAG_ONLY183_100REL() \n
+ *   NUTAG_OUTBOUND() \n
+ *   NUTAG_PATH_ENABLE() \n
+ *   NUTAG_REFER_EXPIRES() \n
+ *   NUTAG_REFER_WITH_ID() \n
+ *   NUTAG_REGISTRAR() \n
+ *   NUTAG_RETRY_COUNT() \n
+ *   NUTAG_SERVICE_ROUTE_ENABLE() \n
+ *   NUTAG_SESSION_REFRESHER() \n
+ *   NUTAG_SESSION_TIMER() \n
+ *   NUTAG_SMIME_ENABLE() \n
+ *   NUTAG_SMIME_KEY_ENCRYPTION() \n
+ *   NUTAG_SMIME_MESSAGE_DIGEST() \n
+ *   NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
+ *   NUTAG_SMIME_OPT() \n
+ *   NUTAG_SMIME_PROTECTION_MODE() \n
+ *   NUTAG_SMIME_SIGNATURE() \n
+ *   NUTAG_SOA_NAME() \n
+ *   NUTAG_SUBSTATE() \n
+ *   NUTAG_UPDATE_REFRESH() \n
+ *   NUTAG_USER_AGENT() \n
+ *   SIPTAG_ALLOW() \n
+ *   SIPTAG_ALLOW_STR() \n
+ *   SIPTAG_ALLOW_EVENTS() \n
+ *   SIPTAG_ALLOW_EVENTS_STR() \n
+ *   SIPTAG_FROM() \n
+ *   SIPTAG_FROM_STR() \n
+ *   SIPTAG_ORGANIZATION() \n
+ *   SIPTAG_ORGANIZATION_STR() \n
+ *   SIPTAG_SUPPORTED() \n
+ *   SIPTAG_SUPPORTED_STR() \n
+ *   SIPTAG_USER_AGENT() \n
+ *   SIPTAG_USER_AGENT_STR() \n
+ *
+ * @sa nua_get_params(), nua_get_hparams(),
+ * nua_set_params(), nua_set_hparams(), #nua_r_set_params
+ *
+ * @END_NUA_EVENT
+ */
+
+/**@internal
+ * Send a list of NUA parameters to the application.
+ *
+ * This function gets invoked when application calls either nua_get_params()
+ * or nua_get_hparams().
+ *
+ * The parameter tag list will initially contain all the relevant parameter
+ * tags, and it will be filtered down to parameters asked by application.
+ *
+ * The handle-specific parameters will contain only the parameters actually
+ * modified by application, either by nua_set_hparams() or some other
+ * handle-specific call. NTA parameters are returned only when application
+ * asks for user-agent-level parameters using nua_get_params().
+ *
+ */
+int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+			 tagi_t const *tags)
+{
+  nua_handle_t *dnh = nua->nua_dhandle;
+  nua_handle_preferences_t const *nhp = nh->nh_prefs;
+
+  tagi_t *lst;
+
+  int has_from;
+  sip_from_t from[1];
+
+  sip_contact_t const *m;
+
+  /* nta */
+  usize_t udp_mtu = 0;
+  unsigned sip_t1 = 0, sip_t2 = 0, sip_t4 = 0, sip_t1x64 = 0;
+  unsigned debug_drop_prob = 0;
+  url_string_t const *proxy = NULL;
+  sip_contact_t const *aliases = NULL;
+  unsigned flags = 0;
+
+  /* soa */
+  tagi_t *media_params = NULL;
+
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(16536)];
+
+  enter;
+
+  su_home_auto(tmphome, sizeof(tmphome));
+
+  nta_agent_get_params(nua->nua_nta,
+		       NTATAG_UDP_MTU_REF(udp_mtu),
+		       NTATAG_SIP_T1_REF(sip_t1),
+		       NTATAG_SIP_T2_REF(sip_t2),
+		       NTATAG_SIP_T4_REF(sip_t4),
+		       NTATAG_SIP_T1X64_REF(sip_t1x64),
+		       NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob),
+		       NTATAG_DEFAULT_PROXY_REF(proxy),
+		       NTATAG_ALIASES_REF(aliases),
+		       NTATAG_SIPFLAGS_REF(flags),
+		       TAG_END());
+
+  if (nh->nh_ds->ds_local)
+    has_from = 1, *from = *nh->nh_ds->ds_local, from->a_params = NULL;
+  else
+    has_from = 0;
+
+  media_params = soa_get_paramlist(nh->nh_soa, TAG_END());
+
+  m = nua_stack_get_contact(nua->nua_registrations);
+
+  /* Include tag in the list returned to user
+   * if it has been earlier set (by user) */
+#define TIF(TAG, pref) \
+  TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
+
+  /* Include string tag made out of SIP header
+   * if it has been earlier set (by user) */
+#define TIF_STR(TAG, pref)						\
+  TAG_IF(nhp->nhp_set.nhb_##pref,				\
+	 TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref	\
+	     ? sip_header_as_string(tmphome, (void *)nhp->nhp_##pref) : NULL))
+
+  /* Include header tag made out of string
+   * if it has been earlier set (by user) */
+#define TIF_SIP(TAG, pref)						\
+  TAG_IF(nhp->nhp_set.nhb_##pref,					\
+	 TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref			\
+	     ? sip_##pref##_make(tmphome, (char *)nhp->nhp_##pref)	\
+	     : NULL))
+
+  lst = tl_filtered_tlist
+    (tmphome, tags,
+     TAG_IF(has_from, SIPTAG_FROM(from)),
+     TAG_IF(has_from,
+	    SIPTAG_FROM_STR(has_from
+			    ? sip_header_as_string(tmphome, (void *)from)
+			    : NULL)),
+
+     TIF(NUTAG_RETRY_COUNT, retry_count),
+     TIF(NUTAG_MAX_SUBSCRIPTIONS, max_subscriptions),
+
+     TIF(NUTAG_SOA_NAME, soa_name),
+     TIF(NUTAG_MEDIA_ENABLE, media_enable),
+     TIF(NUTAG_ENABLEINVITE, invite_enable),
+     TIF(NUTAG_AUTOALERT, auto_alert),
+     TIF(NUTAG_EARLY_ANSWER, early_answer),
+     TIF(NUTAG_EARLY_MEDIA, early_media),
+     TIF(NUTAG_ONLY183_100REL, only183_100rel),
+     TIF(NUTAG_AUTOANSWER, auto_answer),
+     TIF(NUTAG_AUTOACK, auto_ack),
+     TIF(NUTAG_INVITE_TIMER, invite_timeout),
+
+     TIF(NUTAG_SESSION_TIMER, session_timer),
+     TIF(NUTAG_MIN_SE, min_se),
+     TIF(NUTAG_SESSION_REFRESHER, refresher),
+     TIF(NUTAG_UPDATE_REFRESH, update_refresh),
+
+     TIF(NUTAG_ENABLEMESSAGE, message_enable),
+     TIF(NUTAG_ENABLEMESSENGER, win_messenger_enable),
+     /* TIF(NUTAG_AUTORESPOND, autorespond), */
+
+     TIF(NUTAG_CALLEE_CAPS, callee_caps),
+     TIF(NUTAG_MEDIA_FEATURES, media_features),
+     TIF(NUTAG_SERVICE_ROUTE_ENABLE, service_route_enable),
+     TIF(NUTAG_PATH_ENABLE, path_enable),
+     TIF(NUTAG_REFER_EXPIRES, refer_expires),
+     TIF(NUTAG_REFER_WITH_ID, refer_with_id),
+
+     TIF(NUTAG_SUBSTATE, substate),
+
+     TIF(SIPTAG_SUPPORTED, supported),
+     TIF_STR(SIPTAG_SUPPORTED_STR, supported),
+     TIF(SIPTAG_ALLOW, allow),
+     TIF_STR(SIPTAG_ALLOW_STR, allow),
+     TIF(SIPTAG_ALLOW_EVENTS, allow_events),
+     TIF_STR(SIPTAG_ALLOW_EVENTS_STR, allow_events),
+     TIF_SIP(SIPTAG_USER_AGENT, user_agent),
+     TIF(SIPTAG_USER_AGENT_STR, user_agent),
+     TIF(NUTAG_USER_AGENT, user_agent),
+
+     TIF_SIP(SIPTAG_ORGANIZATION, organization),
+     TIF(SIPTAG_ORGANIZATION_STR, organization),
+
+     TIF(NUTAG_REGISTRAR, registrar),
+     TIF(NUTAG_KEEPALIVE, keepalive),
+     TIF(NUTAG_KEEPALIVE_STREAM, keepalive_stream),
+
+     TIF(NUTAG_INSTANCE, instance),
+     TIF(NUTAG_M_DISPLAY, m_display),
+     TIF(NUTAG_M_USERNAME, m_username),
+     TIF(NUTAG_M_PARAMS, m_params),
+     TIF(NUTAG_M_FEATURES, m_features),
+     TIF(NUTAG_OUTBOUND, outbound),
+     TIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
+
+     /* Skip user-agent-level parameters if parameters are for handle only */
+     TAG_IF(nh != dnh, TAG_NEXT(media_params)),
+
+     NTATAG_CONTACT(m),
+
+#if HAVE_SOFIA_SMIME
+     NUTAG_SMIME_ENABLE(nua->sm->sm_enable),
+     NUTAG_SMIME_OPT(nua->sm->sm_opt),
+     NUTAG_SMIME_PROTECTION_MODE(nua->sm->sm_protection_mode),
+     NUTAG_SMIME_MESSAGE_DIGEST(nua->sm->sm_message_digest),
+     NUTAG_SMIME_SIGNATURE(nua->sm->sm_signature),
+     NUTAG_SMIME_KEY_ENCRYPTION(nua->sm->sm_key_encryption),
+     NUTAG_SMIME_MESSAGE_ENCRYPTION(nua->sm->sm_message_encryption),
+#endif
+
+     NTATAG_UDP_MTU(udp_mtu),
+     NTATAG_SIP_T1(sip_t1),
+     NTATAG_SIP_T2(sip_t2),
+     NTATAG_SIP_T4(sip_t4),
+     NTATAG_SIP_T1X64(sip_t1x64),
+     NTATAG_DEBUG_DROP_PROB(debug_drop_prob),
+     NTATAG_DEFAULT_PROXY(proxy),
+     NTATAG_ALIASES(aliases),
+     NTATAG_SIPFLAGS(flags),
+
+     TAG_NEXT(media_params));
+
+  nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, TAG_NEXT(lst));
+
+  su_home_deinit(tmphome);
+
+  tl_vfree(media_params);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_PARAMS_H
+/** Defined when <nua_params.h> has been included. */
+#define NUA_PARAMS_H
+
+/**@internal @file nua_params.h 
+ * @brief Parameters and their handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:38:18 EET 2006  ppessi
+ */
+
+/** NUA preferences.
+ *
+ * This structure contains values for various preferences and a separate
+ * bitmap (nhp_set) for each preference. Preferences are set using
+ * nua_set_params() or nua_set_hparams() or a handle-specific operation
+ * setting the preferences, including nua_invite(), nua_respond(),
+ * nua_ack(), nua_prack(), nua_update(), nua_info(), nua_bye(),
+ * nua_options(), nua_message(), nua_register(), nua_publish(), nua_refer(),
+ * nua_subscribe(), nua_notify(), nua_refer(), and nua_notifier().
+ *
+ * The stack uses preference value if corresponding bit in bitmap is set,
+ * otherwise it uses preference value from default handle.
+ *
+ * @see NHP_GET(), NH_PGET(), NHP_ISSET(), NH_PISSET()
+ */
+typedef struct nua_handle_preferences
+{
+  unsigned         nhp_retry_count;	/**< times to retry a request */
+  unsigned         nhp_max_subscriptions;
+
+  /* Session-related preferences */
+  char const      *nhp_soa_name;
+  unsigned         nhp_media_enable:1;
+  unsigned     	   nhp_invite_enable:1;
+  unsigned     	   nhp_auto_alert:1;
+  unsigned         nhp_early_answer:1; /**< Include answer in 1XX */
+  unsigned         nhp_early_media:1; /**< Establish early media with 100rel */
+  unsigned         nhp_only183_100rel:1;/**< Only 100rel 183. */
+  unsigned         nhp_auto_answer:1;
+  unsigned         nhp_auto_ack:1; /**< Automatically ACK a final response */
+  unsigned         :0;
+
+  /** INVITE timeout. 
+   *
+   * If no response is received in nhp_invite_timeout seconds,
+   * INVITE client transaction times out
+   */
+  unsigned         nhp_invite_timeout;
+  /** Default session timer (in seconds, 0 disables) */
+  unsigned         nhp_session_timer;
+  /** Default Min-SE Delta value */
+  unsigned         nhp_min_se;
+  /** no (preference), local or remote */
+  enum nua_session_refresher nhp_refresher; 
+  unsigned         nhp_update_refresh:1; /**< Use UPDATE to refresh */
+  
+  /* Messaging preferences */
+  unsigned     	   nhp_message_enable : 1;
+  /** Be bug-compatible with Windows Messenger */
+  unsigned     	   nhp_win_messenger_enable : 1;
+  /** PIM-IW hack */
+  unsigned         nhp_message_auto_respond : 1;
+
+  /* Preferences for registration (and dialog establishment) */
+  unsigned         nhp_callee_caps:1; /**< Add callee caps to contact */
+  unsigned         nhp_media_features:1;/**< Add media features to caps*/
+  /** Enable Service-Route */
+  unsigned         nhp_service_route_enable:1;
+  /** Enable Path */
+  unsigned         nhp_path_enable:1;
+  /** Always include id with Event: refer */
+  unsigned         nhp_refer_with_id:1;
+
+  unsigned:0;
+
+  /* Default lifetime for implicit subscriptions created by REFER */
+  unsigned         nhp_refer_expires;
+
+  /* Subscriber state, i.e. nua_substate_pending */
+  unsigned         nhp_substate;
+
+  /* REGISTER Keepalive intervals */
+  unsigned         nhp_keepalive, nhp_keepalive_stream;
+  char const      *nhp_registrar;
+
+  sip_allow_t        *nhp_allow;
+  sip_supported_t    *nhp_supported;
+  sip_allow_events_t *nhp_allow_events;
+  char const         *nhp_user_agent;
+  char const         *nhp_organization;
+
+  char const         *nhp_m_display;
+  char const         *nhp_m_username;
+  char const         *nhp_m_params;
+  char const         *nhp_m_features;
+  char const         *nhp_instance;
+
+  /**< Outbound OPTIONS */
+  char const         *nhp_outbound; 
+  
+  /**< Network detection: NONE, INFORMAL, TRY_FULL */
+  int                 nhp_detect_network_updates;
+  
+  sip_allow_t        *nhp_appl_method;
+
+  union { struct {
+    /* A bit for each feature set by application */
+    unsigned nhb_retry_count:1;
+    unsigned nhb_max_subscriptions:1;
+
+    unsigned nhb_soa_name:1;
+    unsigned nhb_media_enable:1;
+    unsigned nhb_invite_enable:1;
+    unsigned nhb_auto_alert:1;
+    unsigned nhb_early_answer:1;
+    unsigned nhb_early_media:1;
+    unsigned nhb_only183_100rel:1;
+    unsigned nhb_auto_answer:1;
+    unsigned nhb_auto_ack:1;
+    unsigned nhb_invite_timeout:1;
+
+    unsigned nhb_session_timer:1;
+    unsigned nhb_min_se:1;
+    unsigned nhb_refresher:1; 
+    unsigned nhb_update_refresh:1;
+    unsigned nhb_message_enable:1;
+    unsigned nhb_win_messenger_enable:1;
+    unsigned nhb_message_auto_respond:1;
+    unsigned nhb_callee_caps:1;
+    unsigned nhb_media_features:1;
+    unsigned nhb_service_route_enable:1;
+    unsigned nhb_path_enable:1;
+    unsigned nhb_refer_with_id:1;
+    unsigned nhb_refer_expires:1;
+    unsigned nhb_substate:1;
+    unsigned nhb_keepalive:1;
+    unsigned nhb_keepalive_stream:1;
+    unsigned nhb_registrar:1;
+
+    unsigned nhb_allow:1;
+    unsigned nhb_supported:1;
+    unsigned nhb_allow_events:1;
+    unsigned :0;		/* at most 32 bits ... */
+    unsigned nhb_user_agent:1;
+    unsigned nhb_organization:1;
+
+    unsigned nhb_m_display:1;
+    unsigned nhb_m_username:1;
+    unsigned nhb_m_params:1;
+    unsigned nhb_m_features:1;
+    unsigned nhb_instance:1;
+    unsigned nhb_outbound:1;
+    unsigned nhb_detect_network_updates:1;
+    unsigned nhb_appl_method:1;
+    unsigned :0;
+  } set_bits; 
+    unsigned set_unsigned[2];
+  } nhp_set_;
+} nua_handle_preferences_t;
+
+#define nhp_set nhp_set_.set_bits
+
+#define DNHP_GET(dnhp, pref) ((dnhp)->nhp_##pref)
+
+#define NHP_GET(nhp, dnhp, pref)					\
+  ((nhp)->nhp_set.nhb_##pref					\
+   ? (nhp)->nhp_##pref : (dnhp)->nhp_##pref)
+
+#define NHP_SET(nhp, pref, value)					\
+  ((nhp)->nhp_##pref = (value),						\
+   (nhp)->nhp_set.nhb_##pref = 1)
+
+/* Check if preference is set */
+#define NHP_ISSET(nhp, pref)						\
+  ((nhp)->nhp_set.nhb_##pref)
+
+#define NHP_UNSET_ALL(nhp) (memset(&(nhp)->nhp_set, 0, sizeof (nhp)->nhp_set))
+#define NHP_SET_ALL(nhp) (memset(&(nhp)->nhp_set, 255, sizeof (nhp)->nhp_set))
+
+/* Get preference from handle, if set, otherwise from default handle */
+#define NH_PGET(nh, pref)						\
+  NHP_GET((nh)->nh_prefs, (nh)->nh_nua->nua_dhandle->nh_prefs, pref)
+
+/* Get preference from handle, if exists and set, 
+   otherwise from default handle */
+#define NUA_PGET(nua, nh, pref)						\
+  NHP_GET((nh) ? (nh)->nh_prefs : (nua)->nua_dhandle->nh_prefs,		\
+	  (nua)->nua_dhandle->nh_prefs,					\
+	  pref)
+
+/* Get preference from default handle */
+#define DNH_PGET(dnh, pref)						\
+  DNHP_GET((dnh)->nh_prefs, pref)
+/* Check if preference is set in the handle */
+#define NH_PISSET(nh, pref)						\
+  (NHP_ISSET((nh)->nh_prefs, pref) &&					\
+   (nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs)
+
+#endif /* NUA_PARAMS_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,528 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_publish.c
+ * @brief PUBLISH and publications
+ *
+ * @sa @RFC3903
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 17:01:32 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ====================================================================== */
+/* Publish usage */
+
+struct publish_usage {
+  sip_etag_t *pu_etag;
+};
+
+static char const *nua_publish_usage_name(nua_dialog_usage_t const *du);
+static int nua_publish_usage_add(nua_handle_t *nh,
+				  nua_dialog_state_t *ds,
+				  nua_dialog_usage_t *du);
+static void nua_publish_usage_remove(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du);
+static void nua_publish_usage_refresh(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du,
+				      sip_time_t now);
+static int nua_publish_usage_shutdown(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du);
+
+static nua_usage_class const nua_publish_usage[1] = {
+  {
+    sizeof (struct publish_usage),
+    sizeof nua_publish_usage,
+    nua_publish_usage_add,
+    nua_publish_usage_remove,
+    nua_publish_usage_name,
+    NULL,
+    nua_publish_usage_refresh,
+    nua_publish_usage_shutdown,
+  }};
+
+static
+char const *nua_publish_usage_name(nua_dialog_usage_t const *du)
+{
+  return "publish";
+}
+
+static
+int nua_publish_usage_add(nua_handle_t *nh,
+			   nua_dialog_state_t *ds,
+			   nua_dialog_usage_t *du)
+{
+  if (ds->ds_has_publish)
+    return -1;			/* There can be only one */
+  ds->ds_has_publish = 1;
+  return 0;
+}
+
+static
+void nua_publish_usage_remove(nua_handle_t *nh,
+			       nua_dialog_state_t *ds,
+			       nua_dialog_usage_t *du)
+{
+  struct publish_usage *pu = nua_dialog_usage_private(du);
+
+  su_free(nh->nh_home, pu->pu_etag);
+
+  ds->ds_has_publish = 0;	/* There can be only one */
+}
+
+/* ======================================================================== */
+/* PUBLISH */
+
+static int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+			      int refresh, tagi_t const *tags);
+
+static int process_response_to_publish(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+
+
+/**@fn \
+ * void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send PUBLISH request to publication server.
+ *
+ * Request status will be delivered to the application using #nua_r_publish
+ * event. When successful the publication will be updated periodically until
+ * nua_unpublish() is called or handle is destroyed. Note that the periodic
+ * updates and unpublish do not include the original message body nor the @b
+ * Content-Type header. Instead, the periodic update will include the
+ * @SIPIfMatch header, which was generated from the latest @SIPETag
+ * header received in response to @b PUBLISH request.
+ *
+ * The handle used for publication cannot be used for any other purposes.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_publish
+ *
+ * @sa #nua_r_publish, @RFC3903, @SIPIfMatch,
+ * nua_unpublish(), #nua_r_unpublish, #nua_i_publish
+ */
+
+/** @NUA_EVENT nua_r_publish
+ *
+ * Response to an outgoing PUBLISH.
+ *
+ * The PUBLISH request may be sent explicitly by nua_publish() or implicitly
+ * by NUA state machine.
+ *
+ * @param status status code of PUBLISH request
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the publication
+ * @param hmagic application context associated with the handle
+ * @param sip    response to PUBLISH request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_publish(), @RFC3903, @SIPETag, @Expires,
+ * nua_unpublish(), #nua_r_unpublish, #nua_i_publish
+ *
+ * @END_NUA_EVENT
+ */
+
+/**@fn \
+void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send un-PUBLISH request to publication server. Un-PUBLISH request is just
+ * a PUBLISH request with @Expires set to 0. It is possible to un-publish a
+ * publication not associated with the handle by providing correct ETag in
+ * SIPTAG_IF_MATCH() or SIPTAG_IF_MATCH_STR() tags.
+ *
+ * Response to the un-PUBLISH request will be delivered to the application
+ * using #nua_r_unpublish event.
+ *
+ * The handle used for publication cannot be used for any other purposes.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    SIPTAG_IF_MATCH(), SIPTAG_IF_MATCH_STR() \n
+ *    SIPTAG_EVENT(), SIPTAG_EVENT_STR() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_unpublish
+ * 
+ * @sa #nua_r_unpublish, @RFC3903, @SIPIfMatch, 
+ * #nua_i_publish, nua_publish(), #nua_r_publish
+ */
+
+/** @NUA_EVENT nua_r_unpublish
+ *
+ * Response to an outgoing un-PUBLISH.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the publication
+ * @param hmagic application context associated with the handle
+ * @param sip    response to PUBLISH request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_unpublish(), @RFC3903, @SIPETag, @Expires,
+ * nua_publish(), #nua_r_publish, #nua_i_publish
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_publish(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		      tagi_t const *tags)
+{
+  return nua_stack_publish2(nua, nh, e, 0, tags);
+}
+
+static
+int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		       int refresh,
+		       tagi_t const *tags)
+{
+  nua_dialog_usage_t *du;
+  struct publish_usage *pu;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg = NULL;
+  sip_t *sip;
+  int remove_body = 0;
+
+  if (nua_stack_set_handle_special(nh, nh_has_nothing, nua_r_publish) < 0)
+    return UA_EVENT2(e, 900, "Invalid handle for PUBLISH");
+
+  if (cr->cr_orq) {
+    return UA_EVENT2(e, 900, "Request already in progress");
+  }
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  if (e == nua_r_unpublish) {
+    du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
+    if (du)
+      refresh = 1;
+    else
+      du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
+  }
+  else if (!refresh)
+    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
+  else
+    du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
+
+  if (!du)
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+
+  nua_dialog_usage_reset_refresh(du);
+  pu = nua_dialog_usage_private(du); assert(pu);
+
+  if (refresh) {
+    if (cr->cr_msg)
+      msg_destroy(cr->cr_msg);
+    cr->cr_msg = msg_copy(du->du_msg);
+    remove_body = pu->pu_etag != NULL;
+  }
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
+		     SIP_METHOD_PUBLISH,
+		     NUTAG_ADD_CONTACT(0),
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (!msg || !sip) 
+    goto error;
+
+  du->du_terminating =
+    e != nua_r_publish ||
+    (sip->sip_expires && sip->sip_expires->ex_delta == 0);
+
+  if (!du->du_terminating && !refresh) {
+    /* Save template */
+    if (du->du_msg)
+      msg_destroy(du->du_msg);
+    du->du_msg = msg_ref_create(cr->cr_msg);
+  }
+
+  cr->cr_orq =
+    nta_outgoing_mcreate(nua->nua_nta,
+			 process_response_to_publish, nh, NULL,
+			 msg,
+			 SIPTAG_IF_MATCH(pu->pu_etag),
+			 TAG_IF(remove_body, SIPTAG_PAYLOAD(NONE)),
+			 TAG_IF(remove_body, SIPTAG_CONTENT_TYPE(NONE)),
+			 TAG_IF(e != nua_r_publish,
+				SIPTAG_EXPIRES_STR("0")),
+			 SIPTAG_END(), TAG_NEXT(tags));
+  if (!cr->cr_orq)
+    goto error;
+
+  cr->cr_usage = du;
+
+  return cr->cr_event = e;
+
+ error:
+  msg_destroy(msg);
+  if (!du->du_ready == 0)
+    nua_dialog_usage_remove(nh, nh->nh_ds, du);
+  return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+
+static void
+restart_publish(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_publish, tags);
+}
+
+
+static
+int process_response_to_publish(nua_handle_t *nh,
+				nta_outgoing_t *orq,
+				sip_t const *sip)
+{
+  int status = sip->sip_status->st_status;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_dialog_usage_t *du = cr->cr_usage;
+  struct publish_usage *pu = nua_dialog_usage_private(du);
+  unsigned saved_retry_count = cr->cr_retry_count + 1;
+
+  if (nua_creq_check_restart(nh, cr, orq, sip, restart_publish))
+    return 0;
+
+  if (status < 200 || pu == NULL)
+    return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+  if (pu->pu_etag)
+    su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
+
+  if (!du->du_terminating) {
+    int retry = 0, invalid_expiration = 0;
+
+    if (status < 300) {
+      if (!sip->sip_expires)
+	invalid_expiration = 1;
+      else if (sip->sip_expires->ex_delta == 0)
+	retry = 1, invalid_expiration = 1;
+    }
+    else if (status == 412)
+      retry = 1;
+
+    if (status < 300 && !invalid_expiration && !retry) {
+      pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_etag);
+      du->du_ready = 1;
+      nua_dialog_usage_set_expires(du, sip->sip_expires->ex_delta);
+    }
+    else if (retry && saved_retry_count < NH_PGET(nh, retry_count)) {
+      msg_t *response = nta_outgoing_getresponse(orq);
+      nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
+      		100, "Trying re-PUBLISH",
+      		TAG_END());
+      nua_creq_deinit(cr, orq);
+      nua_stack_publish2(nh->nh_nua, nh, cr->cr_event, 1, NULL);
+      cr->cr_retry_count = saved_retry_count;
+      return 0;
+    }
+    else if (invalid_expiration) {
+      msg_t *response = nta_outgoing_getresponse(orq);
+      nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
+      		900, "Received Invalid Expiration Time",
+      		TAG_END());
+      nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
+      nua_creq_deinit(cr, orq);
+      cr->cr_usage = NULL;
+      return 0;
+    }
+  }
+
+  return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}
+
+
+static void nua_publish_usage_refresh(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du,
+				      sip_time_t now)
+{
+  if (ds->ds_cr->cr_usage == du) /* Already publishing. */
+    return;
+  nua_stack_publish2(nh->nh_nua, nh, nua_r_publish, 1, NULL);
+}
+
+/** @interal Shut down PUBLISH usage. 
+ *
+ * @retval >0  shutdown done
+ * @retval 0   shutdown in progress
+ * @retval <0  try again later
+ */
+static int nua_publish_usage_shutdown(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du)
+{
+  nua_client_request_t *cr = ds->ds_cr;
+
+  if (!cr->cr_usage) {
+    /* Unpublish */
+    nua_stack_publish2(nh->nh_nua, nh, nua_r_destroy, 1, NULL);
+    return cr->cr_usage != du;
+  }
+
+  if (!du->du_ready && !cr->cr_orq)
+    return 1;			/* had unauthenticated initial request */
+
+  return -1;  /* Request in progress */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Server side */
+
+static
+int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_publish
+ *
+ * Incoming PUBLISH request.
+ *
+ * In order to receive #nua_i_publish events, the application must enable
+ * both the PUBLISH method with NUTAG_ALLOW() tag and the acceptable SIP
+ * events with nua_set_params() tag NUTAG_ALLOW_EVENTS(). 
+ *
+ * The nua_response() call responding to a PUBLISH request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * a successful response to PUBLISH @b MUST include @Expires and @SIPETag
+ * headers.
+ *
+ * The PUBLISH request does not create a dialog. Currently the processing
+ * of incoming PUBLISH creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the PUBLISH
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the incoming request
+ * @param hmagic application context associated with the call
+ *               (usually NULL)
+ * @param sip    incoming PUBLISH request
+ * @param tags   empty
+ *
+ * @sa @RFC3903, nua_respond(),
+ * @Expires, @SIPETag, @SIPIfMatch, @Event, 
+ * nua_subscribe(), #nua_i_subscribe, 
+ * nua_notifier(), #nua_i_subscription,
+ *
+ * @since First used in @VERSION_1_12_4
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_publish(nua_t *nua,
+			      nua_handle_t *nh,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+  sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+  sip_event_t *o = sip->sip_event;
+  char const *event = o ? o->o_type : NULL;
+  
+  sr = SR_INIT(sr0);
+  
+  if (!allow_events)
+    SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
+  else if (!event || !msg_header_find_param(allow_events->k_common, event))
+    SR_STATUS1(sr, SIP_489_BAD_EVENT);
+
+  sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+			  respond_to_publish, 0);
+
+  return nua_stack_server_event(nua, sr, nua_i_publish, TAG_END());
+}
+
+static
+int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_t *nua = nh->nh_nua;
+  msg_t *msg;
+
+  msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
+
+  if (msg) {
+    nta_incoming_mreply(sr->sr_irq, msg);
+  }
+  else {
+    SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+    nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+    nua_stack_event(nua, nh, NULL,
+		    nua_i_error, 900, "PUBLISH Response Fails",
+		    TAG_END());
+  }
+  
+  return sr->sr_status >= 200 ? sr->sr_status : 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1972 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_register.c
+ * @brief REGISTER and registrations
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+/** @internal SU network changed detector argument pointer type */
+#define SU_NETWORK_CHANGED_MAGIC_T struct nua_s
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_UPDATE_MAGIC_T   struct nua_s
+
+#include "nua_stack.h"
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/tport_tag.h>
+
+#define OUTBOUND_OWNER_T struct nua_handle_s
+
+#include "outbound.h"
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+/* ======================================================================== */
+/* Registrations and contacts */
+
+int nua_registration_from_via(nua_registration_t **list,
+			      nua_handle_t *nh, 
+			      sip_via_t const *via,
+			      int public);
+
+int nua_registration_add(nua_registration_t **list, nua_registration_t *nr);
+
+void nua_registration_remove(nua_registration_t *nr);
+
+int nua_registration_set_aor(su_home_t *, nua_registration_t *nr,
+			     sip_from_t const *aor);
+
+int nua_registration_set_contact(nua_handle_t *,
+				 nua_registration_t *nr,
+				 sip_contact_t const *m,
+				 int terminating);
+
+void nua_registration_set_ready(nua_registration_t *nr, int ready);
+
+/* ====================================================================== */
+/* REGISTER usage */
+
+static char const *nua_register_usage_name(nua_dialog_usage_t const *du);
+
+static int nua_register_usage_add(nua_handle_t *nh,
+				  nua_dialog_state_t *ds,
+				  nua_dialog_usage_t *du);
+static void nua_register_usage_remove(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du);
+static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
+					 nua_dialog_state_t const *ds,
+					 sip_t const *sip);
+static void nua_register_usage_refresh(nua_handle_t *,
+				       nua_dialog_state_t *,
+				       nua_dialog_usage_t *,
+				       sip_time_t);
+static int nua_register_usage_shutdown(nua_handle_t *,
+				       nua_dialog_state_t *,
+				       nua_dialog_usage_t *);
+
+/** REGISTER usage, aka nua_registration_t */
+struct register_usage {
+  nua_registration_t *nr_next, **nr_prev, **nr_list; /* Doubly linked list and its head */
+  sip_from_t *nr_aor;		/**< AoR for this registration, NULL if none */
+  sip_contact_t *nr_contact;	/**< Our Contact */
+  sip_via_t *nr_via;		/**< Corresponding Via headers */
+
+  /** Status of registration */
+  unsigned nr_ready:1;
+  /** Kind of registration.
+   *
+   * If nr_default is true, this is not a real registration but placeholder
+   * for Contact header derived from a transport address.
+   *
+   * If nr_secure is true, this registration supports SIPS/TLS.
+   *
+   * If nr_public is true, transport should have public address.
+   */
+  unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1;
+
+  /** Stack-generated contact */
+  unsigned nr_by_stack:1, :0;
+
+  sip_route_t *nr_route;	/**< Outgoing Service-Route */
+  sip_path_t *nr_path;		/**< Incoming Path */
+
+  tport_t *nr_tport;		/**< Transport to be used when registered */
+  nua_dialog_state_t *nr_dialogs; /**< List of our dialogs */
+
+#if HAVE_SIGCOMP
+  struct sigcomp_compartment *nr_compartment;
+#endif
+
+  outbound_t *nr_ob;	/**< Outbound connection */
+};
+
+nua_usage_class const nua_register_usage[1] = {
+  {
+    sizeof (struct register_usage),
+    (sizeof nua_register_usage),
+    nua_register_usage_add,
+    nua_register_usage_remove,
+    nua_register_usage_name,
+    nua_register_usage_peer_info,
+    nua_register_usage_refresh,
+    nua_register_usage_shutdown
+  }};
+
+static char const *nua_register_usage_name(nua_dialog_usage_t const *du)
+{
+  return "register";
+}
+
+static int nua_register_usage_add(nua_handle_t *nh,
+				  nua_dialog_state_t *ds,
+				  nua_dialog_usage_t *du)
+{
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+
+  if (ds->ds_has_register)
+    return -1;			/* There can be only one usage */
+
+  ds->ds_has_register = 1;
+
+  nr->nr_public = 1;		/* */
+
+  return 0;
+}
+
+
+static void nua_register_usage_remove(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du)
+{
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+
+  if (nr->nr_list)
+    nua_registration_remove(nr);	/* Remove from list of registrations */
+
+  if (nr->nr_ob)
+    outbound_unref(nr->nr_ob);
+
+#if HAVE_SIGCOMP
+  if (nr->nr_compartment)
+    sigcomp_compartment_unref(nr->nr_compartment);
+  nr->nr_compartment = NULL;
+#endif
+
+  ds->ds_has_register = 0;	/* There can be only one */
+}
+
+
+/** @internal Store information about registrar. */
+static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
+					 nua_dialog_state_t const *ds,
+					 sip_t const *sip)
+{
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+  if (nr->nr_ob)
+    outbound_peer_info(nr->nr_ob, sip);
+}
+
+/* ======================================================================== */
+/* REGISTER */
+
+static void restart_register(nua_handle_t *nh, tagi_t *tags);
+
+static int process_response_to_register(nua_handle_t *nh,
+					nta_outgoing_t *orq,
+					sip_t const *sip);
+
+static void unregister_expires_contacts(msg_t *msg, sip_t *sip);
+
+/* Interface towards outbound_t */
+sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
+					 su_home_t *home,
+					 char const *extra_username,
+					 sip_via_t const *v,
+					 char const *transport,
+					 char const *m_param,
+					 ...);
+
+static int nua_stack_outbound_features(nua_handle_t *nh, outbound_t *ob);
+
+static int nua_stack_outbound_refresh(nua_handle_t *,
+				      outbound_t *ob);
+
+static int nua_stack_outbound_status(nua_handle_t *,
+				     outbound_t *ob,
+				     int status, char const *phrase,
+				     tag_type_t tag, tag_value_t value, ...);
+
+static int nua_stack_outbound_failed(nua_handle_t *,
+				     outbound_t *ob,
+				     int status, char const *phrase,
+				     tag_type_t tag, tag_value_t value, ...);
+
+static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc);
+
+outbound_owner_vtable nua_stack_outbound_callbacks = {
+    sizeof nua_stack_outbound_callbacks,
+    nua_handle_contact_by_via,
+    nua_stack_outbound_refresh,
+    nua_stack_outbound_status,
+    nua_stack_outbound_failed,
+    nua_stack_outbound_failed,
+    nua_stack_outbound_credentials
+  };
+
+/**@fn void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ * 
+ * Send SIP REGISTER request to the registrar. 
+ *
+ * Request status will be delivered to the application using #nua_r_register
+ * event. When successful the registration will be updated periodically.
+ *
+ * The handle used for registration cannot be used for any other purposes.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), NUTAG_M_USERNAME(),
+ *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(), 
+ *
+ * @par Events:
+ *     #nua_r_register, #nua_i_outbound
+ * 
+ * @par Generating Contact Header
+ *
+ * If the application did not specify the Contact header in the tags,
+ * nua_register() will generate one. It will obtain the schema, IP address
+ * for the host and port number for the Contact URI from the transport
+ * socket. The diplay name is taken from NUTAG_M_DISPLAY(), URL username
+ * part is taken from NUTAG_M_USERNAME(), URI parameters from
+ * NUTAG_M_PARAMS(), and Contact header parameters from NUTAG_M_FEATURES(). 
+ * If NUTAG_CALLEE_CAPS(1) is specified, additional Contact header
+ * parameters are generated based on SDP capabilities and SIP @Allow header.
+ * 
+ * Note that @b nua may append a identifier of its own to the @Contact URI
+ * username. Such nua-generated identifier trailer always starts with "="
+ * (equal sign), rest of the nua-generated identifier may contain any
+ * url-unreserved characters except "=".
+ *
+ * Likewise, nua may add transport parameters (such as "transport=tcp" or
+ * "maddr") to the @Contact URI. It can add addtional header parameters, like
+ * "+sip.instance" or "reg-id", too.
+ *
+ * For instance, if application uses tags like
+ * @code
+ *   nua_register(nh,
+ *                NUTAG_M_DISPLAY("1"),
+ *                NUTAG_M_USERNAME("line-1"),
+ *                NUTAG_M_PARAMS("user=phone"),
+ *                NUTAG_M_FEATURES("audio"),
+ *                NUTAG_CALLEE_CAPS(0),
+ *                TAG_END())
+ * @endcode
+ * @b nua can generate a Contact header like
+ * @code
+ * Contact: 1 <sip:line-1=SSQAIbjv at 192.168.1.200;transport=tcp;user=phone>
+ *   ;audio;reg-id=1
+ *   ;+sip.instance=urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c
+ * @endcode
+ *
+ * The incoming request from the proxy should contain the registered contact
+ * URI as the request URI. The application can use the username prefix set
+ * by NUTAG_M_USERNAME() and the non-transport parameters of the request URI
+ * set by NUTAG_M_PARAMS() when determining to which registration the
+ * incoming request belongs.
+ * 
+ * For example, a request line correspoding to the @Contact in above example
+ * may look like:
+ * @code
+ * INVITE sip:line-1=SSQAIbjv at 192.168.1.200;user=phone SIP/2.0
+ * @endcode
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(),
+ * NUTAG_M_FEATURES(), NUTAG_CALLEE_CAPS().
+ *
+ * @par NAT, Firewall and Outbound Support
+ *
+ * Normally, @b nua will start start a protocol engine for outbound
+ * connections used for NAT and firewall traversal and connectivity checks
+ * when registering. 
+ *
+ * @note If the application provides @b nua with a
+ * @Contact header of its own (or includes a SIPTAG_CONTACT(NULL) tag in
+ * nua_register() tags), the outbound protocol engine is not started. It is
+ * assumed that the application knows better what it is doing when it sets
+ * the @Contact, or it is using experimental CPL upload as specified in 
+ * <a href="http://www.ietf.org/internet-drafts/draft-lennox-sip-reg-payload-01.txt">
+ * draft-lennox-sip-reg-payload-01.txt</a>.
+ *
+ * First, outbound engine will probe for NATs in between UA and registrar. 
+ * It will send a REGISTER request as usual. Upon receiving the response it
+ * checks for the presence of "received" and "rport" parameters in the Via
+ * header returned by registrar. The presence of NAT is determined from the
+ * "received" parameter in a Via header. When a REGISTER request was sent,
+ * the stack inserted the actual source IP address in the Via header: if
+ * that is different from the source IP address seen by the registrar, the
+ * registrar inserts the source IP address it sees into the "received"
+ * parameter.
+ *
+ * Please note that an ALG (application-level gateway) modifying the Via
+ * headers in outbound requests and again in incoming responses will make
+ * the above-described NAT check to fail.
+ *
+ * The response to the initial REGISTER should also include option tags
+ * indicating whether registrar supports various SIP extension options: @e
+ * outbound, @e pref, @e path, @e gruu.
+ *
+ * Basically, @e outbound means that instead of registering its contact URI
+ * with a particular address-of-record URI, the user-agent registers a
+ * transport-level connection. Such a connection is identified on the
+ * Contact header field with an instance identifier, application-provided
+ * @ref NUTAG_INSTANCE() "unique string" identifying the user-agent instance
+ * and a stack-generated numeric index identifying the transport-level
+ * connection.
+ *
+ * If the @e outbound extension is supported, NUTAG_OUTBOUND() contains
+ * option string "outbound" and the application has provided an instance
+ * identifer to the stack with NUTAG_INSTANCE(), the nua_register() will try
+ * to use outbound.
+ *
+ * If @e outbound is not supported, nua_register() has to generate a URI
+ * that can be used to reach it from outside. It will check for public
+ * transport addresses detected by underlying stack with, e.g., STUN, UPnP
+ * or SOCKS. If there are public addresses, nua_register() will use them. If
+ * there is no public address, it will try to generate a Contact URI from
+ * the "received" and "rport" parameters found in the Via header of the
+ * response message.
+ *
+ * @todo Actually generate public addresses.
+ *
+ * You can disable this kind of NAT traversal by setting "no-natify" into
+ * NUTAG_OUTBOUND() options string.
+ * 
+ * @par GRUU and Service-Route
+ *
+ * After a successful response to the REGISTER request has been received,
+ * nua_register() will update the information about the registration based
+ * on it. If there is a "gruu" parameter included in the response,
+ * nua_register() will save it and use the gruu URI in the Contact header
+ * fields of dialog-establishing messages, such as INVITE or SUBSCRIBE. 
+ * Also, if the registrar has included a Service-Route header in the
+ * response, and the service route feature has not been disabled using
+ * NUTAG_SERVICE_ROUTE_ENABLE(), the route URIs from the Service-Route
+ * header will be used for initial non-REGISTER requests.
+ *
+ * The #nua_r_register message will include the contact header and route
+ * used in with the registration.
+ *
+ * @par Registration Keep-Alive
+ *
+ * After the registration has successfully completed the nua_register() will
+ * validate the registration and initiate the keepalive mechanism, too. The
+ * user-agent validates the registration by sending a OPTIONS requests to
+ * itself. If there is an error, nua_register() will indicate that to the
+ * application using #nua_i_outbound event, and start unregistration
+ * procedure (unless that has been explicitly disabled).
+ *
+ * You can disable validation by inserting "no-validate" into
+ * NUTAG_OUTBOUND() string.
+ *
+ * The keepalive mechanism depends on the network features detected earlier. 
+ * If @a outbound extension is used, the STUN keepalives will be used. 
+ * Otherwise, NUA stack will repeatedly send OPTIONS requests to itself. In
+ * order to save bandwidth, it will include Max-Forwards: 0 in the
+ * keep-alive requests, however. The keepalive interval is determined by
+ * NUTAG_KEEPALIVE() parameter. If the interval is 0, no keepalive messages
+ * is sent.
+ *
+ * You can disable keepalive OPTIONS by inserting "no-options-keepalive"
+ * into NUTAG_OUTBOUND() string. Currently there are no other keepalive
+ * mechanisms available.
+ *
+ * The value of NUTAG_KEEPALIVE_STREAM(), if specified, is used to indicate
+ * the desired transport-layer keepalive interval for stream-based
+ * transports like TLS and TCP.
+ *
+ * @sa #nua_r_register, nua_unregister(), #nua_r_unregister, 
+ * #nua_i_register,
+ * @RFC3261 section 10,
+ * @Expires, @Contact, @CallID, @CSeq,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), 
+ *     SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
+ *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(), 
+ */
+
+/** @NUA_EVENT nua_r_register
+ *
+ * Response to an outgoing REGISTER.
+ *
+ * The REGISTER may be sent explicitly by nua_register() or implicitly by
+ * NUA state machines. 
+ * 
+ * When REGISTER request has been restarted the @a status may be 100 even
+ * while the real response status returned is different.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the registration
+ * @param hmagic application context associated with the registration
+ * @param sip    response message to REGISTER request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_register(), nua_unregister(), #nua_r_unregister,
+ * @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
+ * 
+ * @END_NUA_EVENT
+ */
+
+/**@fn void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ * Unregister. 
+ *
+ * Send a REGISTER request with expiration time 0. This removes the 
+ * registration from the registrar. If the handle was earlier used 
+ * with nua_register() the periodic updates will be terminated. 
+ *
+ * If a SIPTAG_CONTACT_STR() with argument "*" is used, all the
+ * registrations will be removed from the registrar otherwise only the
+ * contact address belonging to the NUA stack is removed.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     NUTAG_REGISTRAR() \n
+ *     Tags in <sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
+ *
+ * @par Events:
+ *     #nua_r_unregister
+ *
+ * @sa nua_register(), #nua_r_register, nua_handle_destroy(), nua_shutdown(),
+ * #nua_i_register,
+ * @Expires, @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), 
+ *     SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
+ *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(), 
+ */
+
+/** @NUA_EVENT nua_r_unregister
+ *
+ * Answer to outgoing un-REGISTER.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the registration
+ * @param hmagic application context associated with the registration
+ * @param sip    response message to REGISTER request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_unregister(), nua_register(), #nua_r_register,
+ * @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
+ * 
+ * @END_NUA_EVENT
+ */
+
+int
+nua_stack_register(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		   tagi_t const *tags)
+{
+  nua_dialog_usage_t *du;
+  nua_registration_t *nr = NULL;
+  outbound_t *ob = NULL;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg = NULL;
+  sip_t *sip;
+  int terminating = e != nua_r_register;
+
+  if (nua_stack_set_handle_special(nh, nh_has_register, nua_r_register) < 0)
+    return UA_EVENT2(e, 900, "Invalid handle for REGISTER");
+  if (cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  du = nua_dialog_usage_add(nh, nh->nh_ds, nua_register_usage, NULL);
+  if (!du)
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  nr = nua_dialog_usage_private(du); assert(nr);
+  nua_registration_add(&nh->nh_nua->nua_registrations, nr);
+  if (!terminating && du->du_terminating)
+    return UA_EVENT2(e, 900, "Unregister in progress");
+
+  if (cr->cr_msg)
+    msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+  /* Use original message as template when unregistering */
+  if (terminating)		
+    cr->cr_msg = msg_ref_create(du->du_msg);
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_msg != NULL,
+		     SIP_METHOD_REGISTER,
+		     TAG_IF(!terminating, NUTAG_USE_DIALOG(1)),
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+  if (!msg || !sip)
+    goto error;
+
+  if (!nr->nr_aor) {
+    if (nua_registration_set_aor(nh->nh_home, nr, sip->sip_to) < 0)
+      goto error;
+  }
+
+  if (terminating)
+    /* Add Expires: 0 and remove the expire parameters from contacts */
+    unregister_expires_contacts(msg, sip);
+
+  if (!sip->sip_contact && cr->cr_has_contact) {
+    terminating = 1;
+  }
+  else if (nua_registration_set_contact(nh, nr, sip->sip_contact, terminating)
+	   < 0)
+    goto error;
+
+  du->du_terminating = terminating;
+
+  if (du->du_msg == NULL && !terminating)
+    du->du_msg = msg_ref_create(cr->cr_msg); /* Save original message */
+
+  ob = nr->nr_ob;
+  
+  if (!ob && (NH_PGET(nh, outbound) || NH_PGET(nh, instance))) {
+    nr->nr_ob = ob = outbound_new(nh, &nua_stack_outbound_callbacks,
+				  nh->nh_nua->nua_root,
+				  nh->nh_nua->nua_nta,
+				  NH_PGET(nh, instance));
+    if (!ob)
+      goto error;
+  }
+
+  if (ob) {
+    outbound_set_options(ob,
+			 NH_PGET(nh, outbound),
+			 NH_PGET(nh, keepalive),
+			 NH_PISSET(nh, keepalive_stream)
+			 ? NH_PGET(nh, keepalive_stream)
+			 : NH_PGET(nh, keepalive));
+    nua_stack_outbound_features(nh, ob);
+    outbound_stop_keepalive(ob);
+
+    if (outbound_set_contact(ob, sip->sip_contact, nr->nr_via, terminating) < 0)
+      goto error;
+  }
+
+  /* This calls nta_outgoing_mcreate() but adds a few tags */
+  cr->cr_orq =
+    outbound_register_request(ob, terminating,
+			      nr->nr_by_stack ? nr->nr_contact : NULL,
+			      nua->nua_nta,
+			      process_response_to_register, nh, NULL,
+			      msg,
+			      SIPTAG_END(), 
+			      TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)),
+			      TAG_IF(!terminating, NTATAG_COMP("sigcomp")),
+			      TAG_NEXT(tags));
+
+  if (!cr->cr_orq)
+    goto error;
+
+  cr->cr_usage = du;
+  return cr->cr_event = e;
+
+ error:
+  msg_destroy(msg);
+  msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+  nua_dialog_usage_remove(nh, nh->nh_ds, du);    
+  return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+static void
+restart_register(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+  nua_dialog_usage_t *du = cr->cr_usage;
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+  int terminating = du && du->du_terminating;
+
+  cr->cr_restart = NULL;
+
+  if (!cr->cr_msg)
+    return;
+
+  msg = nua_creq_msg(nh->nh_nua, nh, cr, 1,
+		     SIP_METHOD_UNKNOWN,
+		     TAG_NEXT(tags));
+
+  if (!msg)
+    return;			/* XXX - Uh-oh */
+
+  if (terminating)
+    unregister_expires_contacts(msg, sip_object(msg));
+
+  /* This calls nta_outgoing_mcreate() but adds a few tags */
+  cr->cr_orq =
+    outbound_register_request(nr->nr_ob, terminating,
+			      nr->nr_by_stack ? nr->nr_contact : NULL,
+			      nh->nh_nua->nua_nta,
+			      process_response_to_register, nh, NULL,
+			      msg,
+			      SIPTAG_END(), 
+			      TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)),
+			      TAG_IF(!terminating, NTATAG_COMP("sigcomp")),
+			      TAG_NEXT(tags));
+
+  if (!cr->cr_orq)
+    msg_destroy(msg);
+}
+
+/** Refresh registration */
+static
+void nua_register_usage_refresh(nua_handle_t *nh,
+				nua_dialog_state_t *ds,
+				nua_dialog_usage_t *du,
+				sip_time_t now)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+  msg_t *msg;
+  sip_t *sip;
+
+  if (du->du_terminating || du->du_shutdown)
+    return;
+
+  if (cr->cr_msg) {
+    /* Dialog is busy, delay of 5 .. 15 seconds */
+    nua_dialog_usage_refresh_range(du, 5, 15);
+    return;
+  }
+
+  outbound_stop_keepalive(nr->nr_ob);
+
+  cr->cr_msg = msg_copy(du->du_msg);
+  msg = nua_creq_msg(nua, nh, cr, 1,
+		     SIP_METHOD_REGISTER,
+		     NUTAG_USE_DIALOG(1),
+		     TAG_END());
+  sip = sip_object(msg);
+  if (!msg || !sip)
+    goto error;
+
+  cr->cr_orq =
+    outbound_register_request(nr->nr_ob, 0,
+			      nr->nr_by_stack ? nr->nr_contact : NULL,
+			      nh->nh_nua->nua_nta,
+			      process_response_to_register, nh, NULL,
+			      msg,
+			      SIPTAG_END(), 
+			      NTATAG_COMP("sigcomp"),
+			      TAG_END());
+  if (!cr->cr_orq)
+    goto error;
+
+  cr->cr_usage = du;
+  cr->cr_event = nua_r_register;
+  return;
+
+ error:
+  msg_destroy(msg);
+  msg_destroy(cr->cr_msg);
+  UA_EVENT2(nua_r_register, NUA_INTERNAL_ERROR, TAG_END());
+  return;
+}
+
+/** Shutdown register usage. 
+ *
+ * Called when stack is shut down or handle is destroyed. Unregister.
+ */
+static
+int nua_register_usage_shutdown(nua_handle_t *nh, 
+				nua_dialog_state_t *ds,
+				nua_dialog_usage_t *du)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+  msg_t *msg;
+  sip_t *sip;
+
+  if (du->du_terminating)	/* Already terminating? */
+    return 100;
+
+  du->du_terminating = 1;
+
+  if (cr->cr_msg)    /* Busy */
+    return 100;
+
+  outbound_stop_keepalive(nr->nr_ob);
+
+  cr->cr_msg = msg_copy(du->du_msg);
+  msg = nua_creq_msg(nua, nh, cr, 1,
+		     SIP_METHOD_REGISTER,
+		     NUTAG_USE_DIALOG(1),
+		     TAG_END());
+  sip = sip_object(msg);
+  if (!msg || !sip)
+    goto error;
+
+  unregister_expires_contacts(msg, sip);
+
+  cr->cr_orq =
+    outbound_register_request(nr->nr_ob, 1,
+			      nr->nr_by_stack ? nr->nr_contact : NULL,
+			      nh->nh_nua->nua_nta,
+			      process_response_to_register, nh, NULL,
+			      msg,
+			      SIPTAG_END(), 
+			      NTATAG_SIGCOMP_CLOSE(1),
+			      TAG_END());
+  if (!cr->cr_orq)
+    goto error;
+
+  cr->cr_usage = du;
+  cr->cr_event = nua_r_destroy;
+  return 200;
+
+ error:
+  nua_dialog_usage_remove(nh, nh->nh_ds, du);
+  msg_destroy(msg);
+  msg_destroy(cr->cr_msg);
+  return 500;
+}
+
+
+static
+int process_response_to_register(nua_handle_t *nh,
+				 nta_outgoing_t *orq,
+				 sip_t const *sip)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_dialog_usage_t *du = cr->cr_usage;
+  nua_registration_t *nr = nua_dialog_usage_private(du);
+  int status, ready, reregister, terminating;
+  char const *phrase;
+  msg_t *_reqmsg = nta_outgoing_getrequest(orq);
+  sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg);
+
+  assert(sip);
+  assert(du && du->du_class == nua_register_usage);
+  status = sip->sip_status->st_status;
+  phrase = sip->sip_status->st_phrase;
+
+  if (status < 200 || !du)
+    return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+  terminating = du->du_terminating;
+  if (!terminating)
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+  reregister = outbound_register_response(nr->nr_ob, terminating, req, sip);
+  if (reregister < 0)
+    SET_STATUS1(NUA_INTERNAL_ERROR);
+  else if (reregister >= ob_reregister) {
+    /* Save msg otherwise nua_creq_check_restart() will zap it */
+    msg_t *msg = msg_ref_create(cr->cr_msg);
+
+    if (nua_creq_check_restart(nh, cr, orq, sip, restart_register)) {
+      msg_destroy(msg);
+      return 0;
+    }
+
+    assert(cr->cr_msg == NULL);
+    cr->cr_msg = msg;
+
+    if (reregister >= ob_reregister_now) {
+      /* We can try to reregister immediately */
+      nua_creq_restart_with(nh, cr, orq, 100, "Updated Contact",
+			    restart_register,
+			    TAG_END());
+    }
+    else {
+      /* Outbound will invoke refresh_register() later */
+      nua_creq_save_restart(nh, cr, orq, 100, "Updated Contact",
+			    restart_register);
+    }
+    return 0;
+  }
+
+  if (status >= 300)
+    if (nua_creq_check_restart(nh, cr, orq, sip, restart_register))
+      return 0;
+
+  ready = !terminating && status < 300;
+  du->du_ready = ready;
+
+  if (status < 300) {
+    if (!du->du_terminating) {
+      sip_time_t mindelta = 0;
+      sip_time_t now = sip_now(), delta, reqdelta;
+      sip_contact_t const *m, *sent;
+
+      /** Search for lowest delta of SIP contacts we tried to register */
+      mindelta = SIP_TIME_MAX;
+
+      reqdelta = req->sip_expires ? req->sip_expires->ex_delta : 0;
+
+      for (m = sip->sip_contact; m; m = m->m_next) {
+        if (m->m_url->url_type != url_sip && 
+            m->m_url->url_type != url_sips)
+          continue;
+        for (sent = req->sip_contact; sent; sent = sent->m_next)
+          if (url_cmp(m->m_url, sent->m_url) == 0) {
+            sip_time_t mdelta = reqdelta;
+
+            if (sent->m_expires)
+              mdelta = strtoul(sent->m_expires, NULL, 10);
+            if (mdelta == 0)
+              mdelta = 3600;
+
+            delta = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+       				 mdelta, now);
+            if (delta > 0 && delta < mindelta)
+              mindelta = delta;
+            if (url_cmp_all(m->m_url, sent->m_url) == 0)
+              break;
+          }
+      }
+
+      if (mindelta == SIP_TIME_MAX)
+        mindelta = 3600;
+      nua_dialog_usage_set_expires(du, mindelta);
+    }
+    else
+      nua_dialog_usage_set_expires(du, 0);
+  }
+
+#if HAVE_SIGCOMP
+  if (ready) {
+    struct sigcomp_compartment *cc;
+    cc = nta_outgoing_compartment(orq);
+    sigcomp_compartment_unref(nr->nr_compartment);
+    nr->nr_compartment = cc;
+  }
+#endif
+
+  /*  RFC 3608 Section 6.1 Procedures at the UA
+
+   The UA performs a registration as usual.  The REGISTER response may
+   contain a Service-Route header field.  If so, the UA MAY store the
+   value of the Service-Route header field in an association with the
+   address-of-record for which the REGISTER transaction had registered a
+   contact.  If the UA supports multiple addresses-of-record, it may be
+   able to store multiple service routes, one per address-of-record.  If
+   the UA refreshes the registration, the stored value of the Service-
+   Route is updated according to the Service-Route header field of the
+   latest 200 class response.  If there is no Service-Route header field
+   in the response, the UA clears any service route for that address-
+   of-record previously stored by the UA.  If the re-registration
+   request is refused or if an existing registration expires and the UA
+   chooses not to re-register, the UA SHOULD discard any stored service
+   route for that address-of-record.
+
+  */
+  if (ready) {
+    su_free(nh->nh_home, nr->nr_route);
+    nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route);
+  }
+  else {
+    su_free(nh->nh_home, nr->nr_route);
+    nr->nr_route = NULL;
+  }
+
+  if (ready) {
+    /* RFC 3327 */
+    /* Store last URI in Path header */
+    sip_path_t *path = sip->sip_path;
+
+    while (path && path->r_next)
+      path = path->r_next;
+
+    if (!nr->nr_path || !path ||
+        url_cmp_all(nr->nr_path->r_url, path->r_url)) {
+      su_free(nh->nh_home, nr->nr_path);
+      nr->nr_path = sip_path_dup(nh->nh_home, path);
+    }
+  }
+
+  if (ready)
+    if (sip->sip_to->a_url->url_type == url_sips)
+      nr->nr_secure = 1;
+
+  if (nr->nr_ob) {
+    if (ready) {
+      outbound_gruuize(nr->nr_ob, sip);
+      outbound_start_keepalive(nr->nr_ob, orq);
+    }
+    else
+      outbound_stop_keepalive(nr->nr_ob);
+  }
+
+  nua_registration_set_ready(nr, ready);
+
+  return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* nua_registration_t interface */
+
+#if HAVE_SOFIA_STUN
+#include <sofia-sip/stun.h>
+#endif
+
+static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta);
+static int nua_registration_add_contact_and_route(nua_registration_t *nr,
+						  msg_t *msg,
+						  sip_t *sip,
+						  int add_contact,
+						  int add_service_route);
+
+int
+nua_stack_init_transport(nua_t *nua, tagi_t const *tags)
+{
+  url_string_t const *contact1 = NULL, *contact2 = NULL;
+  char const *name1 = "sip", *name2 = "sip";
+  char const *certificate_dir = NULL;
+
+  tl_gets(tags,
+          NUTAG_URL_REF(contact1),
+          NUTAG_SIPS_URL_REF(contact2),
+          NUTAG_CERTIFICATE_DIR_REF(certificate_dir),
+          TAG_END());
+
+  if (!contact1 && contact2)
+    contact1 = contact2, contact2 = NULL;
+
+  if (contact1 &&
+      (url_is_string(contact1) 
+       ? strncasecmp(contact1->us_str, "sips:", 5) == 0
+       : contact1->us_url->url_type == url_sips))
+    name1 = "sips";
+
+  if (contact2 && 
+      (url_is_string(contact2) 
+       ? strncasecmp(contact2->us_str, "sips:", 5) == 0
+       : contact2->us_url->url_type == url_sips))
+    name2 = "sips";
+
+  if (!contact1 /* && !contact2 */) {
+    if (nta_agent_add_tport(nua->nua_nta, NULL,
+			    TPTAG_IDENT("sip"),
+			    TPTAG_CERTIFICATE(certificate_dir),
+			    TAG_NEXT(nua->nua_args)) < 0 &&
+        nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*"),
+			    TPTAG_IDENT("sip"),
+			    TPTAG_CERTIFICATE(certificate_dir),
+			    TAG_NEXT(nua->nua_args)) < 0)
+      return -1;
+#if HAVE_SOFIA_STUN
+    if (stun_is_requested(TAG_NEXT(nua->nua_args)) &&
+	nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:0.0.0.0:*"),
+			    TPTAG_IDENT("stun"),
+			    TPTAG_PUBLIC(tport_type_stun), /* use stun */
+			    TPTAG_CERTIFICATE(certificate_dir),
+			    TAG_NEXT(nua->nua_args)) < 0) {
+      SU_DEBUG_0(("nua: error initializing STUN transport\n"));
+    }
+#endif
+  }
+  else {
+    if (nta_agent_add_tport(nua->nua_nta, contact1,
+			    TPTAG_IDENT(name1),
+			    TPTAG_CERTIFICATE(certificate_dir),
+			    TAG_NEXT(nua->nua_args)) < 0)
+      return -1;
+
+    if (contact2 &&
+	nta_agent_add_tport(nua->nua_nta, contact2,
+			    TPTAG_IDENT(name2),
+			    TPTAG_CERTIFICATE(certificate_dir),
+			    TAG_NEXT(nua->nua_args)) < 0) 
+      return -1;
+  }
+
+
+  if (nua_stack_init_registrations(nua) < 0)
+    return -1;
+
+  return 0;
+}
+
+#if 0
+  /* Store network detector param value */
+  if (agent->sa_nw_updates == 0)
+    agent->sa_nw_updates = nw_updates;
+ 	      NTATAG_DETECT_NETWORK_UPDATES_REF(nw_updates),
+  unsigned nw_updates = 0;
+  unsigned nw_updates = 0;
+
+  su_network_changed_t *sa_nw_changed;
+
+#endif
+
+static
+void nua_network_changed_cb(nua_t *nua, su_root_t *root)
+{
+
+  uint32_t nw_updates = NUA_NW_DETECT_TRY_FULL;
+
+  switch (nw_updates) {
+  case NUA_NW_DETECT_ONLY_INFO:
+    nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+		    SIP_200_OK, TAG_END());
+
+    break;
+    
+  case NUA_NW_DETECT_TRY_FULL:
+
+    /* 1) Shutdown all tports */
+    nta_agent_close_tports(nua->nua_nta);
+
+    /* 2) Create new tports */
+    if (nua_stack_init_transport(nua, nua->nua_args) < 0)
+      /* We are hosed */
+      nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+		      900, "Internal Error", TAG_END());
+    else
+      nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+		      SIP_200_OK, TAG_END());
+
+    break;
+    
+  default:
+    break;
+  }
+
+  return;
+}
+
+int nua_stack_launch_network_change_detector(nua_t *nua)
+{
+  su_network_changed_t *snc = NULL;
+
+  snc = su_root_add_network_changed(nua->nua_home,
+				    nua->nua_api_root,
+				    nua_network_changed_cb,
+				    nua);
+  
+  if (!snc)
+    return -1;
+
+  nua->nua_nw_changed = snc;
+
+  return 0;
+}
+
+
+int
+nua_stack_init_registrations(nua_t *nua)
+{
+  /* Create initial identities: peer-to-peer, public, sips */
+  nua_registration_t **nr_list = &nua->nua_registrations, **nr_next;
+  nua_handle_t **nh_list;
+  nua_handle_t *dnh = nua->nua_dhandle;
+  sip_via_t const *v;
+
+  /* Remove existing, local address based registrations and count the
+     rest */
+  while (nr_list && *nr_list) {
+    nr_next = &(*nr_list)->nr_next;
+    if ((*nr_list)->nr_default == 1) {
+      nua_registration_remove(*nr_list);
+      /* memset(*nr_list, 170, sizeof(**nr_list)); */
+      /* XXX - free, too */
+    }
+    nr_list = nr_next;
+  }
+  nr_list = &nua->nua_registrations;
+
+  v = nta_agent_public_via(nua->nua_nta);
+  if (v) {
+    nua_registration_from_via(nr_list, dnh, v, 1);
+  }
+
+  v = nta_agent_via(nua->nua_nta);
+  if (v) {
+    nua_registration_from_via(nr_list, dnh, v, 0);
+  }
+  else {
+    sip_via_t v[2];
+
+    sip_via_init(v)->v_next = v + 1;
+    v[0].v_protocol = sip_transport_udp;
+    v[0].v_host = "addr.is.invalid.";
+    sip_via_init(v + 1);
+    v[1].v_protocol = sip_transport_tcp;
+    v[1].v_host = "addr.is.invalid.";
+
+    nua_registration_from_via(nr_list, dnh, v, 0);
+  }
+
+  /* Go through all the registrations and set to refresh almost
+     immediately */
+  nh_list = &nua->nua_handles;
+  for (; *nh_list; nh_list = &(*nh_list)->nh_next) {
+    nua_dialog_state_t *ds;
+    nua_dialog_usage_t *du;
+
+    ds = (*nh_list)->nh_ds;
+    du = ds->ds_usage;
+
+    if (ds->ds_has_register == 1 && du->du_class->usage_refresh) {
+      nua_dialog_usage_refresh(*nh_list, ds, du, 1);
+    }
+  }
+
+  nta_agent_bind_tport_update(nua->nua_nta, nua, nua_stack_tport_update);
+
+  return 0;
+}
+
+int nua_registration_from_via(nua_registration_t **list,
+			      nua_handle_t *nh,
+			      sip_via_t const *via,
+			      int public)
+{
+  su_home_t *home = nh->nh_home;
+  sip_via_t *v, *pair, /* v2[2], */ *vias, **vv, **prev;
+  nua_registration_t *nr = NULL, **next;
+  su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
+  int nr_items = 0;
+
+  vias = sip_via_copy(su_home_auto(autohome, sizeof autohome), via);
+
+  for (; *list; list = &(*list)->nr_next)
+    ++nr_items;
+
+  next = list;
+
+  for (vv = &vias; (v = *vv);) {
+    char const *protocol;
+    sip_contact_t *contact;
+    sip_via_t v2[2];
+
+    *vv = v->v_next, v->v_next = NULL, pair = NULL;
+
+    if (v->v_protocol == sip_transport_tcp)
+      protocol = sip_transport_udp;
+    else if (v->v_protocol == sip_transport_udp)
+      protocol = sip_transport_tcp;
+    else
+      protocol = NULL;
+
+    if (protocol) {
+      /* Try to pair vias if we have both udp and tcp */
+      for (prev = vv; *prev; prev = &(*prev)->v_next) {
+        if (strcasecmp(protocol, (*prev)->v_protocol))
+          continue;
+        if (strcasecmp(v->v_host, (*prev)->v_host))
+          continue;
+        if (str0cmp(v->v_port, (*prev)->v_port))
+          continue;
+        break;
+      }
+
+      if (*prev) {
+        pair = *prev; *prev = pair->v_next; pair->v_next = NULL;
+      }
+    }
+
+    /* if more than one candidate, ignore local entries */
+    if (v && (*vv || nr_items > 0) && 
+	host_is_local(v->v_host)) {
+      SU_DEBUG_9(("nua_register: ignoring contact candidate %s:%s.\n", 
+		  v->v_host, v->v_port ? v->v_port : ""));
+      continue;
+    }
+     
+    nr = su_zalloc(home, sizeof *nr);
+    if (!nr)
+      break;
+
+    v2[0] = *v;
+
+    if (pair)
+      /* Don't use protocol if we have both udp and tcp */
+      protocol = NULL, v2[0].v_next = &v2[1], v2[1] = *pair;
+    else
+      protocol = via->v_protocol, v2[0].v_next = NULL;
+
+    v2[1].v_next = NULL;
+
+#if 1
+    contact = nua_handle_contact_by_via(nh, home, NULL, v2, protocol, NULL);
+#else
+    contact = sip_contact_create_from_via_with_transport(home, v2, NULL, protocol);
+#endif
+    v = sip_via_dup(home, v2);
+
+    if (!contact || !v) {
+      su_free(home, nr);
+      break;
+    }
+
+    nr->nr_ready = 1, nr->nr_default = 1, nr->nr_public = public;
+    nr->nr_secure = contact->m_url->url_type == url_sips;
+    nr->nr_contact = contact;
+    nr->nr_via = v;
+    nr->nr_ip4 = host_is_ip4_address(contact->m_url->url_host);
+    nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(contact->m_url->url_host);
+
+    SU_DEBUG_9(("nua_register: Adding contact URL '%s' to list.\n", contact->m_url->url_host));
+
+    ++nr_items;
+    nr->nr_next = *next, nr->nr_prev = next; *next = nr, next = &nr->nr_next;
+    nr->nr_list = list;
+  }
+
+  su_home_deinit(autohome);
+
+  return 0;
+}
+
+static
+void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta)
+{
+#if 0
+  nua_registration_t *default_oc;
+  nua_registration_t const *defaults = nua->nua_registrations;
+  sip_via_t *via = nta_agent_via(nta);
+
+  default_oc = outbound_by_aor(defaults, NULL, 1);
+
+  if (default_oc) {
+    assert(default_oc->nr_via);
+
+    outbound_contacts_from_via(default_oc,
+				       via,
+				       via->v_next);
+
+    /* refresh_register(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now); */
+  }
+#endif
+  return;
+}
+
+nua_registration_t *nua_registration_by_aor(nua_registration_t const *list,
+					    sip_from_t const *aor,
+					    url_t const *remote_uri,
+					    int only_default)
+{
+  sip_from_t *alt_aor = NULL, _alt_aor[1];
+  int sips_aor = aor && aor->a_url->url_type == url_sips;
+  int sips_uri = remote_uri && remote_uri->url_type == url_sips;
+
+  nua_registration_t const *nr, *public = NULL, *any = NULL;
+  nua_registration_t const *namewise = NULL, *sipswise = NULL;
+
+  int ip4 = remote_uri && host_is_ip4_address(remote_uri->url_host);
+  int ip6 = remote_uri && host_is_ip6_reference(remote_uri->url_host);
+
+  if (only_default || aor == NULL) {
+    /* Ignore AoR, select only by remote_uri */
+    for (nr = list; nr; nr = nr->nr_next) {
+      if (!nr->nr_ready)
+	continue;
+      if (only_default && !nr->nr_default)
+	continue;
+      if (nr->nr_ip4 && ip6)
+	continue;
+      if (nr->nr_ip6 && ip4)
+	continue;
+      if (sips_uri ? nr->nr_secure : !nr->nr_secure) 
+	return (nua_registration_t *)nr;
+      if (!public && nr->nr_public)
+	public = nr;
+      if (!any)
+	any = nr;
+    }
+    if (public)
+      return (nua_registration_t *)public;
+    if (any)
+      return (nua_registration_t *)any;
+    return NULL;
+  }
+
+  if (!sips_aor && aor)
+    alt_aor = memcpy(_alt_aor, aor, sizeof _alt_aor);
+
+  for (nr = list; nr; nr = nr->nr_next) {
+    if (!nr->nr_ready || !nr->nr_contact)
+      continue;
+    if (nr->nr_aor) {
+      if (aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0)
+	return (nua_registration_t *)nr;
+      if (!namewise && alt_aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0)
+	namewise = nr;
+    }
+    else {
+      if (!sipswise && ((sips_aor || sips_uri) ? 
+			nr->nr_secure : !nr->nr_secure))
+	sipswise = nr;
+    }
+    if (!public && nr->nr_public)
+      public = nr;
+    if (!any)
+      any = nr;
+  }
+
+  if (namewise)
+    return (nua_registration_t *)namewise;
+  if (sipswise)
+    return (nua_registration_t *)sipswise;
+
+  /* XXX - 
+     should we do some policing whether sips_aor or sips_uri can be used
+     with sip contact?
+  */
+  if (public)
+    return (nua_registration_t *)public;
+  if (any)
+    return (nua_registration_t *)any;
+
+  return NULL;
+}
+
+
+nua_registration_t *
+nua_registration_for_request(nua_registration_t const *list, sip_t const *sip)
+{
+  sip_from_t const *aor;
+  url_t *uri;
+
+  aor = sip->sip_from;
+  uri = sip->sip_request->rq_url;
+
+  return nua_registration_by_aor(list, aor, uri, 0);
+}
+
+nua_registration_t *
+nua_registration_for_response(nua_registration_t const *list, 
+			      sip_t const *sip,
+			      sip_record_route_t const *record_route,
+			      sip_contact_t const *remote_contact)
+{
+  nua_registration_t *nr;
+  sip_to_t const *aor = NULL;
+  url_t const *uri = NULL;
+
+  if (sip)
+    aor = sip->sip_to;
+  
+  if (record_route)
+    uri = record_route->r_url;
+  else if (sip && sip->sip_record_route)
+    uri = sip->sip_record_route->r_url;
+  else if (remote_contact)
+    uri = remote_contact->m_url;
+  else if (sip && sip->sip_from)
+    uri = sip->sip_from->a_url;
+
+  nr = nua_registration_by_aor(list, aor, uri, 0);
+
+  return nr;
+}
+
+
+/** Return Contact usable in dialogs */
+sip_contact_t const *nua_registration_contact(nua_registration_t const *nr)
+{
+  if (nr->nr_by_stack && nr->nr_ob) {
+    sip_contact_t const *m = outbound_dialog_contact(nr->nr_ob);
+    if (m)
+      return m;
+  }
+
+  return nr->nr_contact;
+}
+
+/** Return initial route. */
+sip_route_t const *nua_registration_route(nua_registration_t const *nr)
+{
+  return nr ? nr->nr_route : NULL;
+}
+
+sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr)
+{
+  nr = nua_registration_by_aor(nr, NULL, NULL, 1);
+  return nr ? nr->nr_contact : NULL;
+}
+
+/** Add a Contact (and Route) header to request */
+int nua_registration_add_contact_to_request(nua_handle_t *nh,
+					    msg_t *msg,
+					    sip_t *sip,
+					    int add_contact,
+					    int add_service_route)
+{
+  nua_registration_t *nr = NULL;
+
+  if (!add_contact && !add_service_route)
+    return 0;
+
+  if (nh == NULL || msg == NULL)
+    return -1;
+
+  if (sip == NULL)
+    sip = sip_object(msg);
+
+  if (nr == NULL)
+    nr = nua_registration_for_request(nh->nh_nua->nua_registrations, sip);
+
+  return nua_registration_add_contact_and_route(nr, msg, sip, 
+						add_contact, 
+						add_service_route);
+}
+
+/** Add a Contact header to response.
+ *
+ * @param nh
+ * @param msg response message
+ * @param sip response headers
+ * @param record_route record-route from request
+ * @param remote_contact Contact from request
+ */
+int nua_registration_add_contact_to_response(nua_handle_t *nh,
+					     msg_t *msg,
+					     sip_t *sip,
+					     sip_record_route_t const *record_route,
+					     sip_contact_t const *remote_contact)
+{
+  nua_registration_t *nr = NULL;
+
+  if (sip == NULL)
+    sip = sip_object(msg);
+
+  if (nh == NULL || msg == NULL || sip == NULL)
+    return -1;
+
+  if (nr == NULL)
+    nr = nua_registration_for_response(nh->nh_nua->nua_registrations, sip,
+				       record_route, remote_contact);
+
+  return nua_registration_add_contact_and_route(nr, msg, sip, 1, 0);
+}
+
+/** Add a Contact (and Route) header to request */
+static 
+int nua_registration_add_contact_and_route(nua_registration_t *nr,
+					   msg_t *msg,
+					   sip_t *sip,
+					   int add_contact,
+					   int add_service_route)
+{
+  if (nr == NULL)
+    return -1;
+
+  if (add_contact) {
+    sip_contact_t const *m = nua_registration_contact(nr);
+    if (!m || msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)m) < 0)
+      return -1;
+  }
+
+  if (add_service_route && !sip->sip_status) {
+    sip_route_t const *sr = nua_registration_route(nr);
+    if (msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)sr) < 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+/** Add a registration to list of contacts */
+int nua_registration_add(nua_registration_t **list,
+			 nua_registration_t *nr)
+{
+  assert(list && nr);
+
+  if (nr->nr_list == NULL) {
+    nua_registration_t *next = *list;
+    if (next)
+      next->nr_prev = &nr->nr_next;
+    nr->nr_next = next, nr->nr_prev = list, nr->nr_list = list;
+    *list = nr;
+  }
+
+  return 0;
+}
+
+/** Remove from list of registrations */
+void nua_registration_remove(nua_registration_t *nr)
+{
+  if ((*nr->nr_prev = nr->nr_next))
+    nr->nr_next->nr_prev = nr->nr_prev;
+  nr->nr_next = NULL, nr->nr_prev = NULL, nr->nr_list = NULL;
+}
+
+/** Set address-of-record. */
+int nua_registration_set_aor(su_home_t *home,
+			     nua_registration_t *nr,
+			     sip_from_t const *aor)
+{
+  sip_from_t *new_aor, *old_aor;
+
+  if (!home || !nr || !aor)
+    return -1;
+
+  new_aor = sip_from_dup(home, aor);
+  if (!new_aor)
+    return -1;
+
+  old_aor = nr->nr_aor;
+  nr->nr_aor = new_aor;
+  msg_header_free(home, (void *)old_aor);
+
+  return 0;
+}
+
+/** Set contact. */
+int nua_registration_set_contact(nua_handle_t *nh,
+				 nua_registration_t *nr,
+				 sip_contact_t const *application_contact,
+				 int terminating)
+{
+  sip_contact_t *m = NULL, *previous;
+  url_t *uri;
+
+  if (!nh || !nr)
+    return -1;
+
+  uri = nr->nr_aor ? nr->nr_aor->a_url : NULL;
+    
+  previous = nr->nr_contact;
+
+  if (application_contact) {
+    m = sip_contact_dup(nh->nh_home, application_contact);
+  }
+  else if (terminating && nr->nr_contact) {
+    return 0;
+  }
+  else {
+    nua_registration_t *nr0;
+    
+    nr0 = nua_registration_by_aor(*nr->nr_list, NULL, uri, 1);
+
+    if (nr0 && nr0->nr_via) {
+      char const *tport = nr0->nr_via->v_next ? NULL : nr0->nr_via->v_protocol;
+      m = nua_handle_contact_by_via(nh, nh->nh_home,
+				    NULL, nr0->nr_via, tport, NULL);
+    }
+  }
+
+  if (!m)
+    return -1;
+
+  nr->nr_contact = m;
+  nr->nr_ip4 = host_is_ip4_address(m->m_url->url_host);
+  nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(m->m_url->url_host);
+  nr->nr_by_stack = !application_contact;
+
+  msg_header_free(nh->nh_home, (void *)previous);
+
+  return 0;
+}
+
+/** Mark registration as ready */
+void nua_registration_set_ready(nua_registration_t *nr, int ready)
+{
+  assert(!ready || nr->nr_contact);
+  nr->nr_ready = ready;
+}
+
+/** @internal Hook for processing incoming request by registration.
+ *
+ * This is used for keepalive/validate OPTIONS.
+ */
+int nua_registration_process_request(nua_registration_t *list,
+				     nta_incoming_t *irq,
+				     sip_t const *sip)
+{
+  sip_call_id_t *i;
+  nua_registration_t *nr;
+
+  if (!outbound_targeted_request(sip))
+    return 0;
+
+  /* Process by outbound... */
+  i = sip->sip_call_id;
+
+  for (nr = list; nr; nr = nr->nr_next) {
+    outbound_t *ob = nr->nr_ob;
+    if (ob)
+      if (outbound_process_request(ob, irq, sip))
+	return 501;		/* Just in case  */
+  }
+
+  return 481;			/* Call/Transaction does not exist */
+}
+
+/**@internal
+ * Fix contacts for un-REGISTER.
+ *
+ * Remove (possible non-zero) "expires" parameters from contacts and extra
+ * contacts, add Expire: 0.
+ */
+static
+void unregister_expires_contacts(msg_t *msg, sip_t *sip)
+{
+  sip_contact_t *m;
+  int unregister_all;
+
+  if (msg == NULL || sip == NULL)
+    return;
+
+  /* Remove payload */
+  while (sip->sip_payload)
+    sip_header_remove(msg, sip, (sip_header_t *)sip->sip_payload);
+  while (sip->sip_content_type)
+    sip_header_remove(msg, sip, (sip_header_t *)sip->sip_content_type);
+
+  for (m = sip->sip_contact; m; m = m->m_next) {
+    if (m->m_url->url_type == url_any)
+      break;
+    msg_header_remove_param(m->m_common, "expires");
+#if 0
+    msg_header_add_param(msg_home(msg), m->m_common, "expires=0");
+#endif
+  }
+
+  unregister_all = m && (m != sip->sip_contact || m->m_next);
+
+  sip_add_tl(msg, sip,
+             /* Remove existing contacts */
+             TAG_IF(unregister_all, SIPTAG_CONTACT(NONE)),
+             /* Add '*' contact: 0 */
+             TAG_IF(unregister_all, SIPTAG_CONTACT_STR("*")),
+             SIPTAG_EXPIRES_STR("0"),
+             TAG_END());
+}
+
+
+/** Outbound requests us to refresh registration */
+static int nua_stack_outbound_refresh(nua_handle_t *nh,
+				      outbound_t *ob)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_dialog_usage_t *du;
+
+  du = nua_dialog_usage_get(ds, nua_register_usage, NULL);
+
+  if (du)
+    nua_dialog_usage_refresh(nh, ds, du, 1);
+
+  return 0;
+}
+
+/** @NUA_EVENT nua_i_outbound
+ *
+ * Status from outbound engine.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ *               describing the outbound state
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the outbound engine
+ * @param hmagic application context associated with the handle
+ * @param sip    NULL or response message to an keepalive message or 
+ *               registration probe
+ *               (error code and message are in status an phrase parameters)
+ * @param tags   empty
+ *
+ * @sa NUTAG_OUTBOUND(), NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), 
+ * nua_register(), #nua_r_register, nua_unregister(), #nua_r_unregister
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Callback from outbound_t */
+static int nua_stack_outbound_status(nua_handle_t *nh, outbound_t *ob,
+				     int status, char const *phrase,
+				     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  nua_stack_event(nh->nh_nua, nh, NULL,
+		  nua_i_outbound, status, phrase,
+		  ta_tags(ta));
+
+  ta_end(ta);
+
+  return 0;
+}
+
+/** @internal Callback from outbound_t */
+static int nua_stack_outbound_failed(nua_handle_t *nh, outbound_t *ob,
+				     int status, char const *phrase,
+				     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  ta_start(ta, tag, value);
+
+  nua_stack_event(nh->nh_nua, nh, NULL,
+		  nua_i_outbound, status, phrase,
+		  ta_tags(ta));
+
+  ta_end(ta);
+
+  return 0;
+}
+
+/** @internal Callback for obtaining credentials for keepalive */
+static int nua_stack_outbound_credentials(nua_handle_t *nh, 
+					  auth_client_t **auc)
+{
+  return auc_copy_credentials(auc, nh->nh_auth);
+}
+
+#include <ctype.h>
+#include <sofia-sip/bnf.h>
+
+/** @internal Generate a @Contact header. */
+sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
+					 su_home_t *home,
+					 char const *extra_username,
+					 sip_via_t const *v,
+					 char const *transport,
+					 char const *m_param,
+					 ...)
+{
+  su_strlst_t *l;
+  char const *s;
+  char const *scheme = "sip:", *host, *port, *maddr, *comp;
+  int one = 1;
+  char _transport[16];
+  va_list va;
+  sip_contact_t *m;
+
+  if (!v) return NULL;
+
+  host = v->v_host;
+  if (v->v_received)
+    host = v->v_received;
+  port = sip_via_port(v, &one);
+  maddr = v->v_maddr;
+  comp = v->v_comp;
+
+  if (host == NULL)
+    return NULL;
+
+  if (sip_transport_has_tls(v->v_protocol) ||
+      sip_transport_has_tls(transport)) {
+    scheme = "sips:";
+    if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0)
+      port = NULL;
+    if (port || host_is_ip_address(host))
+      transport = NULL;
+  }
+  else if (port && host_is_ip_address(host) &&
+	   strcmp(port, SIP_DEFAULT_SERV) == 0) {
+    port = NULL;
+  }
+
+  if (transport) {
+    if (strncasecmp(transport, "SIP/2.0/", 8) == 0)
+      transport += 8;
+
+    /* Make transport parameter lowercase */
+    if (strlen(transport) < (sizeof _transport)) {
+      char *s = strcpy(_transport, transport);
+
+      for (s = _transport; *s && *s != ';'; s++)
+	if (isupper(*s))
+	  *s = tolower(*s);
+
+      transport = _transport;
+    }
+  }
+
+  l = su_strlst_create(NULL);
+
+  s = NH_PGET(nh, m_display);
+  if (s) {
+    int quote = s[span_token_lws(s)] != '\0';
+
+    su_strlst_append(l, quote ? "\"" : "");
+    su_strlst_append(l, s);
+    su_strlst_append(l, quote ? "\" " : " ");
+  }
+  su_strlst_append(l, "<");
+  su_strlst_append(l, scheme);
+  s = NH_PGET(nh, m_username);
+  if (s) su_strlst_append(l, s);
+  if (extra_username) su_strlst_append(l, s);
+  if (s || extra_username)
+    su_strlst_append(l, "@");
+  su_strlst_append(l, host);
+  if (port)
+    su_strlst_append(l, ":"), su_strlst_append(l, port);
+  if (transport)
+    su_strlst_append(l, ";transport="), su_strlst_append(l, transport);
+  if (maddr)
+    su_strlst_append(l, ";maddr="), su_strlst_append(l, maddr);
+  if (comp)
+    su_strlst_append(l, ";comp="), su_strlst_append(l, comp);
+  s = NH_PGET(nh, m_params);
+  if (s) 
+    su_strlst_append(l, s[0] == ';' ? "" : ";"), su_strlst_append(l, s);
+  su_strlst_append(l, ">");
+
+  va_start(va, m_param);
+
+  for (s = m_param; s; s = va_arg(va, char *)) {
+    if (strlen(s) == 0)
+      continue;
+    su_strlst_append(l, s[0] == ';' ? "" : ";");
+    su_strlst_append(l, s);
+  }
+  
+  va_end(va);
+
+  m = sip_contact_make(home, su_strlst_join(l, su_strlst_home(l), ""));
+  
+  su_strlst_destroy(l);
+  
+  return m;
+}
+
+/** @internal Return a string describing our features. */
+static char *nua_handle_features(nua_handle_t *nh)
+{
+  char *retval = NULL;
+  su_strlst_t *l = su_strlst_create(NULL);
+  su_home_t *home = su_strlst_home(l);
+
+  if (!l)
+    return NULL;
+
+  if (NH_PGET(nh, m_features)) {
+    char const *m_features = NH_PGET(nh, m_features);
+
+    if (m_features[0] != ';')
+      su_strlst_append(l, ";");
+
+    su_strlst_append(l, m_features);
+  }
+
+  if (NH_PGET(nh, callee_caps)) {
+    sip_allow_t const *allow = NH_PGET(nh, allow);
+
+    if (allow) {
+      /* Skip ";" if this is first one */
+      su_strlst_append(l, ";methods=\"" + (su_strlst_len(l) == 0));
+      if (allow->k_items) {
+        size_t i;
+        for (i = 0; allow->k_items[i]; i++) {
+          su_strlst_append(l, allow->k_items[i]);
+          if (allow->k_items[i + 1])
+            su_strlst_append(l, ",");
+        }
+      }
+      su_strlst_append(l, "\"");
+    }
+
+    if (nh->nh_soa) {
+      char **media = soa_media_features(nh->nh_soa, 0, home);
+
+      while (*media) {
+        if (su_strlst_len(l))
+          su_strlst_append(l, ";");
+        su_strlst_append(l, *media++);
+      }
+    }
+  }
+
+  if (su_strlst_len(l))
+    retval = su_strlst_join(l, nh->nh_home, "");
+
+  su_strlst_destroy(l);
+
+  return retval;
+}
+
+static int nua_stack_outbound_features(nua_handle_t *nh, outbound_t *ob)
+{
+  char *features;
+  int retval;
+
+  if (!nh)
+    return -1;
+  if (!ob)
+    return 0;
+
+  features = nua_handle_features(nh);
+  retval = outbound_set_features(ob, features);
+  su_free(nh->nh_home, features);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_registrar.c
+ * @brief REGISTER UAS
+ *
+ * @author Michael Jerris
+ *
+ * @date Created: Tue Oct  3 10:14:54 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_handle_s
+#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* REGISTER */
+
+/** @NUA_EVENT nua_i_register
+ *
+ * Incoming REGISTER request.
+ *
+ * In order to receive #nua_i_register events, the application must enable
+ * the REGISTER method with NUTAG_ALLOW() tag.
+ *
+ * The nua_response() call responding to a REGISTER request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * a successful response to REGISTER @b MUST include the @Contact header
+ * bound to the the AoR URI (in @To header).
+ *
+ * The REGISTER request does not create a dialog. Currently the processing
+ * of incoming REGISTER creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the REGISTER
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the request
+ * @param hmagic application context associated with the handle
+ *               (usually NULL)
+ * @param sip    incoming REGISTER request
+ * @param tags   empty
+ *
+ * @sa nua_respond(), @RFC3261 section 10.3,
+ * @Expires, @Contact, @CallID, @CSeq,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ * nua_register(), #nua_i_register, nua_unregister(), #nua_i_unregister
+ *
+ * @since New in @VERSION_1_12_4
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_register(nua_t *nua,
+			       nua_handle_t *nh,
+			       nta_incoming_t *irq,
+			       sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+
+  sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
+			  nua_default_respond, 0);
+
+  return nua_stack_server_event(nua, sr, nua_i_register, TAG_END());
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3986 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_session.c
+ * @brief SIP session handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 16:17:27 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_server_request
+#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+#include <sofia-sip/soa.h>
+
+#ifndef SDP_H
+typedef struct sdp_session_s sdp_session_t;
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/** @enum nua_callstate
+
+The states for SIP session established with INVITE.
+
+Initially the call states follow the state of the INVITE transaction. If the
+initial INVITE transaction fails, the call is terminated. The status codes
+401 and 407 are an exception: if the client (on the left side in the diagram
+below) receives them, it enters in #nua_callstate_authenticating state.
+
+If a re-INVITE transaction fails, the result depends on the status code in
+failure. The call can return to the ready state, be terminated immediately,
+or be terminated gracefully. The proper action to take is determined with
+sip_response_terminates_dialog().			   
+
+ at sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite
+							   
+ at par Session State Diagram				   
+							   
+ at code							   
+  			 +----------+			   
+  			 |          |---------------------+
+  			 |   Init   |                     |
+  			 |          |----------+          |
+  			 +----------+          |          |
+  			  |        |           |          |
+                 --/INVITE|        |INVITE/100 |          |
+                          V        V           |          |
+     		+----------+      +----------+ |          |
+       +--------|          |      |          | |          |
+       |  18X +-| Calling  |      | Received | |INVITE/   |
+       |   /- | |          |      |          | |  /18X    |
+       |      V +----------+      +----------+ V          |
+       |   +----------+ |           |     |  +----------+ |
+       |---|          | |2XX     -/ |  -/ |  |          | |
+       |   | Proceed- | | /-     2XX|  18X|  |  Early   | |INVITE/
+       |   |   ing    | |           |     +->|          | |  /200
+       |   +----------+ V           V        +----------+ |
+       |     |  +----------+      +----------+   | -/     |
+       |  2XX|  |          |      |          |<--+ 2XX    |
+       |   /-|  | Complet- |      | Complete |<-----------+
+       |     +->|   ing    |      |          |------+
+       |        +----------+      +----------+      |
+       |                  |        |      |         |
+       |401,407/     -/ACK|        |ACK/- |timeout/ |
+       | /ACK             V        V      | /BYE    |
+       |                 +----------+     |         |
+       |                 |          |     |         |
+       |              +--|  Ready   |     |         |
+       |              |  |          |     |         |
+       |              |  +----------+     |         |
+       |              |       |           |         |
+       |         BYE/ |       |-/BYE      |         |BYE/
+       V         /200 |       V           |         |/200
+  +----------+        |  +----------+     |         |
+  |          |        |  |          |     |         |
+  |Authentic-|        |  | Terminat-|<----+         |
+  |  ating   |        |  |   ing    |               |
+  +----------+        |  +----------+               |
+                      |       |                     |
+                      |       |[23456]XX/-          |
+                      |       V                     |
+                      |  +----------+               |
+                      |  |          |               |
+                      +->|Terminated|<--------------+
+                         |          |
+                         +----------+
+                              | 
+                              V
+                         +----------+
+        		 |          |
+                         |   Init   |
+			 |          |
+          		 +----------+
+ at endcode			      
+*/			      
+			      
+/* ---------------------------------------------------------------------- */
+/* Session event usage */
+
+/** Session-related state */
+typedef struct nua_session_usage
+{
+  /* enum nua_callstate */
+  unsigned        ss_state:4;		/**< Session status (enum nua_callstate) */
+  
+  unsigned        ss_100rel:1;	        /**< Use 100rel, send 183 */
+  unsigned        ss_alerting:1;	/**< 180 is sent/received */
+  
+  unsigned        ss_update_needed:2;	/**< Send an UPDATE (do O/A if > 1) */
+
+  unsigned        ss_precondition:1;	/**< Precondition required */
+
+  unsigned        ss_timer_set:1;       /**< We have active session timer. */
+  unsigned        : 0;
+  
+  unsigned        ss_session_timer;	/**< Value of Session-Expires (delta) */
+  unsigned        ss_min_se;		/**< Minimum session expires */
+  enum nua_session_refresher ss_refresher; /**< none, local or remote */
+
+  char const     *ss_ack_needed;	/**< If non-null, need to send an ACK
+					 * (do O/A, if "offer" or "answer")
+					 */
+
+  nua_client_request_t ss_crequest[1];  /* Outgoing invite */
+} nua_session_usage_t;
+
+static char const *nua_session_usage_name(nua_dialog_usage_t const *du);
+static int nua_session_usage_add(nua_handle_t *nh,
+				 nua_dialog_state_t *ds,
+				 nua_dialog_usage_t *du);
+static void nua_session_usage_remove(nua_handle_t *nh,
+				     nua_dialog_state_t *ds,
+				     nua_dialog_usage_t *du);
+static void nua_session_usage_refresh(nua_owner_t *,
+				      nua_dialog_state_t *,
+				      nua_dialog_usage_t *,
+				      sip_time_t now);
+static int nua_session_usage_shutdown(nua_owner_t *,
+				      nua_dialog_state_t *,
+				      nua_dialog_usage_t *);
+
+static nua_usage_class const nua_session_usage[1] = {
+  {
+    sizeof (nua_session_usage_t),
+    sizeof nua_session_usage,
+    nua_session_usage_add,
+    nua_session_usage_remove,
+    nua_session_usage_name,
+    NULL,
+    nua_session_usage_refresh,
+    nua_session_usage_shutdown
+  }};
+
+static char const *nua_session_usage_name(nua_dialog_usage_t const *du)
+{
+  return "session";
+}
+
+static
+int nua_session_usage_add(nua_handle_t *nh,
+			   nua_dialog_state_t *ds,
+			   nua_dialog_usage_t *du)
+{
+  nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+  if (ds->ds_has_session)
+    return -1;
+  ds->ds_has_session = 1;
+
+  nh->nh_ds->ds_cr->cr_next = ss->ss_crequest;
+ 
+  return 0;
+}
+
+static
+void nua_session_usage_remove(nua_handle_t *nh,
+			       nua_dialog_state_t *ds,
+			       nua_dialog_usage_t *du)
+{
+  nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+  ds->ds_has_session = 0;
+
+  if (ss->ss_crequest)
+    nua_creq_deinit(ss->ss_crequest, NULL);
+
+  ds->ds_cr->cr_next = NULL;
+}
+
+static
+nua_session_usage_t *nua_session_usage_get(nua_dialog_state_t const *ds)
+{
+  nua_dialog_usage_t *du;
+
+  if (ds == ((nua_handle_t *)NULL)->nh_ds)
+    return NULL;
+
+  du = nua_dialog_usage_get(ds, nua_session_usage, NULL);
+
+  return (nua_session_usage_t *)nua_dialog_usage_private(du);
+}
+
+/* ======================================================================== */
+/* INVITE and call (session) processing */
+
+static int nua_stack_invite2(nua_t *, nua_handle_t *, nua_event_t e,
+			     int restarted, tagi_t const *tags);
+static int process_response_to_invite(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip);
+static void
+  session_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now);
+
+static void restart_invite(nua_handle_t *nh, tagi_t *tags);
+
+static int process_100rel(nua_handle_t *nh,
+			  nua_session_usage_t *ss,
+			  nta_outgoing_t *orq,
+			  sip_t const *sip);
+
+int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		    tagi_t const *tags);
+
+static int process_response_to_prack(nua_handle_t *nh,
+				     nta_outgoing_t *orq,
+				     sip_t const *sip);
+
+static void nua_session_usage_destroy(nua_handle_t *, nua_session_usage_t *);
+
+static void session_timer_preferences(nua_session_usage_t *ss,
+				      unsigned expires,
+				      unsigned min_se,
+				      enum nua_session_refresher refresher);
+static int session_timer_is_supported(nua_handle_t const *nh);
+static int prefer_session_timer(nua_handle_t const *nh);
+
+static int use_session_timer(nua_session_usage_t *ss, int uas, int always,
+			     msg_t *msg, sip_t *);
+static int init_session_timer(nua_session_usage_t *ss, sip_t const *, int refresher);
+static void set_session_timer(nua_session_usage_t *ss);
+
+static int
+check_session_timer_restart(nua_handle_t *nh,
+			    nua_session_usage_t *ss,
+			    nua_client_request_t *cr,
+			    nta_outgoing_t *orq,
+			    sip_t const *sip,
+			    nua_creq_restart_f *restart_function);
+
+static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);
+static void nh_referral_respond(nua_handle_t *,
+				int status, char const *phrase);
+
+static void signal_call_state_change(nua_handle_t *nh,
+				     nua_session_usage_t *ss,
+				     int status, char const *phrase,
+				     enum nua_callstate next_state,
+				     char const *oa_recv,
+				     char const *oa_sent);
+
+static
+int session_get_description(sip_t const *sip,
+			    char const **return_sdp,
+			    size_t *return_len);
+
+static
+int session_include_description(soa_session_t *soa,
+				int session,
+				msg_t *msg,
+				sip_t *sip);
+
+static
+int session_make_description(su_home_t *home,
+			     soa_session_t *soa,
+			     int session,
+			     sip_content_disposition_t **return_cd,
+			     sip_content_type_t **return_ct,
+			     sip_payload_t **return_pl);
+
+static
+int session_process_response(nua_handle_t *nh,
+			     nua_client_request_t *cr,
+			     nta_outgoing_t *orq,
+			     sip_t const *sip,
+			     char const **return_received);
+
+static
+int respond_with_retry_after(nua_handle_t *nh, nta_incoming_t *irq,
+			     int status, char const *phrase,
+			     int min, int max);
+
+/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Place a call using SIP INVITE method. 
+ *
+ * Incomplete call can be hung-up with nua_cancel(). Complete or incomplete
+ * calls can be hung-up with nua_bye().
+ *
+ * Optionally 
+ * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
+ * - media parameters can be set by SOA tags
+ * - nua_invite() can be used to change status of an existing call: 
+ *   - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
+ *     the value "*" sets all the media beloginging to the session on hold
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    Tags of nua_set_hparams() \n
+ *    NUTAG_INCLUDE_EXTRA_SDP() \n
+ *    SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
+ *    SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(), 
+ *    SOATAG_AUDIO_AUX(), \n
+ *    SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
+ *    See use of tags in <sip_tag.h> below
+ *
+ * @par Events:
+ *    #nua_r_invite \n
+ *    #nua_i_state (#nua_i_active, #nua_i_terminated) \n
+ *    #nua_i_media_error \n
+ *    #nua_i_fork \n
+ *
+ * @par Populating SIP Request Message with Tagged Arguments
+ * The tagged arguments can be used to pass values for any SIP headers to
+ * the stack. When the INVITE message (or any other SIP message) is created,
+ * the tagged values saved with nua_handle() are used first, next the tagged
+ * values given with the operation (nua_invite()) are added.
+ *
+ * @par
+ * When multiple tags for the same header are specified, the behaviour
+ * depends on the header type. If only a single header field can be included
+ * in a SIP message, the latest non-NULL value is used, e.g., @Subject. 
+ * However, if the SIP header can consist of multiple lines or header fields
+ * separated by comma, e.g., @Accept, all the tagged
+ * values are concatenated.
+ * 
+ * @par
+ * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the
+ * values from previous tags are ignored.
+ *
+ * @par
+ * Next, values previously set with nua_set_params() or nua_set_hparams()
+ * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
+ * added to the request if they are not already set.
+ *
+ * @par
+ * Now, the target URI for the request needs to be determined.
+ *
+ * @par
+ * For initial INVITE requests, values from tags are used. If NUTAG_URL() is
+ * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given, it
+ * is used as target URI. If neither is given, the complete request line
+ * already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR() is used. 
+ * If none of the tags above are given, an internal error is returned to the
+ * application. At this point, the target URI is stored in the request line,
+ * together with method name ("INVITE") and protocol version ("SIP/2.0"). 
+ * The initial dialog information is also created: @CallID, @CSeq headers
+ * are generated, if they do not exist, and tag is added to @From header.
+ *
+ * @par
+ * For in-dialog INVITE (re-INVITE), the request URI is taken from the
+ * @Contact header received from the remote party during the dialog
+ * establishment. Also, the @CallID and @CSeq headers and @From and @To tags
+ * are generated based on the dialog information and added to the request. 
+ * If the dialog has a route (set by @RecordRoute headers), it is added to
+ * the request, too.
+ *
+ * @par
+ * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
+ * also added now, if it does not exist.
+ * 
+ * @par
+ * Next, the stack generates a @Contact header for the request (Unless the
+ * application already gave a @Contact header or it does not want to use
+ * @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
+ * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
+ * has registered the URI in @From header, the @Contact header used with
+ * registration is used. Otherwise, the @Contact header is generated from the
+ * local IP address and port number.
+ *
+ * @par
+ * For the initial INVITE requests, @ServiceRoute set received from
+ * the registrar is also added to the request message.
+ *
+ * @par
+ * The INVITE request message created by nua_invite() operation is saved as
+ * a template for automatic re-INVITE requests sent by the session timer
+ * ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please
+ * note that the template message is not used when ACK, PRACK, UPDATE or
+ * INFO requests are created (however, these requests will include
+ * dialog-specific headers like @To, @From, and @CallID as well as
+ * preference headers @Allow, @Supported, @UserAgent, @Organization).
+ *
+ * @par SDP Handling
+ * The initial nua_invite() creates a @ref soa_session_t "soa media session"
+ * unless NUTAG_MEDIA_ENABLE(0) has been given. The SDP description of the
+ * @ref soa_session_t "soa media session" is included in the INVITE request
+ * as message body. 
+ *
+ * @par
+ * The SDP in a 1XX or 2XX response message is interpreted as an answer,
+ * given to the @ref soa_session_t "soa media session" object for
+ * processing.
+ *
+ * @bug If the INVITE request already contains a message body, SDP is not
+ * added. Also, if the response contains a multipart body, it is not parsed.
+ *
+ * @par Authentication
+ * The INVITE request may need authentication. Each proxy or server
+ * requiring authentication can respond with 401 or 407 response. The
+ * nua_authenticate() operation stores authentication information (username
+ * and password) to the handle, and stack tries to authenticate all the rest
+ * of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using same
+ * username and password.
+ *
+ * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
+ *     nua_handle_has_active_call() \n
+ *     nua_handle_has_call_on_hold()\n
+ *     nua_handle_has_invite() \n
+ *     nua_authenticate() \n
+ *     nua_prack() \n
+ *     nua_update() \n
+ *     nua_info() \n 
+ *     nua_cancel() \n
+ *     nua_bye() \n
+ *     #nua_i_invite, nua_respond()
+ */
+
+/* Tags not implemented
+ *    NUTAG_REFER_PAUSE() \n
+ */
+int
+nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		 tagi_t const *tags)
+{
+  char const *what;
+
+  if (nh_is_special(nh) || 
+      nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error))
+    what = "Invalid handle for INVITE";
+  else if (nh_referral_check(nh, tags) < 0) {
+    what = "Invalid referral";
+  }
+  else if (nua_stack_init_handle(nua, nh, TAG_NEXT(tags)) < 0) {
+    what = "Handle initialization failed";
+  }
+  else
+    return nua_stack_invite2(nua, nh, e, 0, tags);
+
+  UA_EVENT2(e, 900, what);
+
+  signal_call_state_change(nh, NULL, 900, what, nua_callstate_init, 0, 0);
+
+  return e;
+}
+
+static int
+nua_stack_invite2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		  int restarted,
+		  tagi_t const *tags)
+{
+  nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr;
+  int offer_sent = 0;
+
+  msg_t *msg = NULL;
+  sip_t *sip = NULL;
+
+  char const *what;
+
+  du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
+  ss = nua_dialog_usage_private(du);
+  cr = ss->ss_crequest;
+  what = nua_internal_error;		/* Internal error */
+
+  if (du == NULL)
+    goto failure;
+
+  if (cr->cr_orq) {
+    what = "INVITE request already in progress";
+    goto failure;
+  }
+
+  if (ss->ss_state == nua_callstate_terminated)
+    ss->ss_state = nua_callstate_init;
+
+  if (!restarted) {
+    session_timer_preferences(ss, 
+			      NH_PGET(nh, session_timer),
+			      NH_PGET(nh, min_se),
+			      NH_PGET(nh, refresher));
+  }
+
+  if (restarted && !cr->cr_msg) {
+    if (du->du_msg)
+      cr->cr_msg = msg_dup(du->du_msg);
+    else
+      restarted = 0;
+  }
+
+  msg = nua_creq_msg(nua, nh, cr, restarted,
+		     SIP_METHOD_INVITE,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (!sip) {
+    what = "Cannot Initialize Request";
+    goto failure;
+  }
+
+  if (!restarted) {
+    msg_destroy(du->du_msg), du->du_msg = msg_dup(msg);
+  }
+
+  if (nh->nh_soa) {
+    soa_init_offer_answer(nh->nh_soa);
+
+    if (sip->sip_payload)
+      offer_sent = 0;
+    else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
+      offer_sent = -1;
+    else
+      offer_sent = 1;
+  }
+
+  if (offer_sent >= 0) {
+    sip_time_t invite_timeout = NH_PGET(nh, invite_timeout);
+    if (invite_timeout == 0)
+      invite_timeout = UINT_MAX;
+    /* Cancel if we don't get response within timeout*/
+    nua_dialog_usage_set_expires(du, invite_timeout);
+    nua_dialog_usage_set_refresh(du, 0);
+
+    /* Add session timer headers */
+    if (session_timer_is_supported(nh))
+      use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+
+    ss->ss_100rel = NH_PGET(nh, early_media);
+    ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
+
+    if (ss->ss_precondition)
+      ss->ss_update_needed = ss->ss_100rel = 1;
+
+    if (offer_sent > 0 &&
+	session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+      what = "Internal media error"; goto failure;
+    }
+
+    if (nh->nh_soa &&
+	NH_PGET(nh, media_features) && !nua_dialog_is_established(nh->nh_ds) &&
+	!sip->sip_accept_contact && !sip->sip_reject_contact) {
+      sip_accept_contact_t ac[1];
+      sip_accept_contact_init(ac);
+
+      ac->cp_params = (msg_param_t *)
+	soa_media_features(nh->nh_soa, 1, msg_home(msg));
+
+      if (ac->cp_params) {
+	msg_header_replace_param(msg_home(msg), ac->cp_common, "explicit");
+	sip_add_dup(msg, sip, (sip_header_t *)ac);
+      }
+    }
+
+    if (nh->nh_auth) {
+      if (auc_authorize(&nh->nh_auth, msg, sip) < 0) {
+	what = "Internal authentication error"; goto failure;
+      }
+    }
+
+      cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+					process_response_to_invite, nh, NULL,
+					msg,
+					NTATAG_REL100(ss->ss_100rel),
+					SIPTAG_END(), TAG_NEXT(tags));
+
+    if (cr->cr_orq) {
+      cr->cr_offer_sent = offer_sent;
+      cr->cr_usage = du;
+      du->du_refresh = 0;
+      signal_call_state_change(nh, ss, 0, "INVITE sent",
+			       nua_callstate_calling, 0,
+			       offer_sent ? "offer" : 0);
+      return cr->cr_event = e;
+    }
+  }
+
+ failure:
+
+  msg_destroy(msg);
+  if (du && !du->du_ready)
+    nua_dialog_usage_remove(nh, nh->nh_ds, du), ss = NULL;
+
+  UA_EVENT2(e, 900, what);
+  signal_call_state_change(nh, ss, 900, what, nua_callstate_init, 0, 0);
+
+  return e;
+}
+
+/** @NUA_EVENT nua_r_invite
+ *
+ * Answer to outgoing INVITE.
+ *
+ * The INVITE may be sent explicitly by nua_invite() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response message to INVITE or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_invite(), @ref nua_call_model, #nua_i_state, #nua_i_invite, 
+ * nua_ack(), NUTAG_AUTOACK()
+ * 
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_invite(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_client_request_t *cr;
+  nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
+  int status = sip->sip_status->st_status;
+  char const *phrase = sip->sip_status->st_phrase;
+  int terminated = 0;
+  int gracefully = 1;
+  char const *received = NULL;
+
+  cr = nua_client_request_by_orq(nh->nh_ds->ds_cr, orq);
+  du = cr ? cr->cr_usage : NULL;
+  ss = nua_dialog_usage_private(du);
+  
+  assert(cr && du && ss);
+
+  if (ss->ss_state == nua_callstate_terminating && 200 <= status) {
+    /*
+     * If the call is being terminated but re-INVITE was responded with 2XX
+     * re-send the BYE, otherwise terminate the call.
+     */
+    gracefully = status < 300, terminated = !gracefully;
+  }
+  else if (status >= 300) {
+    if (sip->sip_retry_after)
+      gracefully = 0;
+
+    terminated = sip_response_terminates_dialog(status, sip_method_invite,
+						&gracefully);
+
+    if (!terminated) {
+      if (check_session_timer_restart(nh, ss, cr, orq, sip, restart_invite))
+	return 0;
+
+      if (ss->ss_state < nua_callstate_ready)
+	terminated = 1;
+    }
+  }
+  else if (status >= 200) {
+    du->du_ready = 1;
+    cr->cr_usage = NULL;
+
+    /* XXX - check remote tag, handle forks */
+    /* Set route, contact, nh_ds->ds_remote_tag */
+    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+    init_session_timer(ss, sip, NH_PGET(nh, refresher));
+    set_session_timer(ss);
+
+    /* signal_call_state_change */
+    if (session_process_response(nh, cr, orq, sip, &received) >= 0) {
+      ss->ss_ack_needed = received ? received : "";
+
+      if (NH_PGET(nh, auto_ack) ||
+	  /* Auto-ACK response to re-INVITE unless auto_ack is set to 0 */
+	  (ss->ss_state == nua_callstate_ready &&
+	   !NH_PISSET(nh, auto_ack)))
+	nua_stack_ack(nua, nh, nua_r_ack, NULL);
+      else
+	signal_call_state_change(nh, ss, status, phrase,
+				 nua_callstate_completing, received, 0);
+      nh_referral_respond(nh, SIP_200_OK);
+      return 0;
+    }
+
+    status = 500, phrase = "Malformed Session in Response";
+
+    nua_stack_ack(nua, nh, nua_r_ack, NULL);
+    gracefully = 1;
+  }
+  else if (sip->sip_rseq) {
+    /* Reliable provisional response */
+    nh_referral_respond(nh, status, phrase);
+
+    return process_100rel(nh, ss, orq, sip); /* signal_call_state_change */
+  }
+  else {
+    /* Provisional response */
+    nh_referral_respond(nh, status, phrase);
+    session_process_response(nh, cr, orq, sip, &received);
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_proceeding, received, 0);
+    return 0;
+  }
+
+  cr->cr_usage = NULL;
+
+  nh_referral_respond(nh, status, phrase);
+  nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+  if (terminated)
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_terminated, 0, 0);
+
+  if (terminated < 0) {
+    nua_dialog_terminated(nh, nh->nh_ds, status, phrase);
+  }
+  else if (terminated > 0) {
+    nua_dialog_usage_remove(nh, nh->nh_ds, du);
+  }
+  else if (gracefully) {
+    char *reason =
+      su_sprintf(NULL, "SIP;cause=%u;text=\"%s\"", 
+		 status > 699 ? 500 : status, phrase);
+
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_terminating, 0, 0);
+
+    nua_stack_post_signal(nh, nua_r_bye,
+			  SIPTAG_REASON_STR(reason),
+			  TAG_END());
+
+    su_free(NULL, reason);
+  }
+
+  return 0;
+}
+
+/**@fn void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Acknowledge a succesful response to INVITE request.
+ *
+ * Acknowledge a successful response (200..299) to INVITE request with the
+ * SIP ACK request message. This function is need only if NUTAG_AUTOACK()
+ * parameter has been cleared.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_i_media_error \n
+ *    #nua_i_state  (#nua_i_active, #nua_i_terminated) 
+ *
+ * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
+ */
+
+int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		  tagi_t const *tags)
+{
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr;
+  nta_outgoing_t *ack = NULL;
+  msg_t *msg;
+  sip_t *sip;
+  int status = 200;
+  char const *phrase = "OK", *reason = NULL, *sent = NULL;
+  char const *received;
+
+  ss = nua_session_usage_get(nh->nh_ds);
+  cr = ss->ss_crequest;
+
+  received = ss ? ss->ss_ack_needed : NULL;
+
+  if (!received)
+    return UA_EVENT2(nua_i_error, 900, "No response to ACK");
+
+  ss->ss_ack_needed = 0;
+
+  if (!received[0])
+    received = NULL;
+
+  if (tags)
+    nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+  msg = nua_creq_msg(nua, nh, cr, 0,
+		     SIP_METHOD_ACK,
+		     /* NUTAG_COPY(0), */
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (sip && nh->nh_soa) {
+    if (tags)
+      soa_set_params(nh->nh_soa, TAG_NEXT(tags));
+
+    if (cr->cr_offer_recv && !cr->cr_answer_sent) {
+      if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
+	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+	reason = soa_error_as_sip_reason(nh->nh_soa);
+	status = 900, phrase = "Internal media error";
+	reason = "SIP;cause=500;text=\"Internal media error\"";
+      }
+      else {
+	cr->cr_answer_sent = 1;
+	soa_activate(nh->nh_soa, NULL);
+
+	/* signal that O/A round is complete */
+	sent = "answer";
+      }
+    }
+
+    if (!reason &&
+	/* ss->ss_offer_sent && !ss->ss_answer_recv */
+	!soa_is_complete(nh->nh_soa)) {
+      /* No SDP answer in 2XX response -> terminate call */
+      status = 988, phrase = "Incomplete offer/answer";
+      reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
+    }
+  }
+
+  if (sip) {
+    msg_t *imsg = nta_outgoing_getrequest(cr->cr_orq);
+    sip_t const *isip = sip_object(imsg);
+    if (isip->sip_proxy_authorization)
+      sip_add_dup(msg, sip, (void *)isip->sip_proxy_authorization);
+    if (isip->sip_authorization)
+      sip_add_dup(msg, sip, (void *)isip->sip_authorization);
+    msg_destroy(imsg);
+  }
+
+  if (sip)
+    ack = nta_outgoing_mcreate(nua->nua_nta, NULL, NULL, NULL, msg,
+			       SIPTAG_END(), TAG_NEXT(tags));
+
+  if (!ack) {
+    if (!reason) {
+      status = 900, phrase = "Cannot send ACK";
+      reason = "SIP;cause=500;text=\"Internal Error\"";
+    }
+    msg_destroy(msg);
+  }
+
+  nua_creq_deinit(cr, NULL);	/* Destroy INVITE transaction */
+  nta_outgoing_destroy(ack);	/* TR engine keeps this around for T2 */
+
+  if (status < 300) {
+    signal_call_state_change(nh, ss, status, phrase, nua_callstate_ready,
+			     received, sent);
+  }
+  else {
+    signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminating,
+			     0, 0);
+    nua_stack_post_signal(nh, nua_r_bye,
+			  SIPTAG_REASON_STR(reason),
+			  TAG_END());
+  }
+
+  return 0;
+}
+
+
+/* Process reliable provisional response */
+static int
+process_100rel(nua_handle_t *nh,
+	       nua_session_usage_t *ss,
+	       nta_outgoing_t *orq,
+	       sip_t const *sip)
+{
+  nua_client_request_t *cr_invite = ss->ss_crequest;
+  nua_client_request_t *cr_prack = nh->nh_ds->ds_cr;
+  
+  sip_rseq_t *rseq;
+  char const *recv = NULL;
+  int status; char const *phrase;
+
+  if (cr_prack->cr_orq) {
+    /* XXX - better luck next time */
+    SU_DEBUG_3(("nua(%p): cannot send PRACK because %s is pending\n", nh,
+		nta_outgoing_method_name(cr_prack->cr_orq)));
+    return 0; /* Wait until this response is re-transmitted */
+  }
+
+  if (!nua_dialog_is_established(nh->nh_ds)) {
+    /* Establish early dialog */
+    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+    
+    /* Tag the INVITE request */
+    cr_invite->cr_orq =
+      nta_outgoing_tagged(orq, process_response_to_invite, nh,
+			  sip->sip_to->a_tag, sip->sip_rseq);
+    nta_outgoing_destroy(orq);
+    orq = cr_invite->cr_orq;
+  }
+  
+  assert(sip);
+
+  status = sip->sip_status->st_status, phrase = sip->sip_status->st_phrase;
+  rseq = sip->sip_rseq;
+
+  if (!rseq) {
+    SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", nh));
+  }
+  else if (rseq->rs_response <= nta_outgoing_rseq(orq)) {
+    SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", nh, 
+		(unsigned)rseq->rs_response,
+		nta_outgoing_rseq(orq)));
+    /* XXX - send nua_r_invite event or not? */
+    return 0;
+  }
+  else if (nta_outgoing_setrseq(orq, rseq->rs_response) < 0) {
+    SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", nh, 
+		(unsigned)rseq->rs_response));
+  }
+  else if (session_process_response(nh, cr_invite, orq, sip, &recv) < 0) {
+    assert(nh->nh_soa);
+    status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+    nua_stack_event(nh->nh_nua, nh, NULL,
+		    nua_i_media_error, status, phrase, TAG_END());
+  }
+  /* Here we could let application PRACK and just send state event */
+  else {
+    sip_rack_t rack[1];
+    tagi_t tags[] = {
+      { TAG_SKIP(nua_stack_prack) }, /* this is autoprack */
+      { NUTAG_STATUS(status), },
+      { NUTAG_PHRASE(phrase), },
+      { NUTAG_PHRASE(recv), },
+      { SIPTAG_RACK(rack) }, 
+      { TAG_END() }
+    };
+
+    sip_rack_init(rack);
+
+    rack->ra_response    = sip->sip_rseq->rs_response;
+    rack->ra_cseq        = sip->sip_cseq->cs_seq;
+    rack->ra_method      = sip->sip_cseq->cs_method;
+    rack->ra_method_name = sip->sip_cseq->cs_method_name;
+
+    nua_stack_prack(nh->nh_nua, nh, nua_r_prack, tags);
+
+    return 0;
+  }
+
+  /* XXX - CANCEL INVITE or BYE this session? */
+  /* Because we don't do forking very well we just cancel INVITE */
+  nua_stack_cancel(nh->nh_nua, nh, nua_r_cancel, NULL);
+
+  return 0;
+}
+
+/**@fn void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ * Send a PRACK request. 
+ *
+ * PRACK is used to acknowledge receipt of 100rel responses. See @RFC3262.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    Tags in <sofia-sip/soa_tag.h>, <sofia-sip/sip_tag.h>.
+ *
+ * @par Events:
+ *    #nua_r_prack
+ */
+
+/** @NUA_EVENT nua_r_prack
+ *
+ * Response to an outgoing @b PRACK request. PRACK request is used to
+ * acknowledge reliable preliminary responses and it is usually sent
+ * automatically by the nua stack.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response to @b PRACK or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_prack(), #nua_i_prack, @RFC3262
+ *
+ * @END_NUA_EVENT
+ */
+
+
+int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		    tagi_t const *tags)
+{
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr;
+  msg_t *msg;
+  sip_t *sip;
+  int offer_sent_in_prack = 0, answer_sent_in_prack = 0;
+
+  int status = 0; char const *phrase = "PRACK sent";
+  char const *recv = NULL, *sent = NULL;
+
+  int autoprack =		/* XXX - should have common indication */
+    tags && tags->t_tag == tag_skip && 
+    tags->t_value == (tag_value_t)nua_stack_prack;
+
+  if (autoprack) {
+    status = (int)tags[1].t_value; 
+    phrase = (char const *)tags[2].t_value;
+    recv = (char const *)tags[3].t_value;
+    tags += 4;
+  }
+
+  ss = nua_session_usage_get(nh->nh_ds);
+
+  if (!ss || !ss->ss_crequest || !nta_outgoing_rseq(ss->ss_crequest->cr_orq))
+    return UA_EVENT2(e, 900, "Nothing to PRACK");
+  else if (nh->nh_ds->ds_cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  cr = nh->nh_ds->ds_cr;
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+		     SIP_METHOD_PRACK,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     TAG_NEXT(tags));
+
+  sip = sip_object(msg);
+
+  if (sip) {
+    nua_client_request_t *cri = ss->ss_crequest;
+    if (nh->nh_soa == NULL)
+      /* It is up to application to handle SDP */;
+    else if (sip->sip_payload)
+      /* XXX - we should just do MIME in session_include_description() */;
+    else if (cri->cr_offer_recv && !cri->cr_answer_sent) {
+
+      if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
+	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+
+	status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+	SU_DEBUG_3(("nua(%p): PRACK answer: %d %s\n", nh, status, phrase));
+	nua_stack_event(nh->nh_nua, nh, NULL,
+			nua_i_media_error, status, phrase, TAG_END());
+
+	goto error;
+      }
+      else {
+	answer_sent_in_prack = 1, sent = "answer";
+	soa_activate(nh->nh_soa, NULL);
+      }
+    }
+    /* When 100rel response status was 183 fake support for preconditions */
+    else if (autoprack && status == 183 && ss->ss_precondition) {
+
+      if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||
+	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+
+	status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+	SU_DEBUG_3(("nua(%p): PRACK offer: %d %s\n", nh, status, phrase));
+	nua_stack_event(nh->nh_nua, nh, NULL,
+			nua_i_media_error, status, phrase, TAG_END());
+	goto error;
+      }
+      else {
+	offer_sent_in_prack = 1, sent = "offer";
+      }
+    }
+
+    if (nh->nh_auth) {
+      if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
+	/* xyzzy */;
+    }
+
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_prack, nh, NULL,
+				      msg,
+				      SIPTAG_END(), TAG_NEXT(tags));
+    if (cr->cr_orq) {
+      cr->cr_usage = nua_dialog_usage_public(ss);
+      cr->cr_event = nua_r_prack;
+
+      if (answer_sent_in_prack)
+	cri->cr_answer_sent = 1;
+      else if (offer_sent_in_prack)
+	cr->cr_offer_sent = 1;
+
+      if (autoprack) 
+	signal_call_state_change(nh, ss, status, phrase,
+				 nua_callstate_proceeding, recv, sent);
+      else
+	signal_call_state_change(nh, ss, 0, "PRACK sent",
+				 nua_callstate_proceeding, NULL, sent);
+	
+
+      return cr->cr_event = e;
+    }
+  }
+
+ error:
+  msg_destroy(msg);
+  return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+void restart_prack(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_prack, tags);
+}
+
+
+static int
+process_response_to_prack(nua_handle_t *nh,
+			  nta_outgoing_t *orq,
+			  sip_t const *sip)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);
+  int status;
+  char const *phrase = "OK", *reason = NULL, *recv = NULL;
+
+  assert(cr->cr_usage && cr->cr_usage->du_class == nua_session_usage);
+
+  if (sip)
+    status = sip->sip_status->st_status, phrase = sip->sip_status->st_phrase;
+  else
+    status = 408, phrase = sip_408_Request_timeout;
+
+  SU_DEBUG_5(("nua: process_response_to_prack: %u %s\n", status, phrase));
+
+  if (nua_creq_check_restart(nh, cr, orq, sip, restart_prack))
+    return 0;
+
+  if (status < 200)
+    return 0;
+
+  cr->cr_usage = NULL;
+
+  if (status < 300) {
+    if (session_process_response(nh, cr, orq, sip, &recv) < 0) {
+      status = 900, phrase = "Malformed Session in Response";
+      reason = "SIP;status=400;phrase=\"Malformed Session in Response\"";
+    }
+  }
+  else
+    nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+  if (recv)
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_proceeding, recv, NULL);
+
+  if (status < 300 && ss->ss_update_needed)
+    nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
+
+  return 0;
+}
+
+/** Refresh session usage */
+static void nua_session_usage_refresh(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du,
+				      sip_time_t now)
+{
+  tagi_t const timer_tags[2] = {
+    { SIPTAG_SUBJECT_STR("Session refresh") }, 
+    { TAG_END() }
+  };
+  tagi_t const refresh_tags[2] = {
+    { SIPTAG_SUBJECT_STR("Dialog refresh") }, 
+    { TAG_END() }
+  };
+
+  nua_session_usage_t const *ss = nua_dialog_usage_private(du);
+  nua_client_request_t const *cri = ss->ss_crequest, *cro = ds->ds_cr;
+  nua_server_request_t const *sr;
+
+  for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+    if (sr->sr_usage == du && 
+	(sr->sr_method == sip_method_invite || 
+	 sr->sr_method == sip_method_update))
+      break;
+
+  /* INVITE or UPDATE in progress or being authenticated */
+  if ((cri && cri->cr_orq) || sr)	
+    return;
+  if (ss->ss_state >= nua_callstate_terminating)
+    return;
+
+  if (!ss->ss_refresher) {
+    if (now >= du->du_expires)
+      session_timeout(nh, du, now);
+    else
+      /* Refreshing contact & route set */
+      nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, refresh_tags);
+  }
+  else if (NH_PGET(nh, update_refresh)) {
+    if (!cro->cr_orq)
+      nua_stack_update(nh->nh_nua, nh, nua_r_update, timer_tags);
+    else
+      nua_dialog_usage_refresh_range(du, 5, 15);
+  }
+  else {
+    nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, timer_tags);
+  }
+}
+
+static
+char const reason_timeout[] = "SIP;cause=408;text=\"Session timeout\"";
+
+static void
+session_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now)
+{
+  if (now > 1) {
+    nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+    signal_call_state_change(nh, ss, 408, "Session Timeout",
+			     nua_callstate_terminating, NULL, NULL);
+
+    nua_stack_post_signal(nh, nua_r_bye,
+			  SIPTAG_REASON_STR(reason_timeout),
+			  TAG_END());
+  }
+}
+
+/** Terminate usage/dialog/handle/agent gracefully */
+static int nua_session_usage_shutdown(nua_handle_t *nh,
+				      nua_dialog_state_t *ds,
+				      nua_dialog_usage_t *du)
+{
+  nua_session_usage_t *ss = nua_dialog_usage_private(du);
+  nua_client_request_t *cr;
+  nua_server_request_t *sr, *sr_next;
+  int status;
+
+  /* Zap client-side invite transaction */
+  if (ss->ss_crequest->cr_orq) {
+    cr = ss->ss_crequest;
+    status = nta_outgoing_status(cr->cr_orq);
+
+    if (status < 200) 
+      nta_outgoing_tcancel(cr->cr_orq, NULL, NULL, TAG_END());
+
+    if (ss->ss_ack_needed) {
+      msg_t *ack = nua_creq_msg(nh->nh_nua, nh, cr, 0,
+				SIP_METHOD_ACK,
+				TAG_END());
+      nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL, 
+			   ack, TAG_END());
+    }
+
+    nua_creq_deinit(cr, NULL);
+  }
+
+  /* Zap server-side transactions */
+  for (sr = ds->ds_sr; sr; sr = sr_next) {
+    sr_next = sr->sr_next;
+    if (sr->sr_usage == du) {
+      assert(sr->sr_usage == du);
+      sr->sr_usage = NULL;
+      if (sr->sr_respond) 
+	nua_server_respond(sr, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
+      else
+	nua_server_request_destroy(sr);
+    }
+  }
+
+  assert(ss == nua_session_usage_get(nh->nh_ds));
+
+  switch (ss->ss_state) {
+  case nua_callstate_completing:
+  case nua_callstate_ready:
+  case nua_callstate_completed:
+    {
+      msg_t *bye;
+
+      cr = ds->ds_cr;
+      nua_creq_deinit(cr, NULL);
+      bye = nua_creq_msg(nh->nh_nua, nh, ds->ds_cr, 0, 
+			 SIP_METHOD_BYE,
+			 TAG_END());
+      cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
+					NULL, NULL, NULL,
+					bye,
+					TAG_END());
+      nua_creq_deinit(cr, NULL);
+    }
+  }
+
+  nua_dialog_usage_remove(nh, ds, du);
+
+  return 0;
+}
+
+/** Restart invite (e.g., after 302 or 407) */
+void
+restart_invite(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, tags);
+}
+
+static int process_response_to_cancel(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip);
+
+/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Cancel an INVITE operation 
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_cancel, #nua_i_state  (#nua_i_active, #nua_i_terminated)
+ *
+ * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
+ */
+
+int
+nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		 tagi_t const *tags)
+{
+  nua_session_usage_t *ss;
+  nua_client_request_t *cri, *crc;
+
+  ss = nua_session_usage_get(nh->nh_ds);
+
+  if (!nh || !ss || !ss->ss_crequest->cr_usage ||
+      nta_outgoing_status(ss->ss_crequest->cr_orq) >= 200) {
+    return UA_EVENT2(e, 481, "No transaction to CANCEL");
+  }
+
+  cri = ss->ss_crequest;
+  crc = nh->nh_ds->ds_cr;
+
+  if (tags)
+    nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+  if (nh && cri->cr_orq && cri->cr_usage) {
+    nta_outgoing_t *orq;
+
+    /* nh_referral_respond(nh, SIP_487_REQUEST_TERMINATED); */
+
+    if (e)
+      orq = nta_outgoing_tcancel(cri->cr_orq, process_response_to_cancel, nh,
+				 TAG_NEXT(tags));
+    else
+      orq = nta_outgoing_tcancel(cri->cr_orq, NULL, NULL, TAG_NEXT(tags));
+
+    if (orq == NULL)
+      return nua_stack_event(nua, nh, NULL, e, 400, "Internal error",
+			     TAG_END());
+
+    if (e && crc->cr_orq == NULL)
+      crc->cr_orq = orq, crc->cr_event = e;
+  }
+
+  return 0;
+}
+
+/** @NUA_EVENT nua_r_cancel
+ *
+ * Answer to outgoing CANCEL.
+ *
+ * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA
+ * state machine.
+ *
+ * @param status response status code 
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response to CANCEL request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(),
+ * #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+
+
+static int process_response_to_cancel(nua_handle_t *nh,
+				      nta_outgoing_t *orq,
+				      sip_t const *sip)
+{
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* UAS side of INVITE */
+
+static int respond_to_invite(nua_server_request_t *sr, tagi_t const *tags);
+
+static int
+  preprocess_invite(nua_t *, nua_handle_t *, nua_server_request_t **, sip_t *),
+  session_check_request(nua_t *nua,
+			nua_handle_t *nh,
+			nta_incoming_t *irq,
+			sip_t const *sip),
+  process_invite(nua_t *, nua_handle_t *, nua_server_request_t *, sip_t *),
+  process_prack(nua_handle_t *, nta_reliable_t *, nta_incoming_t *,
+		sip_t const *);
+
+static int
+  process_ack_or_cancel(nua_server_request_t *, nta_incoming_t *, 
+			sip_t const *),
+  process_ack(nua_server_request_t *, nta_incoming_t *, sip_t const *),
+  process_cancel(nua_server_request_t *, nta_incoming_t *, sip_t const *),
+  process_timeout(nua_server_request_t *, nta_incoming_t *);
+
+/** @NUA_EVENT nua_i_invite
+ *
+ * Indication of incoming call or re-INVITE request. 
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with this call
+ *               (maybe created for this call)
+ * @param hmagic application context associated with this call
+ *               (maybe NULL if call handle was created for this call)
+ * @param sip    incoming INVITE request
+ * @param tags   SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
+ * 
+ * @par Responding to INVITE with nua_respond()
+ *
+ * If @a status in #nua_i_invite event is below 200, the application should
+ * accept or reject the call with nua_respond(). See the @ref nua_call_model
+ * for the detailed explanation of various options in call processing at
+ * server end.
+ *
+ * The @b INVITE request takes care of session setup using SDP Offer-Answer
+ * negotiation as specified in @RFC3264 (updated in @RFC3262 section 5,
+ * @RFC3311, and @RFC3312). The Offer-Answer can be taken care by
+ * application (if NUTAG_MEDIA_ENABLE(0) parameter has been set) or by the
+ * built-in SDP Offer/Answer engine @soa (by default and when
+ * NUTAG_MEDIA_ENABLE(1) parameter has been set). When @soa is enabled, it
+ * will take care of parsing the SDP, negotiating the media and codecs, and
+ * including the SDP in the SIP message bodies as required by the
+ * Offer-Answer model.
+ *
+ * When @soa is enabled, the SDP in the incoming INVITE is parsed and feed
+ * to a #soa_session_t object. The #nua_i_state event sent to the
+ * application immediately after #nua_i_invite will contain the parsing
+ * results in SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR() tags.
+ * 
+ * Note that currently the parser within @nua does not handle MIME
+ * multipart. The SDP Offer/Answer engine can get confused if the SDP offer
+ * is included in a MIME multipart, therefore such an @b INVITE is rejected
+ * with <i>415 Unsupported Media Type</i> error response: the client is
+ * expected to retry the INVITE without MIME multipart content.
+ *
+ * If the call is to be accepted, the application should include the SDP in
+ * the 2XX response. If @soa is not disabled with NUTAG_MEDIA_ENABLE(0), the
+ * SDP should be included in the SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
+ * parameter given to nua_respond(). If it is disabled, the SDP should be
+ * included in message
+ *
+ * @par Preliminary Responses and 100rel
+ *
+ * Call progress can be signaled with preliminary responses (with status
+ * code in the range 101..199). It is possible to conclude the SDP
+ * Offer-Answer negotiation using preliminary responses, too. If
+ * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() parameter is included with in
+ * a preliminary nua_response(), the SDP answer is generated and sent with
+ * the preliminary responses, too.
+ *
+ * The preliminary responses are sent reliably if feature tag "100rel" is
+ * included in the @Require header of the response or if
+ * NUTAG_EARLY_MEDIA(1) parameter has been given. The reliably delivery of
+ * preliminary responses mean that a sequence number is included in the
+ * @RSeq header in the response message and the response message is resent
+ * until the client responds with a @b PRACK request with matching sequence
+ * number in @RAck header.
+ *
+ * Note that only the "183" response is sent reliably if the
+ * NUTAG_ONLY183_100REL(1) parameter has been given. The reliable
+ * preliminary responses are acknowledged with @b PRACK request sent by the
+ * client.
+ *
+ * Note if the SDP offer-answer is completed with the reliable preliminary
+ * responses, the is no need to include SDP in 200 OK response (or other 2XX
+ * response). However, it the tag NUTAG_INCLUDE_EXTRA_SDP(1) is included
+ * with nua_respond(), a copy of the SDP answer generated earlier by @soa is
+ * included as the message body.
+ *
+ * @sa nua_respond(), @ref nua_uas_call_model, #nua_i_state,
+ * NUTAG_MEDIA_ENABLE(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+ * @RFC3262, NUTAG_EARLY_MEDIA(), NUTAG_ONLY183_100REL(), 
+ * NUTAG_INCLUDE_EXTRA_SDP(),
+ * #nua_i_prack, #nua_i_update, nua_update(),
+ * nua_invite(), #nua_r_invite
+ *
+ * @par Third Party Call Control
+ *
+ * When so called 2rd party call control is used, the initial @b INVITE may
+ * not contain SDP offer. In that case, the offer is sent by the recipient
+ * of the @b INVITE request (User-Agent Server, UAS). The SDP sent in 2XX
+ * response (or in a preliminary reliable response) is considered as an
+ * offer, and the answer will be included in the @b ACK request sent by the
+ * UAC (or @b PRACK in case of preliminary reliable response).
+ *
+ * @sa @ref nua_3pcc_call_model
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming INVITE. */
+int nua_stack_process_invite(nua_t *nua,
+			     nua_handle_t *nh,
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+  int status;
+  
+  sr = SR_INIT(sr0);
+  sr->sr_irq = irq;
+
+  status = preprocess_invite(nua, nh, &sr, (sip_t *)sip);
+
+  if (status) {
+    if (sr->sr_status > 100) 
+      nta_incoming_treply(irq, sr->sr_status, sr->sr_phrase,
+			  SIPTAG_USER_AGENT_STR(NUA_PGET(nua, nh, user_agent)),
+			  TAG_END());
+    nua_server_request_destroy(sr);
+    /* if something has failed, respond with 500 Internal Server Error */
+    return 500; 
+  }
+
+  assert(sr != sr0);
+
+  return process_invite(nua, sr->sr_owner, sr, (sip_t *)sip);
+}
+
+/** @internal Preprocess incoming invite - sure we have a valid request. 
+ * 
+ * @return 0 if request is valid, or error statuscode when request has been 
+ * responded.
+ */
+static
+int preprocess_invite(nua_t *nua,
+		      nua_handle_t *nh,
+		      nua_server_request_t **inout_sr,
+		      sip_t *sip)
+{
+  nua_dialog_state_t *ds;
+  nua_server_request_t *sr = *inout_sr;
+  nua_server_request_t const *sr0;
+  nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
+  int have_sdp;
+  char const *sdp;
+  size_t len;
+
+  if (nh) {
+    ds = nh->nh_ds;
+    du = nua_dialog_usage_get(ds, nua_session_usage, NULL);
+    ss = nua_dialog_usage_private(du);
+  }
+  else {
+    nh = nua->nua_dhandle, ds = NULL, du = NULL, ss = NULL;
+  }
+
+  sr->sr_usage = du;
+
+  if (!NUA_PGET(nua, nh, invite_enable))
+    return SR_STATUS1(sr, SIP_403_FORBIDDEN);
+
+  if (session_check_request(nua, nh, sr->sr_irq, sip))
+    return 500;
+
+  have_sdp = session_get_description(sip, &sdp, &len);
+
+  if (ss) {
+    /* Existing session */ 
+
+    for (sr0 = ds->ds_sr; sr0; sr0 = sr0->sr_next) {
+      /* Final response have not been sent to previous INVITE */
+      if (sr0->sr_method == sip_method_invite && sr0->sr_respond)
+	break;
+      /* Or we have sent offer but have not received answer */
+      if (have_sdp && sr0->sr_offer_sent && !sr0->sr_answer_recv)
+	break;
+      /* Or we have received request with offer but not sent answer */
+      if (have_sdp && sr0->sr_offer_recv && !sr0->sr_answer_sent)
+	break;
+    }
+    
+    if (sr0)
+      /* Overlapping invites - RFC 3261 14.2 */
+      return respond_with_retry_after(nh, sr->sr_irq, 
+				      500, "Overlapping Requests",
+				      0, 10);
+
+    if ((ss->ss_crequest && ss->ss_crequest->cr_orq) ||
+	(have_sdp && ds && ds->ds_cr->cr_orq && ds->ds_cr->cr_offer_sent)) {
+      /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
+      return SR_STATUS1(sr, SIP_491_REQUEST_PENDING);
+    }
+  }
+
+  /* Create handle and server request structure when needed */
+  sr = nua_server_request(nua, nh, sr->sr_irq, sip, sr, sizeof *sr,
+			  respond_to_invite, create_dialog);
+  *inout_sr = sr;
+
+  if (sr->sr_status > 100)
+    return sr->sr_status;
+
+  nh = sr->sr_owner; assert(nh != nua->nua_dhandle);
+  ds = nh->nh_ds;
+
+  if (nh->nh_soa) {
+    soa_init_offer_answer(nh->nh_soa);
+
+    if (have_sdp) {
+      if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+	SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh));
+	return SR_STATUS(sr, 400, "Bad Session Description");
+      }
+      else
+	sr->sr_offer_recv = 1;
+    }
+  }
+
+  /* Add the session usage */
+  if (du == NULL)
+    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
+
+  if (!du)
+    return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+
+  sr->sr_usage = du;
+
+  return 0;
+}
+
+static int
+session_check_request(nua_t *nua,
+		      nua_handle_t *nh,
+		      nta_incoming_t *irq,
+		      sip_t const *sip)
+{
+  char const *user_agent = NUA_PGET(nua, nh, user_agent);
+
+  if (nh->nh_soa) {
+    /* Make sure caller uses application/sdp without compression */
+    if (nta_check_session_content(irq, sip,
+				  nua->nua_invite_accept,
+				  SIPTAG_USER_AGENT_STR(user_agent),
+				  SIPTAG_ACCEPT_ENCODING_STR(""),
+				  TAG_END()))
+      return 415;
+
+    /* Make sure caller accepts application/sdp */
+    if (nta_check_accept(irq, sip,
+			 nua->nua_invite_accept,
+			 NULL,
+			 SIPTAG_USER_AGENT_STR(user_agent),
+			 SIPTAG_ACCEPT_ENCODING_STR(""),
+			 TAG_END()))
+      return 406;
+  }
+
+  if (sip->sip_session_expires) {
+    unsigned min_se = NH_PGET(nh, min_se);
+    if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
+      min_se = sip->sip_min_se->min_delta;
+    if (nta_check_session_expires(irq, sip,
+				  min_se,
+				  SIPTAG_USER_AGENT_STR(user_agent),
+				  TAG_END()))
+      return 422;
+  }
+
+  return 0;
+}
+
+/** @internal Process incoming invite - initiate media, etc. */
+static
+int process_invite(nua_t *nua,
+		   nua_handle_t *nh,
+		   nua_server_request_t *sr,
+		   sip_t *sip)
+{
+  nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+  int status = sr->sr_status; char const *phrase = sr->sr_phrase;
+
+  assert(ss); assert(status == 100);
+
+  ss->ss_100rel = NH_PGET(nh, early_media);
+  ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
+  if (ss->ss_precondition)
+    ss->ss_100rel = 1;
+
+  session_timer_preferences(ss, 
+			    NH_PGET(nh, session_timer),
+			    NH_PGET(nh, min_se),
+			    NH_PGET(nh, refresher));
+
+  /* Session Timer negotiation */
+  if (sip_has_supported(NH_PGET(nh, supported), "timer"))
+    init_session_timer(ss, sip, ss->ss_refresher);
+
+  nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);	/* Set route and tags */
+
+  nta_incoming_bind(sr->sr_irq, process_ack_or_cancel, sr);
+
+  assert(ss->ss_state >= nua_callstate_ready ||
+	 ss->ss_state == nua_callstate_init);
+
+  if (NH_PGET(nh, auto_answer) ||
+      /* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
+      (ss->ss_state == nua_callstate_ready &&
+       /* Auto-answer requires enabled media (soa). 
+	* XXX - if the re-INVITE modifies the media we should not auto-answer.
+	*/
+       nh->nh_soa &&
+       !NH_PISSET(nh, auto_answer))) {
+    SET_STATUS1(SIP_200_OK);
+  }
+  else if (NH_PGET(nh, auto_alert)) {
+    if (ss->ss_100rel &&
+	(sip_has_feature(nh->nh_ds->ds_remote_ua->nr_supported, "100rel") ||
+	 sip_has_feature(nh->nh_ds->ds_remote_ua->nr_require, "100rel"))) {
+      SET_STATUS1(SIP_183_SESSION_PROGRESS);
+    }
+    else {
+      SET_STATUS1(SIP_180_RINGING);
+    }
+  }
+
+  /* Magical value indicating autoanswer within respond_to_invite() */
+#define AUTOANSWER ((void*)-1)
+
+  if (status > 100) {
+    sr->sr_auto = 1;
+    nua_server_respond(sr, status, phrase, TAG_END());
+    sr->sr_auto = 0;
+    return 0;
+  }
+
+  nta_incoming_treply(sr->sr_irq, SIP_100_TRYING, 
+		      SIPTAG_USER_AGENT_STR(NUA_PGET(nua, nh, user_agent)),
+		      TAG_END());
+
+  nua_stack_event(nh->nh_nua, nh, 
+		  sr->sr_msg = nta_incoming_getrequest(sr->sr_irq),
+		  nua_i_invite, SIP_100_TRYING,
+		  NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+		  TAG_END());
+
+  signal_call_state_change(nh, ss, SIP_100_TRYING,
+			   nua_callstate_received,
+			   sr->sr_offer_recv ? "offer" : 0, 0);
+
+  return 0;
+}
+
+/** @internal Respond to an INVITE request.
+ *
+ * XXX - use tags to indicate when to use reliable responses.
+ * XXX - change prototype.
+ */
+static
+int respond_to_invite(nua_server_request_t *sr, tagi_t const *tags)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_t *nua = nh->nh_nua;
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
+  msg_t *msg;
+  sip_t *sip;
+  int reliable;
+  int status = sr->sr_status; char const *phrase = sr->sr_phrase;
+  sip_warning_t *warning = NULL;
+
+  int offer = 0, answer = 0, early_answer = 0;
+
+  enter;
+
+  du = sr->sr_usage, ss = nua_dialog_usage_private(du);
+
+  if (du == NULL)
+    return nua_default_respond(sr, tags);
+
+  assert(ss == nua_session_usage_get(nh->nh_ds));
+
+  if (tags) {
+    nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+    if (!NHP_ISSET(nh->nh_prefs, early_answer)
+	&& 100 < status && status < 200) {
+      sdp_session_t const *user_sdp = NULL;
+      char const *user_sdp_str = NULL;
+
+      tl_gets(tags,
+	      SOATAG_USER_SDP_REF(user_sdp),
+	      SOATAG_USER_SDP_STR_REF(user_sdp_str),
+	      TAG_END());
+
+      early_answer = user_sdp || user_sdp_str;
+    }
+    else
+      early_answer = NH_PGET(nh, early_answer);
+  }
+
+  msg = nua_server_response(sr,
+			    status, phrase,
+			    TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)),
+			    SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+			    TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (!sip) {
+    SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR), reliable = 0;
+    goto send_response;
+  }
+
+  reliable =
+    (status >= 200)
+    || (status > 100 && sip->sip_require &&
+	sip_has_feature(sip->sip_require, "100rel"))
+    || (status > 100 &&
+	ds->ds_remote_ua->nr_require &&
+	sip_has_feature(ds->ds_remote_ua->nr_require, "100rel"))
+    || (status > 100 && !NH_PGET(nh, only183_100rel) &&
+	(NH_PGET(nh, early_media) ||
+	 (ds->ds_remote_ua->nr_require &&
+	  sip_has_feature(ds->ds_remote_ua->nr_require, "precondition"))) &&
+	ds->ds_remote_ua->nr_supported &&
+	sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel"))
+    || (status == 183 &&
+	ds->ds_remote_ua->nr_supported &&
+	sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel"))
+    || (status == 183 &&
+	ds->ds_remote_ua->nr_require &&
+	sip_has_feature(ds->ds_remote_ua->nr_require, "precondition"))
+    || (status > 100 &&
+	ds->ds_remote_ua->nr_require &&
+	sip_has_feature(ds->ds_remote_ua->nr_require, "precondition") &&
+	sr->sr_offer_recv && !sr->sr_answer_sent);
+
+  if (!nh->nh_soa)
+    /* Xyzzy */;
+  else if (status >= 300) {
+    soa_clear_remote_sdp(nh->nh_soa);
+  }
+  else {
+    int extra = 0;
+
+    if (sr->sr_offer_sent && !sr->sr_answer_recv)
+      /* Wait for answer */;
+    else if (sr->sr_offer_recv && sr->sr_answer_sent > 1) {
+      /* We have sent answer */
+      /* ...  but we may want to send it again */
+      tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
+      extra = t && t->t_value;
+    }
+    else if (sr->sr_offer_recv && !sr->sr_answer_sent && 
+	     (reliable || early_answer)) {
+      /* Generate answer */ 
+      if (soa_generate_answer(nh->nh_soa, NULL) >= 0) {
+	answer = 1;
+	soa_activate(nh->nh_soa, NULL);
+	/* signal that O/A answer sent (answer to invite) */
+      }
+      else if (status >= 200) {
+	int wcode;
+	char const *text;
+	char const *host = "invalid.";
+	status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+
+	wcode = soa_get_warning(nh->nh_soa, &text);
+	if (wcode) {
+	  if (sip->sip_contact)
+	    host = sip->sip_contact->m_url->url_host;
+	  warning = sip_warning_format(msg_home(msg), "%u %s \"%s\"",
+				       wcode, host, text);
+	}
+      }
+      else {
+	/* 1xx - we don't have to send answer */
+      }
+    }
+    else if (sr->sr_offer_recv && sr->sr_answer_sent == 1 && 
+	     (reliable || early_answer)) {
+      /* The answer was sent unreliably, keep sending it */
+      answer = 1;
+    }
+    else if (!sr->sr_offer_recv && !sr->sr_offer_sent && reliable) {
+      /* Generate offer */
+      if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
+	status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+      else
+	offer = 1;
+    }
+
+    if (offer || answer || extra) {
+      if (session_include_description(nh->nh_soa, 1, msg, sip) < 0)
+	SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+    }
+  }
+
+  if (ss->ss_refresher && 200 <= status && status < 300)
+    if (session_timer_is_supported(nh))
+      use_session_timer(ss, 1, 1, msg, sip);
+
+  if (reliable && status < 200) {
+    nta_reliable_t *rel;
+    rel = nta_reliable_mreply(sr->sr_irq,
+			      process_prack, nh, msg);
+    if (!rel)
+      SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+  }
+
+ send_response:
+
+  if (reliable && status < 200)
+    /* we are done */;
+  else if (status != sr->sr_status) {    /* Error responding */
+    assert(status >= 200);
+    sr->sr_respond = NULL;
+    nta_incoming_treply(sr->sr_irq,
+			status, phrase,
+			SIPTAG_WARNING(warning),
+			SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)),
+			TAG_END());
+    msg_destroy(msg), msg = NULL;
+  }
+  else {
+    if (status >= 200)
+      sr->sr_respond = NULL;
+    nta_incoming_mreply(sr->sr_irq, msg);
+  }
+
+  if (sr->sr_auto) {
+    msg_t *request = nta_incoming_getrequest(sr->sr_irq);
+    if (status < 200)
+      sr->sr_msg = request;
+    nua_stack_event(nh->nh_nua, nh, request,
+		    nua_i_invite, status, phrase,
+		    NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+		    TAG_END());
+  }
+  else if (status != sr->sr_status)
+    nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END());
+
+  sr->sr_status = status, sr->sr_phrase = phrase;
+
+  if (status >= 300)
+    offer = 0, answer = 0;
+
+  if (offer)
+    sr->sr_offer_sent = 1;
+  else if (answer)
+    sr->sr_answer_sent = 1 + reliable;
+
+  /* Update session state */
+  assert(ss->ss_state != nua_callstate_calling);
+  assert(ss->ss_state != nua_callstate_proceeding);
+
+  signal_call_state_change(nh, ss, status, phrase,
+			   status >= 300
+			   ? nua_callstate_init
+			   : status >= 200
+			   ? nua_callstate_completed
+			   : nua_callstate_early,
+			   sr->sr_auto && sr->sr_offer_recv ? "offer" : 0,
+			   offer ? "offer" : answer ? "answer" : 0);
+
+  if (status == 180)
+    ss->ss_alerting = 1;
+  else if (status >= 200)
+    ss->ss_alerting = 0;
+
+  if (status >= 200 && status < 300) {
+    du->du_ready = 1;
+  }
+  else if (status >= 300) {
+    sr->sr_usage = NULL;
+    if (nh->nh_soa)
+      soa_init_offer_answer(nh->nh_soa);
+  }
+
+  if (ss->ss_state == nua_callstate_init) {
+    assert(status >= 300);
+    nua_session_usage_destroy(nh, ss);
+  }
+
+  return status >= 300 ? status : 0;
+}
+
+
+/** @internal Process ACK or CANCEL or timeout (no ACK) for incoming INVITE */
+static
+int process_ack_or_cancel(nua_server_request_t *sr,
+			  nta_incoming_t *irq,
+			  sip_t const *sip)
+{
+  enter;
+
+  assert(sr->sr_usage);
+  assert(sr->sr_usage->du_class == nua_session_usage);
+
+  if (sip && sip->sip_request->rq_method == sip_method_ack)
+    return process_ack(sr, irq, sip);
+  else if (sip && sip->sip_request->rq_method == sip_method_cancel)
+    return process_cancel(sr, irq, sip);
+  else
+    return process_timeout(sr, irq);
+}
+
+/** @NUA_EVENT nua_i_prack
+ *
+ * Incoming PRACK request. PRACK request is used to acknowledge reliable
+ * preliminary responses and it is usually sent automatically by the nua
+ * stack.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    incoming INFO request
+ * @param tags   empty
+ *
+ * @sa nua_prack(), #nua_r_prack, @RFC3262, NUTAG_EARLY_MEDIA()
+ * 
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process PRACK or (timeout from 100rel) */
+static
+int process_prack(nua_handle_t *nh,
+		  nta_reliable_t *rel,
+		  nta_incoming_t *irq,
+		  sip_t const *sip)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
+  nua_server_request_t *sri;
+  int status = 200; char const *phrase = sip_200_OK;
+  char const *recv = NULL, *sent = NULL;
+
+  nta_reliable_destroy(rel);
+
+  ss = nua_session_usage_get(ds); du = nua_dialog_usage_public(ss);
+
+  for (sri = ds->ds_sr; sri; sri = sri->sr_next) {
+    if (sri->sr_method == sip_method_invite && sri->sr_usage == du)
+      break;
+  }
+                     
+  if (!sri || !sri->sr_respond) /* XXX */
+    return 481;
+
+  if (sip)
+    /* received PRACK */;
+  else if (!sri || irq == NULL) { /* Final response interrupted 100rel */
+    /* Ignore */
+    return 200;
+  }
+  else if (sip == NULL) {
+    SET_STATUS(504, "Reliable Response Timeout");
+
+    nua_stack_event(nh->nh_nua, nh, NULL,
+		    nua_i_error, status, phrase,
+		    TAG_END());
+
+    nua_server_respond(sri, status, phrase, TAG_END());
+
+    return status;
+  }
+
+  if (nh->nh_soa) {
+    msg_t *msg = nta_incoming_getrequest(irq);
+    char const *sdp;
+    size_t len;
+
+    if (session_get_description(sip, &sdp, &len)) {
+      su_home_t home[1] = { SU_HOME_INIT(home) };
+
+      sip_content_disposition_t *cd = NULL;
+      sip_content_type_t *ct = NULL;
+      sip_payload_t *pl = NULL;
+
+      if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+	SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh));
+	msg_destroy(msg);
+	status = 400, phrase = "Bad Session Description";
+      }
+
+      /* Respond to PRACK */
+
+      if (status >= 300)
+	;
+      else if (sri->sr_offer_sent) {
+	recv = "answer";
+	sri->sr_answer_recv = 1;
+	if (soa_process_answer(nh->nh_soa, NULL) < 0)
+	  status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+      }
+      else {
+	recv = "offer";
+	if (soa_generate_answer(nh->nh_soa, NULL) < 0) {
+	  status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+	}
+	else {
+	  if (session_make_description(home, nh->nh_soa, 1, &cd, &ct, &pl) > 0)
+	    sent = "answer";
+	}
+      }
+
+      if (nta_incoming_treply(irq, status, phrase,
+			      SIPTAG_CONTENT_DISPOSITION(cd),
+			      SIPTAG_CONTENT_TYPE(ct),
+			      SIPTAG_PAYLOAD(pl),
+			      TAG_END()) < 0)
+	/* Respond with 500 if nta_incoming_treply() failed */
+	SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+
+      su_home_deinit(home);
+    }
+
+    msg_destroy(msg);
+  }
+
+  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+		  nua_i_prack, status, phrase, TAG_END());
+
+  if (status >= 300)
+    return status;
+
+  if (recv || sent) {
+    soa_activate(nh->nh_soa, NULL);
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_early, recv, sent);
+  }
+
+  if (NH_PGET(nh, auto_alert) && !ss->ss_alerting && !ss->ss_precondition)
+    nua_server_respond(sri, SIP_180_RINGING, TAG_END());
+
+  return status;
+}
+
+/** @NUA_EVENT nua_i_ack
+ *
+ * Final response to INVITE has been acknowledged by UAC with ACK. 
+ * 
+ * @note This event is only sent after 2XX response.
+ *
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    incoming ACK request
+ * @param tags   empty
+ *
+ * @sa #nua_i_invite, #nua_i_state, @ref nua_uas_call_model, nua_ack()
+ * 
+ * @END_NUA_EVENT
+ */
+
+int process_ack(nua_server_request_t *sr,
+		nta_incoming_t *irq,
+		sip_t const *sip)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+  msg_t *msg = nta_incoming_getrequest_ackcancel(irq);
+  char const *recv = NULL;
+
+  if (ss == NULL)
+    return 0;
+
+  if (nh->nh_soa && sr->sr_offer_sent && !sr->sr_answer_recv) {
+    char const *sdp;
+    size_t len;
+
+    if (!session_get_description(sip, &sdp, &len) ||
+	!(recv = "answer") ||
+	soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0 ||
+	soa_process_answer(nh->nh_soa, NULL) < 0 ||
+	soa_activate(nh->nh_soa, NULL)) {
+      int status; char const *phrase, *reason;
+
+      status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+      reason = soa_error_as_sip_reason(nh->nh_soa);
+
+      nua_stack_event(nh->nh_nua, nh, msg,
+	       nua_i_ack, status, phrase, TAG_END());
+      nua_stack_event(nh->nh_nua, nh, NULL,
+	       nua_i_media_error, status, phrase, TAG_END());
+
+      signal_call_state_change(nh, ss, 488, "Offer-Answer Error",
+			       nua_callstate_terminating, recv, 0);
+      nua_stack_post_signal(nh, nua_r_bye,
+			    SIPTAG_REASON_STR(reason),
+			    TAG_END());
+
+      return 0;
+    }
+  }
+
+  soa_clear_remote_sdp(nh->nh_soa);
+  nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, TAG_END());
+  signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready, recv, 0);
+  set_session_timer(ss);
+
+  nua_server_request_destroy(sr);
+
+  return 0;
+}
+
+/** @NUA_EVENT nua_i_cancel
+ *
+ * Incoming INVITE has been cancelled by the client.
+ *
+ * @param status status code of response to CANCEL sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    incoming CANCEL request
+ * @param tags   empty
+ *
+ * @sa @ref nua_uas_call_model, nua_cancel(), #nua_i_invite, #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+/* CANCEL  */
+static
+int process_cancel(nua_server_request_t *sr,
+		   nta_incoming_t *irq,
+		   sip_t const *sip)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+  msg_t *cancel = nta_incoming_getrequest_ackcancel(irq);
+
+  assert(nta_incoming_status(irq) < 200);  assert(sr->sr_respond);
+  assert(ss); assert(ss == nua_session_usage_get(nh->nh_ds)); (void)ss;
+
+  nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK, TAG_END());
+
+  nua_server_respond(sr, SIP_487_REQUEST_TERMINATED, TAG_END());
+
+  return 0;
+}
+
+/* Timeout (no ACK or PRACK received) */
+static
+int process_timeout(nua_server_request_t *sr,
+		    nta_incoming_t *irq)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+
+  assert(ss); assert(ss == nua_session_usage_get(nh->nh_ds));
+
+  nua_stack_event(nh->nh_nua, nh, 0, nua_i_error,
+		  408, "Response timeout",
+		  TAG_END());
+
+  if (sr->sr_respond) {
+    /* PRACK timeout */
+    nua_server_respond(sr, SIP_504_GATEWAY_TIME_OUT,
+		       SIPTAG_REASON_STR("SIP;cause=504;"
+					 "text=\"PRACK Timeout\""),
+		       TAG_END());
+    ss = nua_session_usage_get(nh->nh_ds);
+    sr = NULL;
+  }
+
+  if (ss) {
+    /* send BYE, too if 200 OK (or 183 to re-INVITE) timeouts  */
+    signal_call_state_change(nh, ss, 0, "Timeout",
+			     nua_callstate_terminating, 0, 0);
+    nua_stack_post_signal(nh, nua_r_bye,
+			  SIPTAG_REASON_STR("SIP;cause=408;text=\"ACK Timeout\""),
+			  TAG_END());
+  }
+
+  if (sr)
+    nua_server_request_destroy(sr);
+
+  return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* Session timer - RFC 4028 */
+
+static int session_timer_is_supported(nua_handle_t const *nh)
+{
+  /* Is timer feature supported? */
+  return sip_has_supported(NH_PGET(nh, supported), "timer");
+}
+
+static int prefer_session_timer(nua_handle_t const *nh)
+{
+  return 
+    NH_PGET(nh, refresher) != nua_no_refresher || 
+    NH_PGET(nh, session_timer) != 0;
+}
+
+/* Initialize session timer */ 
+static
+void session_timer_preferences(nua_session_usage_t *ss,
+			       unsigned expires,
+			       unsigned min_se,
+			       enum nua_session_refresher refresher)
+{
+  if (expires < min_se)
+    expires = min_se;
+  if (refresher && expires == 0)
+    expires = 3600;
+
+  ss->ss_min_se = min_se;
+  ss->ss_session_timer = expires;
+  ss->ss_refresher = refresher;
+}
+
+
+/** Add timer featuretag and Session-Expires/Min-SE headers */
+static int
+use_session_timer(nua_session_usage_t *ss, int uas, int always,
+		  msg_t *msg, sip_t *sip)
+{
+  sip_min_se_t min_se[1];
+  sip_session_expires_t session_expires[1];
+
+  static sip_param_t const x_params_uac[] = {"refresher=uac", NULL};
+  static sip_param_t const x_params_uas[] = {"refresher=uas", NULL};
+
+  /* Session-Expires timer */
+  if (ss->ss_refresher == nua_no_refresher && !always)
+    return 0;
+
+  sip_min_se_init(min_se)->min_delta = ss->ss_min_se;
+  sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer;
+
+  if (ss->ss_refresher == nua_remote_refresher)
+    session_expires->x_params = uas ? x_params_uac : x_params_uas;
+  else if (ss->ss_refresher == nua_local_refresher)
+    session_expires->x_params = uas ? x_params_uas : x_params_uac;
+
+  sip_add_tl(msg, sip,
+	     TAG_IF(ss->ss_session_timer,
+		    SIPTAG_SESSION_EXPIRES(session_expires)),
+	     TAG_IF(ss->ss_min_se != 0
+		    /* Min-SE: 0 is optional with initial INVITE */
+		    || ss->ss_state != nua_callstate_init,
+		    SIPTAG_MIN_SE(min_se)),
+	     TAG_IF(ss->ss_refresher == nua_remote_refresher,
+		    SIPTAG_REQUIRE_STR("timer")),
+	     TAG_END());
+
+  return 1;
+}
+
+static int
+init_session_timer(nua_session_usage_t *ss,
+		   sip_t const *sip,
+		   int refresher)
+{
+  int server;
+
+  /* Session timer is not needed */
+  if (!sip->sip_session_expires) {
+    if (!sip_has_supported(sip->sip_supported, "timer"))
+      ss->ss_refresher = nua_local_refresher;
+    return 0;
+  }
+
+  ss->ss_refresher = nua_no_refresher;
+  ss->ss_session_timer = sip->sip_session_expires->x_delta;
+
+  if (sip->sip_min_se != NULL
+      && sip->sip_min_se->min_delta > ss->ss_min_se)
+    ss->ss_min_se = sip->sip_min_se->min_delta;
+
+  server = sip->sip_request != NULL;
+
+  if (!sip_has_supported(sip->sip_supported, "timer"))
+    ss->ss_refresher = nua_local_refresher;
+  else if (!str0casecmp("uac", sip->sip_session_expires->x_refresher))
+    ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher;
+  else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher))
+    ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher;
+  else if (!server)
+    return 0;			/* XXX */
+  /* User preferences */
+  else if (refresher == nua_local_refresher)
+    ss->ss_refresher = nua_local_refresher;
+  else
+    ss->ss_refresher = nua_remote_refresher;
+
+  SU_DEBUG_7(("nua session: session expires in %u refreshed by %s (%s %s)\n",
+	      ss->ss_session_timer,
+	      ss->ss_refresher == nua_local_refresher ? "local" : "remote",
+	      server ? sip->sip_request->rq_method_name : "response to",
+	      server ? "request" : sip->sip_cseq->cs_method_name));
+
+  return 1;
+}
+
+static void
+set_session_timer(nua_session_usage_t *ss)
+{
+  nua_dialog_usage_t *du = nua_dialog_usage_public(ss);
+
+  if (ss == NULL)
+    return;
+
+  if (ss->ss_refresher == nua_local_refresher) {
+    ss->ss_timer_set = 1;
+    nua_dialog_usage_set_expires(du, ss->ss_session_timer);
+  }
+  else if (ss->ss_refresher == nua_remote_refresher) {
+    ss->ss_timer_set = 1;
+    nua_dialog_usage_set_expires(du, ss->ss_session_timer + 32);
+    nua_dialog_usage_reset_refresh(du);
+  }
+  else {
+    ss->ss_timer_set = 0;
+    nua_dialog_usage_set_expires(du, UINT_MAX);
+    nua_dialog_usage_reset_refresh(du);
+  }
+}
+
+static int
+check_session_timer_restart(nua_handle_t *nh,
+			    nua_session_usage_t *ss,
+			    nua_client_request_t *cr,
+			    nta_outgoing_t *orq,
+			    sip_t const *sip,
+			    nua_creq_restart_f *restart_function)
+{
+  if (ss && sip && sip->sip_status->st_status == 422) {
+    if (sip->sip_min_se && ss->ss_min_se < sip->sip_min_se->min_delta)
+      ss->ss_min_se = sip->sip_min_se->min_delta;
+    if (ss->ss_min_se > ss->ss_session_timer)
+      ss->ss_session_timer = ss->ss_min_se;
+  
+    if (orq == cr->cr_orq)
+      cr->cr_orq = NULL;
+
+    return nua_creq_restart_with(nh, cr, orq,
+				 100, "Re-Negotiating Session Timer",
+				 restart_function, TAG_END());
+  }
+
+  return nua_creq_check_restart(nh, cr, orq, sip, restart_function);
+}
+
+static inline int
+is_session_timer_set(nua_session_usage_t *ss)
+{
+  return ss->ss_timer_set;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Automatic notifications from a referral */
+
+static int
+nh_referral_check(nua_handle_t *nh, tagi_t const *tags)
+{
+  sip_event_t const *event = NULL;
+  int pause = 1;
+  struct nua_referral *ref = nh->nh_referral;
+  nua_handle_t *ref_handle = ref->ref_handle;
+
+  if (!ref_handle
+      &&
+      tl_gets(tags,
+	      NUTAG_NOTIFY_REFER_REF(ref_handle),
+	      NUTAG_REFER_EVENT_REF(event),
+	      NUTAG_REFER_PAUSE_REF(pause),
+	      TAG_END()) == 0
+      &&
+      tl_gets(nh->nh_tags,
+	      NUTAG_NOTIFY_REFER_REF(ref_handle),
+	      NUTAG_REFER_EVENT_REF(event),
+	      NUTAG_REFER_PAUSE_REF(pause),
+	      TAG_END()) == 0)
+    return 0;
+
+  if (!ref_handle)
+    return 0;
+
+  /* Remove nh_referral and nh_notevent */
+  tl_tremove(nh->nh_tags,
+	     NUTAG_NOTIFY_REFER(ref_handle),
+	     TAG_IF(event, NUTAG_REFER_EVENT(event)),
+	     TAG_END());
+
+  if (event)
+    ref->ref_event = sip_event_dup(nh->nh_home, event);
+
+  if (!nh_validate(nh->nh_nua, ref_handle)) {
+    SU_DEBUG_3(("nua: invalid NOTIFY_REFER handle\n"));
+    return -1;
+  }
+  else if (!ref->ref_event) {
+    SU_DEBUG_3(("nua: NOTIFY event missing\n"));
+    return -1;
+  }
+
+  if (ref_handle != ref->ref_handle) {
+    if (ref->ref_handle)
+      nua_handle_unref(ref->ref_handle);
+    ref->ref_handle = nua_handle_ref(ref_handle);
+  }
+
+#if 0
+  if (pause) {
+    /* Pause media on REFER handle */
+    nmedia_pause(nua, ref_handle->nh_nm, NULL);
+  }
+#endif
+
+  return 0;
+}
+
+
+static void
+nh_referral_respond(nua_handle_t *nh, int status, char const *phrase)
+{
+  char payload[128];
+  char const *substate;
+  struct nua_referral *ref = nh->nh_referral;
+
+  if (!nh_validate(nh->nh_nua, ref->ref_handle)) {
+    if (ref) {
+      if (ref->ref_handle)
+	SU_DEBUG_1(("nh_handle_referral: stale referral handle %p\n",
+		    ref->ref_handle));
+      ref->ref_handle = NULL;
+    }
+    return;
+  }
+
+  /* XXX - we should have a policy here whether to send 101..199 */
+
+  assert(ref->ref_event);
+
+  if (status >= 300)
+    status = 503, phrase = sip_503_Service_unavailable;
+
+  snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase);
+
+  if (status < 200)
+    substate = "active";
+  else
+    substate = "terminated ;reason=noresource";
+
+  nua_stack_post_signal(ref->ref_handle,
+			nua_r_notify,
+			SIPTAG_EVENT(ref->ref_event),
+			SIPTAG_SUBSCRIPTION_STATE_STR(substate),
+			SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+			SIPTAG_PAYLOAD_STR(payload),
+			TAG_END());
+
+  if (status < 200)
+    return;
+
+  su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL;
+
+  nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL;
+}
+
+
+/** Zap the session associated with the handle */
+static
+void nua_session_usage_destroy(nua_handle_t *nh,
+			       nua_session_usage_t *ss)
+{
+  nh->nh_has_invite = 0;
+  nh->nh_active_call = 0;
+  nh->nh_hold_remote = 0;
+
+  if (nh->nh_soa)
+    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+
+  /* Remove usage */
+  nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss));
+
+  SU_DEBUG_5(("nua: terminated session %p\n", nh));
+}
+
+
+/* ======================================================================== */
+/* INFO */
+
+static int process_response_to_info(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+
+/**@fn void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send an INFO request. 
+ *
+ * INFO is used to send call related information like DTMF 
+ * digit input events. See @RFC2976.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    Tags in <sip_tag.h>.
+ *
+ * @par Events:
+ *    #nua_r_info
+ *
+ * @sa #nua_i_info
+ */
+
+int
+nua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+
+  if (nh_is_special(nh)) {
+    return UA_EVENT2(e, 900, "Invalid handle for INFO");
+  }
+  else if (cr->cr_orq) {
+    return UA_EVENT2(e, 900, "Request already in progress");
+  }
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+			 SIP_METHOD_INFO ,
+			 NUTAG_ADD_CONTACT(1),
+			 TAG_NEXT(tags));
+
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_info, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(tags));
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  return cr->cr_event = e;
+}
+
+void restart_info(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_info, tags);
+}
+
+/** @NUA_EVENT nua_r_info
+ *
+ * Response to an outgoing @b INFO request.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response to @b INFO or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_info(), #nua_i_info, @RFC2976
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_info(nua_handle_t *nh,
+				    nta_outgoing_t *orq,
+				    sip_t const *sip)
+{
+  if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_info))
+    return 0;
+  return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/** @NUA_EVENT nua_i_info
+ *
+ * Incoming session INFO request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    incoming INFO request
+ * @param tags   empty
+ *
+ * @sa nua_info(), #nua_r_info, @RFC2976
+ * 
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_info(nua_t *nua,
+			   nua_handle_t *nh,
+			   nta_incoming_t *irq,
+			   sip_t const *sip)
+{
+  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+		  nua_i_info, SIP_200_OK, TAG_END());
+
+  return 200;		/* Respond automatically with 200 Ok */
+}
+
+
+/* ======================================================================== */
+/* UPDATE */
+
+static int process_response_to_update(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip);
+
+/**@fn void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Update a session. 
+ * 
+ * Update a session using SIP UPDATE method. See @RFC3311.
+ *
+ * Update method can be used when the session has been established with
+ * INVITE. It's mainly used during the session establishment when
+ * preconditions are used (@RFC3312). It can be also used during the call if
+ * no user input is needed for offer/answer negotiation.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    same as nua_invite()
+ *
+ * @par Events:
+ *    #nua_r_update \n
+ *    #nua_i_state (#nua_i_active, #nua_i_terminated)\n
+ *    #nua_i_media_error \n
+ *
+ * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
+ */
+
+int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		     tagi_t const *tags)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr;
+  msg_t *msg;
+  sip_t *sip;
+  char const *offer_sent = 0;
+
+  ss = nua_session_usage_get(ds);
+  cr = ds->ds_cr;
+
+  if (!ss)
+    return UA_EVENT2(e, 900, "Invalid handle for UPDATE");
+  else if (cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+		     SIP_METHOD_UPDATE,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     TAG_NEXT(tags));
+
+  sip = sip_object(msg);
+
+  if (sip) {
+    nua_client_request_t *cri = ss->ss_crequest;
+    nua_server_request_t *sr;
+
+    for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+      if ((sr->sr_offer_sent && !sr->sr_answer_recv) ||
+	  (sr->sr_offer_recv && !sr->sr_answer_sent))
+	break;
+    
+    if (nh->nh_soa && !sip->sip_payload && 
+	!sr &&
+	!(cri && cri->cr_offer_sent && !cri->cr_answer_recv) &&
+	!(cri && cri->cr_offer_recv && !cri->cr_answer_sent)) {
+      soa_init_offer_answer(nh->nh_soa);
+
+      if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||
+	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+	if (ss->ss_state < nua_callstate_ready) {
+	  /* XXX */
+	}
+	msg_destroy(msg);
+	return UA_EVENT2(e, 900, "Local media failed");
+      }
+
+      offer_sent = "offer";
+    }
+
+    /* Add session timer headers */
+    if (session_timer_is_supported(nh))
+      use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+
+    if (nh->nh_auth) {
+      if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
+	/* xyzzy */;
+    }
+
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_update, nh, NULL,
+				      msg,
+				      SIPTAG_END(), TAG_NEXT(tags));
+    if (cr->cr_orq) {
+      if (offer_sent)
+	cr->cr_offer_sent = 1;
+      ss->ss_update_needed = 0;
+      signal_call_state_change(nh, ss, 0, "UPDATE sent",
+			       ss->ss_state, 0, offer_sent);
+      return cr->cr_event = e;
+    }
+  }
+
+  msg_destroy(msg);
+  return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+void restart_update(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_update, tags);
+}
+
+/** @NUA_EVENT nua_r_update
+ *
+ * Answer to outgoing UPDATE.
+ *
+ * The UPDATE may be sent explicitly by nua_update() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response to UPDATE request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_update(nua_handle_t *nh,
+				       nta_outgoing_t *orq,
+				       sip_t const *sip)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+
+  int status = sip->sip_status->st_status;
+  char const *phrase = sip->sip_status->st_phrase;
+  char const *recv = NULL;
+  int terminate = 0, gracefully = 1;
+
+  ss = nua_session_usage_get(nh->nh_ds); assert(ss);
+
+  if (status >= 300) {
+    if (sip->sip_retry_after)
+      gracefully = 0;
+
+    terminate = sip_response_terminates_dialog(status, sip_method_update,
+					       &gracefully);
+
+    if (!terminate &&
+	check_session_timer_restart(nh, ss, cr, orq, sip, restart_update)) {
+      return 0;
+    }
+    /* XXX - if we have a concurrent INVITE, what we do with it? */
+  }
+  else if (status >= 200) {
+    /* XXX - check remote tag, handle forks */
+    /* Set (route), contact, (remote tag) */
+    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+    if (is_session_timer_set(ss)) {
+      init_session_timer(ss, sip, NH_PGET(nh, refresher));
+      set_session_timer(ss);
+    }
+
+    if (session_process_response(nh, cr, orq, sip, &recv) < 0) {
+      nua_stack_event(nua, nh, NULL, nua_i_error,
+	       400, "Bad Session Description", TAG_END());
+    }
+
+    signal_call_state_change(nh, ss, status, phrase, ss->ss_state, recv, 0);
+
+    return 0;
+  }
+  else
+    gracefully = 0;
+
+  nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+  if (!terminate && !gracefully)
+    return 0;
+
+  nh_referral_respond(nh, status, phrase);
+  
+  if (ss == NULL) {
+
+  } 
+  else if (terminate || 
+      (ss->ss_state < nua_callstate_completed &&
+       ss->ss_state != nua_callstate_completing)) {
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_terminated, recv, 0);
+    nua_session_usage_destroy(nh, ss);
+  }
+  else /* if (gracefully) */ {
+    signal_call_state_change(nh, ss, status, phrase,
+			     nua_callstate_terminating, recv, 0);
+#if 0
+    if (nh->nh_ss->ss_crequest->cr_orq)
+      nua_stack_post_signal(nh, nua_r_cancel, TAG_END());
+    else
+#endif
+      nua_stack_post_signal(nh, nua_r_bye, TAG_END());
+  }
+
+  return 0;
+}
+
+int nua_stack_process_update(nua_t *nua,
+			     nua_handle_t *nh,
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_session_usage_t *ss;
+  nua_dialog_usage_t *du;
+  msg_t *msg = nta_incoming_getrequest(irq);
+
+  char const *sdp;
+  size_t len;
+
+  int original_status = 200, status = 200;
+  char const *phrase = sip_200_OK;
+
+  char const *offer_recv = NULL, *answer_sent = NULL;
+  int use_timer = 0;
+
+  msg_t *rmsg;
+  sip_t *rsip;
+
+  ss = nua_session_usage_get(ds); du = nua_dialog_usage_public(ss);
+  if (!ss) {
+    /* RFC 3261 section 12.2.2:
+       If the UAS wishes to reject the request because it does not wish to
+       recreate the dialog, it MUST respond to the request with a 481
+       (Call/Transaction Does Not Exist) status code and pass that to the
+       server transaction.
+    */
+    return 481;
+  }
+
+  if (session_check_request(nua, nh, irq, sip))
+    return 501;
+
+  /* Do session timer negotiation */
+  if (sip->sip_session_expires) {
+    use_timer = 1;
+    init_session_timer(ss, sip, NH_PGET(nh, refresher));
+  }
+
+  if (status < 300 && nh->nh_soa &&
+      session_get_description(sip, &sdp, &len)) {
+    nua_client_request_t *cr;
+    nua_server_request_t *sr;
+    int overlap = 0;
+
+    /*
+      A UAS that receives an UPDATE before it has generated a final
+      response to a previous UPDATE on the same dialog MUST return a 500
+      response to the new UPDATE, and MUST include a Retry-After header
+      field with a randomly chosen value between 0 and 10 seconds.
+
+      If an UPDATE is received that contains an offer, and the UAS has
+      generated an offer (in an UPDATE, PRACK or INVITE) to which it has
+      not yet received an answer, the UAS MUST reject the UPDATE with a 491
+      response.  Similarly, if an UPDATE is received that contains an
+      offer, and the UAS has received an offer (in an UPDATE, PRACK, or
+      INVITE) to which it has not yet generated an answer, the UAS MUST
+      reject the UPDATE with a 500 response, and MUST include a Retry-After
+      header field with a randomly chosen value between 0 and 10 seconds.
+    */
+    for (cr = ds->ds_cr; cr && !overlap; cr = cr->cr_next)
+      overlap = cr->cr_offer_sent && !cr->cr_answer_recv;
+    for (sr = ds->ds_sr; sr && !overlap; sr = sr->sr_next)
+      overlap = (sr->sr_offer_recv && !sr->sr_answer_sent) ||
+	(sr->sr_method == sip_method_update && sr->sr_respond);
+
+    if (overlap)
+      return respond_with_retry_after(nh, irq, 
+				      500, "Overlapping Offer/Answer",
+				      0, 10);
+
+    offer_recv = "offer";
+
+    if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+      SU_DEBUG_5(("nua(%p): error parsing SDP in UPDATE\n", nh));
+      msg_destroy(msg);
+      status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+      offer_recv = NULL;
+    }
+    /* Respond to UPDATE */
+    else if (soa_generate_answer(nh->nh_soa, NULL) < 0) {
+      SU_DEBUG_5(("nua(%p): error processing SDP in UPDATE\n", nh));
+      msg_destroy(msg);
+      status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+    }
+    else if (soa_activate(nh->nh_soa, NULL) < 0) {
+      SU_DEBUG_5(("nua(%p): error activating media after %s\n",
+		  nh, "UPDATE"));
+      /* XXX */
+    }
+    else {
+      answer_sent = "answer";
+    }
+  }
+
+  rmsg = nh_make_response(nua, nh, irq,
+			  status, phrase,
+			  TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)),
+			  SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+			  TAG_NEXT(NULL));
+  rsip = sip_object(rmsg);
+  assert(sip);			/* XXX */
+
+  if (answer_sent && 
+      session_include_description(nh->nh_soa, 1, rmsg, rsip) < 0) {
+    status = 500, phrase = sip_500_Internal_server_error;
+    answer_sent = NULL;
+  }
+
+  if (200 <= status && status < 300 && session_timer_is_supported(nh)) {
+    use_session_timer(ss, 1, use_timer, rmsg, rsip);
+    set_session_timer(ss);
+  }
+
+  if (status == original_status) {
+    if (nta_incoming_mreply(irq, rmsg) < 0)
+      status = 500, phrase = sip_500_Internal_server_error;
+  }
+
+  if (status != original_status) {
+    nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END());
+    nta_incoming_treply(irq, status, phrase, TAG_END());
+    msg_destroy(rmsg), rmsg = NULL;
+  }
+
+/** @NUA_EVENT nua_i_update
+ *
+ * @brief Incoming session UPDATE request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    incoming UPDATE request
+ * @param tags   empty
+ *
+ * @sa nua_update(), #nua_r_update, #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+  nua_stack_event(nh->nh_nua, nh, msg, nua_i_update, status, phrase, TAG_END());
+
+  if (offer_recv || answer_sent)
+    /* signal offer received, answer sent */
+    signal_call_state_change(nh, ss, 200, "OK", ss->ss_state,
+			     offer_recv, answer_sent);
+
+  if (NH_PGET(nh, auto_alert)
+      && ss->ss_state < nua_callstate_ready
+      && !ss->ss_alerting
+      && ss->ss_precondition) {
+    nua_server_request_t *sr;
+    
+    for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+      if (sr->sr_method == sip_method_invite && 
+	  sr->sr_usage == du && sr->sr_respond)
+	break;
+
+    if (sr)
+      nua_server_respond(sr, SIP_180_RINGING, TAG_END());
+  }
+
+  return status;
+}
+
+
+/* ======================================================================== */
+/* BYE */
+
+static int process_response_to_bye(nua_handle_t *nh,
+				   nta_outgoing_t *orq,
+				   sip_t const *sip);
+
+/**@fn void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Hangdown a call.
+ *
+ * Hangdown a call using SIP BYE method. Also the media session 
+ * associated with the call is terminated. 
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    none
+ *
+ * @par Events:
+ *    #nua_r_bye \n
+ *    #nua_i_media_error
+ */
+
+int
+nua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+  nua_session_usage_t *ss;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+  nta_outgoing_t *orq;
+
+  ss = nua_session_usage_get(nh->nh_ds);
+  
+  if (!ss || ss->ss_state >= nua_callstate_terminating)
+    return UA_EVENT2(e, 900, "Invalid handle for BYE");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  if (!nua_dialog_is_established(nh->nh_ds)) {
+    nua_client_request_t *cri = ss->ss_crequest;
+
+    if (cri->cr_orq == NULL)
+      return UA_EVENT2(e, 900, "No session to BYE");
+
+    /* No (early) dialog. BYE is invalid action, do CANCEL instead */
+    orq = nta_outgoing_tcancel(cri->cr_orq,
+			       process_response_to_cancel, nh,
+			       TAG_NEXT(tags));
+    if (!cr->cr_orq)
+      cr->cr_orq = orq, cr->cr_event = e;
+
+    return 0;
+  }
+
+  if (cr->cr_orq) {
+    if (cr->cr_usage == nua_dialog_usage_public(ss)) {
+      nua_creq_deinit(cr, cr->cr_orq);
+    }
+    else {
+      cr = ss->ss_crequest;
+      if (cr->cr_orq)
+	nua_creq_deinit(cr, cr->cr_orq);
+    }
+  }
+
+  assert(!cr->cr_orq);
+
+  msg = nua_creq_msg(nua, nh, cr, 0, SIP_METHOD_BYE, TAG_NEXT(tags));
+
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_bye, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(tags));
+
+  ss->ss_state = nua_callstate_terminating;
+  if (nh->nh_soa)
+    soa_terminate(nh->nh_soa, 0);
+
+  if (cr->cr_orq) {
+    cr->cr_event = e;
+  }
+  else {
+    msg_destroy(msg);
+    UA_EVENT2(e, 400, "Internal error");
+    signal_call_state_change(nh, ss, 400, "Failure sending BYE",
+			     nua_callstate_terminated, 0, 0);
+    nua_session_usage_destroy(nh, ss);
+  }
+
+  return 0;
+}
+
+
+void restart_bye(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_bye, tags);
+}
+
+/** @NUA_EVENT nua_r_bye
+ *
+ * Answer to outgoing BYE.
+ *
+ * The BYE may be sent explicitly by nua_bye() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    response to BYE request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   empty
+ *
+ * @sa nua_bye(), @ref nua_call_model, #nua_i_state, #nua_r_invite()
+ * 
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_bye(nua_handle_t *nh,
+				   nta_outgoing_t *orq,
+				   sip_t const *sip)
+{
+  nua_client_request_t *cr = NULL;
+  nua_session_usage_t *ss;
+  int status = sip ? sip->sip_status->st_status : 400;
+  char const *phrase = sip ? sip->sip_status->st_phrase : "";
+
+  cr = nua_client_request_by_orq(nh->nh_ds->ds_cr, orq); assert(cr);
+
+  if (cr) {
+    if (nua_creq_check_restart(nh, cr, orq, sip, restart_bye))
+      return 0;
+    nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+  }
+  else {			/* No cr for BYE */
+    msg_t *msg = nta_outgoing_getresponse(orq);
+    nua_stack_event(nh->nh_nua, nh, msg, nua_r_bye, status, phrase, TAG_END());
+    nta_outgoing_destroy(orq);
+  }
+
+  ss = nua_session_usage_get(nh->nh_ds);
+
+  if (status >= 200 && ss) {
+    if (ss->ss_crequest->cr_orq) {
+      /* Do not destroy usage while INVITE is alive */
+    }
+    else {
+      signal_call_state_change(nh, ss, status, "to BYE",
+			       nua_callstate_terminated, 0, 0);
+      nua_session_usage_destroy(nh, ss);
+    }
+  }
+
+  return 0;
+}
+
+
+/** @NUA_EVENT nua_i_bye
+ *
+ * Incoming BYE request, call hangup.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    pointer to BYE request
+ * @param tags   empty
+ *
+ * @sa @ref nua_call_model, #nua_i_state, nua_bye(), nua_bye(), #nua_r_cancel
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_bye(nua_t *nua,
+			  nua_handle_t *nh,
+			  nta_incoming_t *irq,
+			  sip_t const *sip)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_session_usage_t *ss;
+  nua_server_request_t *sr, *sr_next;
+  int early = 0;
+
+  ss = nua_session_usage_get(ds);
+  if (!ss)
+    return 481;
+
+  assert(nh && ss);
+
+  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+		  nua_i_bye, SIP_200_OK, TAG_END());
+  nta_incoming_treply(irq, SIP_200_OK, TAG_END());
+  nta_incoming_destroy(irq), irq = NULL;
+
+  for (sr = ds->ds_sr; sr; sr = sr_next) {
+    sr_next = sr->sr_next;
+    if (sr->sr_respond && sr->sr_usage == nua_dialog_usage_public(ss)) {
+      char const *phrase;
+      early = ss->ss_state < nua_callstate_ready;
+      phrase = early ? "Early Session Terminated" : "Session Terminated";
+      sr->sr_usage = NULL;
+      if (sr->sr_respond)
+	nua_server_respond(sr, 487, phrase, TAG_END());
+      else
+	nua_server_request_destroy(sr);
+    }
+  }
+
+  signal_call_state_change(nh, ss, 200,
+			   early ? "Received early BYE" : "Received BYE",
+			   nua_callstate_terminated, 0, 0);
+
+  nua_session_usage_destroy(nh, ss);
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Delivers call state changed event to the nua client. @internal
+ *
+ * @param nh call handle
+ * @param status status code
+ * @param tr_event SIP transaction event triggering this change
+ * @param oa_recv Received SDP
+ * @param oa_sent Sent SDP
+ */
+
+static void signal_call_state_change(nua_handle_t *nh,
+				     nua_session_usage_t *ss,
+				     int status, char const *phrase,
+				     enum nua_callstate next_state,
+				     char const *oa_recv,
+				     char const *oa_sent)
+{
+  enum nua_callstate ss_state;
+
+  sdp_session_t const *remote_sdp = NULL;
+  char const *remote_sdp_str = NULL;
+  sdp_session_t const *local_sdp = NULL;
+  char const *local_sdp_str = NULL;
+
+  int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
+
+  ss_state = ss ? ss->ss_state : nua_callstate_init;
+
+  if (ss_state < nua_callstate_ready || next_state > nua_callstate_ready)
+    SU_DEBUG_5(("nua(%p): call state changed: %s -> %s%s%s%s%s\n",
+		nh, nua_callstate_name(ss_state),
+		nua_callstate_name(next_state),
+		oa_recv ? ", received " : "", oa_recv ? oa_recv : "",
+		oa_sent && oa_recv ? ", and sent " :
+		oa_sent ? ", sent " : "", oa_sent ? oa_sent : ""));
+  else
+    SU_DEBUG_5(("nua(%p): ready call updated: %s%s%s%s%s\n",
+		nh, nua_callstate_name(next_state),
+		oa_recv ? " received " : "", oa_recv ? oa_recv : "",
+		oa_sent && oa_recv ? ", sent " :
+		oa_sent ? " sent " : "", oa_sent ? oa_sent : ""));
+
+  if (oa_recv) {
+    soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0);
+    offer_recv = strcasecmp(oa_recv, "offer") == 0;
+    answer_recv = strcasecmp(oa_recv, "answer") == 0;
+  }
+
+  if (oa_sent) {
+    soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0);
+    offer_sent = strcasecmp(oa_sent, "offer") == 0;
+    answer_sent = strcasecmp(oa_sent, "answer") == 0;
+  }
+
+  if (answer_recv || answer_sent) {
+    /* Update nh_hold_remote */
+
+    char const *held;
+
+    soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held), TAG_END());
+
+    nh->nh_hold_remote = held && strlen(held) > 0;
+  }
+
+  if (ss) {
+    /* Update state variables */
+    if (next_state > ss_state)
+      ss->ss_state = next_state;
+    else if (next_state == nua_callstate_init && ss_state < nua_callstate_ready)
+      ss->ss_state = nua_callstate_init, next_state = nua_callstate_terminated;
+  }
+
+  if (ss && ss->ss_state == nua_callstate_ready)
+    nh->nh_active_call = 1;
+  else if (next_state == nua_callstate_terminated)
+    nh->nh_active_call = 0;
+
+  /* Send events */
+  if (phrase == NULL)
+    phrase = "Call state";
+
+/** @NUA_EVENT nua_i_state
+ *
+ * @brief Call state has changed.
+ *
+ * This event will be sent whenever the call state changes. 
+ *
+ * In addition to basic changes of session status indicated with enum
+ * ::nua_callstate, the @RFC3264 SDP Offer/Answer negotiation status is also
+ * included if it is enabled (by default or with NUTAG_MEDIA_ENABLE(1)). The
+ * received remote SDP is included in tag SOATAG_REMOTE_SDP(). The tags
+ * NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV() indicate whether the remote SDP
+ * was an offer or an answer. The SDP negotiation result is included in the
+ * tags SOATAG_LOCAL_SDP() and SOATAG_LOCAL_SDP_STR() and tags
+ * NUTAG_OFFER_SENT() or NUTAG_ANSWER_SENT() indicate whether the local SDP
+ * was an offer or answer.
+ *
+ * SOATAG_ACTIVE_AUDIO() and SOATAG_ACTIVE_VIDEO() are informational tags
+ * used to indicate what is the status of audio or video.
+ *
+ * Note that #nua_i_state also covers call establisment events
+ * (#nua_i_active) and termination (#nua_i_terminated).
+ *
+ * @param status protocol status code \n
+ *               (always present)
+ * @param phrase short description of status code \n
+ *               (always present)
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    NULL
+ * @param tags   NUTAG_CALLSTATE(), 
+ *               SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
+ *               NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT(),
+ *               SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
+ *               NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
+ *               SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
+ *               SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
+ *
+ * @sa @ref nua_call_model, #nua_i_active, #nua_i_terminated,
+ * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(), 
+ * NUTAG_AUTOALERT(), NUTAG_AUTOANSWER(), NUTAG_EARLY_MEDIA(),
+ * NUTAG_EARLY_ANSWER(), NUTAG_INCLUDE_EXTRA_SDP(),
+ * nua_ack(), NUTAG_AUTOACK(), nua_bye(), #nua_r_bye, #nua_i_bye,
+ * nua_cancel(), #nua_r_cancel, #nua_i_cancel,
+ * nua_prack(), #nua_r_prack, #nua_i_prack,
+ * nua_update(), #nua_r_update, #nua_i_update
+ *
+ * @END_NUA_EVENT
+ */
+
+  nua_stack_event(nh->nh_nua, nh, NULL, nua_i_state,
+		  status, phrase,
+		  NUTAG_CALLSTATE(next_state),
+		  NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+		  /* NUTAG_SOA_SESSION(nh->nh_soa), */
+		  TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv)),
+		  TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv)),
+		  TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent)),
+		  TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent)),
+		  TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp)),
+		  TAG_IF(oa_recv, SOATAG_REMOTE_SDP_STR(remote_sdp_str)),
+		  TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp)),
+		  TAG_IF(oa_sent, SOATAG_LOCAL_SDP_STR(local_sdp_str)),
+		  TAG_END());
+
+/** @NUA_EVENT nua_i_active
+ *
+ * A call has been activated.
+ *
+ * This event will be sent after a succesful response to the initial
+ * INVITE has been received and the media has been activated.
+ *
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    NULL
+ * @param tags   SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
+ *               SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
+ *
+ * @deprecated Use #nua_i_state instead.
+ *
+ * @sa @ref nua_call_model, #nua_i_state, #nua_i_terminated, 
+ * #nua_i_invite
+ *
+ * @END_NUA_EVENT
+ */
+
+  if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) {
+    nua_stack_event(nh->nh_nua, nh, NULL, nua_i_active, status, "Call active",
+	     NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+	     /* NUTAG_SOA_SESSION(nh->nh_soa), */
+	     TAG_END());
+  }
+
+/** @NUA_EVENT nua_i_terminated
+ *
+ * A call has been terminated.
+ *
+ * This event will be sent after a call has been terminated. A call is
+ * terminated, when
+ * 1) an error response (300..599) is sent to an incoming initial INVITE
+ * 2) a reliable response (200..299 or reliable preliminary response) to
+ *    an incoming initial INVITE is not acknowledged with ACK or PRACK
+ * 3) BYE is received or sent
+ *
+ * @param nh     operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip    NULL
+ * @param tags   empty
+ *
+ * @deprecated Use #nua_i_state instead.
+ *
+ * @sa @ref nua_call_model, #nua_i_state, #nua_i_active, #nua_i_bye,
+ * #nua_i_invite
+ *
+ * @END_NUA_EVENT
+ */
+
+  else if (next_state == nua_callstate_terminated) {
+    nua_stack_event(nh->nh_nua, nh, NULL, nua_i_terminated, status, phrase,
+	     TAG_END());
+  }
+}
+
+/* ======================================================================== */
+
+static
+int respond_with_retry_after(nua_handle_t *nh, nta_incoming_t *irq,
+			     int status, char const *phrase,
+			     int min, int max)
+{
+  sip_retry_after_t af[1];
+
+  sip_retry_after_init(af);
+  af->af_delta = (unsigned)su_randint(min, max);
+  af->af_comment = phrase;
+
+  nta_incoming_treply(irq, status, phrase,
+		      SIPTAG_RETRY_AFTER(af),
+		      SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)),
+		      TAG_END());
+
+  return 500;
+}
+
+/* ======================================================================== */
+
+/** Get SDP from a SIP message */
+static
+int session_get_description(sip_t const *sip,
+			    char const **return_sdp,
+			    size_t *return_len)
+{
+  sip_payload_t const *pl = sip->sip_payload;
+  sip_content_type_t const *ct = sip->sip_content_type;
+  int matching_content_type = 0;
+
+  if (pl == NULL)
+    return 0;
+  else if (pl->pl_len == 0 || pl->pl_data == NULL)
+    return 0;
+  else if (ct == NULL)
+    /* Be bug-compatible with our old gateways */
+    SU_DEBUG_3(("nua: no %s, assuming %s\n",
+		"Content-Type", SDP_MIME_TYPE));
+  else if (ct->c_type == NULL)
+    SU_DEBUG_3(("nua: empty %s, assuming %s\n",
+		"Content-Type", SDP_MIME_TYPE));
+  else if (strcasecmp(ct->c_type, SDP_MIME_TYPE)) {
+    SU_DEBUG_5(("nua: unknown %s: %s\n", "Content-Type", ct->c_type));
+    return 0;
+  }
+  else
+    matching_content_type = 1;
+
+  if (pl == NULL)
+    return 0;
+
+  if (!matching_content_type) {
+    /* Make sure we got SDP */
+    if (pl->pl_len < 3 || strncasecmp(pl->pl_data, "v=0", 3))
+      return 0;
+  }
+
+  *return_sdp = pl->pl_data;
+  *return_len = pl->pl_len;
+
+  return 1;
+}
+
+/** Insert SDP into SIP message */
+static
+int session_include_description(soa_session_t *soa,
+				int session,
+				msg_t *msg,
+				sip_t *sip)
+{
+  su_home_t *home = msg_home(msg);
+
+  sip_content_disposition_t *cd = NULL;
+  sip_content_type_t *ct = NULL;
+  sip_payload_t *pl = NULL;
+
+  int retval;
+
+  if (!soa)
+    return 0;
+
+  retval = session_make_description(home, soa, session, &cd, &ct, &pl);
+
+  if (retval <= 0)
+    return retval;
+
+  if ((cd && sip_header_insert(msg, sip, (sip_header_t *)cd) < 0) ||
+      sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 ||
+      sip_header_insert(msg, sip, (sip_header_t *)pl) < 0)
+    return -1;
+
+  return retval;
+}
+
+/** Generate SDP headers */
+static
+int session_make_description(su_home_t *home,
+			     soa_session_t *soa,
+			     int session,
+			     sip_content_disposition_t **return_cd,
+			     sip_content_type_t **return_ct,
+			     sip_payload_t **return_pl)
+{
+  char const *sdp;
+  isize_t len;
+  int retval;
+
+  if (!soa)
+    return 0;
+
+  if (session)
+    retval = soa_get_local_sdp(soa, 0, &sdp, &len);
+  else
+    retval = soa_get_capability_sdp(soa, 0, &sdp, &len);
+
+  if (retval > 0) {
+    *return_pl = sip_payload_create(home, sdp, len);
+    *return_ct = sip_content_type_make(home, SDP_MIME_TYPE);
+    if (session)
+      *return_cd = sip_content_disposition_make(home, "session");
+    else
+      *return_cd = NULL;
+
+    if (!*return_pl || !*return_cd)
+      return -1;
+
+    if (session && !*return_cd)
+      return -1;
+  }
+
+  return retval;
+}
+
+/**
+ * Stores and processes SDP from incoming response, then calls
+ * nua_stack_process_response().
+ *
+ * @retval 1 if there was SDP to process.
+ */
+static
+int session_process_response(nua_handle_t *nh,
+			     nua_client_request_t *cr,
+			     nta_outgoing_t *orq,
+			     sip_t const *sip,
+			     char const **return_received)
+{
+  char const *method = nta_outgoing_method_name(orq);
+  msg_t *msg = nta_outgoing_getresponse(orq);
+  int retval = 0;
+  char const *sdp = NULL;
+  size_t len;
+
+  if (nh->nh_soa == NULL)
+    /* Xyzzy */;
+  else if (!session_get_description(sip, &sdp, &len))
+    /* No SDP */;
+  else if (cr->cr_answer_recv) {
+    /* Ignore spurious answers after completing O/A */
+    SU_DEBUG_3(("nua(%p): %s: ignoring duplicate SDP in %u %s\n",
+		nh, method,
+		sip->sip_status->st_status, sip->sip_status->st_phrase));
+    sdp = NULL;
+  }
+  else if (!cr->cr_offer_sent &&
+	   nta_outgoing_method(orq) != sip_method_invite) {
+    /* If non-invite request did not have offer, ignore SDP in response */
+    SU_DEBUG_3(("nua(%p): %s: ignoring extra SDP in %u %s\n",
+		nh, method,
+		sip->sip_status->st_status, sip->sip_status->st_phrase));
+    sdp = NULL;
+  }
+  else {
+    if (cr->cr_offer_sent) {
+      cr->cr_answer_recv = sip->sip_status->st_status;
+      *return_received = "answer";
+    }
+    else {
+      cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
+      *return_received = "offer";
+    }
+
+    if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+      SU_DEBUG_5(("nua(%p): %s: error parsing SDP in %u %s\n",
+		  nh, method,
+		  sip->sip_status->st_status,
+		  sip->sip_status->st_phrase));
+      retval = -1;
+      sdp = NULL;
+    }
+    else if (cr->cr_offer_recv) {
+      /* note: case 1: incoming offer */
+      SU_DEBUG_5(("nua(%p): %s: get SDP %s in %u %s\n",
+		  nh, method, "offer",
+		  sip->sip_status->st_status,
+		  sip->sip_status->st_phrase));
+      retval = 1;
+    }
+    else if (soa_process_answer(nh->nh_soa, NULL) < 0) {
+      SU_DEBUG_5(("nua(%p): %s: error processing SDP answer in %u %s\n",
+		  nh, method,
+		  sip->sip_status->st_status,
+		  sip->sip_status->st_phrase));
+      sdp = NULL;
+    }
+    else {
+      /* note: case 2: answer to our offer */
+      if (soa_activate(nh->nh_soa, NULL) < 0) {
+	SU_DEBUG_3(("nua(%p): %s: error activating media after %u %s\n",
+		    nh, method,
+		    sip->sip_status->st_status,
+		    sip->sip_status->st_phrase));
+	/* XXX */
+      }
+      else {
+	SU_DEBUG_5(("nua(%p): %s: processed SDP answer in %u %s\n",
+		    nh, method,
+		    sip->sip_status->st_status,
+		    sip->sip_status->st_phrase));
+      }
+
+      assert(!cr->cr_offer_recv);
+    }
+  }
+
+  msg_destroy(msg);		/* unref */
+
+  nua_stack_process_response(nh, cr, orq, sip,
+			     NH_REMOTE_MEDIA_TAGS(sdp != NULL, nh->nh_soa),
+			     TAG_END());
+
+  return retval;
+}
+
+#if 0
+/** Parse and store SDP from incoming request */
+static
+int session_process_request(nua_handle_t *nh,
+			    nta_incoming_t *irq,
+			    sip_t const *sip)
+{
+  char const *sdp = NULL;
+  isize_t len;
+
+  if (nh->nh_soa) {
+    msg_t *msg = nta_outgoing_getresponse(irq);
+
+    if (session_get_description(msg, sip, &sdp, &len)) {
+      if (soa_is_complete(nh->nh_soa)) {
+	/* Ignore spurious answers after completing O/A */
+	SU_DEBUG_5(("nua: ignoring duplicate SDP in %u %s\n",
+		    sip->sip_status->st_status, sip->sip_status->st_phrase));
+	sdp = NULL;
+      }
+      else if (soa_parse_sdp(nh->nh_soa, sdp, len) < 0) {
+	SU_DEBUG_5(("nua: error parsing SDP in %u %s\n",
+		    sip->sip_status->st_status,
+		    sip->sip_status->st_phrase));
+	sdp = NULL;
+      }
+    }
+
+    msg_destroy(msg);
+  }
+
+  return
+    nua_stack_process_response(nh, cr, orq, sip,
+			       NH_REMOTE_MEDIA_TAGS(sdp != NULL, nh->nh_soa),
+			       TAG_END());
+}
+#endif
+
+static int respond_to_options(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_options
+ *
+ * Incoming OPTIONS request. The user-agent should respond to an OPTIONS
+ * request with the same statuscode as it would respond to an INVITE
+ * request.
+ *
+ * Stack responds automatically to OPTIONS request unless OPTIONS is
+ * included in the set of application methods, set by NUTAG_APPL_METHOD().
+ *
+ * The OPTIONS request does not create a dialog. Currently the processing
+ * of incoming OPTIONS creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the OPTIONS
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the OPTIONS request
+ * @param hmagic application context associated with the call
+ *               (NULL if outside session)
+ * @param sip    incoming OPTIONS request
+ * @param tags   empty
+ *
+ * @sa nua_respond(), nua_options(), #nua_r_options, @RFC3261 section 11.2
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_options(nua_t *nua,
+			      nua_handle_t *nh,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  nua_server_request_t *sr, sr0[1];
+  int done;
+
+  /* Hook to outbound */
+  done = nua_registration_process_request(nua->nua_registrations, irq, sip);
+  if (done)
+    return done;
+
+  sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
+			  respond_to_options, 0);
+
+  SR_STATUS1(sr, SIP_200_OK);
+
+  return nua_stack_server_event(nua, sr, nua_i_options, TAG_END());
+}
+
+/** @internal Respond to an OPTIONS request.
+ *
+ */
+static int respond_to_options(nua_server_request_t *sr, tagi_t const *tags)
+{
+  nua_handle_t *nh = sr->sr_owner;
+  nua_t *nua = nh->nh_nua;
+  msg_t *msg;
+  int final;
+
+  msg = nua_server_response(sr,
+			    sr->sr_status, sr->sr_phrase,
+			    SIPTAG_ALLOW(NH_PGET(nh, allow)),
+			    SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+			    TAG_IF(NH_PGET(nh, path_enable),
+				   SIPTAG_SUPPORTED_STR("path")),
+			    SIPTAG_ACCEPT_STR(SDP_MIME_TYPE),
+			    TAG_NEXT(tags));
+
+  final = sr->sr_status >= 200;
+
+  if (msg) {
+    sip_t *sip = sip_object(msg);
+
+    if (!sip->sip_payload) {	/* XXX - do MIME multipart? */
+      soa_session_t *soa = nh->nh_soa;
+
+      if (soa == NULL)
+	soa = nua->nua_dhandle->nh_soa;
+
+      session_include_description(soa, 0, msg, sip);
+    }
+
+    if (nta_incoming_mreply(sr->sr_irq, msg) < 0)
+      final = 1;
+  }
+
+  return final;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_stack.c
+ * @brief Sofia-SIP User Agent Engine implementation
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ * @author Remeres Jacobs <Remeres.Jacobs at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_ROOT_MAGIC_T   struct nua_s
+#define SU_MSG_ARG_T      struct event_s
+
+#define NUA_SAVED_EVENT_T su_msg_t *
+
+#define NTA_AGENT_MAGIC_T    struct nua_s
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_handle_s
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/auth_client.h>
+
+#include <sofia-sip/soa.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <assert.h>
+
+/* ========================================================================
+ *
+ *                       Protocol stack side
+ *
+ * ======================================================================== */
+
+nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);
+static void nh_append(nua_t *nua, nua_handle_t *nh);
+static void nh_remove(nua_t *nua, nua_handle_t *nh);
+
+static int nh_authorize(nua_handle_t *nh,
+			tag_type_t tag, tag_value_t value, ...);
+
+static int nh_challenge(nua_handle_t *nh, sip_t const *sip);
+
+static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);
+
+/* ---------------------------------------------------------------------- */
+/* Constant data */
+
+/**@internal Default internal error. */
+char const nua_internal_error[] = "Internal NUA Error";
+
+char const nua_application_sdp[] = "application/sdp";
+
+#define NUA_STACK_TIMER_INTERVAL (1000)
+
+/* ----------------------------------------------------------------------
+ * Initialization & deinitialization
+ */
+
+int nua_stack_init(su_root_t *root, nua_t *nua)
+{
+  su_home_t *home;
+  nua_handle_t *dnh;
+
+  static int initialized_logs = 0;
+
+  enter;
+
+  if (!initialized_logs) {
+    extern su_log_t tport_log[];
+    extern su_log_t nta_log[];
+    extern su_log_t nea_log[];
+    extern su_log_t iptsec_log[];
+
+    su_log_init(tport_log);
+    su_log_init(nta_log);
+    su_log_init(nea_log);
+    su_log_init(iptsec_log);
+
+    initialized_logs = 1;
+  }
+
+  nua->nua_root = root;
+  nua->nua_timer = su_timer_create(su_root_task(root),
+				   NUA_STACK_TIMER_INTERVAL);
+  if (!nua->nua_timer)
+    return -1;
+
+  home = nua->nua_home;
+  nua->nua_handles_tail = &nua->nua_handles;
+  sip_from_init(nua->nua_from);
+
+  dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
+  if (!dnh)
+    return -1;
+
+  dnh->nh_prefs = (void *)(dnh + 1);
+  dnh->nh_valid = nua_handle;
+  dnh->nh_nua = nua;
+  nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1; 
+  nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
+  nh_append(nua, dnh);
+  dnh->nh_identity = dnh;
+  dnh->nh_ds->ds_local = nua->nua_from;
+  dnh->nh_ds->ds_remote = nua->nua_from;
+
+  if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
+    return -1;
+
+  if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
+    return -1;
+
+  nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);
+
+  nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
+				  NTATAG_MERGE_482(1),
+				  NTATAG_CLIENT_RPORT(1),
+				  NTATAG_UA(1),
+#if HAVE_SOFIA_SMIME
+				  NTATAG_SMIME(nua->sm),
+#endif
+				  TPTAG_STUN_SERVER(1),
+				  TAG_NEXT(nua->nua_args));
+
+  dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
+				       nua_stack_process_request, dnh,
+				       NTATAG_NO_DIALOG(1),
+				       TAG_END());
+
+  if (nua->nua_nta == NULL ||
+      dnh->nh_ds->ds_leg == NULL || 
+      nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
+      nua_stack_init_transport(nua, nua->nua_args) < 0) {
+    SU_DEBUG_1(("nua: initializing SIP stack failed\n"));
+    return -1;
+  }
+
+  if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
+    return -1;
+
+  if (NHP_ISSET(dnh->nh_prefs, detect_network_updates))
+    nua_stack_launch_network_change_detector(nua);
+
+  nua_stack_timer(nua, nua->nua_timer, NULL);
+
+  return 0;
+}
+
+void nua_stack_deinit(su_root_t *root, nua_t *nua)
+{
+  enter;
+
+  su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
+  nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * Sending events to client application
+ */
+
+static void nua_stack_shutdown(nua_t *);
+
+void
+  nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+  nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *),
+  nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *);
+
+/* Notifier */
+void
+  nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+  nua_stack_notifier(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+  nua_stack_terminate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *);
+
+int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev,
+			 tag_type_t t, tag_value_t v, ...);
+
+/** @internal Send an event to the application. */
+int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+		    nua_event_t event, int status, char const *phrase,
+		    tag_type_t tag, tag_value_t value, ...)
+{
+  su_msg_r sumsg = SU_MSG_R_INIT;
+
+  ta_list ta;
+  size_t e_len, len, xtra, p_len;
+
+  if (event == nua_r_ack || event == nua_i_none)
+    return event;
+
+  enter;
+
+  if (nua_log->log_level >= 5) {
+    char const *name = nua_event_name(event) + 4;
+    char const *p = phrase ? phrase : "";
+
+    if (status == 0)
+      SU_DEBUG_5(("nua(%p): %s %s\n", nh, name, p));
+    else
+      SU_DEBUG_5(("nua(%p): %s %u %s\n", nh, name, status, p));
+  }
+
+  if (event == nua_r_destroy) {
+    if (msg)
+      msg_destroy(msg);
+    if (status >= 200) {
+      nh_destroy(nua, nh);
+    }
+    return event;
+  }
+
+  if ((event > nua_r_authenticate && event <= nua_r_ack)
+      || event < nua_i_error
+      || (nh && !nh->nh_valid)
+      || (nua->nua_shutdown && event != nua_r_shutdown)) {
+    if (msg)
+      msg_destroy(msg);
+    return event;
+  }
+
+  ta_start(ta, tag, value);
+
+  e_len = offsetof(event_t, e_tags);
+  len = tl_len(ta_args(ta));
+  xtra = tl_xtra(ta_args(ta), len);
+  p_len = phrase ? strlen(phrase) + 1 : 1;
+
+  if (su_msg_create(sumsg, nua->nua_client, su_task_null,
+		    nua_event, e_len + len + xtra + p_len) == 0) {
+    event_t *e = su_msg_data(sumsg);
+
+    tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len);
+    void *b = t_end, *end = (char *)b + xtra;
+
+    t = tl_dup(t, ta_args(ta), &b);
+    assert(t == t_end); assert(b == end);
+
+    e->e_event = event;
+    e->e_nh = nh ? nua_handle_ref(nh) : nua->nua_dhandle;
+    e->e_status = status;
+    e->e_phrase = strcpy(end, phrase ? phrase : "");
+    if (msg)
+      e->e_msg = msg, su_home_threadsafe(msg_home(msg));
+
+    if (su_msg_send(sumsg) != 0)
+      nua_handle_unref(nh);
+  }
+
+  ta_end(ta);
+
+  return event;
+}
+
+/* ----------------------------------------------------------------------
+ * Post signal to stack itself
+ */
+void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  ta_start(ta, tag, value);
+  nua_signal((nh)->nh_nua, nh, NULL, 1, event, 0, NULL, ta_tags(ta));
+  ta_end(ta);
+}
+
+
+/* ----------------------------------------------------------------------
+ * Receiving events from client
+ */
+void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
+{
+  nua_handle_t *nh = e->e_nh;
+  tagi_t *tags = e->e_tags;
+
+  assert(tags);
+
+  if (nh) {
+    if (!nh->nh_prev)
+      nh_append(nua, nh);
+    if (!nh->nh_ref_by_stack) {
+      /* Mark handle as used by stack */
+      nh->nh_ref_by_stack = 1;
+      nua_handle_ref(nh);
+    }
+  }
+
+  if (nua_log->log_level >= 5) {
+    char const *name = nua_event_name(e->e_event);
+    if (e->e_status == 0)
+      SU_DEBUG_5(("nua(%p): signal %s\n", nh, name + 4));
+    else
+      SU_DEBUG_5(("nua(%p): signal %s %u %s\n",
+		  nh, name + 4, e->e_status, e->e_phrase ? e->e_phrase : ""));
+  }
+
+  su_msg_save(nua->nua_signal, msg);
+
+  if (nua->nua_shutdown && !e->e_always) {
+    /* Shutting down */
+    nua_stack_event(nua, nh, NULL, e->e_event,
+		    901, "Stack is going down",
+		    TAG_END());
+  }
+
+  else switch (e->e_event) {
+  case nua_r_get_params:
+    nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, e->e_event, tags);
+    break;
+  case nua_r_set_params:
+    nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, e->e_event, tags);
+    break;
+  case nua_r_shutdown:
+    nua_stack_shutdown(nua);
+    break;
+  case nua_r_register:
+  case nua_r_unregister:
+    nua_stack_register(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_invite:
+    nua_stack_invite(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_cancel:
+    nua_stack_cancel(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_bye:
+    nua_stack_bye(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_options:
+    nua_stack_options(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_refer:
+    nua_stack_refer(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_publish:
+  case nua_r_unpublish:
+    nua_stack_publish(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_info:
+    nua_stack_info(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_update:
+    nua_stack_update(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_message:
+    nua_stack_message(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_subscribe:
+  case nua_r_unsubscribe:
+    nua_stack_subscribe(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_notify:
+    nua_stack_notify(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_notifier:
+    nua_stack_notifier(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_terminate:
+    nua_stack_terminate(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_method:
+    nua_stack_method(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_authenticate:
+    nua_stack_authenticate(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_authorize:
+    nua_stack_authorize(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_ack:
+    nua_stack_ack(nua, nh, e->e_event, tags);
+    break;
+  case nua_r_respond:
+    nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags);
+    break;
+  case nua_r_destroy:
+    nua_stack_destroy_handle(nua, nh, tags);
+    break;
+  default:
+    break;
+  }
+
+  if (su_msg_is_non_null(nua->nua_signal))
+    su_msg_destroy(nua->nua_signal);
+
+  if (nh != nua->nua_dhandle)
+    nua_handle_unref(nh);
+}
+
+/* ====================================================================== */
+
+static int nh_call_pending(nua_handle_t *nh, sip_time_t time);
+
+/**@internal
+ * Timer routine.
+ *
+ * Go through all active handles and execute pending tasks
+ */
+void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a)
+{
+  nua_handle_t *nh, *nh_next;
+  sip_time_t now = sip_now();
+  su_root_t *root = su_timer_root(t);
+
+  su_timer_set(t, nua_stack_timer, a);
+
+  if (nua->nua_shutdown) {
+    nua_stack_shutdown(nua);
+    return;
+  }
+
+  for (nh = nua->nua_handles; nh; nh = nh_next) {
+    nh_next = nh->nh_next;
+    nh_call_pending(nh, now);
+    su_root_yield(root);	/* Handle received packets */
+  }
+}
+
+
+static
+int nh_call_pending(nua_handle_t *nh, sip_time_t now)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_dialog_usage_t *du;
+  sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;
+
+  for (du = ds->ds_usage; du; du = du->du_next) {
+    if (now == 0)
+      break;
+    if (du->du_refresh && du->du_refresh < next)
+      break;
+  }
+
+  if (du == NULL)
+    return 0;
+
+  nua_handle_ref(nh);
+
+  while (du) {
+    nua_dialog_usage_t *du_next = du->du_next;
+
+    nua_dialog_usage_refresh(nh, ds, du, now);
+
+    if (du_next == NULL)
+      break;
+
+    for (du = nh->nh_ds->ds_usage; du; du = du->du_next)
+      if (du == du_next)
+	break;
+
+    for (; du; du = du->du_next) {
+      if (now == 0)
+	break;
+      if (du->du_refresh && du->du_refresh < next)
+	break;
+    }
+  }
+
+  nua_handle_unref(nh);
+
+  return 1;
+}
+
+
+/* ====================================================================== */
+
+/**Shutdown a @nua stack.
+ *
+ * When the @nua stack is shutdown, ongoing calls are released,
+ * registrations unregistered, publications un-PUBLISHed and subscriptions
+ * terminated. If the stack cannot terminate everything within 30 seconds,
+ * it sends the #nua_r_shutdown event with status 500.
+ *
+ * @param nua         Pointer to @nua stack object
+ *
+ * @return
+ *     nothing
+ *
+ * @par Related tags:
+ *     none
+ *
+ * @par Events:
+ *     #nua_r_shutdown
+ *
+ * @sa #nua_r_shutdown, nua_destroy(), nua_create(), nua_bye(),
+ * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_notify(),
+ * nua_handle_destroy(), nua_handle_unref()
+ */
+
+/** @NUA_EVENT nua_r_shutdown
+ *
+ * Answer to nua_shutdown().
+ *
+ * Status codes
+ * - 100 shutdown started
+ * - 101 shutdown in progress (sent when shutdown has been progressed)
+ * - 200 shutdown was successful
+ * - 500 shutdown timeout after 30 sec
+ *
+ * @param status shutdown status code
+ * @param nh     NULL
+ * @param hmagic NULL
+ * @param sip    NULL
+ * @param tags   empty
+ *
+ * @sa nua_shutdown(), nua_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Shut down stack. */
+void nua_stack_shutdown(nua_t *nua)
+{
+  nua_handle_t *nh, *nh_next;
+  int busy = 0;
+  sip_time_t now = sip_now();
+  int status;
+  char const *phrase;
+
+  enter;
+
+  if (!nua->nua_shutdown)
+    nua->nua_shutdown = now;
+
+  for (nh = nua->nua_handles; nh; nh = nh_next) {
+    nua_dialog_state_t *ds = nh->nh_ds;
+    nua_server_request_t *sr, *sr_next;
+
+    nh_next = nh->nh_next;
+
+    for (sr = ds->ds_sr; sr; sr = sr_next) {
+      sr_next = sr->sr_next;
+
+      if (sr->sr_respond) {
+	SR_STATUS1(sr, SIP_410_GONE);
+	sr->sr_usage = NULL;
+	sr->sr_respond(sr, NULL);
+	sr->sr_respond = NULL;
+	busy++;
+      }
+	
+      nua_server_request_destroy(sr);
+    }
+
+    busy += nh_call_pending(nh, 0);
+
+    if (nh->nh_soa) {
+      soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+    }
+
+    if (nua_client_request_pending(ds->ds_cr))
+      busy++;
+
+    if (nh_notifier_shutdown(nh, NULL, NEATAG_REASON("noresource"), TAG_END()))
+      busy++;
+  }
+
+  if (!busy)
+    SET_STATUS(200, "Shutdown successful");
+  else if (now == nua->nua_shutdown)
+    SET_STATUS(100, "Shutdown started");
+  else if (now - nua->nua_shutdown < 30)
+    SET_STATUS(101, "Shutdown in progress");
+  else
+    SET_STATUS(500, "Shutdown timeout");
+
+  if (status >= 200) {
+    for (nh = nua->nua_handles; nh; nh = nh_next) {
+      nh_next = nh->nh_next;
+      while (nh->nh_ds && nh->nh_ds->ds_usage) {
+	nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage);
+      }
+    }
+    su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
+    nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
+  }
+
+  nua_stack_event(nua, NULL, NULL, nua_r_shutdown, status, phrase, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** @internal Create a handle */
+nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  nua_handle_t *nh;
+
+  enter;
+
+  ta_start(ta, tag, value);
+  nh = nh_create_handle(nua, NULL, ta_args(ta));
+  ta_end(ta);
+
+  if (nh) {
+    nh->nh_ref_by_stack = 1;
+    nh_append(nua, nh);
+  }
+
+  return nh;
+}
+
+/** @internal Append an handle to the list of handles */
+void nh_append(nua_t *nua, nua_handle_t *nh)
+{
+  nh->nh_next = NULL;
+  nh->nh_prev = nua->nua_handles_tail;
+  *nua->nua_handles_tail = nh;
+  nua->nua_handles_tail = &nh->nh_next;
+}
+
+nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe)
+{
+  nua_handle_t *nh;
+
+  if (maybe)
+    for (nh = nua->nua_handles; nh; nh = nh->nh_next)
+      if (nh == maybe)
+	return nh;
+
+  return NULL;
+}
+
+void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
+{
+  nh_call_pending(nh, 0);	/* Call pending operations with 0 */
+
+  if (nh->nh_notifier)
+    nua_stack_terminate(nua, nh, 0, NULL);
+
+#if 0
+  if (nh->nh_ref_by_user) {
+    nh->nh_ref_by_user = 0;
+    nua_handle_unref(nh);
+  }
+#endif
+
+  nh_destroy(nua, nh);
+}
+
+#define nh_is_inserted(nh) ((nh)->nh_prev != NULL)
+
+/** @internal Remove a handle from list of handles */
+static
+void nh_remove(nua_t *nua, nua_handle_t *nh)
+{
+  assert(nh_is_inserted(nh)); assert(*nh->nh_prev == nh);
+
+  if (nh->nh_next)
+    nh->nh_next->nh_prev = nh->nh_prev;
+  else
+    nua->nua_handles_tail = nh->nh_prev;
+
+  *nh->nh_prev = nh->nh_next;
+
+  nh->nh_prev = NULL;
+  nh->nh_next = NULL;
+}
+
+
+void nh_destroy(nua_t *nua, nua_handle_t *nh)
+{
+  assert(nh); assert(nh != nua->nua_dhandle);
+
+  nh_enter;
+
+  if (nh->nh_notifier)
+    nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
+
+  nua_creq_deinit(nh->nh_ds->ds_cr, NULL);
+
+  nua_dialog_deinit(nh, nh->nh_ds);
+
+  if (nh->nh_soa)
+    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+
+  if (nh_is_inserted(nh))
+    nh_remove(nua, nh);
+
+  nua_handle_unref(nh);		/* Remove stack reference */
+}
+
+/* ======================================================================== */
+
+/**@internal
+ * Initialize handle Allow and authentication info, save parameters.
+ *
+ * @retval -1 upon an error
+ * @retval 0 when successful
+ */
+int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh,
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int retval = 0;
+
+  if (nh == NULL)
+    return -1;
+
+  assert(nh != nua->nua_dhandle);
+
+  ta_start(ta, tag, value);
+
+  if (nua_stack_set_params(nua, nh, nua_i_error, ta_args(ta)) < 0)
+    retval = -1;
+
+  if (!retval && nh->nh_soa)
+    if (soa_set_params(nh->nh_soa, ta_tags(ta)) < 0)
+      retval = -1;
+
+  ta_end(ta);
+
+  if (retval || nh->nh_init) /* Already initialized? */
+    return retval;
+
+  if (nh->nh_tags)
+    nh_authorize(nh, TAG_NEXT(nh->nh_tags));
+
+  nh->nh_init = 1;
+
+  return 0;
+}
+
+/** @internal Create a handle for processing incoming request */
+nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
+					nta_incoming_t *irq,
+					sip_t const *sip,
+					int create_dialog)
+{
+  nua_handle_t *nh;
+  url_t const *url;
+  sip_to_t to[1];
+  sip_from_t from[1];
+
+  assert(sip && sip->sip_from && sip->sip_to);
+
+  if (sip->sip_contact)
+    url = sip->sip_contact->m_url;
+  else
+    url = sip->sip_from->a_url;
+
+  /* Strip away parameters */
+  sip_from_init(from)->a_display = sip->sip_to->a_display;
+  *from->a_url = *sip->sip_to->a_url;
+
+  sip_to_init(to)->a_display = sip->sip_from->a_display;
+  *to->a_url = *sip->sip_from->a_url;
+
+  nh = nh_create(nua,
+		 NUTAG_URL((url_string_t *)url), /* Remote target */
+		 SIPTAG_TO(to), /* Local AoR */
+		 SIPTAG_FROM(from), /* Remote AoR */
+		 TAG_END());
+
+  if (nua_stack_init_handle(nh->nh_nua, nh, TAG_END()) < 0)
+    nh_destroy(nua, nh), nh = NULL;
+
+  if (nh && create_dialog) {
+    struct nua_dialog_state *ds = nh->nh_ds;
+
+    nua_dialog_store_peer_info(nh, ds, sip);
+
+    ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh,
+				 SIPTAG_CALL_ID(sip->sip_call_id),
+				 SIPTAG_FROM(sip->sip_to),
+				 SIPTAG_TO(sip->sip_from),
+				 NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq),
+				 TAG_END());
+
+    if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL)))
+      nh_destroy(nua, nh), nh = NULL;
+  }
+
+  if (nh)
+    nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+
+  return nh;
+}
+
+
+/** Set flags and special event on handle.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int nua_stack_set_handle_special(nua_handle_t *nh,
+				 enum nh_kind kind,
+				 nua_event_t special)
+{
+  if (nh == NULL)
+    return -1;
+
+  if (special && nh->nh_special && nh->nh_special != special)
+    return -1;
+
+  if (!nh_is_special(nh) && !nh->nh_has_invite) {
+    switch (kind) {
+    case nh_has_invite:    nh->nh_has_invite = 1;    break;
+    case nh_has_subscribe: nh->nh_has_subscribe = 1; break;
+    case nh_has_notify:    nh->nh_has_notify = 1;    break;
+    case nh_has_register:  nh->nh_has_register = 1;  break;
+    case nh_has_nothing:
+    default:
+      break;
+    }
+
+    if (special)
+      nh->nh_special = special;
+  }
+
+  return 0;
+}
+
+sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh, 
+					       su_home_t *home,
+					       int early_only)
+{
+  if (nh && nh->nh_ds && nh->nh_ds->ds_leg)
+    return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only);
+  else
+    return NULL;
+}
+
+nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
+					   sip_replaces_t const *r)
+{
+  if (nua) {
+    nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r);
+    if (leg)
+      return nta_leg_magic(leg, nua_stack_process_request);
+  }
+  return NULL;
+}
+
+
+/** @internal Add authorization data */
+int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+  int retval = 0;
+  tagi_t const *ti;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  for (ti = ta_args(ta); ti; ti = tl_next(ti)) {
+    if (ti->t_tag == nutag_auth && ti->t_value) {
+      char *data = (char *)ti->t_value;
+      int rv = auc_credentials(&nh->nh_auth, nh->nh_home, data);
+
+      if (rv > 0) {
+	retval = 1;
+      }
+      else if (rv < 0) {
+	retval = -1;
+	break;
+      }
+    }
+  }
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/**@internal
+ * Collect challenges from response.
+ *
+ * @return Number of updated challenges, 0 if no updates found.
+ * @retval -1 upon error.
+ */
+static
+int nh_challenge(nua_handle_t *nh, sip_t const *sip)
+{
+  int server = 0, proxy = 0;
+
+  if (sip->sip_www_authenticate)
+    server = auc_challenge(&nh->nh_auth, nh->nh_home,
+			   sip->sip_www_authenticate,
+			   sip_authorization_class);
+
+  if (sip->sip_proxy_authenticate)
+    proxy = auc_challenge(&nh->nh_auth, nh->nh_home,
+			  sip->sip_proxy_authenticate,
+			  sip_proxy_authorization_class);
+
+  if (server < 0 || proxy < 0)
+    return -1;
+
+  return server + proxy;
+}
+
+#include <sofia-sip/su_tag_inline.h>
+
+/** Check if tag list has contact */
+int nua_tagis_have_contact_tag(tagi_t const *t)
+{
+  for (; t && t->t_tag; t = t_next(t))
+    if (t->t_tag == siptag_contact ||
+	t->t_tag == siptag_contact_str)
+      return 1;
+  return 0;
+}
+
+/**@internal
+ * Create a request message.
+ *
+ * @param nua
+ * @param nh
+ * @param cr
+ * @param restart
+ * @param method
+ * @param name
+ * @param tag, value, ... list of tag-value pairs
+ */
+msg_t *nua_creq_msg(nua_t *nua,
+		    nua_handle_t *nh,
+		    nua_client_request_t *cr,
+		    int restart,
+		    sip_method_t method, char const *name,
+		    tag_type_t tag, tag_value_t value, ...)
+{
+  struct nua_dialog_state *ds = nh->nh_ds;
+  msg_t *msg = NULL;
+  sip_t *sip;
+  ta_list ta;
+  url_string_t const *url = NULL;
+  long seq = -1;
+  int copy = 1;
+
+  /* If restarting, use existing message */
+  if (restart) {
+    msg = cr->cr_msg; sip = sip_object(msg);
+
+    /* Trying to restart different method? */
+    if (sip && method && sip->sip_request->rq_method != method) {
+      SU_DEBUG_3(("nua(%p): trying to %s "
+		  "but there is already %s waiting to restart\n",
+		  nh, name, sip->sip_request->rq_method_name));
+      restart = 0, msg = NULL; sip = NULL;
+    }
+
+    /* Remove CSeq */
+    if (sip && sip->sip_cseq)
+      sip_header_remove(msg, sip, (sip_header_t *)sip->sip_cseq);
+    if (sip && sip->sip_request)
+      method = sip->sip_request->rq_method,
+	name = sip->sip_request->rq_method_name;
+  }
+
+  if (!restart) {
+    if (cr->cr_msg) {
+      /* If method is ACK or CANCEL, use existing CSeq */
+      if (method == sip_method_ack || method == sip_method_cancel) {
+	sip_t *nh_sip = sip_object(cr->cr_msg);
+	if (nh_sip && nh_sip->sip_cseq)
+	  seq = nh_sip->sip_cseq->cs_seq;
+	/* ACK/CANCEL cannot be restarted so we do not copy message */
+	copy = 0;
+      }
+      else
+	msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+    }
+    msg = nta_msg_create(nua->nua_nta, 0);
+
+    /**@par Populating SIP Request Message with Tagged Arguments
+     *
+     * The tagged arguments can be used to pass values for any SIP headers
+     * to the stack. When the INVITE message (or any other SIP message) is
+     * created, the tagged values saved with nua_handle() are used first,
+     * next the tagged values given with the operation (nua_invite()) are
+     * added.
+     *
+     * When multiple tags for the same header are specified, the behaviour
+     * depends on the header type. If only a single header field can be
+     * included in a SIP message, the latest non-NULL value is used, e.g.,
+     * @Subject. However, if the SIP header can consist of multiple lines or
+     * header fields separated by comma, e.g., @Accept, all the tagged
+     * values are concatenated.
+     *
+     * However, if a tag value is #SIP_NONE (-1 casted as a void pointer),
+     * the values from previous tags are ignored.
+     */
+    tl_gets(nh->nh_tags, NUTAG_URL_REF(url), TAG_END());
+    sip_add_tl(msg, sip_object(msg), TAG_NEXT(nh->nh_tags));
+  }
+
+  ta_start(ta, tag, value);
+
+  sip = sip_object(msg);
+  if (!sip)
+    goto error;
+  if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+    goto error;
+
+  if (method != sip_method_ack) {
+    /**
+     * Next, values previously set with nua_set_params() or nua_set_hparams()
+     * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
+     * added to the request if they are not already set. 
+     */
+    if (!sip->sip_allow && !ds->ds_remote_tag)
+      sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow));
+
+    if (!sip->sip_supported && NH_PGET(nh, supported))
+      sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported));
+    
+    if (method == sip_method_register && NH_PGET(nh, path_enable) &&
+	!sip_has_feature(sip->sip_supported, "path") &&
+	!sip_has_feature(sip->sip_require, "path"))
+      sip_add_make(msg, sip, sip_supported_class, "path");
+
+    if (!sip->sip_organization && NH_PGET(nh, organization))
+      sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization));
+
+    if (!sip->sip_user_agent && NH_PGET(nh, user_agent))
+      sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent));
+  }
+	  
+  {
+    int add_contact = 0, use_dialog = 0, add_service_route, has_contact = 0;
+    tagi_t const *t;
+
+    for (t = ta_args(ta); t; t = t_next(t)) {
+      if (t->t_tag == siptag_contact ||
+	  t->t_tag == siptag_contact_str)
+	has_contact = 1;
+      else if (t->t_tag == nutag_url)
+	url = (url_string_t const *)t->t_value;
+      else if (t->t_tag == nutag_method && method == sip_method_unknown)
+	name = (char const *)t->t_value;
+      else if (t->t_tag == nutag_use_dialog)
+	use_dialog = t->t_value != 0;
+      else if (t->t_tag == _nutag_add_contact)
+	add_contact = t->t_value != 0;
+    }
+
+    if (!restart)
+      cr->cr_has_contact = has_contact;
+
+    if (has_contact) add_contact = 0;
+
+    if (method == sip_method_register && url == NULL)
+      url = (url_string_t const *)NH_PGET(nh, registrar);
+
+    if (seq != -1) {
+      sip_cseq_t *cseq;
+     
+      assert(method != sip_method_unknown || name || sip->sip_request);
+      
+      if (method || name)
+	cseq = sip_cseq_create(msg_home(msg), seq, method, name);
+      else 
+	cseq = sip_cseq_create(msg_home(msg), seq, 
+			       sip->sip_request->rq_method, 
+			       sip->sip_request->rq_method_name);
+
+      sip_header_insert(msg, sip, (sip_header_t *)cseq);
+    }
+
+    /**
+     * Now, the target URI for the request needs to be determined.
+     *
+     * For initial requests, values from tags are used. If NUTAG_URL() is
+     * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given,
+     * it is used as target URI. If neither is given, the complete request
+     * line already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR()
+     * is used. At this point, the target URI is stored in the request line,
+     * together with method name and protocol version ("SIP/2.0"). The
+     * initial dialog information is also created: @CallID, @CSeq headers
+     * are generated, if they do not exist, and a tag is added to the @From
+     * header.
+     */
+    if (!ds->ds_leg) {
+      nta_leg_t *leg = nua->nua_dhandle->nh_ds->ds_leg;
+
+      if ((ds->ds_remote_tag && ds->ds_remote_tag[0] && 
+	   sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
+	  || 
+	  (sip->sip_from == NULL &&
+	   sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0))
+	goto error;
+
+      if (use_dialog) {
+	ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
+				     nua_stack_process_request, nh,
+				     SIPTAG_CALL_ID(sip->sip_call_id),
+				     SIPTAG_FROM(sip->sip_from),
+				     SIPTAG_TO(sip->sip_to),
+				     SIPTAG_CSEQ(sip->sip_cseq),
+				     TAG_END());
+	if (!ds->ds_leg)
+	  goto error;
+
+	leg = ds->ds_leg;
+
+	if (!sip->sip_from->a_tag &&
+	    sip_from_tag(msg_home(msg), sip->sip_from,
+			 nta_leg_tag(ds->ds_leg, NULL)) < 0)
+	  goto error;
+      }
+
+      if (nta_msg_request_complete(msg, leg, method, name, url) < 0)
+	goto error;
+
+      add_service_route = !restart;
+    }
+    else {
+      /**
+       * For in-dialog requests, the request URI is taken from the @Contact
+       * header received from the remote party during dialog establishment, 
+       * and the NUTAG_URL() is ignored.
+       */
+      if (ds->ds_route)
+	url = NULL;
+
+      /**Also, the @CallID and @CSeq headers and @From and @To tags are
+       * generated based on the dialog information and added to the request. 
+       * If the dialog has a route, it is added to the request, too.
+       */
+      if (nta_msg_request_complete(msg, ds->ds_leg, method, name, url) < 0)
+	goto error;
+      add_service_route = 0;
+    }
+    /***
+     * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
+     * also added now, if it does not exist.
+     */
+
+    /**
+     * Next, the stack generates a @Contact header for the request (unless
+     * the application already gave a @Contact header or it does not want to
+     * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
+     * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the
+     * application has registered the URI in @From header, the @Contact
+     * header used with registration is used. Otherwise, the @Contact header
+     * is generated from the local IP address and port number.
+     */
+    if (!add_contact ||
+	sip->sip_contact ||
+	nua_tagis_have_contact_tag(nh->nh_tags) ||
+	nua_tagis_have_contact_tag(ta_args(ta)))
+      add_contact = 0;
+
+    /**For the initial requests, @ServiceRoute set received from the registrar
+     * is also added to the request message.
+     */
+    if (add_contact || add_service_route) {
+      if (nua_registration_add_contact_to_request(nh, msg, sip, 
+						  add_contact, 
+						  add_service_route) < 0)
+	goto error;
+    }
+
+    if (method != sip_method_ack) {
+      if (nh->nh_auth) {
+	nh_authorize(nh, ta_tags(ta));
+
+	if (method != sip_method_invite &&
+	    method != sip_method_update &&
+	    method != sip_method_prack &&
+	    /* auc_authorize() removes existing authentication headers */
+	    auc_authorize(&nh->nh_auth, msg, sip) < 0)
+	  goto error;
+      }
+    }
+    else /* ACK */ {
+      while (sip->sip_allow)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);
+      while (sip->sip_priority)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);
+      while (sip->sip_proxy_require)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);
+      while (sip->sip_require)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);
+      while (sip->sip_subject)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);
+      while (sip->sip_supported)
+	sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);
+    }
+
+    ta_end(ta);
+
+    if (!ds->ds_remote)
+      ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to);
+    if (!ds->ds_local)
+      ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from);
+
+    if (copy) {
+      cr->cr_msg = msg;
+      msg = msg_copy(msg);
+    }
+  }
+
+  return msg;
+
+ error:
+  ta_end(ta);
+  msg_destroy(msg);
+  return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+nua_client_request_t *
+nua_client_request_pending(nua_client_request_t const *cr)
+{
+  for (;cr;cr = cr->cr_next)
+    if (cr->cr_orq)
+      return (nua_client_request_t *)cr;
+
+  return NULL;
+}
+
+nua_client_request_t *
+nua_client_request_restarting(nua_client_request_t const *cr)
+{
+  for (;cr;cr = cr->cr_next)
+    if (cr->cr_restart)
+      return (nua_client_request_t *)cr;
+
+  return NULL;
+}
+
+nua_client_request_t *
+nua_client_request_by_orq(nua_client_request_t const *cr,
+			  nta_outgoing_t const *orq)
+{
+  for (;cr;cr = cr->cr_next)
+    if (cr->cr_orq == orq)
+      return (nua_client_request_t *)cr;
+
+  return NULL;
+}
+
+void nua_creq_deinit(nua_client_request_t *cr, nta_outgoing_t *orq)
+{
+  if (orq == NULL || orq == cr->cr_orq) {
+    cr->cr_retry_count = 0;
+    cr->cr_offer_sent = cr->cr_answer_recv = 0;
+
+    if (cr->cr_msg)
+      msg_destroy(cr->cr_msg);
+    cr->cr_msg = NULL;
+
+    if (cr->cr_orq)
+      nta_outgoing_destroy(cr->cr_orq);
+    cr->cr_orq = NULL;
+  }
+  else {
+    nta_outgoing_destroy(orq);
+  }
+}
+
+
+/**@internal
+ * Get remote contact header for @a irq */
+static inline
+sip_contact_t const *incoming_contact(nta_incoming_t *irq)
+{
+  sip_contact_t const *retval = NULL;
+  msg_t *request;
+  sip_t *sip;
+
+  request = nta_incoming_getrequest(irq);
+  sip = sip_object(request);
+  if (sip)
+    retval = sip->sip_contact;
+  msg_destroy(request);
+
+  return retval;
+}
+
+/**@internal
+ * Create a response message.
+ */
+msg_t *nh_make_response(nua_t *nua,
+			nua_handle_t *nh,
+			nta_incoming_t *irq,
+			int status, char const *phrase,
+			tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  msg_t *msg = nta_msg_create(nua->nua_nta, 0);
+  sip_t *sip = sip_object(msg);
+  msg_t *retval = NULL;
+  tagi_t const *t;
+
+  ta_start(ta, tag, value);
+
+  if (!msg)
+    /* retval is NULL */;
+  else if (nta_msg_response_complete(msg, irq, status, phrase) < 0)
+    msg_destroy(msg);
+  else if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+    msg_destroy(msg);
+  else if (sip_complete_message(msg) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_supported && NH_PGET(nh, supported) &&
+	   sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_user_agent && NH_PGET(nh, user_agent) &&
+	   sip_add_make(msg, sip, sip_user_agent_class, 
+			NH_PGET(nh, user_agent)) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_organization && NH_PGET(nh, organization) &&
+	   sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization)) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_allow && NH_PGET(nh, allow) &&
+	   sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_allow_events && 
+	   (sip->sip_cseq && 
+	    (sip->sip_cseq->cs_method == sip_method_publish ||
+	     sip->sip_cseq->cs_method == sip_method_subscribe)) &&
+	   NH_PGET(nh, allow_events) &&
+	   sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow_events)) < 0)
+    msg_destroy(msg);
+  else if (!sip->sip_contact &&
+	   (t = tl_find(ta_args(ta), _nutag_add_contact)) &&
+	   t->t_value && 
+	   nua_registration_add_contact_to_response(nh, msg, sip, NULL, 
+						    incoming_contact(irq)) < 0)
+    msg_destroy(msg);
+  else
+    retval = msg;
+
+  ta_end(ta);
+
+  return retval;
+}
+
+
+/* ======================================================================== */
+/* Generic processing */
+
+int nua_stack_process_unknown(nua_t *nua,
+			      nua_handle_t *nh,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  return 501;
+}
+
+/**@internal
+ * Relay response message to the application.
+ *
+ * If handle has already been marked as destroyed by nua_handle_destroy(),
+ * release the handle with nh_destroy().
+ */
+int nua_stack_process_response(nua_handle_t *nh,
+			       nua_client_request_t *cr,
+			       nta_outgoing_t *orq,
+			       sip_t const *sip,
+			       tag_type_t tag, tag_value_t value, ...)
+{
+  msg_t *msg = nta_outgoing_getresponse(orq);
+  int status = sip->sip_status->st_status;
+  char const *phrase = sip->sip_status->st_phrase;
+  ta_list ta;
+  int final;
+
+  if (status >= 200 && status < 300)
+    nh_challenge(nh, sip);  /* Collect nextnonce */
+
+  if (nta_outgoing_method(orq) == sip_method_invite)
+    final = status >= 300;
+  else
+    final = status >= 200;
+
+  if (final && cr) {
+    nua_creq_deinit(cr, orq);
+
+    if (cr->cr_usage && nh->nh_ds->ds_cr == cr) {
+      if ((status >= 300 && !cr->cr_usage->du_ready) ||
+	  cr->cr_usage->du_terminating)
+	nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
+    }
+
+    cr->cr_usage = NULL;
+  }
+
+  ta_start(ta, tag, value);
+
+  nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase,
+		  ta_tags(ta));
+
+  if (final)
+    cr->cr_event = nua_i_error;
+
+  ta_end(ta);
+
+  return 0;
+}
+
+static inline
+int can_redirect(sip_contact_t const *m, sip_method_t method)
+{
+  if (m && m->m_url->url_host) {
+    enum url_type_e type = m->m_url->url_type;
+    return
+      type == url_sip ||
+      type == url_sips ||
+      (type == url_tel &&
+       (method == sip_method_invite || method == sip_method_message)) ||
+      (type == url_im && method == sip_method_message) ||
+      (type == url_pres && method == sip_method_subscribe);
+  }
+  return 0;
+}
+
+int nua_creq_restart_with(nua_handle_t *nh,
+			  nua_client_request_t *cr,
+			  nta_outgoing_t *orq,
+			  int status, char const *phrase,
+			  nua_creq_restart_f *f,
+			  TAG_LIST)
+{
+  ta_list ta;
+  msg_t *msg = nta_outgoing_getresponse(orq);
+
+  nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase,
+		  TAG_END());
+
+  nta_outgoing_destroy(orq);
+
+  if (f) {
+    ta_start(ta, tag, value);
+    f(nh, ta_args(ta));
+    ta_end(ta);
+  }
+
+  return 1;
+}
+
+
+/** @internal Save operation until it can be restarted */
+int nua_creq_save_restart(nua_handle_t *nh,
+			  nua_client_request_t *cr,
+			  nta_outgoing_t *orq,
+			  int status, char const *phrase,
+			  nua_creq_restart_f *restart_function)
+{
+  nua_dialog_usage_t *du = cr->cr_usage;
+  msg_t *msg = nta_outgoing_getresponse(orq);
+
+  nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event,
+		  status, phrase, 
+		  TAG_END());
+  nta_outgoing_destroy(orq);
+
+  if (du)
+    du->du_refresh = 0;
+
+  cr->cr_restart = restart_function;
+  return 1;
+}
+
+
+/**@internal
+ * Check response, return true if we can restart the request.
+ *
+ */
+int nua_creq_check_restart(nua_handle_t *nh,
+			   nua_client_request_t *cr,
+			   nta_outgoing_t *orq,
+			   sip_t const *sip,
+			   nua_creq_restart_f *restart_function)
+{
+  int status = sip->sip_status->st_status;
+  sip_method_t method = nta_outgoing_method(orq);
+
+  nua_dialog_usage_t *du = cr->cr_usage;
+
+  assert(restart_function);
+
+  if (orq != cr->cr_orq)
+    return 0;
+
+  cr->cr_orq = NULL;
+  cr->cr_restart = NULL;
+
+  if (cr->cr_msg == NULL || status < 200)
+    ;
+  else if (++cr->cr_retry_count > NH_PGET(nh, retry_count))
+    ;
+  else if (status == 302) {
+    if (can_redirect(sip->sip_contact, method)) {
+      return
+	nua_creq_restart_with(nh, cr, orq, 100, "Redirected",
+			      restart_function,
+			      NUTAG_URL(sip->sip_contact->m_url),
+			      TAG_END());
+    }
+  }
+  else if (status == 423) {
+    sip_t *req = sip_object(cr->cr_msg);
+    unsigned my_expires = 0;
+
+    if (req->sip_expires)
+      my_expires = req->sip_expires->ex_delta;
+
+    if (sip->sip_min_expires &&
+	sip->sip_min_expires->me_delta > my_expires) {
+      sip_expires_t ex[1];
+      sip_expires_init(ex);
+      ex->ex_delta = sip->sip_min_expires->me_delta;
+
+      return
+	nua_creq_restart_with(nh, cr, orq,
+			      100, "Re-Negotiating Expiration",
+			      restart_function, 
+			      SIPTAG_EXPIRES(ex),
+			      TAG_END());
+    }
+  }
+  else if (method != sip_method_ack && method != sip_method_cancel &&
+	   ((status == 401 && sip->sip_www_authenticate) ||
+	    (status == 407 && sip->sip_proxy_authenticate)) &&
+	   nh_challenge(nh, sip) > 0) {
+    msg_t *request = nta_outgoing_getrequest(orq);
+    sip_t *rsip = sip_object(request);
+    int done;
+
+    /* XXX - check for instant restart */
+    done = auc_authorization(&nh->nh_auth, cr->cr_msg, (msg_pub_t*)NULL,
+			     rsip->sip_request->rq_method_name,
+			     rsip->sip_request->rq_url,
+			     rsip->sip_payload);
+
+    msg_destroy(request);
+
+    if (done > 0) {
+      return
+	nua_creq_restart_with(nh, cr, orq,
+			      100, "Request Authorized by Cache",
+			      restart_function, TAG_END());
+    }
+    else if (done == 0) {
+      /* Operation waits for application to call nua_authenticate() */
+      return nua_creq_save_restart(nh, cr, orq, 
+				   status, sip->sip_status->st_phrase, 
+				   restart_function);
+    }
+    else {
+      SU_DEBUG_5(("nua(%p): auc_authorization failed\n", nh));
+    }
+  }
+
+  /* This was final response that cannot be restarted. */
+  cr->cr_orq = orq;
+
+  if (du)
+    du->du_refresh = 0;
+  cr->cr_retry_count = 0;
+
+  if (cr->cr_msg)
+    msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+
+  return 0;
+}
+
+/** @internal Restart a request */
+int nua_creq_restart(nua_handle_t *nh,
+		     nua_client_request_t *cr,
+		     nta_response_f *cb,
+		     tagi_t *tags)
+{
+  msg_t *msg;
+
+  cr->cr_restart = NULL;
+
+  if (!cr->cr_msg)
+    return 0;
+
+  msg = nua_creq_msg(nh->nh_nua, nh, cr, 1, SIP_METHOD_UNKNOWN,
+		     TAG_NEXT(tags));
+
+  cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta, cb, nh, NULL, msg,
+				    SIPTAG_END(), TAG_NEXT(tags));
+
+  if (!cr->cr_orq) {
+    msg_destroy(msg);
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ======================================================================== */
+/* Authentication */
+
+/** @NUA_EVENT nua_r_authenticate
+ *
+ * Response to nua_authenticate(). Under normal operation, this event is
+ * never sent but rather the unauthenticated operation is completed. 
+ * However, if there is no operation to authentication or if there is an
+ * authentication error the #nua_r_authenticate event is sent to the
+ * application with the status code as follows:
+ * - <i>202 No operation to restart</i>:\n
+ *   The authenticator associated with the handle was updated, but there was
+ *   no operation to retry with the new credentials.
+ * - <i>900 Cannot add credentials</i>:\n
+ *   There was internal problem updating authenticator.
+ * - <i>904 No matching challenge</i>:\n
+ *   There was no challenge matching with the credentials provided by
+ *   nua_authenticate(), e.g., their realm did not match with the one 
+ *   received with the challenge.
+ * 
+ * @param status status code from authentication 
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle authenticated
+ * @param hmagic application context associated with the handle
+ * @param sip    NULL
+ * @param tags   empty
+ * 
+ * @sa nua_terminate(), nua_handle_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+void
+nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		       tagi_t const *tags)
+{
+  int status = nh_authorize(nh, TAG_NEXT(tags));
+
+  if (status > 0) {
+    nua_client_request_t *cr;
+    nua_creq_restart_f *restart = NULL;
+
+    cr = nua_client_request_restarting(nh->nh_ds->ds_cr);
+
+    if (cr) 
+      restart = cr->cr_restart, cr->cr_restart = NULL;
+
+    if (restart) {
+      /* nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END()); */
+      restart(nh, (tagi_t *)tags);	/* Restart operation */
+    }
+    else {
+      nua_stack_event(nua, nh, NULL, e, 
+		      202, "No operation to restart",
+		      TAG_END());
+    }
+  }
+  else if (status < 0) {
+    nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", TAG_END());
+  }
+  else {
+    nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", TAG_END());
+  }
+}
+
+/* ======================================================================== */
+/*
+ * Process incoming requests
+ */
+
+int nua_stack_process_request(nua_handle_t *nh,
+			      nta_leg_t *leg,
+			      nta_incoming_t *irq,
+			      sip_t const *sip)
+{
+  nua_t *nua = nh->nh_nua;
+  sip_method_t method = sip->sip_request->rq_method;
+  char const *user_agent = NH_PGET(nh, user_agent);
+  sip_supported_t const *supported = NH_PGET(nh, supported);
+  sip_allow_t const *allow = NH_PGET(nh, allow);
+  enter;
+
+  nta_incoming_tag(irq, NULL);
+
+  if (nta_check_method(irq, sip, allow,
+		       SIPTAG_SUPPORTED(supported),
+		       SIPTAG_USER_AGENT_STR(user_agent),
+		       TAG_END()))
+    return 405;
+
+  switch (sip->sip_request->rq_url->url_type) {
+  case url_sip:
+  case url_sips:
+  case url_im:
+  case url_pres:
+  case url_tel:
+    break;
+  default:
+    nta_incoming_treply(irq, SIP_416_UNSUPPORTED_URI,
+			SIPTAG_ALLOW(allow),
+			SIPTAG_SUPPORTED(supported),
+			SIPTAG_USER_AGENT_STR(user_agent),
+			TAG_END());
+  }
+
+  if (nta_check_required(irq, sip, supported,
+			 SIPTAG_ALLOW(allow),
+			 SIPTAG_USER_AGENT_STR(user_agent),
+			 TAG_END()))
+    return 420;
+
+  if (nh == nua->nua_dhandle) {
+    if (!sip->sip_to->a_tag)
+      ;
+    else if (method == sip_method_message && NH_PGET(nh, win_messenger_enable))
+      ;
+    else {
+      nta_incoming_treply(irq, 481, "Initial transaction with a To tag",
+			  TAG_END());
+      return 481;
+    }
+    nh = NULL;
+  }
+
+  if (sip->sip_timestamp)
+    nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+  switch (method) {
+  case sip_method_invite:
+    return nua_stack_process_invite(nua, nh, irq, sip);
+
+  case sip_method_info:
+    if (nh) return nua_stack_process_info(nua, nh, irq, sip);
+    /*FALLTHROUGH*/
+
+  case sip_method_update:
+    if (nh) return nua_stack_process_update(nua, nh, irq, sip);
+    /*FALLTHROUGH*/
+
+  case sip_method_bye:
+    if (nh) return nua_stack_process_bye(nua, nh, irq, sip);
+
+    nta_incoming_treply(irq,
+			481, "Call Does Not Exist",
+			SIPTAG_ALLOW(allow),
+			SIPTAG_SUPPORTED(supported),
+			SIPTAG_USER_AGENT_STR(user_agent),
+			TAG_END());
+    return 481;
+
+  case sip_method_message:
+    return nua_stack_process_message(nua, nh, irq, sip);
+
+  case sip_method_notify:
+    return nua_stack_process_notify(nua, nh, irq, sip);
+
+  case sip_method_subscribe:
+    return nua_stack_process_subscribe(nua, nh, irq, sip);
+
+  case sip_method_register:
+    return nua_stack_process_register(nua, nh, irq, sip);
+
+  case sip_method_options:
+    return nua_stack_process_options(nua, nh, irq, sip);
+
+  case sip_method_refer:
+    return nua_stack_process_refer(nua, nh, irq, sip);
+
+  case sip_method_publish:
+    return nua_stack_process_publish(nua, nh, irq, sip);
+
+  case sip_method_ack:
+  case sip_method_cancel:
+    SU_DEBUG_1(("nua(%p): strange %s from <" URL_PRINT_FORMAT ">\n", nh,
+		sip->sip_request->rq_method_name,
+		URL_PRINT_ARGS(sip->sip_from->a_url)));
+    /* Send nua_i_error ? */
+    return 481;
+
+  case sip_method_unknown:
+    return nua_stack_process_method(nua, nh, irq, sip);
+
+  default:
+    return nua_stack_process_unknown(nua, nh, irq, sip);
+  }
+}
+
+nua_server_request_t *nua_server_request(nua_t *nua,
+					 nua_handle_t *nh,
+					 nta_incoming_t *irq,
+					 sip_t const *sip,
+					 nua_server_request_t *sr,
+					 size_t size,
+					 nua_server_respond_f *respond,
+					 int create_dialog)
+{
+  int initial = 1, final = 200;
+
+  assert(nua && irq && sip && sr);
+
+  initial = nh == NULL || nh == nua->nua_dhandle;
+
+  /* INVITE server request is not finalized after 2XX response */
+  if (sip->sip_request->rq_method == sip_method_invite)
+    final = 300;
+
+  /* Create handle if request does not fail */
+  if (sr->sr_status >= 300)
+    ;
+  else if (initial) {
+    if (!(nh = nua_stack_incoming_handle(nua, irq, sip, create_dialog)))
+      SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+  }
+  else if (create_dialog) {
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+    nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+  }
+
+  if (nh == NULL)
+    nh = nua->nua_dhandle;
+
+  if (sr->sr_status < final) {
+    nua_server_request_t *sr0 = sr;
+
+    if (size < (sizeof *sr))
+      size = sizeof *sr;
+
+    sr = su_zalloc(nh->nh_home, size);
+
+    if (sr) {
+      if ((sr->sr_next = nh->nh_ds->ds_sr))
+	*(sr->sr_prev = sr->sr_next->sr_prev) = sr,
+	  sr->sr_next->sr_prev = &sr->sr_next;
+      else
+	*(sr->sr_prev = &nh->nh_ds->ds_sr) = sr;
+      SR_STATUS(sr, sr0->sr_status, sr0->sr_phrase);
+    }
+    else {
+      sr = sr0;
+      SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+    }
+  }
+
+  sr->sr_owner = nh;
+  sr->sr_method = sip->sip_request->rq_method;
+  sr->sr_respond = respond;
+  sr->sr_irq = irq;
+  sr->sr_initial = initial;
+
+  return sr;
+}		 
+
+void nua_server_request_destroy(nua_server_request_t *sr)
+{
+  if (sr->sr_irq)
+    nta_incoming_destroy(sr->sr_irq), sr->sr_irq = NULL;
+
+  sr->sr_msg = NULL;
+
+  if (sr->sr_prev) {
+    if ((*sr->sr_prev = sr->sr_next))
+      sr->sr_next->sr_prev = sr->sr_prev;
+
+    if (sr->sr_owner)
+      su_free(sr->sr_owner->nh_home, sr);
+  }
+}
+
+/** Send server event (nua_i_*) to the application. */
+int nua_stack_server_event(nua_t *nua,
+			   nua_server_request_t *sr,
+			   nua_event_t event,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  nua_handle_t *nh = sr->sr_owner; 
+  int status, final = 0;
+
+  if (nh == NULL) nh = nua->nua_dhandle;
+
+  if (sr->sr_status > 100)
+    /* Note that this may change the sr->sr_status */
+    final = sr->sr_respond(sr, NULL);
+
+  status = sr->sr_status;
+
+  if (status >= 200)
+    sr->sr_respond = NULL;
+  
+  if (status < 300 || !sr->sr_initial) {
+    ta_list ta;
+    msg_t *request;
+
+    ta_start(ta, tag, value);
+
+    assert(sr->sr_owner);
+    request = nta_incoming_getrequest(sr->sr_irq);
+    nua_stack_event(nua, sr->sr_owner, request, event, 
+		    sr->sr_status, sr->sr_phrase, 
+		    ta_tags(ta));
+    ta_end(ta);
+
+    if (final)
+      nua_server_request_destroy(sr);
+    else if (sr->sr_status < 200)
+      sr->sr_msg = request;
+  }
+  else {
+    nh = sr->sr_owner;
+
+    nua_server_request_destroy(sr);
+
+    if (nh && nh != nua->nua_dhandle)
+      nh_destroy(nua, nh);
+  }
+
+  return 0;
+}
+
+/** Respond to a request. */
+int nua_server_respond(nua_server_request_t *sr,
+		       int status, char const *phrase,
+		       tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int final;
+
+  assert(sr && sr->sr_respond);
+  SR_STATUS(sr, status, phrase);
+
+  ta_start(ta, tag, value);
+  final = sr->sr_respond(sr, ta_args(ta));
+  ta_end(ta);
+
+  if (final) {
+    nua_server_request_destroy(sr);    
+    return final;
+  }
+
+  if (sr->sr_status >= 200)
+    sr->sr_respond = NULL;
+
+  return 0;
+}
+
+msg_t *nua_server_response(nua_server_request_t *sr,
+			   int status, char const *phrase,
+			   tag_type_t tag, tag_value_t value, ...)
+{
+  msg_t *msg;
+  ta_list(ta);
+
+  assert(sr && sr->sr_owner && sr->sr_owner->nh_nua);
+
+  ta_start(ta, tag, value);
+
+  msg = nh_make_response(sr->sr_owner->nh_nua, sr->sr_owner, sr->sr_irq,
+			 sr->sr_status, sr->sr_phrase,
+			 ta_tags(ta));
+  
+  ta_end(ta);
+
+  return msg;
+}
+
+int nua_default_respond(nua_server_request_t *sr,
+			tagi_t const *tags)
+{
+  msg_t *m;
+
+  assert(sr && sr->sr_owner && sr->sr_owner->nh_nua);
+
+  m = nh_make_response(sr->sr_owner->nh_nua, sr->sr_owner, 
+		       sr->sr_irq,
+		       sr->sr_status, sr->sr_phrase,
+		       TAG_NEXT(tags));
+
+  if (m) {
+    if (nta_incoming_mreply(sr->sr_irq, m) < 0)
+      SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);      
+  }
+  
+  return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
+
+/** Respond to an request with given status. 
+ *
+ * When nua protocol engine receives an incoming SIP request, it can either
+ * respond to the request automatically or let it up to application to
+ * respond to the request. The automatic answer is sent if the request fails
+ * because of method, SIP extension or, in some times, MIME content
+ * negotiation fails.
+ *
+ * When responding to an incoming INVITE request, the nua_respond() can be
+ * called without NUTAG_WITH() (or NUTAG_WITH_CURRENT() or
+ * NUTAG_WITH_SAVED()). Otherwise, NUTAG_WITH() will contain an indication
+ * of the request being responded.
+ *
+ * In order to simplify the simple applications, most requests are responded
+ * automatically. The set of requests always responded by the stack include
+ * BYE, CANCEL and NOTIFY. The application can add methods that it likes to
+ * handle by itself with NUTAG_APPL_METHOD(). The default set of
+ * NUTAG_APPL_METHOD() includes INVITE, PUBLISH, REGISTER and SUBSCRIBE. 
+ * Note that unless the method is also included in the set of allowed
+ * methods with NUTAG_ALLOW(), the stack will respond to the incoming
+ * methods with <i>405 Not Allowed</i>.
+ *
+ * Note that certain methods are rejected outside a SIP session (created
+ * with INVITE transaction). They include BYE, UPDATE, PRACK and INFO. Also
+ * the auxiliary methods ACK and CANCEL are rejected by stack if there is no
+ * ongoing INVITE transaction corresponding to them.
+ *
+ * @param nh              Pointer to operation handle
+ * @param status          SIP response status (see RFCs of SIP)
+ * @param phrase          free text (default response phrase used if NULL)
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_WITH(), NUTAG_WITH_CURRENT(), NUTAG_WITH_SAVED() \n
+ *    NUTAG_EARLY_ANSWER() \n
+ *    SOATAG_ADDRESS() \n
+ *    SOATAG_AF() \n
+ *    SOATAG_HOLD() \n
+ *    Tags in <sip_tag.h>.
+ *
+ * @par Events:
+ *    #nua_i_state \n
+ *    #nua_i_media_error \n
+ *    #nua_i_error \n
+ *    #nua_i_active \n
+ *    #nua_i_terminated \n
+ *
+ * @sa #nua_i_invite, #nua_i_register, #nua_i_subscribe, #nua_i_publish
+ */
+void
+nua_stack_respond(nua_t *nua, nua_handle_t *nh,
+		  int status, char const *phrase, tagi_t const *tags)
+{
+  nua_server_request_t *sr;
+  tagi_t const *t;
+  msg_t const *request = NULL;
+
+  t = tl_find_last(tags, nutag_with);
+
+  if (t)
+    request = (msg_t const *)t->t_value;
+
+  for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) {
+    if (request && sr->sr_msg == request)
+      break;
+    /* nua_respond() to INVITE can be used without NUTAG_WITH() */
+    if (!t && sr->sr_method == sip_method_invite && sr->sr_respond)
+      break;
+  }
+  
+  if (sr && sr->sr_respond) {
+    int final;
+    SR_STATUS(sr, status, phrase);
+    final = sr->sr_respond(sr, tags);
+    if (final)
+      nua_server_request_destroy(sr);    
+    else if (sr->sr_status >= 200)
+      sr->sr_respond = NULL;
+    return;
+  }
+  else if (sr) {
+    nua_stack_event(nua, nh, NULL, nua_i_error,
+		    500, "Already Sent Final Response", TAG_END());
+    return;
+  }
+
+  nua_stack_event(nua, nh, NULL, nua_i_error,
+		  500, "Responding to a Non-Existing Request", TAG_END());
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,505 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_STACK_H
+/** Defined when <nua_stack.h> has been included. */
+#define NUA_STACK_H
+/**@IFILE nua_stack.h 
+ * @brief Sofia-SIP User Agent Engine - internal stack interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <su_config.h>
+#endif
+
+#ifndef SU_OS_NW_H
+#include <sofia-sip/su_os_nw.h>
+#endif
+#ifndef SOA_H
+#include "sofia-sip/soa.h"
+#endif
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+#ifndef AUTH_CLIENT_H
+#include <sofia-sip/auth_client.h>
+#endif
+#ifndef NEA_H
+#include <sofia-sip/nea.h>
+#endif
+#ifndef NUA_H
+#include <sofia-sip/nua.h>
+#endif
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#ifndef NUA_DIALOG_H
+#define NUA_OWNER_T struct nua_handle_s
+#include <nua_dialog.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#ifndef NUA_PARAMS_H
+#include <nua_params.h>
+#endif
+
+typedef struct event_s event_t;
+
+#define       NONE ((void *)-1)
+
+typedef struct register_usage nua_registration_t;
+
+#define \
+  NH_ACTIVE_MEDIA_TAGS(include, soa)					\
+  TAG_IF((include) && (soa) && soa_is_audio_active(soa) >= 0,		\
+	 SOATAG_ACTIVE_AUDIO(soa_is_audio_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_video_active(soa) >= 0,		\
+	 SOATAG_ACTIVE_VIDEO(soa_is_video_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_image_active(soa) >= 0,		\
+	 SOATAG_ACTIVE_IMAGE(soa_is_image_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_chat_active(soa) >= 0,		\
+	 SOATAG_ACTIVE_CHAT(soa_is_chat_active(soa)))
+
+#define \
+  NH_REMOTE_MEDIA_TAGS(include, soa)					\
+  TAG_IF((include) && (soa) && soa_is_remote_audio_active(soa) >= 0,	\
+	 SOATAG_ACTIVE_AUDIO(soa_is_remote_audio_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_remote_video_active(soa) >= 0,	\
+	 SOATAG_ACTIVE_VIDEO(soa_is_remote_video_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_remote_image_active(soa) >= 0,	\
+	 SOATAG_ACTIVE_IMAGE(soa_is_remote_image_active(soa))),		\
+  TAG_IF((include) && (soa) && soa_is_remote_chat_active(soa) >= 0,	\
+	 SOATAG_ACTIVE_CHAT(soa_is_remote_chat_active(soa)))
+
+/** NUA handle. 
+ *
+ */
+struct nua_handle_s 
+{
+  su_home_t       nh_home[1];	/**< Memory home  */
+  nua_handle_t   *nh_next;
+  nua_handle_t  **nh_prev;
+
+  nua_t        	 *nh_nua;	/**< Pointer to NUA object  */
+  void           *nh_valid;
+  nua_hmagic_t 	 *nh_magic;	/**< Application context */
+
+  tagi_t         *nh_tags;	/**< Initial tags */
+  tagi_t         *nh_ptags;	/**< Initial parameters */
+
+  nua_handle_t   *nh_identity;	/**< Identity */
+
+  nua_handle_preferences_t *nh_prefs; /**< Preferences */
+
+  /* Handle type is determined by special event and flags. */
+  nua_event_t     nh_special;	/**< Special event */
+  unsigned        nh_has_invite:1;     /**< Has call */
+  unsigned        nh_has_subscribe:1;  /**< Has watcher */
+  unsigned        nh_has_notify:1;     /**< Has notifier */
+  unsigned        nh_has_register:1;   /**< Has registration */
+
+  /* Call status */
+  unsigned        nh_active_call:1;
+  unsigned        nh_hold_remote:1;
+
+  unsigned        nh_ref_by_stack:1;	/**< Has stack used the handle? */
+  unsigned        nh_ref_by_user:1;	/**< Has user used the handle? */
+  unsigned        nh_init:1;	        /**< Handle has been initialized */
+  unsigned        nh_used_ptags:1;	/**< Ptags has been used */
+  unsigned :0;
+
+  nua_dialog_state_t nh_ds[1];
+
+  auth_client_t  *nh_auth;	/**< Authorization objects */
+
+  soa_session_t  *nh_soa;	/**< Media session */
+
+  struct nua_referral {
+    nua_handle_t  *ref_handle;	/**< Referring handle */
+    sip_event_t   *ref_event;	/**< Event used with NOTIFY */
+  } nh_referral[1];
+
+  nea_server_t   *nh_notifier;	/**< SIP notifier */
+};
+
+#define NH_IS_VALID(nh) ((nh) && (nh)->nh_valid)
+
+#define NH_STATUS(nh) \
+  (nh)->nh_status, \
+  (nh)->nh_phrase, \
+  SIPTAG_WARNING_STR(nh->nh_warning)
+
+#define NH_IS_DEFAULT(nh) ((nh) == (nh)->nh_nua->nua_handles)
+
+static inline
+int nh_is_special(nua_handle_t *nh)
+{
+  return nh == NULL || nh->nh_special;
+}
+
+extern char const nua_internal_error[];
+
+#define NUA_INTERNAL_ERROR 900, nua_internal_error
+
+struct nua_s {
+  su_home_t            nua_home[1];
+
+  /* API (client) side */
+  su_root_t    	      *nua_api_root;
+  su_clone_r   	       nua_clone;
+  su_task_r            nua_client;
+
+  su_network_changed_t *nua_nw_changed;
+
+  nua_callback_f       nua_callback;
+  nua_magic_t         *nua_magic;
+
+  nua_saved_event_t    nua_current[1];
+  nua_saved_event_t    nua_signal[1];
+
+  /* Engine state flags */
+  unsigned             nua_shutdown_started:1; /**< Shutdown initiated */
+  unsigned             nua_shutdown_final:1; /**< Shutdown is complete */
+  unsigned :0;
+  
+  /**< Used by stop-and-wait args calls */
+  tagi_t const        *nua_args;
+
+  /**< Local SIP address. Contents are kept around for ever. */
+  sip_from_t          nua_from[1];
+
+  /* Protocol (server) side */
+
+  nua_registration_t *nua_registrations; /**< Active registrations */
+
+  /* Constants */
+  sip_accept_t       *nua_invite_accept; /* What we accept for invite */
+
+  su_root_t          *nua_root;
+  su_task_r           nua_server;
+  nta_agent_t        *nua_nta;
+  su_timer_t         *nua_timer;
+
+  void         	      *nua_sip_parser;
+
+  sip_time_t           nua_shutdown;
+
+  /* Route */
+  sip_service_route_t *nua_service_route;
+
+  /* User-agent parameters */
+  unsigned             nua_media_enable:1;
+
+  unsigned     	       :0;
+
+#if HAVE_SMIME		/* Start NRC Boston */
+  sm_object_t          *sm;
+#endif                  /* End NRC Boston */
+
+  nua_handle_t        *nua_handles;
+  nua_handle_t       **nua_handles_tail;
+};
+
+#define nua_dhandle    nua_handles
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __func__))
+#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "nua"
+#endif
+
+/* Internal prototypes */
+int  nua_stack_init(su_root_t *root, nua_t *nua);
+void nua_stack_deinit(su_root_t *root, nua_t *nua);
+void nua_stack_signal(nua_t *nua, su_msg_r msg, event_t *e);
+
+int nua_stack_init_transport(nua_t *nua, tagi_t const *tags);
+
+int nua_stack_init_registrations(nua_t *nua);
+
+nua_registration_t *nua_registration_by_aor(nua_registration_t const *list,
+					    sip_from_t const *aor,
+					    url_t const *remote_uri,
+					    int only_default);
+
+sip_contact_t const *nua_registration_contact(nua_registration_t const *nr);
+
+int nua_registration_process_request(nua_registration_t *nr,
+				     nta_incoming_t *irq,
+				     sip_t const *sip);
+
+void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event, 
+			   tag_type_t tag, tag_value_t value, ...);
+
+typedef int nua_stack_signal_handler(nua_t *, 
+				     nua_handle_t *, 
+				     nua_event_t, 
+				     tagi_t const *);
+
+nua_stack_signal_handler 
+  nua_stack_set_params, nua_stack_get_params,
+  nua_stack_register, 
+  nua_stack_invite, nua_stack_ack, nua_stack_cancel, 
+  nua_stack_bye, nua_stack_info, nua_stack_update, 
+  nua_stack_options, nua_stack_publish, nua_stack_message, 
+  nua_stack_subscribe, nua_stack_notify, nua_stack_refer,
+  nua_stack_method;
+
+#define UA_EVENT1(e, statusphrase) \
+  nua_stack_event(nua, nh, NULL, e, statusphrase, TAG_END())
+
+#define UA_EVENT2(e, status, phrase)			\
+  nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END())
+
+#define UA_EVENT3(e, status, phrase, tag)			\
+  nua_stack_event(nua, nh, NULL, e, status, phrase, tag, TAG_END())
+
+int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+		    nua_event_t event, int status, char const *phrase,
+		    tag_type_t tag, tag_value_t value, ...);
+
+nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
+			       tagi_t *tags);
+
+nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
+					nta_incoming_t *irq,
+					sip_t const *sip,
+					int create_dialog);
+
+enum { create_dialog = 1 };
+
+int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, 
+			  tag_type_t tag, tag_value_t value, ...);
+
+enum nh_kind {
+  nh_has_nothing,
+  nh_has_invite,
+  nh_has_subscribe,
+  nh_has_notify,
+  nh_has_register,
+  nh_has_streaming
+};
+
+int nua_stack_set_handle_special(nua_handle_t *nh,
+				 enum nh_kind kind,
+				 nua_event_t special);
+
+int nua_handle_save_tags(nua_handle_t *h, tagi_t *tags);
+
+void nh_destroy(nua_t *nua, nua_handle_t *nh);
+
+nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe);
+
+sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *handle, 
+					       su_home_t *home,
+					       int early_only);
+
+nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
+					   sip_replaces_t const *r);
+
+/* ---------------------------------------------------------------------- */
+
+int nua_stack_set_defaults(nua_handle_t *nh, nua_handle_preferences_t *nhp);
+
+int nua_stack_set_from(nua_t *, int initial, tagi_t const *tags);
+
+int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags);
+
+int nua_stack_process_request(nua_handle_t *nh,
+			      nta_leg_t *leg,
+			      nta_incoming_t *irq,
+			      sip_t const *sip);
+
+int nua_stack_process_response(nua_handle_t *nh,
+			       nua_client_request_t *cr,
+			       nta_outgoing_t *orq,
+			       sip_t const *sip,
+			       tag_type_t tag, tag_value_t value, ...);
+
+int nua_stack_launch_network_change_detector(nua_t *nua);
+
+msg_t *nua_creq_msg(nua_t *nua, nua_handle_t *nh,
+		    nua_client_request_t *cr,
+		    int restart, 
+		    sip_method_t method, char const *name,
+		    tag_type_t tag, tag_value_t value, ...);
+
+int nua_tagis_have_contact_tag(tagi_t const *t);
+
+int nua_creq_check_restart(nua_handle_t *nh,
+			   nua_client_request_t *cr,
+			   nta_outgoing_t *orq,
+			   sip_t const *sip,
+			   nua_creq_restart_f *f);
+
+int nua_creq_restart_with(nua_handle_t *nh,
+			  nua_client_request_t *cr,
+			  nta_outgoing_t *orq,
+			  int status, char const *phrase,
+			  nua_creq_restart_f *f, 
+			  tag_type_t tag, tag_value_t value, ...);
+
+int nua_creq_save_restart(nua_handle_t *nh,
+			  nua_client_request_t *cr,
+			  nta_outgoing_t *orq,
+			  int status, char const *phrase,
+			  nua_creq_restart_f *f);
+
+int nua_creq_restart(nua_handle_t *nh,
+		     nua_client_request_t *cr,
+		     nta_response_f *cb,
+		     tagi_t *tags);
+
+void nua_creq_deinit(nua_client_request_t *cr, nta_outgoing_t *orq);
+
+sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr);
+
+int nua_registration_add_contact_to_request(nua_handle_t *nh,
+					    msg_t *msg, 
+					    sip_t *sip,
+					    int add_contact,
+					    int add_service_route);
+
+int nua_registration_add_contact_to_response(nua_handle_t *nh,
+					     msg_t *msg,
+					     sip_t *sip,
+					     sip_record_route_t const *,
+					     sip_contact_t const *remote);
+
+msg_t *nh_make_response(nua_t *nua, nua_handle_t *nh, 
+			nta_incoming_t *irq,
+			int status, char const *phrase,
+			tag_type_t tag, tag_value_t value, ...);
+
+
+typedef int nua_stack_process_request_t(nua_t *nua,
+					nua_handle_t *nh,
+					nta_incoming_t *irq,
+					sip_t const *sip);
+
+nua_stack_process_request_t nua_stack_process_invite;
+nua_stack_process_request_t nua_stack_process_info;
+nua_stack_process_request_t nua_stack_process_update;
+nua_stack_process_request_t nua_stack_process_bye;
+nua_stack_process_request_t nua_stack_process_message;
+nua_stack_process_request_t nua_stack_process_options;
+nua_stack_process_request_t nua_stack_process_publish;
+nua_stack_process_request_t nua_stack_process_subscribe;
+nua_stack_process_request_t nua_stack_process_notify;
+nua_stack_process_request_t nua_stack_process_refer;
+nua_stack_process_request_t nua_stack_process_unknown;
+nua_stack_process_request_t nua_stack_process_register;
+nua_stack_process_request_t nua_stack_process_method;
+
+nua_client_request_t
+  *nua_client_request_pending(nua_client_request_t const *),
+  *nua_client_request_restarting(nua_client_request_t const *),
+  *nua_client_request_by_orq(nua_client_request_t const *cr,
+			     nta_outgoing_t const *orq);
+
+nua_server_request_t *nua_server_request(nua_t *nua,
+					 nua_handle_t *nh,
+					 nta_incoming_t *irq,
+					 sip_t const *sip,
+					 nua_server_request_t *sr,
+					 size_t size,
+					 nua_server_respond_f *respond,
+					 int create_dialog);
+
+int nua_stack_server_event(nua_t *nua,
+			   nua_server_request_t *sr,
+			   nua_event_t event,
+			   tag_type_t tag, tag_value_t value, ...);
+
+/* ---------------------------------------------------------------------- */
+
+#ifndef SDP_MIME_TYPE
+#define SDP_MIME_TYPE nua_application_sdp
+#endif
+
+extern char const nua_application_sdp[];
+
+/* ---------------------------------------------------------------------- */
+
+#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL
+
+/* Private tags */
+#define NUTAG_ADD_CONTACT(v) _nutag_add_contact, tag_bool_v(v)
+extern tag_typedef_t _nutag_add_contact;
+
+#define NUTAG_ADD_CONTACT_REF(v) _nutag_add_contact_ref, tag_bool_vr(&v)
+extern tag_typedef_t _nutag_add_contact_ref;
+
+#define NUTAG_COPY(v) _nutag_copy, tag_bool_v(v)
+extern tag_typedef_t _nutag_copy;
+
+#define NUTAG_COPY_REF(v) _nutag_copy_ref, tag_bool_vr(&v)
+extern tag_typedef_t _nutag_copy_ref;
+
+/* ---------------------------------------------------------------------- */
+
+typedef unsigned longlong ull;
+
+#define SET_STATUS(_status, _phrase) status = _status, phrase = _phrase
+
+#define SET_STATUS2(_status, _phrase) status = _status, phrase = _phrase
+
+/* This is an "interesting" macro:
+ * x is a define expanding to <i>num, str</i>.
+ * @a num is assigned to variable status, @a str to variable phrase.
+ * Macro SET_STATUS1 expands to two comma-separated expressions that are
+ * also usable as function arguments.
+ */
+#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))
+
+/* ---------------------------------------------------------------------- */
+/* Application side prototypes */
+
+void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
+		nua_event_t event, int status, char const *phrase,
+		tag_type_t tag, tag_value_t value, ...);
+
+void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e);
+
+SOFIA_END_DECLS
+
+#endif /* NUA_STACK_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,926 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_subnotref.c
+ * @brief Subscriber (event watcher)
+ *
+ * This file contains implementation SUBSCRIBE UAC, NOTIFY UAS, REFER UAC.
+ * The implementation of SUBSCRIBE UAS, NOTIFY UAC and REFER UAS is in
+ * nua_notifier.c.
+ * Alternative implementation using nea is in nua_event_server.c.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 15:10:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T      struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ---------------------------------------------------------------------- */
+/* Subcriber event usage */
+
+struct event_usage
+{
+  enum nua_substate  eu_substate;	/**< Subscription state */
+  sip_time_t eu_expires;	        /**< Proposed expiration time */
+  unsigned eu_notified;		        /**< Number of NOTIFYs received */
+  unsigned eu_final_wait:1;	        /**< Waiting for final NOTIFY */
+  unsigned eu_no_id:1;		        /**< Do not use "id" (even if we have one) */
+};
+
+static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du);
+static int nua_subscribe_usage_add(nua_handle_t *nh, 
+				   nua_dialog_state_t *ds,
+				   nua_dialog_usage_t *du);
+static void nua_subscribe_usage_remove(nua_handle_t *nh, 
+				       nua_dialog_state_t *ds,
+				       nua_dialog_usage_t *du);
+static void nua_subscribe_usage_refresh(nua_handle_t *,
+					nua_dialog_state_t *,
+					nua_dialog_usage_t *,
+					sip_time_t);
+static int nua_subscribe_usage_shutdown(nua_handle_t *,
+					nua_dialog_state_t *,
+					nua_dialog_usage_t *);
+
+static nua_usage_class const nua_subscribe_usage[1] = {
+  {
+    sizeof (struct event_usage), (sizeof nua_subscribe_usage),
+    nua_subscribe_usage_add,
+    nua_subscribe_usage_remove,
+    nua_subscribe_usage_name,
+    NULL,
+    nua_subscribe_usage_refresh,
+    nua_subscribe_usage_shutdown
+  }};
+
+static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du)
+{
+  return "subscribe";
+}
+
+static 
+int nua_subscribe_usage_add(nua_handle_t *nh, 
+			   nua_dialog_state_t *ds,
+			   nua_dialog_usage_t *du)
+{
+  ds->ds_has_events++;
+  ds->ds_has_subscribes++;
+  return 0;
+}
+
+static 
+void nua_subscribe_usage_remove(nua_handle_t *nh, 
+			       nua_dialog_state_t *ds,
+			       nua_dialog_usage_t *du)
+{
+  ds->ds_has_events--;	
+  ds->ds_has_subscribes--;	
+}
+
+/* ====================================================================== */
+/* SUBSCRIBE */
+
+/** Subscribe to a SIP event. 
+ *
+ * Subscribe a SIP event using the SIP SUBSCRIBE request. If the 
+ * SUBSCRBE is successful a subscription state is established and 
+ * the subscription is refreshed regularly. The refresh requests will
+ * generate #nua_r_subscribe events.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL()
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_subscribe \n
+ *    #nua_i_notify
+ *
+ * @sa NUTAG_SUBSTATE(), @RFC3265
+ */
+
+/** Unsubscribe an event. 
+ *
+ * Unsubscribe an active or pending subscription with SUBSCRIBE request 
+ * containing Expires: header with value 0. The dialog associated with 
+ * subscription will be destroyed if there is no other subscriptions or 
+ * call using this dialog.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
+ *    Tags in <sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
+ *
+ * @par Events:
+ *    #nua_r_unsubscribe 
+ *
+ * @sa NUTAG_SUBSTATE(), @RFC3265
+ */
+
+static int process_response_to_subscribe(nua_handle_t *nh,
+					 nta_outgoing_t *orq,
+					 sip_t const *sip);
+
+
+int
+nua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+		    tagi_t const *tags)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_dialog_usage_t *du = NULL;
+  struct event_usage *eu;
+  msg_t *msg;
+  sip_t *sip;
+
+  if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
+    return UA_EVENT3(e, 500, "Invalid handle for SUBSCRIBE", 
+		     NUTAG_SUBSTATE(nua_substate_terminated));
+  else if (cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  /* Initialize allow and auth */
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  msg = nua_creq_msg(nua, nh, cr, 0,
+		     SIP_METHOD_SUBSCRIBE,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (sip) {
+    sip_event_t *o = sip->sip_event;
+
+    du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o);
+
+    if (du == NULL && o == NULL)
+      du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE);
+
+    eu = nua_dialog_usage_private(du);
+
+    if (du && du->du_event && (o == NULL || (o->o_id && eu->eu_no_id))) {
+      if (eu->eu_no_id)		/* No id (XXX - nor other parameters) */
+	sip_add_make(msg, sip, sip_event_class, du->du_event->o_type);
+      else
+	sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
+    }
+
+    if (e == nua_r_subscribe) {	
+      if (du == NULL)		/* Create dialog usage */
+	/* We allow here SUBSCRIBE without event */
+	du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o);
+    }
+    else if (du) { /* Unsubscribe */
+      /* Embryonic subscription is just a placeholder */
+      if (eu->eu_substate == nua_substate_terminated ||
+	  eu->eu_substate == nua_substate_embryonic) {
+	nua_dialog_usage_remove(nh, nh->nh_ds, du);
+	msg_destroy(msg);
+	return UA_EVENT3(e, SIP_200_OK, 
+			 NUTAG_SUBSTATE(nua_substate_terminated),
+			 TAG_END());
+      }
+    }
+  }
+
+  /* Store message template with supported features (eventlist) */
+  if (du && sip) {
+    if (du->du_msg)
+      msg_destroy(du->du_msg);
+    du->du_msg = msg_ref_create(cr->cr_msg);
+  }
+
+  if (du)
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_subscribe, nh, NULL,
+				      msg,
+				      TAG_IF(e != nua_r_subscribe,
+					     SIPTAG_EXPIRES_STR("0")),
+				      SIPTAG_END(), TAG_NEXT(tags));
+
+  eu = nua_dialog_usage_private(du);
+
+  if (!cr->cr_orq) {
+    int substate = nua_substate_terminated;
+
+    if (du == NULL)
+      ;
+    else if (du->du_ready)
+      substate = eu->eu_substate; /* No change in subscription state  */
+    else
+      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+
+    msg_destroy(msg);
+
+    return UA_EVENT3(e, NUA_INTERNAL_ERROR, 
+		     NUTAG_SUBSTATE(substate), TAG_END());
+  }
+
+  nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */
+  du->du_terminating = e != nua_r_subscribe; /* Unsubscribe or destroy */
+
+  if (du->du_terminating)
+    eu->eu_expires = 0;
+  else if (sip->sip_expires)
+    eu->eu_expires = sip->sip_expires->ex_delta;
+  else
+    /* We just use common default value, but the default is actually
+       package-specific according to the RFC 3265 section 4.4.4:
+       [Event] packages MUST also define a
+       default "Expires" value to be used if none is specified. */
+    eu->eu_expires = 3600;
+
+  eu->eu_final_wait = 0;
+    
+  if (sip->sip_expires && sip->sip_expires->ex_delta == 0)
+    du->du_terminating = 1;
+
+  if (eu->eu_substate == nua_substate_terminated)
+    eu->eu_substate = nua_substate_embryonic;
+
+  cr->cr_usage = du;
+  return cr->cr_event = e;
+}
+
+static void restart_subscribe(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_subscribe, tags);
+}
+
+/** @NUA_EVENT nua_r_subscribe
+ *
+ * Response to an outgoing SUBSCRIBE request.
+ *
+ * The SUBSCRIBE request may have been sent explicitly by nua_subscribe() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip    response to SUBSCRIBE request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   NUTAG_SUBSTATE()
+ *
+ * @sa nua_subscribe(), @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_r_unsubscribe
+ *
+ * Response to an outgoing un-SUBSCRIBE.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip    response to SUBSCRIBE request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags   NUTAG_SUBSTATE()
+ *
+ * @sa nua_unsubscribe(), @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_subscribe(nua_handle_t *nh,
+					 nta_outgoing_t *orq,
+					 sip_t const *sip)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  nua_dialog_usage_t *du = cr->cr_usage; 
+  struct event_usage *eu = nua_dialog_usage_private(du);
+  int status = sip ? sip->sip_status->st_status : 408;
+  int gracefully = 0;
+  int substate = nua_substate_embryonic;
+
+  assert(du); assert(du->du_class == nua_subscribe_usage);
+
+  if (status < 200)
+    ;
+  else if (du == NULL) {
+    /* NOTIFY already removed du */
+  }
+  /* We have not received NOTIFY. */
+  else if (status < 300) {
+    int win_messenger_enable = NH_PGET(nh, win_messenger_enable);
+    sip_time_t delta, now = sip_now();
+
+    du->du_ready = 1;
+    substate = eu->eu_substate;
+    
+    if (du->du_terminating)
+      delta = 0;
+    else
+      /* If there is no expires header,
+	 use default value stored in eu_expires */
+      delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, 
+				  eu->eu_expires, now);
+
+    if (win_messenger_enable && !nua_dialog_is_established(nh->nh_ds)) {
+      /* Notify from messanger does not match with dialog tag */ 
+      nh->nh_ds->ds_remote_tag = su_strdup(nh->nh_home, "");
+    }
+
+    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+    if (delta > 0) {
+      nua_dialog_usage_set_refresh(du, delta);
+    }
+    else if (!eu->eu_notified) {
+      /* This is a fetch: subscription was really terminated
+	 but we wait 32 seconds for NOTIFY. */
+      delta = 64 * NTA_SIP_T1 / 1000;
+
+      if (win_messenger_enable)
+	delta = 4 * 60; 	/* Wait 4 minutes for NOTIFY from Messenger */
+
+      eu->eu_final_wait = 1;
+
+      /* Do not remove usage in nua_stack_process_response  */
+      cr->cr_usage = NULL;	
+
+      nua_dialog_usage_refresh_range(du, delta, delta);
+    }
+    else {
+      eu->eu_substate = substate = nua_substate_terminated;
+    }
+  }
+  else /* if (status >= 300) */ {
+    int terminated;
+
+    if (nua_creq_check_restart(nh, cr, orq, sip, restart_subscribe))
+      return 0;
+
+    cr->cr_usage = NULL; /* We take care of removing/not removing usage */
+
+    substate = eu->eu_substate;
+
+    if (!sip || !sip->sip_retry_after)
+      gracefully = 1;
+
+    terminated = 
+      sip_response_terminates_dialog(status, sip_method_subscribe, 
+				     &gracefully);
+
+    /* XXX - zap dialog if terminated < 0 ? */
+
+    if (terminated || !du->du_ready || du->du_terminating) {
+      substate = nua_substate_terminated;
+      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+    }
+    else if (gracefully && substate != nua_substate_terminated) 
+      /* Post un-subscribe event */
+      nua_stack_post_signal(nh, nua_r_unsubscribe, 
+			    SIPTAG_EVENT(du->du_event), 
+			    SIPTAG_EXPIRES_STR("0"),
+			    TAG_END());
+  }
+
+  nua_stack_process_response(nh, cr, orq, sip, 
+			     TAG_IF(substate >= 0, NUTAG_SUBSTATE(substate)),
+			     TAG_END());
+  return 0;
+}
+
+/** Refresh subscription */
+static void nua_subscribe_usage_refresh(nua_handle_t *nh,
+					nua_dialog_state_t *ds,
+					nua_dialog_usage_t *du,
+					sip_time_t now)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_client_request_t *cr = ds->ds_cr;
+  struct event_usage *eu = nua_dialog_usage_private(du);
+  msg_t *msg;
+
+  assert(eu);
+  
+  if (eu->eu_final_wait) {
+    /* Did not receive NOTIFY for fetch... */
+    sip_event_t const *o = du->du_event;
+    char const *id = o ? o->o_id : NULL;
+
+    SU_DEBUG_3(("nua(%p): fetch event %s%s%s timeouts\n",
+		nh, o ? o->o_type : "(empty)",
+		id ? "; id=" : "", id ? id : ""));
+
+    nua_stack_event(nh->nh_nua, nh,  NULL,
+		    nua_i_notify, 408, "Fetch Timeouts without NOTIFY", 
+		    NUTAG_SUBSTATE(nua_substate_terminated),
+		    SIPTAG_EVENT(o),
+		    TAG_END());
+
+    nua_dialog_usage_remove(nh, ds, du);
+
+    return;
+  }
+
+  if (du->du_terminating)	/* No need to refresh. */
+    return;
+
+  if (cr->cr_msg) {
+    /* Already doing something, delay 5..15 seconds? */
+    if (cr->cr_usage != du)
+      nua_dialog_usage_refresh_range(du, 5, 15);
+    return;
+  }
+
+  cr->cr_msg = msg_copy(du->du_msg);
+
+  msg = nua_creq_msg(nua, nh, cr, 1,
+		     SIP_METHOD_SUBSCRIBE,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     /* If dialog is established, remove initial route */
+		     TAG_IF(nua_dialog_is_established(nh->nh_ds),
+			    SIPTAG_ROUTE(NONE)),
+		     TAG_END());
+
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_subscribe, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(NULL));
+  if (cr->cr_orq) {
+    cr->cr_usage = du;
+    cr->cr_event = nua_r_subscribe;
+    return;
+  }
+
+  if (du->du_terminating)
+    nua_dialog_usage_remove(nh, nh->nh_ds, du);
+  else   /* Try again later? */
+    nua_dialog_usage_refresh_range(du, 5, 15);
+
+  msg_destroy(msg);
+  UA_EVENT3(nua_r_subscribe, NUA_INTERNAL_ERROR, 
+	    NUTAG_SUBSTATE(eu->eu_substate),
+	    TAG_END());
+}
+
+
+/** Terminate subscription */
+static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
+					nua_dialog_state_t *ds,
+					nua_dialog_usage_t *du)
+{
+  nua_t *nua = nh->nh_nua;
+  nua_client_request_t *cr = ds->ds_cr;
+  struct event_usage *eu = nua_dialog_usage_private(du);
+  msg_t *msg;
+
+  assert(eu); (void)eu;
+
+  if (du->du_terminating)
+    return 100;			/* ...in progress */
+  
+  if (cr->cr_msg)
+    /* XXX - already doing something else? */
+    return 100;
+
+  cr->cr_msg = msg_copy(du->du_msg);
+
+  msg = nua_creq_msg(nua, nh, cr, 1,
+		     SIP_METHOD_SUBSCRIBE,
+		     NUTAG_USE_DIALOG(1),
+		     NUTAG_ADD_CONTACT(1),
+		     SIPTAG_EXPIRES_STR("0"),
+		     /* If dialog is established, remove initial route */
+		     TAG_IF(nua_dialog_is_established(nh->nh_ds),
+			    SIPTAG_ROUTE(NONE)),
+		     TAG_END());
+
+  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				    process_response_to_subscribe, nh, NULL,
+				    msg,
+				    SIPTAG_END(), TAG_NEXT(NULL));
+  if (cr->cr_orq) {
+    cr->cr_usage = du;
+    cr->cr_event = nua_r_destroy;
+    return 100;
+  }
+
+  /* Too bad. */
+  nua_dialog_usage_remove(nh, ds, du);
+  msg_destroy(msg);
+  return 200;
+}
+
+/* ======================================================================== */
+/* NOTIFY server */
+
+/** @NUA_EVENT nua_i_notify
+ *
+ * Event for incoming NOTIFY request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip    incoming NOTIFY request
+ * @param tags   NUTAG_SUBSTATE() indicating the subscription state
+ *
+ * @sa nua_subscribe(), nua_unsubscribe(), @RFC3265, #nua_i_subscribe
+ * 
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming NOTIFY. */
+int nua_stack_process_notify(nua_t *nua,
+			     nua_handle_t *nh,
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  nua_dialog_state_t *ds = nh->nh_ds;
+  nua_dialog_usage_t *du;
+  struct event_usage *eu;
+  sip_subscription_state_t *subs = sip ? sip->sip_subscription_state : NULL;
+  sip_subscription_state_t ss0[1];
+  msg_t *response;
+  char expires[32];
+  int retry = -1;
+  char const *what = NULL, *why = NULL;
+
+  enter;
+
+  if (nh == NULL) {
+    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", 
+			TAG_END());
+    return 481;
+  }
+  assert(nh);
+
+  if (/* XXX - support forking of subscriptions?... */
+      ds->ds_remote_tag && ds->ds_remote_tag[0] && 
+      sip && sip->sip_from->a_tag &&
+      strcmp(ds->ds_remote_tag, sip->sip_from->a_tag)) {
+    sip_contact_t const *m = NULL;
+    sip_warning_t *w = NULL, w0[1];
+
+    m = nua_stack_get_contact(nua->nua_registrations);
+    if (m) {
+      w = sip_warning_init(w0);
+      w->w_code = 399;
+      w->w_host = m->m_url->url_host;
+      w->w_port = m->m_url->url_port;
+      w->w_text = "Forking SUBSCRIBEs are not supported";
+    }
+
+    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", 
+			SIPTAG_WARNING(w),
+			TAG_END());
+    return 481;
+  }
+
+  du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, sip->sip_event);
+
+  if (du == NULL) {
+    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END());
+    return 481;
+  }
+
+  eu = nua_dialog_usage_private(du); assert(eu);
+  eu->eu_notified++;
+
+  if (!sip->sip_event->o_id) {
+    eu->eu_no_id = 1;
+  }
+
+  if (subs == NULL) {
+    /* Do some compatibility stuff here */
+    unsigned long delta;
+
+    sip_subscription_state_init(subs = ss0);
+
+    delta = sip->sip_expires ? sip->sip_expires->ex_delta : eu->eu_expires;
+
+    if (delta == 0)
+      subs->ss_substate = "terminated";
+    else
+      subs->ss_substate = "active";
+
+    if (delta > 0 && sip->sip_expires) {
+      snprintf(expires, sizeof expires, "%lu", delta);
+      subs->ss_expires = expires;
+    }
+  }
+
+  nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+  nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+
+  if (strcasecmp(subs->ss_substate, what = "terminated") == 0) {
+    eu->eu_substate = nua_substate_terminated;
+
+    if (str0casecmp(subs->ss_reason, why = "deactivated") == 0) {
+      eu->eu_substate = nua_substate_embryonic;
+      retry = 0;		/* retry immediately */
+    } 
+    else if (str0casecmp(subs->ss_reason, why = "probation") == 0) {
+      eu->eu_substate = nua_substate_embryonic;
+      retry = 30;
+      if (subs->ss_retry_after)
+	retry = strtoul(subs->ss_retry_after, NULL, 10);
+      if (retry > 3600)
+	retry = 3600;
+    }
+    else
+      why = subs->ss_reason;
+  }
+  else if (strcasecmp(subs->ss_substate, what = "pending") == 0)
+    eu->eu_substate = nua_substate_pending;
+  else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ {
+    /* Any extended state is considered as active */
+    what = subs->ss_substate ? subs->ss_substate : "active";
+    eu->eu_substate = nua_substate_active;
+  }
+
+  if (du->du_terminating)
+    retry = -1;
+  
+  response = nh_make_response(nua, nh, irq, SIP_200_OK,
+			      SIPTAG_ALLOW(NH_PGET(nh, allow)),
+			      SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+			      TAG_END());
+
+  if (response && 
+      nua_registration_add_contact_to_response(nh, response, NULL, 
+					       sip->sip_record_route,
+					       sip->sip_contact) >= 0)
+    nta_incoming_mreply(irq, response);
+  else
+    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+
+  if (eu->eu_substate == nua_substate_terminated && retry > 0)
+    eu->eu_substate = nua_substate_embryonic;
+
+  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+		  nua_i_notify, SIP_200_OK, 
+		  NUTAG_SUBSTATE(eu->eu_substate),
+		  TAG_END());
+
+  nta_incoming_destroy(irq), irq = NULL;
+
+  SU_DEBUG_5(("nua(%p): nua_stack_process_notify: %s (%s)\n", 
+	      nh, what, why ? why : ""));
+
+  if (eu->eu_substate == nua_substate_terminated) {
+    if (du != nh->nh_ds->ds_cr->cr_usage)
+      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+    else
+      nua_dialog_usage_reset_refresh(du);
+  }
+  else if (eu->eu_substate == nua_substate_embryonic) {
+    if (retry >= 0) {
+      /* Try to subscribe again */
+      nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */
+      nua_dialog_usage_refresh_range(du, retry, retry + 5);
+    }
+    else if (du != nh->nh_ds->ds_cr->cr_usage)
+      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+    else
+      nua_dialog_usage_reset_refresh(du);
+  }
+  else if (du->du_terminating) {
+    nua_dialog_usage_reset_refresh(du);
+  }
+  else {
+    sip_time_t delta;
+
+    if (subs->ss_expires)
+      delta = strtoul(subs->ss_expires, NULL, 10);
+    else
+      delta = eu->eu_expires;
+    
+    nua_dialog_usage_set_refresh(du, delta);
+  }
+
+  return 0;
+}
+
+/* ======================================================================== */
+/* REFER */
+
+/** Transfer a call. 
+ * 
+ * Send a REFER request asking the recipient to transfer the call. 
+ *
+ * The REFER request also establishes an implied subscription to the "refer"
+ * event. The "refer" event can have an "id" parameter, which has the value
+ * of CSeq number in the REFER request. After initiating the REFER request,
+ * the nua engine sends application a #nua_r_refer event with status 100 and
+ * tag NUTAG_REFER_EVENT() containing a matching event header with id
+ * parameter.
+ *
+ * Note that the @Event header in the locally generated #nua_r_refer event
+ * contains the @a id parameter. The @a id parameter contains the @CSeq
+ * number of the REFER request, and it may get incremented if the request is
+ * retried because it got challenged or redirected. In that case, the
+ * application gets a new #nua_r_refer event with status 100 and tag
+ * NUTAG_REFER_EVENT(). Also the recipient of the REFER request may or may
+ * not include the @a id parameter with the @Event header in the NOTIFY
+ * requests messages which it sends to the sender of the REFER request.
+ *
+ * Therefore the application is not able to modify the state of the implied
+ * subscription before receiving the first NOTIFY request.
+ *
+ * @param nh              Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return 
+ *    nothing
+ *
+ * @par Related Tags:
+ *    NUTAG_URL() \n
+ *    Tags of nua_set_hparams() \n
+ *    Tags in <sip_tag.h>
+ *
+ * @par Events:
+ *    #nua_r_refer \n
+ *    #nua_i_notify
+ *
+ * @sa #nua_r_refer, NUTAG_SUBSTATE(), NUTAG_REFER_EVENT(),#nua_i_refer,
+ * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
+ */
+
+static int process_response_to_refer(nua_handle_t *nh,
+				     nta_outgoing_t *orq,
+				     sip_t const *sip);
+
+int
+nua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+  nua_dialog_usage_t *du = NULL;
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  msg_t *msg;
+  sip_t *sip;
+  sip_referred_by_t by[1];
+  sip_event_t *event = NULL;
+
+  if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
+    return UA_EVENT2(e, 900, "Invalid handle for REFER");
+  else if (cr->cr_orq)
+    return UA_EVENT2(e, 900, "Request already in progress");
+
+  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+  sip_referred_by_init(by);
+  by->b_display = nua->nua_from->a_display;
+  *by->b_url = *nua->nua_from->a_url;
+
+  /* Now we create a REFER request message */
+  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+			 SIP_METHOD_REFER,
+			 NUTAG_USE_DIALOG(1),
+			 SIPTAG_EVENT(SIP_NONE), /* remove event */
+			 SIPTAG_REFERRED_BY(by), /* Overriden by user tags */
+			 NUTAG_ADD_CONTACT(1),
+			 TAG_NEXT(tags));
+  sip = sip_object(msg);
+
+  if (sip && sip->sip_cseq)
+    event = sip_event_format(nh->nh_home, "refer;id=%u", 
+			     sip->sip_cseq->cs_seq);
+
+  if (event)
+    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event);
+  
+  if (du)
+    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+				      process_response_to_refer, nh, NULL,
+				      msg,
+				      SIPTAG_END(), TAG_NEXT(tags));
+  
+  if (!cr->cr_orq) {
+    if (du)
+      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+    su_free(nh->nh_home, event);
+    msg_destroy(msg);
+    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+  }
+
+  /*
+   * We send a 100 trying event so that application gets a event 
+   * it can use to match NOTIFYs with its REFER
+   */
+  nua_stack_event(nua, nh, NULL, e, SIP_100_TRYING, 
+	   NUTAG_REFER_EVENT(event),
+	   TAG_END());
+  su_free(nh->nh_home, event);
+
+  cr->cr_usage = du;
+
+  return cr->cr_event = e;
+}
+
+void restart_refer(nua_handle_t *nh, tagi_t *tags)
+{
+  nua_stack_refer(nh->nh_nua, nh, nh->nh_ds->ds_cr->cr_event, tags);
+}
+
+/**@NUA_EVENT nua_r_refer
+ *
+ * @brief Response to outgoing REFER.
+ *
+ * @param status response status code
+ *               (if the request is retried, @a status is 100, the @a
+ *               sip->sip_status->st_status contain the real status code
+ *               from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh     operation handle associated with the REFER request
+ * @param hmagic application context associated with the handle
+ * @param sip    response to REFER request or NULL upon an error
+ *               (status code is in @a status and 
+ *                descriptive message in @a phrase parameters)
+ * @param tags    NUTAG_REFER_EVENT() \n
+ *                NUTAG_SUBSTATE()
+ *
+ * @sa nua_refer(), NUTAG_SUBSTATE(), #nua_i_refer,
+ * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_refer(nua_handle_t *nh,
+				     nta_outgoing_t *orq,
+				     sip_t const *sip)
+{
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
+  int status = sip ? sip->sip_status->st_status : 408;
+
+  if (status < 200)
+    ;
+  else if (status < 300) {
+    if (cr->cr_usage)
+      cr->cr_usage->du_ready = 1;
+    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+  }
+  else /* if (status >= 300) */ {
+    if (cr->cr_usage)
+      nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage), cr->cr_usage = NULL;
+    if (nua_creq_check_restart(nh, cr, orq, sip, restart_refer))
+      return 0;
+  }
+
+  return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_tag.c  Tags and tag lists for NUA
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Feb 21 10:13:29 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "nua"
+
+#include "sofia-sip/nua_tag.h"
+
+#include <sofia-sip/msg_header.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/sip_hclasses.h>
+
+tag_typedef_t nutag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t nutag_url = URLTAG_TYPEDEF(url);
+tag_typedef_t nutag_address = STRTAG_TYPEDEF(address);
+tag_typedef_t nutag_method = STRTAG_TYPEDEF(method);
+tag_typedef_t nutag_uicc = STRTAG_TYPEDEF(uicc);
+tag_typedef_t nutag_media_features = BOOLTAG_TYPEDEF(media_features);
+tag_typedef_t nutag_callee_caps = BOOLTAG_TYPEDEF(callee_caps);
+tag_typedef_t nutag_early_media = BOOLTAG_TYPEDEF(early_media);
+tag_typedef_t nutag_only183_100rel = BOOLTAG_TYPEDEF(only183_100rel);
+tag_typedef_t nutag_early_answer = BOOLTAG_TYPEDEF(early_answer);
+tag_typedef_t nutag_include_extra_sdp = BOOLTAG_TYPEDEF(include_extra_sdp);
+tag_typedef_t nutag_media_enable = BOOLTAG_TYPEDEF(media_enable);
+
+tag_typedef_t nutag_soa_session = PTRTAG_TYPEDEF(soa_session);
+tag_typedef_t nutag_soa_name = STRTAG_TYPEDEF(soa_name);
+
+tag_typedef_t nutag_retry_count = UINTTAG_TYPEDEF(retry_count);
+tag_typedef_t nutag_max_subscriptions = UINTTAG_TYPEDEF(max_subscriptions);
+
+tag_typedef_t nutag_callstate = INTTAG_TYPEDEF(callstate);
+tag_typedef_t nutag_offer_recv = BOOLTAG_TYPEDEF(offer_recv);
+tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv);
+tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent);
+tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent);
+tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate);
+tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer);
+tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer);
+tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se);
+tag_typedef_t nutag_session_refresher = INTTAG_TYPEDEF(session_refresher);
+tag_typedef_t nutag_update_refresh = BOOLTAG_TYPEDEF(update_refresh);
+tag_typedef_t nutag_refer_expires = UINTTAG_TYPEDEF(refer_expires);
+tag_typedef_t nutag_refer_with_id = BOOLTAG_TYPEDEF(refer_with_id);
+tag_typedef_t nutag_autoalert = BOOLTAG_TYPEDEF(autoAlert);
+tag_typedef_t nutag_autoanswer = BOOLTAG_TYPEDEF(autoAnswer);
+tag_typedef_t nutag_autoack = BOOLTAG_TYPEDEF(autoACK);
+tag_typedef_t nutag_enableinvite = BOOLTAG_TYPEDEF(enableInvite);
+tag_typedef_t nutag_enablemessage = BOOLTAG_TYPEDEF(enableMessage);
+tag_typedef_t nutag_enablemessenger = BOOLTAG_TYPEDEF(enableMessenger);
+
+
+/* Start NRC Boston */
+tag_typedef_t nutag_smime_enable = BOOLTAG_TYPEDEF(smime_enable);
+tag_typedef_t nutag_smime_opt = INTTAG_TYPEDEF(smime_opt);
+tag_typedef_t nutag_smime_protection_mode = 
+  INTTAG_TYPEDEF(smime_protection_mode);
+tag_typedef_t nutag_smime_message_digest = 
+  STRTAG_TYPEDEF(smime_message_digest);
+tag_typedef_t nutag_smime_signature = 
+  STRTAG_TYPEDEF(smime_signature);
+tag_typedef_t nutag_smime_key_encryption = 
+  STRTAG_TYPEDEF(smime_key_encryption);
+tag_typedef_t nutag_smime_message_encryption = 
+  STRTAG_TYPEDEF(smime_message_encryption);
+/* End NRC Boston */
+
+tag_typedef_t nutag_sips_url = URLTAG_TYPEDEF(sips_url);
+tag_typedef_t nutag_certificate_dir = STRTAG_TYPEDEF(certificate_dir);
+tag_typedef_t nutag_certificate_phrase = STRTAG_TYPEDEF(certificate_phrase);
+
+tag_typedef_t nutag_registrar = URLTAG_TYPEDEF(registrar);
+tag_typedef_t nutag_identity = PTRTAG_TYPEDEF(identity);
+tag_typedef_t nutag_m_display = STRTAG_TYPEDEF(m_display);
+tag_typedef_t nutag_m_username = STRTAG_TYPEDEF(m_username);
+tag_typedef_t nutag_m_params = STRTAG_TYPEDEF(m_params);
+tag_typedef_t nutag_m_features = STRTAG_TYPEDEF(m_features);
+tag_typedef_t nutag_instance = STRTAG_TYPEDEF(instance);
+tag_typedef_t nutag_outbound = STRTAG_TYPEDEF(outbound);
+
+tag_typedef_t nutag_outbound_set1 = STRTAG_TYPEDEF(outbound_set1);
+tag_typedef_t nutag_outbound_set2 = STRTAG_TYPEDEF(outbound_set2);
+tag_typedef_t nutag_outbound_set3 = STRTAG_TYPEDEF(outbound_set3);
+tag_typedef_t nutag_outbound_set4 = STRTAG_TYPEDEF(outbound_set4);
+
+tag_typedef_t nutag_keepalive = UINTTAG_TYPEDEF(keepalive);
+tag_typedef_t nutag_keepalive_stream = UINTTAG_TYPEDEF(keepalive_stream);
+
+tag_typedef_t nutag_use_dialog = BOOLTAG_TYPEDEF(use_dialog);
+
+tag_typedef_t nutag_auth = STRTAG_TYPEDEF(auth);
+tag_typedef_t nutag_authtime = INTTAG_TYPEDEF(authtime);
+
+tag_typedef_t nutag_event = INTTAG_TYPEDEF(event);
+tag_typedef_t nutag_status = INTTAG_TYPEDEF(status);
+tag_typedef_t nutag_phrase = STRTAG_TYPEDEF(phrase);
+
+tag_typedef_t nutag_handle = PTRTAG_TYPEDEF(handle);
+
+tag_typedef_t nutag_hold = BOOLTAG_TYPEDEF(hold);
+
+tag_typedef_t nutag_notify_refer = PTRTAG_TYPEDEF(notify_refer);
+tag_typedef_t nutag_refer_event = SIPHDRTAG_NAMED_TYPEDEF(refer_event, event);
+tag_typedef_t nutag_refer_pause = BOOLTAG_TYPEDEF(refer_pause);
+tag_typedef_t nutag_user_agent = STRTAG_TYPEDEF(user_agent);
+tag_typedef_t nutag_allow = STRTAG_TYPEDEF(allow);
+tag_typedef_t nutag_allow_events = STRTAG_TYPEDEF(allow_events);
+tag_typedef_t nutag_appl_method = STRTAG_TYPEDEF(appl_method);
+tag_typedef_t nutag_supported = STRTAG_TYPEDEF(supported);
+tag_typedef_t nutag_path_enable = BOOLTAG_TYPEDEF(path_enable);
+tag_typedef_t nutag_service_route_enable = 
+  BOOLTAG_TYPEDEF(service_route_enable);
+
+tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates);
+
+tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with);
+
+tag_typedef_t _nutag_add_contact = BOOLTAG_TYPEDEF(add_contact);
+tag_typedef_t _nutag_copy = BOOLTAG_TYPEDEF(copy);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1237 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE outbound.c
+ * @brief Implementation of SIP NAT traversal and outbound
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed May 10 12:11:54 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#define NTA_OUTGOING_MAGIC_T struct outbound
+
+#include <outbound.h>
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/nta_tport.h>
+
+#include <sofia-sip/su_md5.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/token64.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+struct outbound {
+  su_home_t ob_home[1];
+  outbound_owner_vtable
+  const *ob_oo;			/**< Callbacks */
+  outbound_owner_t *ob_owner;	/**< Backpointer */
+
+  su_root_t *ob_root;		/**< Root for timers and stuff */
+  nta_agent_t *ob_nta;		/**< SIP transactions */
+
+  char ob_cookie[32];		/**< Our magic cookie */
+
+  struct outbound_prefs {
+    unsigned interval;	/**< Default keepalive interval for datagram */
+    unsigned stream_interval;	/**< Default keepalive interval for streams */
+    unsigned gruuize:1;		/**< Establish a GRUU */
+    unsigned outbound:1;	/**< Try to use outbound */
+    unsigned natify:1;		/**< Try to detect NAT */
+    unsigned okeepalive:1;	/**< Connection keepalive with OPTIONS */
+    unsigned validate:1;	/**< Validate registration with OPTIONS */
+    /* How to detect NAT binding or connect to outbound: */
+    unsigned use_connect:1;	/**< Use HTTP connect */
+    unsigned use_rport:1;	/**< Use received/rport */
+    unsigned use_socks:1;	/**< Detect and use SOCKS V5 */
+    unsigned use_upnp:1;	/**< Detect and use UPnP */
+    unsigned use_stun:1;	/**< Detect and try to use STUN */
+    unsigned :0;
+  } ob_prefs;
+
+  struct outbound_info {
+    /* See enum outbound_feature: */
+    /* 0 do not support, 1 - perhaps supports, 2 - supports, 3 - requires */
+    unsigned gruu:2, outbound:2, pref:2;
+  } ob_info;
+
+  /** Source of Contact header */
+  unsigned ob_by_stack:1;
+  /** Self-generated contacts */
+  unsigned ob_contacts:1, :0;
+
+  /* The registration state machine. */
+  /** Initial REGISTER containing ob_rcontact has been sent */
+  unsigned ob_registering:1;
+  /** 2XX response to REGISTER containg ob_rcontact has been received */
+  unsigned ob_registered:1;
+  /**The registration has been validated:
+   * We have successfully sent OPTIONS to ourselves.
+   */
+  unsigned ob_validated:1;
+  /** The registration has been validated once.
+   *   We have successfully sent OPTIONS to ourselves, so do not give
+   *   up if OPTIONS probe fails.
+   */
+  unsigned ob_once_validated:1;
+  unsigned :0;
+
+  char const *ob_instance;	/**< Our instance ID */
+  int32_t ob_reg_id;		/**< Flow-id */
+  char const *ob_features;	/**< Feature parameters for rcontact */
+  sip_contact_t *ob_rcontact;	/**< Our contact */
+  sip_contact_t *ob_dcontact;	/**< Contact for dialogs */
+  sip_contact_t *ob_previous;	/**< Stale contact */
+  sip_contact_t *ob_gruu;	/**< Contact added to requests */
+  sip_via_t *ob_via;		/**< Via header used to generate contacts */
+
+  sip_contact_t *ob_obp;	/**< Contacts from outbound proxy */
+
+  char *ob_nat_detected;	/**< Our public address */
+  char *ob_nat_port;		/**< Our public port number */
+
+  void *ob_stun;		/**< Stun context */
+  void *ob_upnp;		/**< UPnP context  */
+
+  struct {
+    char *sipstun;		/**< Stun server usable for keep-alives */
+    unsigned interval;		/**< Interval. */
+    su_timer_t *timer;		/**< Keep-alive timer */
+    msg_t *msg;			/**< Keep-alive OPTIONS message */
+    nta_outgoing_t *orq;	/**< Keep-alive OPTIONS transaction */
+    auth_client_t *auc[1];	/**< Authenticator for OPTIONS */
+    /** Progress of registration validation */
+    unsigned validating:1, validated:1,:0;
+  } ob_keepalive;		/**< Keepalive informatio */
+};
+
+static
+int outbound_nat_detect(outbound_t *ob,
+       			 sip_t const *request,
+       			 sip_t const *response);
+
+/** Return values for outbound_nat_detect(). */
+enum {
+  ob_nat_error = -1,		/* or anything below zero */
+  ob_no_nat = 0,
+  ob_nat_detected = 1,
+  ob_nat_changed = 2
+};
+
+/* ---------------------------------------------------------------------- */
+
+#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL
+
+/** Content-Type sent in OPTIONS probing connectivity */
+char const * const outbound_content_type = "application/vnd.nokia-register-usage";
+
+static
+int outbound_check_for_nat(outbound_t *ob,
+			   sip_t const *request,
+			   sip_t const *response);
+
+enum outbound_feature {
+  outbound_feature_unsupported = 0,
+  outbound_feature_unsure = 1,
+  outbound_feature_supported = 2,
+  outbound_feature_required = 3
+};
+
+static enum outbound_feature feature_level(sip_t const *sip,
+					   char const *tag, int level);
+
+static int outbound_contacts_from_via(outbound_t *ob,
+				      sip_via_t const *via);
+
+/* ---------------------------------------------------------------------- */
+
+/** Create a new outbound object */
+outbound_t *
+outbound_new(outbound_owner_t *owner,
+	     outbound_owner_vtable const *owner_methods,
+	     su_root_t *root,
+	     nta_agent_t *agent,
+	     char const *instance)
+{
+  outbound_t *ob;
+
+  if (!owner || !owner_methods || !root || !agent)
+    return NULL;
+
+  ob = su_home_clone((su_home_t *)owner, sizeof *ob);
+  
+  if (ob) {
+    su_md5_t md5[1];
+    uint8_t digest[SU_MD5_DIGEST_SIZE];
+    su_guid_t guid[1];
+
+    ob->ob_owner = owner;
+    ob->ob_oo = owner_methods;
+    ob->ob_root = root;
+    ob->ob_nta = agent;
+
+    if (instance)
+      ob->ob_instance = su_strcat_all(ob->ob_home, "+sip.instance=\"<", instance, ">\"", NULL);
+    ob->ob_reg_id = 0;
+
+    /* Generate a cookie (used as Call-ID) for us */
+    su_md5_init(md5);
+    su_guid_generate(guid);
+    if (instance)
+      su_md5_update(md5, (void *)instance, strlen(instance));
+    su_md5_update(md5, (void *)guid, sizeof guid);
+    su_md5_digest(md5, digest);
+    token64_e(ob->ob_cookie, sizeof ob->ob_cookie, digest, sizeof digest);
+    
+    if (instance && !ob->ob_instance)
+      su_home_unref(ob->ob_home), ob = NULL;
+  }
+
+  return ob;
+}
+
+void outbound_unref(outbound_t *ob)
+{
+  if (ob->ob_keepalive.timer)
+    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+  if (ob->ob_keepalive.orq)
+    nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;
+
+  if (ob->ob_keepalive.msg)
+    msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;
+
+  su_home_unref(ob->ob_home);
+}
+
+#include <sofia-sip/bnf.h>
+
+/** Set various outbound and nat-traversal related options. */
+int outbound_set_options(outbound_t *ob,
+			 char const *options,
+			 unsigned interval,
+			 unsigned stream_interval)
+{
+  struct outbound_prefs prefs[1] = {{ 0 }};
+  char const *s;
+
+  prefs->interval = interval;
+  prefs->stream_interval = stream_interval;
+
+  prefs->gruuize = 1;
+  prefs->outbound = 0;
+  prefs->natify = 1;
+  prefs->okeepalive = 1;
+  prefs->validate = 1;
+  prefs->use_rport = 1;
+
+#define MATCH(v) (len == sizeof(#v) - 1 && strncasecmp(#v, s, len) == 0)
+
+  for (s = options; s && s[0]; ) {
+    size_t len = span_token(s);
+    int value = 1;
+
+    if (len > 3 && strncasecmp(s, "no-", 3) == 0)
+      value = 0, s += 3, len -= 3;
+    else if (len > 4 && strncasecmp(s, "not-", 4) == 0)
+      value = 0, s += 4, len -= 4;
+    else if (len > 3 && strncasecmp(s, "no_", 3) == 0)
+      value = 0, s += 3, len -= 3;
+    else if (len > 4 && strncasecmp(s, "not_", 4) == 0)
+      value = 0, s += 4, len -= 4;
+
+    if (len == 0)
+      break;
+    else if (MATCH(gruuize)) prefs->gruuize = value;
+    else if (MATCH(outbound)) prefs->outbound = value;
+    else if (MATCH(natify)) prefs->natify = value;
+    else if (MATCH(validate)) prefs->validate = value;
+    else if (MATCH(options-keepalive)) prefs->okeepalive = value;
+    else if (MATCH(options_keepalive)) prefs->okeepalive = value;
+    else if (MATCH(use-connect)) prefs->use_connect = value;
+    else if (MATCH(use_connect)) prefs->use_connect = value;
+    else if (MATCH(use-rport) || MATCH(use_rport)) prefs->use_rport = value;
+    else if (MATCH(use-socks) || MATCH(use_socks)) prefs->use_socks = value;
+    else if (MATCH(use-upnp) || MATCH(use_upnp)) prefs->use_upnp = value;
+    else if (MATCH(use-stun) || MATCH(use_stun)) prefs->use_stun = value;
+    else
+      SU_DEBUG_1(("outbound_t: unknown option \"%.*s\"\n", (int)len, s));
+
+    s += len;
+    len = strspn(s, " \t\n\r,;");
+    if (len == 0)
+      break;
+    s += len;
+  }
+
+  if (s && s[0]) {
+    SU_DEBUG_1(("outbound_t: invalid options \"%s\"\n", options));
+    return -1;
+  }
+
+  if (prefs->natify &&
+      !(prefs->outbound ||
+	prefs->use_connect ||
+	prefs->use_rport ||
+	prefs->use_socks ||
+	prefs->use_upnp ||
+	prefs->use_stun)) {
+    SU_DEBUG_1(("outbound(%p): no nat traversal method given\n", ob->ob_owner));
+  }
+
+  ob->ob_prefs = *prefs;
+  ob->ob_reg_id = prefs->outbound ? 1 : 0;
+
+  return 0;
+}
+
+/** Set the feature string (added to the Contact header when registering). */
+int outbound_set_features(outbound_t *ob, char *features)
+{
+  char *old_features = (char *)ob->ob_features;
+  char *new_features = su_strdup(ob->ob_home, features);
+
+  if (features && !new_features)
+    return -1;
+
+  ob->ob_features = new_features;
+  su_free(ob->ob_home, old_features);
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Hook for sending register request with extra outbound-ish headers. */
+nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating, 
+					  sip_contact_t *stack_contact,
+					  nta_agent_t *nta,
+					  nta_response_f *callback,
+					  nta_outgoing_magic_t *magic,
+					  url_string_t *next_hop,
+					  msg_t *msg,
+					  tag_type_t tag, tag_value_t value,
+					  ...)
+{
+  sip_contact_t *previous_contact = NULL;
+  ta_list ta;
+  nta_outgoing_t *orq;
+
+  if (stack_contact) {
+    if (ob) {
+      if (ob->ob_contacts)
+	stack_contact = ob->ob_rcontact;
+      previous_contact = ob->ob_previous;
+    }
+  }
+
+  ta_start(ta, tag, value);
+
+  orq = nta_outgoing_mcreate(nta, callback, magic, next_hop, msg,
+			     TAG_IF(previous_contact,
+				    SIPTAG_CONTACT(previous_contact)),
+			     TAG_IF(stack_contact,
+				    SIPTAG_CONTACT(stack_contact)),
+			     ta_tags(ta));
+
+  ta_end(ta);
+
+  if (orq && ob)
+    ob->ob_registering = 1;
+
+  return orq;
+}
+
+/** Process response to REGISTER request */
+int outbound_register_response(outbound_t *ob,
+			       int terminating,
+			       sip_t const *request,
+			       sip_t const *response)
+{
+  int status, reregister;
+
+  if (!ob)
+    return 0;
+
+  assert(!request || request->sip_request);
+  assert(!response || response->sip_status);
+  
+  if (!response || !request)
+    return 0;
+
+  if (terminating) {
+    ob->ob_registered = ob->ob_registering = 0;
+    return 0;			/* Cleanup is done separately */
+  }  
+
+  reregister = outbound_check_for_nat(ob, request, response);
+  if (reregister)
+    return reregister;
+
+  status = response->sip_status->st_status;
+
+  if (status < 300) {
+    if (request->sip_contact && response->sip_contact)
+      ob->ob_registered = ob->ob_registering;
+    else
+      ob->ob_registered = 0;
+
+    if (ob->ob_previous)
+      msg_header_free(ob->ob_home, (void *)ob->ob_previous);
+    ob->ob_previous = NULL;
+  }
+
+  return 0;
+}
+
+
+/** @internal Check if there is a NAT between us and registrar */
+static
+int outbound_check_for_nat(outbound_t *ob,
+			   sip_t const *request,
+			   sip_t const *response)
+{
+  int binding_changed;
+  sip_contact_t *m = ob->ob_rcontact;
+
+  /* Update NAT information */
+  binding_changed = outbound_nat_detect(ob, request, response);
+
+  if (!ob->ob_nat_detected)
+    return ob_no_nat;
+
+  /* Contact was set by application, do not change it */
+  if (!ob->ob_by_stack)
+    return ob_no_nat;
+
+  /* Application does not want us to do any NAT traversal */ 
+  if (!ob->ob_prefs.natify)
+    return ob_no_nat;
+
+  /* We have detected NAT. Now, what to do?
+   * 1) do nothing - register as usual and let proxy take care of it?
+   * 2) try to detect our public nat binding and use it
+   * 2A) use public vias from nta generated by STUN or UPnP
+   * 2B) use SIP Via header
+   */
+
+  /* Do we have to ask for reregistration */
+  if (!m || binding_changed >= ob_nat_changed) {
+    if (ob->ob_stun) {
+      /* Use STUN? */
+      return 1;
+    }
+    else if (ob->ob_upnp) {
+      /* Use UPnP */
+      return 1;
+    }
+    else {
+      if (outbound_contacts_from_via(ob, response->sip_via) < 0)
+        return -1;
+    }
+
+    return 2;
+  }
+
+  return 0;
+}
+
+/**@internal
+ *
+ * Detect NAT.
+ *
+ * Based on "received" and possible "rport" parameters in the top-most Via,
+ * check and update our NAT status.
+ *
+ * @retval ob_nat_changed (2) change in public NAT binding detected
+ * @retval ob_nat_detected (1) NAT binding detected
+ * @retval ob_no_nat (0) no NAT binding detected
+ * @retval -1 an error occurred
+ */
+static
+int outbound_nat_detect(outbound_t *ob,
+			sip_t const *request,
+			sip_t const *response)
+{
+  sip_via_t const *v;
+  int one = 1;
+  char const *received, *rport;
+  char *nat_detected, *nat_port;
+  char *new_detected, *new_port;
+
+  assert(request && request->sip_request);
+  assert(response && response->sip_status);
+
+  if (!ob || !response || !response->sip_via || !request->sip_via)
+    return -1;
+
+  v = response->sip_via;
+
+  received = v->v_received;
+  if (!received || !strcmp(received, request->sip_via->v_host))
+    return 0;
+
+  if (!host_is_ip_address(received)) {
+    if (received[0])
+      SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n",
+		  ob->ob_owner, received));
+    return 0;
+  }
+
+  rport = sip_via_port(v, &one); assert(rport);
+
+  nat_detected = ob->ob_nat_detected;
+  nat_port = ob->ob_nat_port;
+
+  if (nat_detected && host_cmp(received, nat_detected) == 0) {
+    if (nat_port && strcasecmp(rport, nat_port) == 0)
+      return 1;
+    if (!v->v_rport || !v->v_rport[0])
+      return 1;
+  }
+
+  if (!nat_detected) {
+    SU_DEBUG_1(("outbound(%p): detected NAT: %s != %s\n",
+		ob->ob_owner, v->v_host, received));
+    if (ob->ob_oo && ob->ob_oo->oo_status)
+      ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END());
+  }
+  else {
+    SU_DEBUG_1(("outbound(%p): NAT binding changed: "
+		"[%s]:%s != [%s]:%s\n",
+		ob->ob_owner, nat_detected, nat_port, received, rport));
+    if (ob->ob_oo && ob->ob_oo->oo_status)
+      ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END());
+  }
+
+  /* Save our nat binding */
+  new_detected = su_strdup(ob->ob_home, received);
+  new_port = su_strdup(ob->ob_home, rport);
+
+  if (!new_detected || !new_port) {
+    su_free(ob->ob_home, new_detected);
+    su_free(ob->ob_home, new_port);
+    return -1;
+  }
+
+  ob->ob_nat_detected = new_detected;
+  ob->ob_nat_port = new_port;
+
+  su_free(ob->ob_home, nat_detected);
+  su_free(ob->ob_home, nat_port);
+
+  return 2;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Convert "gruu" parameter returned by registrar to Contact header. */
+int outbound_gruuize(outbound_t *ob, sip_t const *sip)
+{
+  sip_contact_t *m = NULL;
+  char *gruu;
+
+  if (!ob)
+    return 0;
+
+  if (ob->ob_rcontact == NULL)
+    return -1;
+
+  if (!ob->ob_prefs.gruuize && ob->ob_instance) {
+    char const *my_instance, *my_reg_id = NULL;
+    char const *instance, *reg_id;
+
+    m = ob->ob_rcontact;
+    my_instance = msg_header_find_param(m->m_common, "+sip.instance=");
+    if (my_instance)
+      my_reg_id = msg_header_find_param(m->m_common, "reg-id=");
+
+    for (m = sip->sip_contact; m; m = m->m_next) {
+      if (my_instance) {
+	instance = msg_header_find_param(m->m_common, "+sip.instance=");
+	if (!instance || strcmp(instance, my_instance))
+	  continue;
+	if (my_reg_id) {
+	  reg_id = msg_header_find_param(m->m_common, "reg-id=");
+	  if (!reg_id || strcmp(reg_id, my_reg_id))
+	    continue;
+	}
+      }
+
+      if (url_cmp_all(ob->ob_rcontact->m_url, m->m_url) == 0)
+	break;
+    }
+  }
+
+  if (m == NULL) {
+    if (ob->ob_gruu)
+      msg_header_free(ob->ob_home, (void *)ob->ob_gruu), ob->ob_gruu = NULL;
+    return 0;
+  }
+
+  gruu = (char *)msg_header_find_param(m->m_common, "gruu=");
+
+  if (gruu == NULL || gruu[0] == '\0')
+    return 0;
+
+  gruu = msg_unquote_dup(NULL, gruu);
+  m = gruu ? sip_contact_format(ob->ob_home, "<%s>", gruu) : NULL;
+  su_free(NULL, gruu);
+
+  if (!m)
+    return -1;
+
+  if (ob->ob_gruu)
+    msg_header_free(ob->ob_home, (void *)ob->ob_gruu);
+  ob->ob_gruu = m;
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int create_keepalive_message(outbound_t *ob,
+				    sip_t const *register_request);
+
+static int keepalive_options(outbound_t *ob);
+static int keepalive_options_with_registration_probe(outbound_t *ob);
+
+static int response_to_keepalive_options(outbound_t *ob,
+					 nta_outgoing_t *orq,
+					 sip_t const *sip);
+
+static void keepalive_timer(su_root_magic_t *root_magic,
+			    su_timer_t *t,
+			    su_timer_arg_t *ob_as_timer_arg);
+
+/** Start OPTIONS keepalive or contact validation process */
+void outbound_start_keepalive(outbound_t *ob,
+			      nta_outgoing_t *register_transaction)
+{
+  unsigned interval = 0;
+  int need_to_validate;
+
+  if (!ob)
+    return;
+
+  if (ob->ob_prefs.natify && ob->ob_prefs.okeepalive)
+    interval = ob->ob_prefs.interval;
+  need_to_validate = ob->ob_prefs.validate && !ob->ob_validated;
+
+  if (!ob->ob_nat_detected || !register_transaction ||
+      !(need_to_validate || interval != 0)) {
+    outbound_stop_keepalive(ob);
+    return;
+  }
+
+  if (ob->ob_keepalive.timer)
+    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+  if (interval)
+    ob->ob_keepalive.timer =
+      su_timer_create(su_root_task(ob->ob_root), interval);
+
+  ob->ob_keepalive.interval = interval;
+
+  if (!ob->ob_validated && ob->ob_keepalive.sipstun 
+      && 0 /* Stun is disabled for now */) {
+    nta_tport_keepalive(register_transaction);
+  }
+  else {
+    if (register_transaction) {
+      msg_t *msg = nta_outgoing_getrequest(register_transaction);
+      sip_t const *register_request = sip_object(msg);
+      create_keepalive_message(ob, register_request);
+      msg_destroy(msg);
+    }
+
+    keepalive_options(ob);
+  }
+}
+
+void outbound_stop_keepalive(outbound_t *ob)
+{
+  if (!ob)
+    return;
+
+  ob->ob_keepalive.interval = 0;
+
+  if (ob->ob_keepalive.timer)
+    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+  if (ob->ob_keepalive.orq)
+    nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;
+
+  if (ob->ob_keepalive.msg)
+    msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;
+}
+
+/** @internal Create a message template for keepalive. */
+static int create_keepalive_message(outbound_t *ob, sip_t const *regsip)
+{
+  msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous;
+  sip_t *osip = sip_object(msg);
+  sip_accept_contact_t *ac;
+
+  char const *p1 = ob->ob_instance;
+  char const *p2 = ob->ob_features;
+
+  unsigned d = ob->ob_keepalive.interval;
+
+  assert(regsip); assert(regsip->sip_request);
+
+  if (p1 || p2) {
+    ac = sip_accept_contact_format(msg_home(msg), "*;require;explicit;%s%s%s",
+				   p1 ? p1 : "",
+				   p2 && p2 ? ";" : "",
+				   p2 ? p2 : "");
+    msg_header_insert(msg, NULL, (void *)ac);
+  }
+
+  if (0 >
+      /* Duplicate essential headers from REGISTER request: */
+      sip_add_tl(msg, osip,
+		 SIPTAG_TO(regsip->sip_to),
+		 SIPTAG_FROM(regsip->sip_from),
+		 /* XXX - we should only use loose routing here */
+		 /* XXX - if we used strict routing,
+		    the route header/request_uri must be restored
+		 */
+		 SIPTAG_ROUTE(regsip->sip_route),
+		 /* Add Max-Forwards 0 */
+		 TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")),
+		 TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")),
+		 SIPTAG_CALL_ID_STR(ob->ob_cookie),
+		 SIPTAG_ACCEPT_STR(outbound_content_type),
+		 TAG_END()) ||
+      /* Create request-line, Call-ID, CSeq */
+      nta_msg_request_complete(msg,
+       			nta_default_leg(ob->ob_nta),
+       			SIP_METHOD_OPTIONS,
+       			(void *)regsip->sip_to->a_url) < 0 ||
+      msg_serialize(msg, (void *)osip) < 0 ||
+      msg_prepare(msg) < 0)
+    return msg_destroy(msg), -1;
+
+  previous = ob->ob_keepalive.msg;
+  ob->ob_keepalive.msg = msg;
+  msg_destroy(previous);
+
+  return 0;
+}
+
+static int keepalive_options(outbound_t *ob)
+{
+  msg_t *req;
+  sip_t *sip;
+
+  if (ob->ob_keepalive.orq)
+    return 0;
+
+  if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated)
+    return keepalive_options_with_registration_probe(ob);
+
+  req = msg_copy(ob->ob_keepalive.msg);
+  if (!req)
+    return -1;
+  sip = sip_object(req); assert(sip); assert(sip->sip_request);
+
+  if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta),
+			       SIP_METHOD_UNKNOWN, NULL) < 0)
+    return msg_destroy(req), -1;
+
+  if (ob->ob_keepalive.auc[0])
+    auc_authorization(ob->ob_keepalive.auc, req, (void *)sip,
+		      "OPTIONS", sip->sip_request->rq_url, sip->sip_payload);
+
+  ob->ob_keepalive.orq =
+    nta_outgoing_mcreate(ob->ob_nta,
+			 response_to_keepalive_options,
+			 ob,
+			 NULL,
+			 req,
+			 TAG_END());
+
+  if (!ob->ob_keepalive.orq)
+    return msg_destroy(req), -1;
+
+  return 0;
+}
+
+static int response_to_keepalive_options(outbound_t *ob,
+					 nta_outgoing_t *orq,
+					 sip_t const *sip)
+{
+  int status = 408;
+  char const *phrase = sip_408_Request_timeout;
+  int binding_check;
+  int challenged = 0, credentials = 0;
+  msg_t *_reqmsg = nta_outgoing_getrequest(orq);
+  sip_t *request = sip_object(_reqmsg); msg_destroy(_reqmsg);
+
+  if (sip && sip->sip_status) {
+    status = sip->sip_status->st_status;
+    phrase = sip->sip_status->st_phrase;
+  }
+
+  if (status == 100) {
+    /* This probably means that we are in trouble. whattodo, whattodo */
+  }
+
+  if (status < 200)
+    return 0;
+
+  if (status == 401 || status == 407) {
+    if (sip->sip_www_authenticate)
+      challenged += auc_challenge(ob->ob_keepalive.auc,
+				  ob->ob_home,
+				  sip->sip_www_authenticate,
+				  sip_authorization_class) > 0;
+    if (sip->sip_proxy_authenticate)
+      challenged += auc_challenge(ob->ob_keepalive.auc,
+				  ob->ob_home,
+				  sip->sip_proxy_authenticate,
+				  sip_proxy_authorization_class) > 0;
+    if (ob->ob_oo->oo_credentials)
+      credentials = ob->ob_oo->oo_credentials(ob->ob_owner,
+					      ob->ob_keepalive.auc);
+  }
+
+  binding_check = outbound_nat_detect(ob, request, sip);
+
+  if (orq == ob->ob_keepalive.orq)
+    ob->ob_keepalive.orq = NULL;
+  nta_outgoing_destroy(orq);
+
+  if (binding_check > 1) {
+    /* Bindings have changed */
+    if (outbound_contacts_from_via(ob, sip->sip_via) == 0) {
+      /* XXX - Destroy old keepalive template message */
+
+      /* re-REGISTER */
+      ob->ob_oo->oo_refresh(ob->ob_owner, ob);
+      return 0;
+    }
+  }
+
+  if (binding_check <= 1 && ob->ob_registered && ob->ob_keepalive.validating) {
+    int failed = 0;
+    unsigned loglevel = 3;
+
+    if (challenged > 0 && credentials > 0) {
+      keepalive_options_with_registration_probe(ob);
+      return 0;
+    }
+
+    if (status < 300 && ob->ob_keepalive.validated) {
+      loglevel = 5;
+      if (ob->ob_validated) 
+	loglevel = 99;		/* only once */
+      ob->ob_validated = ob->ob_once_validated = 1;
+    }
+    else if (status == 401 || status == 407 || status == 403) 
+      loglevel = 5, failed = 1;
+    else
+      loglevel = 3, failed = 1;
+      
+    loglevel = 1;		/* XXX ... for now */
+
+    if (loglevel >= SU_LOG->log_level) {
+      su_llog(SU_LOG, loglevel,       
+	      "outbound(%p): %s <" URL_PRINT_FORMAT ">\n",
+	      ob->ob_owner, failed ? "FAILED to validate" : "validated", 
+	      URL_PRINT_ARGS(ob->ob_rcontact->m_url));
+      if (failed)
+	su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n", 
+		ob->ob_owner, status, phrase);
+    }
+
+    if (failed) 
+      ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END());
+  }
+  else if (status == 408) {
+    SU_DEBUG_1(("outbound(%p): keepalive timeout\n", ob->ob_owner));
+    ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END());
+    return 0;
+  }
+
+  ob->ob_keepalive.validating = 0;
+
+  if (ob->ob_keepalive.timer)
+    su_timer_set(ob->ob_keepalive.timer, keepalive_timer, ob);
+
+  return 0;
+}
+
+static void keepalive_timer(su_root_magic_t *root_magic,
+			    su_timer_t *t,
+			    su_timer_arg_t *ob_casted_as_timer_arg)
+{
+  outbound_t *ob = (outbound_t *)ob_casted_as_timer_arg;
+
+  (void)root_magic;
+
+  if (keepalive_options(ob) < 0)
+    su_timer_set(t, keepalive_timer, ob_casted_as_timer_arg);	/* XXX */
+}
+
+
+/** @internal Send a keepalive OPTIONS that probes the registration */
+static int keepalive_options_with_registration_probe(outbound_t *ob)
+{
+  msg_t *req;
+  sip_t *sip;
+  void *request_uri;
+
+  if (ob->ob_keepalive.orq)
+    return 0;
+
+  req = msg_copy(ob->ob_keepalive.msg);
+  if (!req)
+    return -1;
+
+  sip = sip_object(req); assert(sip);
+  request_uri = sip->sip_to->a_url;
+
+  if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta),
+       			SIP_METHOD_OPTIONS, request_uri) < 0)
+    return msg_destroy(req), -1;
+
+  if (ob->ob_keepalive.auc[0])
+    auc_authorization(ob->ob_keepalive.auc, req, (void *)sip,
+		      "OPTIONS", request_uri, sip->sip_payload);
+
+  ob->ob_keepalive.orq =
+    nta_outgoing_mcreate(ob->ob_nta,
+			 response_to_keepalive_options,
+			 ob,
+			 NULL,
+			 req,
+			 SIPTAG_SUBJECT_STR("REGISTRATION PROBE"),
+			 /* NONE is used to remove
+			    Max-Forwards: 0 found in ordinary keepalives */
+			 SIPTAG_MAX_FORWARDS(SIP_NONE),
+			 TAG_END());
+
+  if (!ob->ob_keepalive.orq)
+    return msg_destroy(req), -1;
+
+  ob->ob_keepalive.validating = 1;
+  ob->ob_keepalive.validated = 0;
+
+  return 0;
+}
+
+/** Check if request should be processed by outbound */
+int outbound_targeted_request(sip_t const *sip)
+{
+  return 
+    sip && sip->sip_request &&
+    sip->sip_request->rq_method == sip_method_options &&
+    sip->sip_accept &&
+    sip->sip_accept->ac_type &&
+    strcasecmp(sip->sip_accept->ac_type, outbound_content_type) == 0;
+}
+
+/** Answer to the connectivity probe OPTIONS */
+int outbound_process_request(outbound_t *ob, 
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  /* XXX - We assume that Call-ID is not modified. */
+  if (strcmp(sip->sip_call_id->i_id, ob->ob_cookie))
+    return 0;
+
+  if (ob->ob_keepalive.validating) {
+    SU_DEBUG_1(("outbound(%p): registration check OPTIONS received\n", 
+		ob->ob_owner));
+    ob->ob_keepalive.validated = 1;
+  }
+
+  nta_incoming_treply(irq, SIP_200_OK,
+		      SIPTAG_CONTENT_TYPE_STR(outbound_content_type),
+		      SIPTAG_PAYLOAD_STR(ob->ob_cookie),
+		      TAG_END());
+  return 200;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/**@internal
+ * Create contacts for outbound.
+ *
+ * There are two contacts: 
+ * one suitable for registrations (ob_rcontact) and another that can be used
+ * in dialogs (ob_dcontact).
+ */
+int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via)
+{
+  su_home_t *home = ob->ob_home;
+  sip_contact_t *rcontact, *dcontact;
+  int reg_id = 0;
+  char reg_id_param[20] = "";
+  sip_contact_t *previous_previous, *previous_rcontact, *previous_dcontact;
+  sip_via_t *v, v0[1], *previous_via;
+  int contact_uri_changed;
+
+  if (!via)
+    return -1;
+
+  v = v0; *v0 = *via; v0->v_next = NULL;
+
+  dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+				   NULL, v, v->v_protocol, NULL);
+
+  if (ob->ob_instance && ob->ob_reg_id != 0)
+    snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
+
+  rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+				   NULL, v, v->v_protocol, 
+				   ob->ob_features ? ob->ob_features : "",
+				   ob->ob_instance, reg_id_param, NULL);
+    
+#if 0
+  char *uri;
+
+  /* uri contains < > */
+  uri = sip_contact_string_from_via(NULL, via, NULL, v->v_protocol);
+
+  dcontact = sip_contact_make(home, uri);
+
+
+
+  if (ob->ob_instance) {
+    char reg_id[20];
+
+    if (ob->ob_instance && ob->ob_reg_id)
+      snprintf(reg_id, sizeof reg_id, ";reg-id=%u", ob->ob_reg_id);
+    else
+      strcpy(reg_id, "");
+
+    rcontact = sip_contact_format(home, "%s;%s%s%s%s",
+				  uri, ob->ob_instance, reg_id,
+				  ob->ob_features ? ";" : "",
+				  ob->ob_features ? ob->ob_features : "");
+  }
+  else if (ob->ob_features)
+    rcontact = sip_contact_format(home, "%s;%s", uri, ob->ob_features);
+  else
+    rcontact = dcontact;
+
+  free(uri);
+#endif
+
+  v = sip_via_dup(home, v);
+
+  if (!rcontact || !dcontact || !v) {
+    msg_header_free(home, (void *)dcontact);
+    if (rcontact != dcontact)
+      msg_header_free(home, (void *)rcontact);
+    msg_header_free(home, (void *)v);
+    return -1;
+  }
+
+  contact_uri_changed = !ob->ob_rcontact ||
+    url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url);
+
+  if (contact_uri_changed) {
+    previous_previous = ob->ob_previous;
+    previous_dcontact = ob->ob_dcontact;
+    previous_via = ob->ob_via;
+
+    if (ob->ob_registering &&
+        (reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported))
+      previous_rcontact = NULL, ob->ob_previous = ob->ob_rcontact;
+    else
+      previous_rcontact = ob->ob_rcontact, ob->ob_previous = NULL;
+
+    if (ob->ob_previous)
+      msg_header_replace_param(home, (void*)ob->ob_previous, "expires=0");
+  }
+  else {
+    previous_previous = ob->ob_rcontact;
+    previous_rcontact = NULL;
+    previous_dcontact = ob->ob_dcontact;
+    previous_via = ob->ob_via;
+  }
+
+  ob->ob_contacts = 1;
+
+  ob->ob_rcontact = rcontact;
+  ob->ob_dcontact = dcontact;
+  ob->ob_via = v;
+
+  if (contact_uri_changed) {
+    ob->ob_registering = 0;
+    ob->ob_registered = 0;
+    ob->ob_validated = 0;
+  }
+
+  msg_header_free(home, (void *)previous_rcontact);
+  msg_header_free(home, (void *)previous_previous);
+  if (previous_dcontact != ob->ob_previous &&
+      previous_dcontact != previous_rcontact &&
+      previous_dcontact != previous_previous)
+    msg_header_free(home, (void *)previous_dcontact);
+  msg_header_free(home, (void *)previous_via);
+
+  return 0;
+}
+
+/**Set new contact.
+ *
+ * @retval 0 when successful
+ * @retval -1 error setting contact
+ */
+int outbound_set_contact(outbound_t *ob,
+			 sip_contact_t const *application_contact,
+			 sip_via_t const *v,
+			 int terminating)
+{
+  su_home_t *home = ob->ob_home;
+  sip_contact_t *rcontact = NULL, *dcontact = NULL, *previous = NULL;
+  sip_contact_t *m1, *m2, *m3;
+  int contact_uri_changed = 0;
+
+  m1 = ob->ob_rcontact;
+  m2 = ob->ob_dcontact;
+  m3 = ob->ob_previous;
+
+  if (terminating) {
+    if (ob->ob_contacts)
+      previous = ob->ob_rcontact;
+  }
+  else if (application_contact) {
+    if (!ob->ob_rcontact || 
+	url_cmp_all(ob->ob_rcontact->m_url, application_contact->m_url)) {
+      contact_uri_changed = 1;
+      previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
+    }
+  }
+  else if (v) {
+    char const *tport = !v->v_next ? v->v_protocol : NULL; 
+    char reg_id_param[20];
+
+    dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+				     NULL, v, tport, NULL);
+    if (!dcontact)
+      return -1;
+
+    if (ob->ob_instance && ob->ob_reg_id != 0)
+      snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
+
+    rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+				     NULL, v, v->v_protocol, 
+				     ob->ob_features ? ob->ob_features : "",
+				     ob->ob_instance, reg_id_param, NULL);
+    if (!rcontact)
+      return -1;
+
+    if (!ob->ob_rcontact || 
+	url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url)) {
+      contact_uri_changed = 1;
+      previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
+    }
+  }
+
+  ob->ob_by_stack = application_contact == NULL;
+
+  ob->ob_rcontact = rcontact;
+  ob->ob_dcontact = dcontact;
+  ob->ob_previous = previous;
+
+  if (contact_uri_changed) {
+    ob->ob_registering = 0;
+    ob->ob_registered = 0;
+    ob->ob_validated = 0;
+    ob->ob_once_validated = 0;
+  }
+
+  if (m1 != previous)
+    msg_header_free(home, (void *)m1);
+  if (m2 != m1 && m2 != m3)
+    msg_header_free(home, (void *)m2);
+  msg_header_free(home, (void *)m3);
+
+  return 0;
+}
+
+sip_contact_t const *outbound_dialog_contact(outbound_t const *ob)
+{
+  if (ob == NULL)
+    return NULL;
+  else if (ob->ob_gruu)
+    return ob->ob_gruu;
+  else
+    return ob->ob_dcontact;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+static enum outbound_feature
+feature_level(sip_t const *sip, char const *tag, int level)
+{
+  if (sip_has_feature(sip->sip_require, tag))
+    return outbound_feature_required;
+  else if (sip_has_feature(sip->sip_supported, tag))
+    return outbound_feature_supported;
+  else if (sip_has_feature(sip->sip_unsupported, tag))
+    return outbound_feature_unsupported;
+  else
+    return level;
+}
+
+
+void outbound_peer_info(outbound_t *ob, sip_t const *sip)
+{
+  if (sip == NULL) {
+    ob->ob_info.outbound = outbound_feature_unsure;
+    ob->ob_info.gruu = outbound_feature_unsure;
+    ob->ob_info.pref = outbound_feature_unsure;
+    return;
+  }
+
+  ob->ob_info.outbound = feature_level(sip, "outbound", ob->ob_info.outbound);
+  ob->ob_info.gruu = feature_level(sip, "gruu", ob->ob_info.gruu);
+  ob->ob_info.pref = feature_level(sip, "pref", ob->ob_info.pref);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OUTBOUND_H
+/** Defined when <outbound.h> has been included. */
+#define OUTBOUND_H
+/**@IFILE outbound.h 
+ *
+ * @brief Interface to SIP NAT traversal and outbound
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed May 10 12:01:38 EEST 2006 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+#ifndef AUTH_CLIENT_H
+#include <sofia-sip/auth_client.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+/* Outbound connection */
+
+#ifndef OUTBOUND_OWNER_T
+#define OUTBOUND_OWNER_T struct nua_handle_s /* Just for now */
+#endif
+
+typedef struct outbound outbound_t;
+typedef struct outbound_owner_vtable outbound_owner_vtable;
+typedef OUTBOUND_OWNER_T outbound_owner_t;
+
+outbound_t *outbound_new(outbound_owner_t *owner,
+			 outbound_owner_vtable const *owner_methods,
+			 su_root_t *root,
+			 nta_agent_t *agent,
+			 char const *instance);
+
+void outbound_unref(outbound_t *ob);
+
+int outbound_set_options(outbound_t *ob,
+			 char const *options,
+			 unsigned dgram_interval,
+			 unsigned stream_interval);
+
+int outbound_set_features(outbound_t *ob, char *features);
+
+nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating, 
+					  sip_contact_t *stack_contact,
+					  nta_agent_t *nta,
+					  nta_response_f *callback,
+					  nta_outgoing_magic_t *magic,
+					  url_string_t *next_hop,
+					  msg_t *msg,
+					  tag_type_t tag, tag_value_t value,
+					  ...);
+
+int outbound_register_response(outbound_t *ob,
+			       int terminating,
+			       sip_t const *request,
+			       sip_t const *response);
+
+/** Return values for outbound_register_response(). */
+enum {
+  ob_register_error = -1,	/* Or anything below zero */
+  ob_register_ok = 0,		/* No need to re-register */
+  ob_reregister = 1,		/* Re-register when oo_refresh() is called */
+  ob_reregister_now = 2		/* Re-register immediately */
+};
+
+int outbound_set_contact(outbound_t *ob,
+			 sip_contact_t const *application_contact,
+			 sip_via_t const *v,
+			 int terminating);
+
+sip_contact_t const *outbound_dialog_contact(outbound_t const *ob);
+
+int outbound_gruuize(outbound_t *ob, sip_t const *sip);
+
+void outbound_start_keepalive(outbound_t *ob,
+			      nta_outgoing_t *register_trans);
+
+void outbound_stop_keepalive(outbound_t *ob);
+
+int outbound_targeted_request(sip_t const *sip);
+
+int outbound_process_request(outbound_t *ob, 
+			     nta_incoming_t *irq,
+			     sip_t const *sip);
+
+void outbound_peer_info(outbound_t *ob, sip_t const *sip);
+
+struct outbound_owner_vtable
+{
+  int oo_size;
+  sip_contact_t *(*oo_contact)(outbound_owner_t *,
+			       su_home_t *home,
+			       char const *extra_username,
+			       sip_via_t const *v,
+			       char const *transport,
+			       char const *m_param,
+			       ...);
+  int (*oo_refresh)(outbound_owner_t *, outbound_t *ob);
+  int (*oo_status)(outbound_owner_t *, outbound_t *ob,
+		   int status, char const *phrase,
+		   tag_type_t tag, tag_value_t value, ...);
+  int (*oo_probe_error)(outbound_owner_t *, outbound_t *ob,
+			int status, char const *phrase,
+			tag_type_t tag, tag_value_t value, ...);
+  int (*oo_keepalive_error)(outbound_owner_t *, outbound_t *ob,
+			    int status, char const *phrase,
+			    tag_type_t tag, tag_value_t value, ...);
+  int (*oo_credentials)(outbound_owner_t *, auth_client_t **auc);
+};
+
+SOFIA_END_DECLS
+
+#endif /* OUTBOUND_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,379 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/nua.h  
+ * @brief Sofia-SIP User Agent Library API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef NUA_H
+/** Defined when <sofia-sip/nua.h> has been included. */
+#define NUA_H
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef NUA_TAG_H
+#include <sofia-sip/nua_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef NUA_MAGIC_T 
+#define NUA_MAGIC_T void
+#endif
+/** Application context for NUA agent. */
+typedef NUA_MAGIC_T nua_magic_t;
+
+#ifndef NUA_HMAGIC_T 
+#define NUA_HMAGIC_T void
+#endif
+/** Application context for NUA handle. */
+typedef NUA_HMAGIC_T nua_hmagic_t;
+
+/**Network change event levels given to NUTAG_DETECT_NETWORK_UPDATES().
+ *
+ * @sa NUTAG_DETECT_NETWORK_UPDATES(), #nua_i_network_changed
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef enum nua_nw_detector_e {
+  NUA_NW_DETECT_NOTHING = 0,
+  NUA_NW_DETECT_ONLY_INFO,
+  NUA_NW_DETECT_TRY_FULL,
+} nua_nw_detector_t;
+
+/** Events */
+typedef enum nua_event_e {
+  /* Event used by stack internally */
+  nua_i_none = -1,
+
+  /* Indications */
+  nua_i_error,			/**< Error indication */
+
+  nua_i_invite,			/**< Incoming call INVITE */
+  nua_i_cancel,			/**< Incoming INVITE has been cancelled */
+  nua_i_ack,			/**< Final response to INVITE has been ACKed */
+  nua_i_fork,			/**< Outgoing call has been forked */
+  nua_i_active,			/**< A call has been activated */
+  nua_i_terminated,		/**< A call has been terminated */
+  nua_i_state,		        /**< Call state has changed */
+
+  nua_i_outbound,		/**< Status from outbound processing */
+
+  nua_i_bye,			/**< Incoming BYE call hangup */
+  nua_i_options,		/**< Incoming OPTIONS */
+  nua_i_refer,			/**< Incoming REFER call transfer */
+  nua_i_publish,		/**< Incoming PUBLISH */
+  nua_i_prack,			/**< Incoming PRACK */
+  nua_i_info,			/**< Incoming session INFO */
+  nua_i_update,			/**< Incoming session UPDATE */
+  nua_i_message,		/**< Incoming MESSAGE */
+  nua_i_chat,			/**< Incoming chat MESSAGE  */
+  nua_i_subscribe,		/**< Incoming SUBSCRIBE  */
+  nua_i_subscription,		/**< Incoming subscription to be authorized */
+  nua_i_notify,			/**< Incoming event NOTIFY */
+  nua_i_method,			/**< Incoming, unknown method */
+
+  nua_i_media_error,		/**< Offer-answer error indication */
+
+  /* Responses */
+  nua_r_set_params,		/**< Answer to nua_set_params() or 
+				 * nua_get_hparams(). */
+  nua_r_get_params,		/**< Answer to nua_get_params() or 
+				 * nua_get_hparams(). */
+  nua_r_shutdown,		/**< Answer to nua_shutdown() */
+  nua_r_notifier,		/**< Answer to nua_notifier() */
+  nua_r_terminate,		/**< Answer to nua_terminate() */
+  nua_r_authorize,		/**< Answer to nua_authorize()  */
+
+  /* SIP responses */
+  nua_r_register,		/**< Answer to outgoing REGISTER */
+  nua_r_unregister,		/**< Answer to outgoing un-REGISTER */
+  nua_r_invite,		        /**< Answer to outgoing INVITE */
+  nua_r_cancel,			/**< Answer to outgoing CANCEL */
+  nua_r_bye,			/**< Answer to outgoing BYE */
+  nua_r_options,		/**< Answer to outgoing OPTIONS */
+  nua_r_refer,			/**< Answer to outgoing REFER */
+  nua_r_publish,		/**< Answer to outgoing PUBLISH */
+  nua_r_unpublish,		/**< Answer to outgoing un-PUBLISH */
+  nua_r_info,		        /**< Answer to outgoing INFO */
+  nua_r_prack,			/**< Answer to outgoing PRACK */
+  nua_r_update,		        /**< Answer to outgoing UPDATE */
+  nua_r_message,		/**< Answer to outgoing MESSAGE */
+  nua_r_chat,			/**< Answer to outgoing chat message */
+  nua_r_subscribe,		/**< Answer to outgoing SUBSCRIBE */
+  nua_r_unsubscribe,		/**< Answer to outgoing un-SUBSCRIBE */
+  nua_r_notify,			/**< Answer to outgoing NOTIFY */
+  nua_r_method,			/**< Answer to unknown outgoing method */
+ 
+  nua_r_authenticate,		/**< Answer to nua_authenticate() */
+
+  /* Internal events: nua hides them from application */
+  nua_r_redirect,
+  nua_r_destroy,
+  nua_r_respond,
+  nua_r_nit_respond,
+  nua_r_ack,			/*#< Answer to ACK */
+
+  /* NOTE: Post 1.12 release events come here (below) to keep ABI
+     compatibility! */
+  nua_i_network_changed,        /**< Local IP(v6) address has changed. 
+				   @NEW_1_12_2 */
+  nua_i_register,		/**< Incoming REGISTER. @NEW_1_12_4. */
+} nua_event_t;
+
+typedef struct event_s {
+  nua_handle_t *e_nh;
+  int           e_event;
+  short         e_always;
+  short         e_status;
+  char const   *e_phrase;
+  msg_t        *e_msg;
+  tagi_t        e_tags[1];
+} nua_event_data_t;
+
+/** NUA API version */
+#define NUA_VERSION "2.0"
+/** NUA module version */
+SOFIAPUBVAR char const nua_version[];
+
+typedef void (*nua_callback_f)(nua_event_t event,
+			       int status, char const *phrase,
+			       nua_t *nua, nua_magic_t *magic,
+			       nua_handle_t *nh, nua_hmagic_t *hmagic,
+			       sip_t const *sip,
+			       tagi_t tags[]);
+
+/** Create a NUA agent. */
+SOFIAPUBFUN nua_t *nua_create(su_root_t *root,
+			      nua_callback_f callback,
+			      nua_magic_t *magic,
+			      tag_type_t tag, tag_value_t value,
+			      ...);
+
+/** Shutdown NUA stack. */
+SOFIAPUBFUN void nua_shutdown(nua_t *nua);
+
+/** Destroy the NUA stack. */
+SOFIAPUBFUN void nua_destroy(nua_t *nua);
+
+/** Fetch callback context from nua. */
+SOFIAPUBFUN nua_magic_t *nua_magic(nua_t *nua);
+
+/** Set NUA parameters. */
+SOFIAPUBFUN void nua_set_params(nua_t *, tag_type_t, tag_value_t, ...);
+
+/** Get NUA parameters. */
+SOFIAPUBFUN void nua_get_params(nua_t *nua, tag_type_t, tag_value_t, ...);
+
+/** Obtain default operation handle of the NUA stack object. */
+SOFIAPUBFUN nua_handle_t *nua_default(nua_t *nua);
+
+/** Create an operation handle */
+SOFIAPUBFUN nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
+				     tag_type_t, tag_value_t, ...);
+
+/** Destroy a handle */
+SOFIAPUBFUN void nua_handle_destroy(nua_handle_t *h);
+
+/** Make a new reference to handle */
+SOFIAPUBFUN nua_handle_t *nua_handle_ref(nua_handle_t *);
+
+/** Destroy reference to handle */
+SOFIAPUBFUN int nua_handle_unref(nua_handle_t *);
+
+/** Bind a callback context to an operation handle. */
+SOFIAPUBFUN void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *magic);
+
+/** Fetch a callback context from an operation handle. */
+SOFIAPUBFUN nua_hmagic_t *nua_handle_magic(nua_handle_t *nh);
+
+/** Set handle parameters. */
+SOFIAPUBFUN void nua_set_hparams(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Get handle parameters. */
+SOFIAPUBFUN void nua_get_hparams(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Check if operation handle is used for INVITE */
+SOFIAPUBFUN int nua_handle_has_invite(nua_handle_t const *nh);
+
+/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request. */
+SOFIAPUBFUN int nua_handle_has_subscribe(nua_handle_t const *nh);
+
+/** Check if operation handle has been used with nua_register() or nua_unregister(). */
+SOFIAPUBFUN int nua_handle_has_register(nua_handle_t const *nh);
+
+/** Check if operation handle has an active call */
+SOFIAPUBFUN int nua_handle_has_active_call(nua_handle_t const *nh);
+
+/** Check if operation handle has a call on hold */
+SOFIAPUBFUN int nua_handle_has_call_on_hold(nua_handle_t const *nh);
+
+/** Check if handle has active event subscriptions (refers sent). */
+SOFIAPUBFUN int nua_handle_has_events(nua_handle_t const *nh);
+
+/** Check if operation handle has active registrations */
+SOFIAPUBFUN int nua_handle_has_registrations(nua_handle_t const *nh);
+
+/** Get the remote address (From/To header) of operation handle */
+SOFIAPUBFUN sip_to_t const *nua_handle_remote(nua_handle_t const *nh);
+
+/** Get the local address (From/To header) of operation handle  */
+SOFIAPUBFUN sip_to_t const *nua_handle_local(nua_handle_t const *nh);
+
+/** Get name for NUA event. */
+SOFIAPUBFUN char const *nua_event_name(nua_event_t event);
+
+/** Get name for NUA callstate. */
+SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
+
+/** Send SIP REGISTER request to the registrar. */ 
+SOFIAPUBFUN void nua_register(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Unregister. */ 
+SOFIAPUBFUN void nua_unregister(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Place a call using SIP INVITE method. */
+SOFIAPUBFUN void nua_invite(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Acknowledge a succesfull response to INVITE request. */ 
+SOFIAPUBFUN void nua_ack(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Acknowledge a reliable preliminary response to INVITE request. */
+SOFIAPUBFUN void nua_prack(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Query capabilities from server */
+SOFIAPUBFUN void nua_options(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send PUBLISH request to publication server. */
+SOFIAPUBFUN void nua_publish(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send un-PUBLISH request to publication server. */
+SOFIAPUBFUN void nua_unpublish(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send an instant message. */
+SOFIAPUBFUN void nua_message(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send a chat message. */
+SOFIAPUBFUN void nua_chat(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send an INFO request. */
+SOFIAPUBFUN void nua_info(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Subscribe a SIP event. */
+SOFIAPUBFUN void nua_subscribe(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Unsubscribe an event. */
+SOFIAPUBFUN void nua_unsubscribe(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Send a NOTIFY message. */
+SOFIAPUBFUN void nua_notify(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Create an event server. */
+SOFIAPUBFUN void nua_notifier(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Terminate an event server. */
+SOFIAPUBFUN void nua_terminate(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Transfer a call. */
+SOFIAPUBFUN void nua_refer(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Update a call */ 
+SOFIAPUBFUN void nua_update(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Hangdown a call. */
+SOFIAPUBFUN void nua_bye(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Cancel an INVITE operation */
+SOFIAPUBFUN void nua_cancel(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Authenticate an operation. */
+SOFIAPUBFUN void nua_authenticate(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Authorize a subscriber. */
+SOFIAPUBFUN void nua_authorize(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/*# Redirect an operation. @deprecated */
+SOFIAPUBFUN void nua_redirect(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Extension request method. */
+SOFIAPUBFUN void nua_method(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Respond with given status. */
+SOFIAPUBFUN void nua_respond(nua_handle_t *nh, 
+			     int status, char const *phrase,
+			     tag_type_t, tag_value_t, 
+			     ...);
+
+#define nua_handle_home(nh) ((su_home_t *)(nh))
+
+/** Generate an instance identifier */
+SOFIAPUBFUN char const *nua_generate_instance_identifier(su_home_t *);
+
+#ifndef NUA_SAVED_EVENT_T
+#define NUA_SAVED_EVENT_T struct nua_saved_event *
+#endif
+/** Abstract type for saved nua events. */
+typedef NUA_SAVED_EVENT_T nua_saved_event_t;
+
+/** Save last nua event */
+SOFIAPUBFUN int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1]);
+
+/** Get information from saved event */
+SOFIAPUBFUN nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1]);
+
+/** Destroy a save nua event */
+SOFIAPUBFUN void nua_destroy_event(nua_saved_event_t *saved);
+
+/** Get request message from saved nua event. */
+SOFIAPUBFUN msg_t *nua_saved_event_request(nua_saved_event_t const *saved);
+
+/** Get current request message. */
+SOFIAPUBFUN  msg_t *nua_current_request(nua_t const *nua);
+
+SOFIAPUBFUN sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh, 
+						     su_home_t *home,
+						     int early_only);
+
+SOFIAPUBFUN nua_handle_t *nua_handle_by_replaces(nua_t *nua,
+						 sip_replaces_t const *rp);
+
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2199 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_TAG_H
+/** Defined when <sofia-sip/nua_tag.h> has been included. */
+#define NUA_TAG_H
+
+/**@file sofia-sip/nua_tag.h
+ * @brief Tags for Sofia-SIP User Agent Library
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Mon Feb 19 18:54:26 EET 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SDP_TAG_H
+#include <sofia-sip/sdp_tag.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+#ifndef NEA_TAG_H
+#include <sofia-sip/nea_tag.h>
+#endif
+#ifndef SOA_TAG_H
+#include <sofia-sip/soa_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** NUA agent. */
+typedef struct nua_s nua_t;
+
+/** NUA transaction handle. */
+typedef struct nua_handle_s nua_handle_t;
+
+/** List of all NUA tags. */
+SOFIAPUBVAR tag_type_t nua_tag_list[];
+
+/** Filter tag matching any nua tag. */
+#define NUTAG_ANY()          nutag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t nutag_any;
+
+/** URL address from application to NUA
+ *
+ * @par Used with
+ *    any function that create SIP request or nua_handle() \n
+ *    nua_create() \n
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    #url_string_t, which is either a pointer to #url_t or NULL terminated
+ *    character string representing URL \n
+ *
+ * For normal nua calls, this tag is used as request target, which is usually
+ * stored as request-URI.
+ *
+ * It is used to set stack's own address with nua_create(), nua_set_params()
+ * and nua_get_params().
+ *
+ * @sa SIPTAG_TO()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_URL_REF()
+ */
+#define NUTAG_URL(x)            nutag_url, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_url;
+
+#define NUTAG_URL_REF(x)        nutag_url_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_url_ref;
+
+/** Address as a string
+ *
+ * @deprecated Not used.
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    String in form "name <url>"
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_ADDRESS_REF()
+ */
+#define NUTAG_ADDRESS(x)        nutag_address, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_address;
+
+#define NUTAG_ADDRESS_REF(x)    nutag_address_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_address_ref;
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    msg_t *
+ *
+ * @par Values
+ *   Pointer to a request message.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa NUTAG_WITH_THIS(), NUTAG_WITH_SAVED()
+ */
+#define NUTAG_WITH(x)         nutag_with, tag_ptr_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_with;
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    nua_t *
+ *
+ * @par Values
+ *   Pointer to the nua agent instance object.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa nua_save_event(), NUTAG_WITH(), NUTAG_WITH_SAVED()
+ */
+#define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua)))
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    msg_t *
+ *
+ * @par Values
+ *   Pointer to a saved event.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa nua_save_event(), NUTAG_WITH(), NUTAG_WITH_THIS()
+ */
+#define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e)))
+
+/**Set request retry count.
+ *
+ * Retry count determines how many times stack will automatically retry
+ * after an recoverable error response, like 302, 401 or 407.
+ *
+ * @par Used with
+ *    nua_set_params(), nua_set_hparams() \n
+ *    nua_get_params(), nua_get_hparams() \n
+ *    nua_invite(), nua_ack()
+ *
+ * @par Parameter type
+ *    unsigned
+ *
+ * @par Values
+ *    @c 0   Never retry automatically \n
+ *
+ * @NEW_1_12_4.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_RETRY_COUNT_REF()
+ */
+#define NUTAG_RETRY_COUNT(x)      nutag_retry_count, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_retry_count;
+
+#define NUTAG_RETRY_COUNT_REF(x)  nutag_retry_count_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_retry_count_ref;
+
+/** Extension method name.
+ *
+ * Specify extension method name with nua_method() function.
+ *
+ * @par Used with
+ *    nua_method() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    Extension method name (e.g., "SERVICE")
+ *
+ * Corresponding tag taking reference parameter is NUTAG_METHOD_REF()
+ *
+ * @sa nua_method(), SIP_METHOD_UNKNOWN()
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+#define NUTAG_METHOD(x)            nutag_method, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_method;
+
+#define NUTAG_METHOD_REF(x)        nutag_method_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_method_ref;
+
+/**Set maximum number of simultaneous subscribers per single event server.
+ *
+ * Determines how many subscribers can simultaneously subscribe to a single
+ * event.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    unsigned
+ *
+ * @par Values
+ *    @c 0   Do not allow any subscriptions \n
+ *
+ * @sa nua_notifier(), nua_authorize()
+ *
+ * Corresponding tag taking reference parameter is 
+ * NUTAG_MAX_SUBSCRIPTIONS_REF()
+ */
+#define NUTAG_MAX_SUBSCRIPTIONS(x)      nutag_max_subscriptions, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_max_subscriptions;
+
+#define NUTAG_MAX_SUBSCRIPTIONS_REF(x) \
+nutag_max_subscriptions_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_max_subscriptions_ref;
+
+/** Intentionally undocumented. */
+#define NUTAG_UICC(x)  nutag_uicc, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_uicc;
+
+#define NUTAG_UICC_REF(x) nutag_uicc_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_uicc_ref;
+
+/** Ask NUA to create dialog for this handle
+ *
+ * @par Used with nua calls that send a SIP request
+ *
+ * @par Parameter type
+ *   int
+ *
+ * @par Values
+ *    @c False (zero) \n
+ *    @c True (nonzero)
+ *
+ * Corresponding tag taking reference parameter is NUTAG_USE_DIALOG_REF()
+ */
+#define NUTAG_USE_DIALOG(x)        nutag_use_dialog, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_use_dialog;
+
+#define NUTAG_USE_DIALOG_REF(x)    nutag_use_dialog_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_use_dialog_ref;
+
+
+/* Protocol engine parameters,
+ * set by nua_set_params(), get by nua_get_params() */
+
+#if 0
+
+/**Pointer to a SDP Offer-Answer session object.
+ *
+ * Pointer to the media session object.
+ *
+ * @par Used with nua_create(), nua_handle().
+ *
+ * @par Parameter type
+ *    void * (actually soa_session_t *)
+ *
+ * @par Values
+ *    Pointer to MSS media session.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SOA_SESSION_REF.
+ */
+#define NUTAG_SOA_SESSION(x)  nutag_soa_session, tag_ptr_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_soa_session;
+
+#define NUTAG_SOA_SESSION_REF(x) \
+ nutag_soa_session_ref, tag_ptr_vr(&(x),(x))
+SOFIAPUBVAR tag_typedef_t nutag_soa_session_ref;
+
+#endif
+
+/**Name for SDP Offer-Answer session object.
+ *
+ * SDP Offer-Answer session object name.
+ *
+ * @par Used with nua_create(), nua_handle().
+ *
+ * @par Parameter type
+ *    void * (actually soa_session_t *)
+ *
+ * @par Values
+ *    Pointer to MSS media session.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SOA_SESSION_REF.
+ */
+#define NUTAG_SOA_NAME(x)  nutag_soa_name, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_soa_name;
+
+#define NUTAG_SOA_NAME_REF(x) \
+ nutag_soa_name_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_soa_name_ref;
+
+/**Establish early media session using 100rel, 183 responses and PRACK.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_set_hparams() \n
+ *    nua_get_hparams() \n
+ *    nua_invite() \n
+ *    nua_respond() \n
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * @sa NUTAG_EARLY_ANWER()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EARLY_MEDIA_REF()
+ */
+#define NUTAG_EARLY_MEDIA(x)    nutag_early_media, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_early_media;
+
+#define NUTAG_EARLY_MEDIA_REF(x) nutag_early_media_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_early_media_ref;
+
+/**Respond only 183 with 100rel.
+ *
+ * If this parameter is set, stack uses 100rel only with 183: otherwise, all
+ * 1XX responses (except <i>100 Trying</i>) uses 100rel.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_set_hparams() \n
+ *    nua_get_hparams() \n
+ *    nua_invite() \n
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ONLY183_100REL_REF()
+*/
+#define NUTAG_ONLY183_100REL(x)    nutag_only183_100rel, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_only183_100rel;
+
+#define NUTAG_ONLY183_100REL_REF(x) nutag_only183_100rel_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_only183_100rel_ref;
+
+/**Establish early media session by including SDP answer in 1XX response.
+ *
+ * @par Used with
+ *    nua_respond(), nua_set_params(), nua_set_hparams()
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EARLY_ANSWER_REF().
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ *
+ * @sa NUTAG_EARLY_MEDIA(), NUTAG_AUTOALERT(), NUTAG_MEDIA_ENABLE()
+ * 
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_EARLY_ANSWER(x)    nutag_early_answer, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_early_answer;
+
+#define NUTAG_EARLY_ANSWER_REF(x) nutag_early_answer_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_early_answer_ref;
+
+/**Include an extra copy of SDP answer in the response.
+ *
+ * When NUTAG_INCLUDE_EXTRA_SDP(1) is included in nua_respond() tags, stack
+ * will include in the response a copy of the SDP offer/answer that was last
+ * sent to the client. This tag should be used only when you know that the
+ * remote end requires the extra SDP, for example, some versions of Cisco
+ * SIPGateway need a copy of answer in 200 OK even when they indicate
+ * support for 100rel.
+ *
+ * @par Used with
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_INCLUDE_EXTRA_SDP_REF().
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ *
+ * @sa NUTAG_EARLY_ANSWER(), NUTAG_EARLY_MEDIA(), NUTAG_AUTOALERT(),
+ * NUTAG_MEDIA_ENABLE(), @RFC3264, @RFC3264
+ * 
+ * @since New in @VERSION_1_12_4.
+ */
+#define NUTAG_INCLUDE_EXTRA_SDP(x)    nutag_include_extra_sdp, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp;
+
+#define NUTAG_INCLUDE_EXTRA_SDP_REF(x) \
+   nutag_include_extra_sdp_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp_ref;
+
+/** Timer for outstanding INVITE in seconds.
+ *
+ * INVITE will be canceled if no answer is received before timer expires.
+ *
+ * @par Used with
+ *    nua_invite() \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int (enum nua_af)
+ *
+ * @par Values
+ *    @c 0  no timer \n
+ *    @c >0 timer in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_INVITE_TIMER_REF()
+ */
+#define NUTAG_INVITE_TIMER(x)  nutag_invite_timer, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_invite_timer;
+
+#define NUTAG_INVITE_TIMER_REF(x) nutag_invite_timer_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
+
+/**Default session timer in seconds.
+ *
+ * Set default session timer in seconds when using session timer extension. 
+ * The value given here is the proposed session expiration time in seconds.
+ * Note that the session timer extension is ponly used 
+ *
+ * @par Sending INVITE and UPDATE Requests 
+ *
+ * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is
+ * used in the @SessionExpires header included in the INVITE or UPDATE
+ * requests. The intermediate proxies or the ultimate destination can lower
+ * the interval in @SessionExpires header. If the value is too low, they can
+ * reject the request with the status code <i>422 Session Timer Too
+ * Small</i>. When Re-INVITE will be sent in given intervals. In that case,
+ * @b nua retries the request automatically.
+ * 
+ * @par Returning Response to the INVITE and UPDATE Requests 
+ *
+ * The NUTAG_SESSION_TIMER() value is also used when sending the final
+ * response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER()
+ * value is 0 or the value in the @SessionExpires header of the requeast is
+ * lower than the value in NUTAG_SESSION_TIMER(), the value from the
+ * incoming @SessionExpires header is used. However, if the value in
+ * @SessionExpires is lower than the minimal acceptable session expiration
+ * interval specified with the tag NUTAG_MIN_SE() the request is
+ * automatically rejected with <i>422 Session Timer Too Small</i>.
+ *
+ * @par When to Use NUTAG_SESSION_TIMER()?
+ *
+ * The session time extension is enabled ("timer" feature tag is included in
+ * @Supported header) but not activated by default (no @SessionExpires
+ * header is included in the requests or responses by default). Using
+ * non-zero value with NUTAG_SESSION_TIMER() activates it. When the
+ * extension is activated, @nua refreshes the call state by sending periodic
+ * re-INVITE or UPDATE requests unless the remote end indicated that it will
+ * take care of refreshes.
+ *
+ * The session timer extension is mainly useful for proxies or back-to-back
+ * user agents that keep call state. The call state is "soft" meaning that
+ * if no call-related SIP messages are processed for certain time the state
+ * will be destroyed. An ordinary user-agent can also make use of session
+ * timer if it cannot get any activity feedback from RTP or other media.
+ *
+ * @par Used with
+ *    nua_invite(), nua_update(), nua_respond() \n
+ *    nua_set_params() or nua_set_hparams() \n
+ *    nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of the the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ *    @c 0  disable \n
+ *    @c >0 interval in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF()
+ *
+ * @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(),
+ * nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update,
+ * #nua_i_update, 
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_SESSION_TIMER(x)  nutag_session_timer, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_session_timer;
+
+#define NUTAG_SESSION_TIMER_REF(x) nutag_session_timer_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_session_timer_ref;
+
+/** Minimum acceptable refresh interval for session.
+ *
+ * Specifies the value of @MinSE header in seconds. The @b Min-SE header is
+ * used to specify minimum acceptable refresh interval for session timer
+ * extension.
+ *
+ * @par Used with
+ *    nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ *    nua_set_params() or nua_set_hparams() \n
+ *    nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ *    interval in seconds.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MIN_SE_REF()
+ *
+ * @sa NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @MinSE, @SessionExpires
+ */
+#define NUTAG_MIN_SE(x)         nutag_min_se, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_min_se;
+
+#define NUTAG_MIN_SE_REF(x)     nutag_min_se_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_min_se_ref;
+
+enum nua_session_refresher {
+  nua_no_refresher,		/**< Disable session timer. */
+  nua_local_refresher,		/**< Session refresh by local end. */
+  nua_remote_refresher,		/**< Session refresh by remote end. */
+  nua_any_refresher		/**< No preference (default). */
+};
+
+/**Specify the preferred refresher.
+ *
+ * Specify for session timer extension which party is the preferred refresher.
+ *
+ * @par Used with
+ *    nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ *    nua_set_params() or nua_set_hparams() \n
+ *    nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of all the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ *   enum { #nua_no_refresher,  #nua_local_refresher, #nua_remote_refresher,
+ *          #nua_any_refresher }
+ *
+ * @par Values
+ *    @c nua_no_refresher (session timers are disabled) \n
+ *    @c nua_local_refresher \n
+ *    @c nua_remote_refresher \n
+ *    @c nua_any_refresher (default) \n
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_SESSION_REFRESHER_REF()
+ *
+ * @sa NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_SESSION_REFRESHER(x)  nutag_session_refresher, tag_int_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_session_refresher;
+
+#define NUTAG_SESSION_REFRESHER_REF(x) nutag_session_refresher_ref, tag_int_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_session_refresher_ref;
+
+/** Use UPDATE as refresh method.
+ *
+ * If this parameter is true and the remote endpoint has included UPDATE in
+ * Allow header, the nua stack uses UPDATE instead of INVITE to refresh the 
+ * session when using the session timer extension.
+ *
+ * Note that the session timer headers @SessionExpires and @MinSE are always
+ * included in the UPDATE request and responses regardless of the value of
+ * this tag.
+ *
+ * @par Used with
+ *    nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ *    nua_set_params() or nua_set_hparams() \n
+ *    nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of all the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ *    boolean
+ *
+ * @par Values
+ *    @c 1 Use UPDATE \n
+ *    @c 0 Use INVITE
+ *
+ * Corresponding tag taking reference parameter is NUTAG_UPDATE_REFRESH_REF()
+ *
+ * @sa #nua_r_update, NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_UPDATE_REFRESH(x)  nutag_update_refresh, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_update_refresh;
+
+#define NUTAG_UPDATE_REFRESH_REF(x) nutag_update_refresh_ref, tag_bool_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_update_refresh_ref;
+
+/** Send alerting (180 Ringing) automatically
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   No automatic sending of "180 Ringing" \n
+ *    @c !=0 "180 Ringing" sent automatically
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTOALERT_REF()
+ */
+#define NUTAG_AUTOALERT(x)      nutag_autoalert, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoalert;
+
+#define NUTAG_AUTOALERT_REF(x)  nutag_autoalert_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoalert_ref;
+
+/** ACK automatically
+ *
+ * If this parameter is true, ACK is sent automatically after receiving 2XX
+ * series response to INVITE. Note that ACK is always sent automatically by
+ * lower layers of the stack after receiving an error response 3XX, 4XX, 5XX
+ * or 6XX.
+ *
+ * @par Used with
+ *    nua_set_params(), nua_set_hparams(), \n
+ *    nua_get_params(), nua_get_hparams(), \n
+ *    nua_invite(), nua_ack(), nua_respond(), nua_update() \n
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0    No automatic sending of ACK \n
+ *    @c !=0 ACK sent automatically
+ *
+ * Default value is NUTAG_AUTOACK(1).
+ * 
+ * Corresponding tag taking reference parameter is NUTAG_AUTOACK_REF()
+ */
+#define NUTAG_AUTOACK(x)        nutag_autoack, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoack;
+
+#define NUTAG_AUTOACK_REF(x)    nutag_autoack_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoack_ref;
+
+/** Answer (with 200 Ok) automatically to incoming call.
+ *
+ * @par Used with
+ *    nua_set_params(), nua_set_hparams() \n
+ *    nua_get_params(), nua_get_hparams() \n
+ *    nua_invite() \n
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0    No automatic sending of "200 Ok" \n
+ *    @c !=0 "200 Ok" sent automatically
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTOANSWER_REF()
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ * 
+ * @par Auto-Answer to Re-INVITE requests
+ * By default, NUA tries to auto answer the re-INVITEs used to refresh the
+ * session when the media is enabled. Set NUTAG_AUTOANSWER(0) on the call
+ * handle (e.g., include the tag with nua_invite(), nua_respond()) in order
+ * to disable the auto answer on re-INVITEs.
+ *
+ * @bug If the re-INVITE modifies the session (e.g., SDP contains offer that
+ * adds video stream to the session), NUA auto-answers it if
+ * NUTAG_AUTOANSWER(0) has not been set on the handle. It accepts or rejects
+ * media based on the existing user SDP (set with SOATAG_USER_SDP(), for
+ * example). It should auto-answer only session refresh request and let
+ * application decide how to handle requests to modify the session.
+ *
+ * @sa NUTAG_MEDIA_ENABLE(), NUTAG_AUTOALERT(), NUTAG_AUTOACK().
+ */
+#define NUTAG_AUTOANSWER(x)     nutag_autoanswer, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoanswer;
+
+#define NUTAG_AUTOANSWER_REF(x) nutag_autoanswer_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoanswer_ref;
+
+/** Enable incoming INVITE
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   Incoming INVITE not enabled. NUA answers 403 Forbidden \n
+ *    @c !=0 Incoming INVITE enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEINVITE_REF()
+ */
+#define NUTAG_ENABLEINVITE(x)   nutag_enableinvite, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enableinvite;
+
+#define NUTAG_ENABLEINVITE_REF(x) nutag_enableinvite_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enableinvite_ref;
+
+/** Enable incoming MESSAGE
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   Incoming MESSAGE not enabled. NUA answers 403 Forbidden \n
+ *    @c !=0 Incoming MESSAGE enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSAGE_REF()
+ */
+#define NUTAG_ENABLEMESSAGE(x)  nutag_enablemessage, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enablemessage;
+
+#define NUTAG_ENABLEMESSAGE_REF(x) nutag_enablemessage_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enablemessage_ref;
+
+/** Enable incoming MESSAGE with To tag.
+ *
+ * Set this parameter if you want to chat with Windows Messenger.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSENGER_REF()
+ */
+#define NUTAG_ENABLEMESSENGER(x)  nutag_enablemessenger, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enablemessenger;
+
+#define NUTAG_ENABLEMESSENGER_REF(x) \
+  nutag_enablemessenger_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enablemessenger_ref;
+
+/* Start NRC Boston */
+
+/** Enable S/MIME
+ *
+ * @par Used with
+ *    nua_create() \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    boolean
+ *
+ * @par Values
+ *    @c 0   S/MIME is Disabled \n
+ *    @c !=0 S/MIME is Enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_ENABLE_REF()
+ */
+#define NUTAG_SMIME_ENABLE(x)  nutag_smime_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_enable;
+
+#define NUTAG_SMIME_ENABLE_REF(x) nutag_smime_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_enable_ref;
+
+/** S/MIME Options
+ *
+ * This tag specifies the type of S/MIME security services requested
+ * by the user.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_message()
+ *
+ * @par Parameter type
+ *   int
+ *
+ * @par Values
+ *   @c -1 (SM_ID_NULL) No security service needed \n
+ *   @c  0 (SM_ID_CLEAR_SIGN) Clear signing \n
+ *   @c  1 (SM_ID_SIGN) S/MIME signing \n
+ *   @c  2 (SM_ID_ENCRYPT) S/MIME encryption
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_OPT_REF()
+ */
+#define NUTAG_SMIME_OPT(x)  nutag_smime_opt, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_opt;
+
+#define NUTAG_SMIME_OPT_REF(x) nutag_smime_opt_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_opt_ref;
+
+/* End NRC Boston */
+
+/** S/MIME protection mode
+ *
+ * This tag specifies the protection mode of the SIP message by
+ * S/MIME as requested by the user
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *   unsigned int
+ *
+ * @par Values
+ *   @c -1 (SM_MODE_NULL) Unspecified \n
+ *   @c  0 (SM_MODE_PAYLOAD_ONLY) SIP payload only \n
+ *   @c  1 (SM_MODE_TUNNEL) SIP tunneling mode \n
+ *   @c  2 (SM_MODE_SIPFRAG) SIPfrag protection
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_PROTECTION_MODE_REF()
+ */
+#define NUTAG_SMIME_PROTECTION_MODE(x) nutag_smime_protection_mode, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_protection_mode;
+
+#define NUTAG_SMIME_PROTECTION_MODE_REF(x) \
+           nutag_smime_protection_mode_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_protection_mode_ref;
+
+/** S/MIME digest algorithm
+ *
+ * This tag specifies the message digest algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ *    To be implemented
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_MESSAGE_DIGEST_REF()
+ */
+#define NUTAG_SMIME_MESSAGE_DIGEST(x) nutag_smime_message_digest, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_digest;
+
+#define NUTAG_SMIME_MESSAGE_DIGEST_REF(x) \
+            nutag_smime_message_digest_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_digest_ref;
+
+/** S/MIME signature algorithm
+ *
+ * This tag specifies the signature algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ *    To be implemented.
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_SIGNATURE_REF()
+ */
+#define NUTAG_SMIME_SIGNATURE(x) nutag_smime_signature, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_signature;
+
+#define NUTAG_SMIME_SIGNATURE_REF(x) \
+            nutag_smime_signature_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_signature_ref;
+
+/** S/MIME key encryption algorithm
+ *
+ * This tag specifies the key encryption algorithm to be used by S/MIME.
+ *
+ * @par Used with
+ *    To be implemented
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_KEY_ENCRYPTION_REF()
+ */
+#define NUTAG_SMIME_KEY_ENCRYPTION(x) nutag_smime_key_encryption, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_key_encryption;
+
+#define NUTAG_SMIME_KEY_ENCRYPTION_REF(x) \
+          nutag_smime_key_encryption_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_key_encryption_ref;
+
+/** S/MIME message encryption algorithm
+ *
+ * This tag specifies the message encryption algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ *    To be implemented.
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_MESSAGE_ENCRYPTION_REF()
+ */
+#define NUTAG_SMIME_MESSAGE_ENCRYPTION(x) nutag_smime_message_encryption, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_encryption;
+
+#define NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(x) \
+           nutag_smime_message_encryption_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_encryption_ref;
+
+/** x.500 certificate directory
+ *
+ * @par Used with
+ *    nua_create()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    NULL terminated pathname of directory containing agent.pem and cafile.pem files.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CERTIFICATE_DIR_REF()
+ */
+#define NUTAG_CERTIFICATE_DIR(x) nutag_certificate_dir, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_certificate_dir;
+
+#define NUTAG_CERTIFICATE_DIR_REF(x) \
+          nutag_certificate_dir_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_certificate_dir_ref;
+
+/** Certificate phrase
+ *
+ * @par Used with
+ *    Currently not processed by NUA
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CERTIFICATE_PHRASE_REF()
+ */
+#define NUTAG_CERTIFICATE_PHRASE(x) nutag_certificate_phrase, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_certificate_phrase;
+
+#define NUTAG_CERTIFICATE_PHRASE_REF(x) \
+          nutag_certificate_phrase_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_certificate_phrase_ref;
+
+/** Local SIPS url.
+ *
+ * The application can specify an alternative local address for
+ * NUA user agent engine. Usually the alternative address is a
+ * secure SIP URI (SIPS) used with TLS transport.
+ *
+ * @par Used with
+ *    nua_create()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SIPS_URL_REF()
+ */
+#define NUTAG_SIPS_URL(x)       nutag_sips_url, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_sips_url;
+
+#define NUTAG_SIPS_URL_REF(x)   nutag_sips_url_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_sips_url_ref;
+
+/** Outbound proxy URL
+ *
+ * Same tag as NTATAG_DEFAULT_PROXY()
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_create()
+ *
+ * @par Parameter type
+ *    url_string_t const * (either char const * or url_t *)
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_PROXY_REF()
+ */
+#define NUTAG_PROXY(x)          NTATAG_DEFAULT_PROXY(x)
+#define NUTAG_PROXY_REF(x)      NTATAG_DEFAULT_PROXY_REF(x)
+#define nutag_proxy             ntatag_default_proxy
+
+/** Registrar URL
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    url_string_t const * (either char const * or url_t *)
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REGISTRAR_REF()
+ */
+#define NUTAG_REGISTRAR(x)      nutag_registrar, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_registrar;
+
+#define NUTAG_REGISTRAR_REF(x)  nutag_registrar_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
+
+/** Outbound option string.
+ *
+ * The outbound option string can specify how the NAT traversal is handled.
+ * The option tokens are as follows:
+ * - "gruuize": try to generate a GRUU
+ * - "outbound": use SIP outbound extension (off by default)
+ * - "validate": validate registration behind a NAT by sending OPTIONS to self
+ * - "natify": try to traverse NAT
+ * - "use-rport": use rport to traverse NAT
+ * - "options-keepalive": send periodic OPTIONS requests as keepalive messages
+ *
+ * An option token with "no-" or "not-" prefix turns the option off. For
+ * example, if you want to try to traverse NATs but not to use OPTIONS
+ * keepalive, use NUTAG_OUTBOUND("natify no-options-keepalive").
+ *
+ * @note
+ * Options string is used so that no new tags need to be added when the
+ * outbound functionality changes.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_REF()
+ */
+#define NUTAG_OUTBOUND(x)      nutag_outbound, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound;
+
+#define NUTAG_OUTBOUND_REF(x)  nutag_outbound_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_ref;
+
+#if notyet
+
+/** Outbound proxy set 1.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET1_REF()
+ */
+#define NUTAG_OUTBOUND_SET1(x)      nutag_outbound_set1, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set1;
+
+#define NUTAG_OUTBOUND_SET1_REF(x)  nutag_outbound_set1_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set1_ref;
+
+/** Outbound proxy set 2.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET2_REF()
+ */
+#define NUTAG_OUTBOUND_SET2(x)      nutag_outbound_set2, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set2;
+
+#define NUTAG_OUTBOUND_SET2_REF(x)  nutag_outbound_set2_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set2_ref;
+
+/** Outbound proxy set 3.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET3_REF()
+ */
+#define NUTAG_OUTBOUND_SET3(x)      nutag_outbound_set3, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set3;
+
+#define NUTAG_OUTBOUND_SET3_REF(x)  nutag_outbound_set3_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set3_ref;
+
+/** Outbound proxy set 4.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET4_REF()
+ */
+#define NUTAG_OUTBOUND_SET4(x)      nutag_outbound_set4, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set4;
+
+#define NUTAG_OUTBOUND_SET4_REF(x)  nutag_outbound_set4_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set4_ref;
+
+#endif	/* ...notyet */
+
+/** Pointer to SIP parser structure
+ *
+ * @par Used with
+ *    nua_create()
+ *
+ * @par Parameter type
+ *    msg_mclass_t *
+ *
+ * @par Values
+ *    Pointer to an extended SIP parser.
+ *
+ * @sa msg_mclass_clone(), msg_mclass_insert_header()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SIP_PARSER_REF().
+ */
+#define NUTAG_SIP_PARSER(x)     NTATAG_MCLASS(x)
+#define NUTAG_SIP_PARSER_REF(x) NTATAG_MCLASS_REF(x)
+
+/** Authentication data ("scheme" "realm" "user" "password")
+ *
+ * @par Used with
+ *    nua_authenticate()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    NULL terminated string of format: \n
+ *    basic digest scheme:"realm":user:password  \n
+ *    @b NOTE the double quotes around realm!
+ *    For example: \n
+ *	\code Digest:"nokia proxy":xyz:secret \endcode
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTH_REF()
+ */
+#define NUTAG_AUTH(x)		nutag_auth, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_auth;
+
+#define NUTAG_AUTH_REF(x)	    nutag_auth_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_auth_ref;
+
+/** Keepalive interval in milliseconds.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values 
+ *   - 0 - disable keepalives
+ *   - 120000 - default value (120000 milliseconds, 120 seconds)
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_KEEPALIVE_REF()
+ */
+#define NUTAG_KEEPALIVE(x) nutag_keepalive, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_keepalive;
+
+#define NUTAG_KEEPALIVE_REF(x) nutag_keepalive_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_ref;
+
+/** Transport-level keepalive interval for streams.
+ *
+ * @par Used with
+ *    nua_register()   \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *    nua_set_hparams() \n
+ *    nua_get_hparams()
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values 
+ *
+ * Transport-level keepalive interval for streams in milliseconds. If this
+ * parameter specified, it takes presedence over value given in
+ * NUTAG_KEEPALIVE().
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_KEEPALIVE_STREAM_REF()
+ *
+ * @todo Actually pass NUTAG_KEEPALIVE_STREAM() to transport layer.
+ */
+#define NUTAG_KEEPALIVE_STREAM(x) nutag_keepalive_stream, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_stream;
+
+#define NUTAG_KEEPALIVE_STREAM_REF(x) \
+nutag_keepalive_stream_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_stream_ref;
+
+/** Lifetime of authentication data in seconds.
+ *
+ * @par Used with
+ *    Currently not processed by NUA
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ *    @c 0   Use authentication data only for this handle \n
+ *    @c !=0 Lifetime in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTHTIME_REF()
+ */
+#define NUTAG_AUTHTIME(x)	nutag_authtime, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_authtime;
+
+#define NUTAG_AUTHTIME_REF(x)	nutag_authtime_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_authtime_ref;
+
+/**Display name for @Contact.
+ *
+ * Specify display name for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Note that display name is not included the request-URI when proxy
+ * forwards the request towards user-agent.
+ *
+ * @par Used with
+ *    nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ *    string (char *)
+ *
+ * @par Values
+ *    Valid display name.
+ *
+ * @sa NUTAG_M_USERNAME(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_DISPLAY_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_DISPLAY(x)   nutag_m_display, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_display;
+
+#define NUTAG_M_DISPLAY_REF(x) nutag_m_display_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_display_ref;
+
+/**Username prefix for @Contact.
+ *
+ * Specify username part for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Using username, application can make multiple registrations using
+ * multiple identities, or it can distinguish between different logical
+ * destinations.
+ *
+ * @par Used with
+ *    nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ *    string (char *)
+ *
+ * @par Values
+ *    Valid SIP username.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_USERNAME_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_USERNAME(x)   nutag_m_username, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_username;
+
+#define NUTAG_M_USERNAME_REF(x) nutag_m_username_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_username_ref;
+
+/**URL parameters for @Contact.
+ *
+ * Specify URL parameters for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Please note that some proxies may remove even the non-transport
+ * parameters from the request-URI when they forward the request towards
+ * user-agent.
+ *
+ * @par Used with
+ *    nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ *    string (char *)
+ *
+ * @par Values
+ *    Semicolon-separated URL parameters.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_PARAMS_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_PARAMS(x)   nutag_m_params, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_params;
+
+#define NUTAG_M_PARAMS_REF(x) nutag_m_params_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_params_ref;
+
+/**Header parameters for registration @Contact.
+ *
+ * Specify header parameters for the @Contact header generated for
+ * registration request and dialog-creating requests/responses. Such header
+ * parameters include "q", indicating preference for the @Contact URI, and
+ * "expires", indicating the desired expiration time for the registration.
+ *
+ * Additional header parameters are typically media feature tags, specified in
+ * @RFC3840. If NUTAG_CALLEE_CAPS(1) is specified, additional @Contact header
+ * parameters are generated based on SDP capabilities and SIP @Allow header.
+ *
+ * When using the "outbound" extension option, the stack will also add
+ * "+sip.instance" and "reg-id" header parameters to the @Contact.
+ *
+ * @par Used with
+ *    nua_register(), nua_set_hparams(), nua_set_params()
+ *
+ * @par Parameter type
+ *    string (char *)
+ *
+ * @par Values
+ *    Semicolon-separated SIP header parameters.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(),
+ * NUTAG_CALLEE_CAPS(), NUTAG_IDENTITY().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_FEATURES_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_FEATURES(x)   nutag_m_features, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_features;
+
+#define NUTAG_M_FEATURES_REF(x) nutag_m_features_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_features_ref;
+
+/**NUA event.
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ *    enum nua_event_e
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EVENT_REF()
+ */
+#define NUTAG_EVENT(x)          nutag_event, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_event;
+
+#define NUTAG_EVENT_REF(x)      nutag_event_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_event_ref;
+
+/** Response status code
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ * 100 - preliminary response, request is being processed by next hop \n
+ * 1XX - preliminary response, request is being processed by UAS \n
+ * 2XX - successful final response \n
+ * 3XX - redirection error response \n
+ * 4XX - client error response \n
+ * 5XX - server error response \n
+ * 6XX - global error response \n
+ *
+ * Corresponding tag taking reference parameter is NUTAG_STATUS_REF()
+ */
+#define NUTAG_STATUS(x)         nutag_status, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_status;
+
+#define NUTAG_STATUS_REF(x)     nutag_status_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_status_ref;
+
+/** Response phrase
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_PHRASE_REF()
+ */
+#define NUTAG_PHRASE(x)         nutag_phrase, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_phrase;
+
+#define NUTAG_PHRASE_REF(x)     nutag_phrase_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_phrase_ref;
+
+/** NUA Handle
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ *    nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_HANDLE_REF()
+ */
+#define NUTAG_HANDLE(x)         nutag_handle, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_handle;
+
+#define NUTAG_HANDLE_REF(x)     nutag_handle_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_handle_ref;
+
+/** Registration handle (used with requests and nua_respond()) (NOT YET IMPLEMENTED)
+ *
+ * When a new request is made or new call is responded, a new identity can
+ * be selected with NUTAG_IDENTITY(). The identity comprises of @b From
+ * header, initial route set, local contact header and media tags associated
+ * with it, soa handle and so on. User can make multiple registrations using
+ * multiple identities.
+ *
+ * @par Used with
+ *    nua_invite()
+ *
+ * @par Parameter type
+ *    nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_IDENTITY_REF()
+*/
+#define NUTAG_IDENTITY(x)   nutag_identity, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_identity;
+
+#define NUTAG_IDENTITY_REF(x) nutag_identity_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_identity_ref;
+
+/**Intance identifier.
+ *
+ * @par Used with
+ *    nua_create(), nua_set_params(), nua_get_params(), 
+ *    nua_register()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Value
+ *    urn:uuid string, a globally unique identifier for this user-agent
+ *    instance.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_INSTANCE_REF()
+ */
+#define NUTAG_INSTANCE(x)        nutag_instance, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_instance;
+
+#define NUTAG_INSTANCE_REF(x)    nutag_instance_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_instance_ref;
+
+/** Refer reply handle (used with refer)
+ *
+ * When making a call in response to a REFER request [RFC3515] with
+ * nua_invite(), the application can ask NUA to automatically generate
+ * notifications about the call progress to the referrer. In order to
+ * do that the application should pass to the stack the handle, which
+ * it used to receive the REFER request. It should also pass the event
+ * header object along with the handle using NUTAG_REFER_EVENT().
+ *
+ * @par Used with
+ *    nua_invite()
+ *
+ * @par Parameter type
+ *    nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_NOTIFY_REFER_REF()
+*/
+#define NUTAG_NOTIFY_REFER(x)   nutag_notify_refer, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_notify_refer;
+
+#define NUTAG_NOTIFY_REFER_REF(x) nutag_notify_refer_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_notify_refer_ref;
+
+/** Event used with automatic refer notifications.
+ *
+ * When creating a call in response to a REFER request [RFC3515]
+ * the application can ask NUA to automatically generate notifications
+ * about the call progress to the referrer. The #nua_i_refer event will
+ * contain a suitable SIP event header for the notifications in the
+ * NUTAG_REFER_EVENT() tag. The application should store the SIP event
+ * header and when it makes the referred call, it should pass it back
+ * to the stack again using the NUTAG_REFER_EVENT() tag.
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ *    sip_event_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_EVENT_REF()
+ */
+#define NUTAG_REFER_EVENT(x)   nutag_refer_event, siptag_event_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_event;
+
+#define NUTAG_REFER_EVENT_REF(x) nutag_refer_event_ref, siptag_event_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_event_ref;
+
+/** Invite pauses referrer's handle.
+ *
+ * When creating a call in response to a REFER [RFC3515] request,
+ * the application can ask that the original call will be muted
+ * when the new call is connected by specifying NUTAG_REFER_PAUSE()
+ * along with NUTAG_NOTIFY_REFER() as a parameter to nua_invite() call.
+ *
+ * @par Used with
+ *    nua_invite()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_PAUSE_REF()
+ *
+ * @deprecated Not implemented.
+ */
+#define NUTAG_REFER_PAUSE(x)   nutag_refer_pause, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_pause;
+
+#define NUTAG_REFER_PAUSE_REF(x) nutag_refer_pause_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_pause_ref;
+
+/**User-Agent string.
+ *
+ * Indicate the User-Agent header used by the stack. The value set with this
+ * tag is concatenated with the value indicating the stack name and version,
+ * e.g., "sofia-sip/1.12.1" unless the stack name "sofia-sip" followed by
+ * slash is already included in the string. The concatenated value is
+ * returned in SIPTAG_USER_AGENT_STR() and NUTAG_USER_AGENT() when
+ * nua_get_params() is called.
+ *
+ * If you want to set the complete string, use SIPTAG_USER_AGENT_STR() or
+ * SIPTAG_USER_AGENT().
+ *
+ * @par Used with
+ *    nua_set_params(), nua_set_hparams() \n
+ *    nua_get_params(), nua_get_hparams(), #nua_r_get_params \n
+ *    any handle-specific nua call
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    See @RFC3261 \n
+ *    If NULL, stack uses default string which of format "sofia-sip/1.12".
+ *
+ * Corresponding tag taking reference parameter is NUTAG_USER_AGENT_REF()
+ */
+#define NUTAG_USER_AGENT(x)     nutag_user_agent, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_user_agent;
+
+#define NUTAG_USER_AGENT_REF(x) nutag_user_agent_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_user_agent_ref;
+
+/** Allow a method (or methods).
+ *
+ * This tag is used to add a new method to the already existing set of
+ * allowed methods. If you want to ignore the existing set of allowed
+ * methods, use SIPTAG_ALLOW_STR() or SIPTAG_ALLOW().
+ *
+ * The set of allowed methods is added to the @Allow header in the response
+ * or request messages. For incoming request, an error response <i>405
+ * Method Not Allowed</i> is automatically returned if the incoming method
+ * is not included in the set.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_set_hparams() \n
+ *    any handle-specific nua call
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    Valid method name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ALLOW_REF()
+ */
+#define NUTAG_ALLOW(x)     nutag_allow, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_allow;
+
+#define NUTAG_ALLOW_REF(x) nutag_allow_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_allow_ref;
+
+
+/** Indicate that a method (or methods) are handled by application.
+ *
+ * This tag is used to add a new method to the already existing set of
+ * methods handled by application, or clear the set. If you want to
+ * determine the set explicitly, include NUTAG_APPL_METHOD() twice,
+ * first with NULL and then with your supported set.
+ *
+ * The default set of application methods now include INVITE, REGISTER,
+ * PUBLISH and SUBSCRIBE.
+ *
+ * If the request method is in the set of methods handled by application,
+ * the nua stack does not automatically respond to the incoming request nor
+ * it will automatically send such a request. Note if the application adds
+ * the PRACK and UPDATE requests to the set of application methods it must
+ * also take care for sending the PRACK and UPDATE requests during the call
+ * setup when necessary.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_set_hparams() \n
+ *    any handle-specific nua call
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    Valid method name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_APPL_METHOD_REF()
+ *
+ * @since Working since @VERSION_1_12_5. 
+ */
+#define NUTAG_APPL_METHOD(x)     nutag_appl_method, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_appl_method;
+
+#define NUTAG_APPL_METHOD_REF(x) nutag_appl_method_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_appl_method_ref;
+
+
+/** Support a feature.
+ *
+ * This tag is used to add a new feature to the existing set of supported
+ * SIP features. If you want to ignore the existing set of supported
+ * features, use SIPTAG_SUPPORTED_STR() or SIPTAG_SUPPORTED().
+ *
+ * The set of supported features is added to the @Supported header in the
+ * response or request messages. For incoming requests, an error response
+ * <i>420 Bad Extension </i> is automatically returned if the request
+ * requires features that are not included in the supported feature set.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_set_hparams() \n
+ *    any handle-specific nua call
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    Feature name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SUPPORTED_REF()
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_SUPPORTED(x)     nutag_supported, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_supported;
+
+#define NUTAG_SUPPORTED_REF(x) nutag_supported_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_supported_ref;
+
+/** Allow an event or events.
+ *
+ * This tag is used to add a new event to the already existing set of
+ * allowed events. If you want to ignore the existing set of allowed events,
+ * set the allowed event set with SIPTAG_ALLOW_EVENTS_STR() or
+ * SIPTAG_ALLOW_EVENTS().
+ *
+ * The set of allowed methods is added to the @AllowEvents header in the
+ * response to the SUBSCRIBE or PUBLISH requests. For incoming SUBSCRIBE or
+ * PUBLISH request, an error response <i>489 Bad Event</i> is automatically
+ * returned if the incoming method is not included in the set.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_set_hparams() \n
+ *    any handle-specific nua call
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    Valid event name, or comma-separated list of them.
+ *
+ * @sa @AllowEvents, @RFC3265, @RFC3903, #nua_i_subscribe, #nua_i_publish,
+ * nua_subscribe(), nua_publish(), SIPTAG_ALLOW_EVENTS(),
+ * SIPTAG_ALLOW_EVENTS_STR()
+ *
+ * @NEW_1_12_4.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ALLOW_EVENTS_REF()
+ */
+#define NUTAG_ALLOW_EVENTS(x)     nutag_allow_events, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_allow_events;
+
+#define NUTAG_ALLOW_EVENTS_REF(x) nutag_allow_events_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_allow_events_ref;
+
+/** Call state
+ *
+ * @par Used with
+ *    #nua_i_state
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ * - #nua_callstate_init - Initial state
+ * - #nua_callstate_authenticating - 401/407 received
+ * - #nua_callstate_calling - INVITE sent
+ * - #nua_callstate_proceeding - 18X received
+ * - #nua_callstate_completing   - 2XX received
+ * - #nua_callstate_received - INVITE received (and 100 Trying sent)
+ * - #nua_callstate_early       - 18X sent
+ * - #nua_callstate_completed   - 2XX sent
+ * - #nua_callstate_ready       - 2XX and ACK received/sent
+ * - #nua_callstate_terminating - BYE sent
+ * - #nua_callstate_terminated  - BYE complete
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CALLSTATE_REF()
+ */
+#define NUTAG_CALLSTATE(x) nutag_callstate, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_callstate;
+
+#define NUTAG_CALLSTATE_REF(x) nutag_callstate_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_callstate_ref;
+
+enum nua_callstate {
+  nua_callstate_init,		/**< Initial state */
+  nua_callstate_authenticating, /**< 401/407 received */
+  nua_callstate_calling,	/**< INVITE sent */
+  nua_callstate_proceeding,	/**< 18X received */
+  nua_callstate_completing,	/**< 2XX received */
+  nua_callstate_received,	/**< INVITE received */
+  nua_callstate_early,		/**< 18X sent (w/SDP) */
+  nua_callstate_completed,	/**< 2XX sent */
+  nua_callstate_ready,		/**< 2XX received, ACK sent, or vice versa */
+  nua_callstate_terminating,	/**< BYE sent */
+  nua_callstate_terminated	/**< BYE complete */
+};
+
+/** Get name for NUA call state */
+SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
+
+/** Subscription state
+ *
+ * @par Used with
+ *    #nua_r_subscribe \n
+ *    #nua_i_notify
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *   @c nua_substate_embryonic (0) \n
+ *   @c nua_substate_pending (1) \n
+ *   @c nua_substate_active (2) \n
+ *   @c nua_substate_terminated	(3) \n
+ *
+ * see
+ * <a href="http://www.ietf.org/rfc/rfc3265.txt">RFC 3265</a>
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SUBSTATE_REF()
+*/
+#define NUTAG_SUBSTATE(x) nutag_substate, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_substate;
+
+#define NUTAG_SUBSTATE_REF(x) nutag_substate_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_substate_ref;
+
+/** Parameter type of NUTAG_SUBSTATE() */
+enum nua_substate {
+  /** Extended state, considered as active. */
+  nua_substate_extended = nea_extended,
+  /** Embryonic subscription: SUBSCRIBE sent */
+  nua_substate_embryonic = nea_embryonic,
+  nua_substate_pending = nea_pending,   /**< Pending subscription */
+  nua_substate_active = nea_active,	/**< Active subscription */
+  nua_substate_terminated = nea_terminated /**< Terminated subscription */
+};
+
+/**Default lifetime for implicit subscriptions created by REFER.
+ *
+ * Default expiration time in seconds for implicit subscriptions created by
+ * REFER.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_set_hparams() \n
+ *    nua_get_hparams() \n
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ *    @c 0  disable \n
+ *    @c >0 interval in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_EXPIRES()
+ */
+#define NUTAG_REFER_EXPIRES(x)  nutag_refer_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_expires;
+
+#define NUTAG_REFER_EXPIRES_REF(x) nutag_refer_expires_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_refer_expires_ref;
+
+/**Always use id parameter with refer event.
+ *
+ * When an incoming REFER creates an implicit subscription, the event header
+ * in the NOTIFY request may have an id parameter. The id parameter can be
+ * either always included (default behavior), or the parameter can be used
+ * only for the second and subsequent REFER requests received in a given
+ * dialog.
+ *
+ * Note that once the subscription is created, the event header should not
+ * be modified. Therefore this tag has no effect on already established
+ * subscriptions, and its use makes sense largely on nua_set_params() only.
+ *
+ * @par Used with
+ *    nua_set_params() (nua_set_hparams(), nua_invite(), nua_respond(),
+ *    nua_update()).
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *   0 (false, do not use id with subscription created with first REFER request) \n
+ *   1 (true, use id with all subscriptions created with REFER request) \n
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_WITH_ID_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_REFER_WITH_ID(x)   nutag_refer_with_id, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_with_id;
+
+#define NUTAG_REFER_WITH_ID_REF(x) nutag_refer_with_id_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_with_id_ref;
+
+/**Add media tags from our offer to Accept-Contact headers.
+ *
+ * Automatically generate @AcceptContact headers for caller
+ * preference processing according to our the media capabilities in @a soa.
+ *
+ * @par Used with
+ *    nua_invite()  \n
+ *    nua_update()  \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   Do not add media tags \n
+ *    @c !=0 Add media tags
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MEDIA_FEATURES_REF()
+ *
+ * @sa nua_invite(), SOATAG_USER_SDP(), SIPTAG_ACCEPT_CONTACT(),
+ *     NUTAG_CALLEE_CAPS()
+ */
+#define NUTAG_MEDIA_FEATURES(x) nutag_media_features, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_media_features;
+
+#define NUTAG_MEDIA_FEATURES_REF(x) \
+          nutag_media_features_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_media_features_ref;
+
+/** Add methods and media tags to Contact headers. */
+#define NUTAG_CALLEE_CAPS(x) nutag_callee_caps, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_callee_caps;
+
+#define NUTAG_CALLEE_CAPS_REF(x) \
+          nutag_callee_caps_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_callee_caps_ref;
+
+/** If true, add "path" to Supported in REGISTER.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc3327.txt">RFC 3327</a>,
+ * <i>"SIP Extension Header Field for Registering Non-Adjacent Contacts"</i>,
+ * D. Willis, B. Hoeneisen,
+ * December 2002.
+ */
+#define NUTAG_PATH_ENABLE(x)   nutag_path_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_path_enable;
+
+#define NUTAG_PATH_ENABLE_REF(x) nutag_path_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_path_enable_ref;
+
+/** Use route from Service-Route header in response to REGISTER.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc3327.txt">RFC 3327</a>,
+ * <i>"SIP Extension Header Field for Registering Non-Adjacent Contacts"</i>,
+ * D. Willis, B. Hoeneisen,
+ * December 2002.
+ */
+#define NUTAG_SERVICE_ROUTE_ENABLE(x) nutag_service_route_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_service_route_enable;
+
+#define NUTAG_SERVICE_ROUTE_ENABLE_REF(x) \
+          nutag_service_route_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_service_route_enable_ref;
+
+/** Enable built-in media session handling
+ *
+ * The built-in media session object @soa takes care of most details
+ * of offer-answer negotiation. 
+ *
+ * @par Used with
+ *    nua_create()
+ *
+ * @par Parameter type
+ *    int
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MEDIA_ENABLE_REF()
+*/
+#define NUTAG_MEDIA_ENABLE(x) nutag_media_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_media_enable;
+
+#define NUTAG_MEDIA_ENABLE_REF(x) \
+          nutag_media_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_media_enable_ref;
+
+/** Indicate that SDP offer has been received.
+ *
+ * @par Used with
+ *    #nua_i_state
+ *
+ * @par Parameter type
+ *    boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OFFER_RECV_REF()
+ */
+#define NUTAG_OFFER_RECV(x) nutag_offer_recv, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_offer_recv;
+
+#define NUTAG_OFFER_RECV_REF(x) nutag_offer_recv_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_offer_recv_ref;
+
+/** Indicate that SDP answer has been received.
+ *
+ * @par Used with
+ *    #nua_i_state
+ *
+ * @par Parameter type
+ *    boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ANSWER_RECV_REF()
+ */
+#define NUTAG_ANSWER_RECV(x) nutag_answer_recv, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_answer_recv;
+
+#define NUTAG_ANSWER_RECV_REF(x) nutag_answer_recv_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_answer_recv_ref;
+
+/** Indicate that SDP offer has been sent.
+ *
+ * @par Used with
+ *    #nua_i_state
+ *
+ * @par Parameter type
+ *    boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OFFER_SENT_REF()
+ */
+#define NUTAG_OFFER_SENT(x) nutag_offer_sent, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_offer_sent;
+
+#define NUTAG_OFFER_SENT_REF(x) nutag_offer_sent_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_offer_sent_ref;
+
+/** Indicate that SDP answer has been sent.
+ *
+ * @par Used with
+ *    #nua_i_state
+ *
+ * @par Parameter type
+ *    int (boolean: nonzero is true, zero is false)
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ANSWER_SENT_REF()
+ */
+#define NUTAG_ANSWER_SENT(x) nutag_answer_sent, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_answer_sent;
+
+#define NUTAG_ANSWER_SENT_REF(x) nutag_answer_sent_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_answer_sent_ref;
+
+/**Enable detection of local IP address updates.
+ *
+ * @par Used with
+ *    nua_create() \n
+ *    nua_set_params() \n
+ *    nua_get_params()
+ *
+ * @par Parameter type
+ *    int (enum nua_nw_detector_e aka #nua_nw_detector_t)
+ *
+ * @sa #nua_i_network_changed, #nua_nw_detector_t
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_DETECT_NETWORK_UPDATES_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_DETECT_NETWORK_UPDATES(x) \
+          nutag_detect_network_updates, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates;
+
+#define NUTAG_DETECT_NETWORK_UPDATES_REF(x) \
+          nutag_detect_network_updates_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates_ref;
+
+/* Pass nua handle as tagged argument */
+#if SU_HAVE_INLINE
+su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }
+su_inline tag_value_t nutag_handle_vr(nua_handle_t **vp) {return(tag_value_t)vp;}
+#else
+#define nutag_handle_v(v)   (tag_value_t)(v)
+#define nutag_handle_vr(v)  (tag_value_t)(v)
+#endif
+
+/* Tags for compatibility */
+
+#define NUTAG_USE_LEG(x) NUTAG_USE_DIALOG(x)
+#define NUTAG_USE_LEG_REF(x) NUTAG_USE_DIALOG_REF(x)
+
+#define NUTAG_AF(x) SOATAG_AF((x))
+#define NUTAG_AF_REF(x) SOATAG_AF_REF((x))
+
+enum nua_af {
+  nutag_af_any = SOA_AF_ANY,
+  nutag_af_ip4_only = SOA_AF_IP4_ONLY,
+  nutag_af_ip6_only = SOA_AF_IP6_ONLY,
+  nutag_af_ip4_ip6 = SOA_AF_IP4_IP6,
+  nutag_af_ip6_ip4 = SOA_AF_IP6_IP4
+};
+
+#define NUTAG_AF_ANY      nutag_af_any
+#define NUTAG_AF_IP4_ONLY nutag_af_ip4_only
+#define NUTAG_AF_IP6_ONLY nutag_af_ip6_only
+#define NUTAG_AF_IP4_IP6  nutag_af_ip4_ip6
+#define NUTAG_AF_IP6_IP4  nutag_af_ip6_ip4
+
+#define NUTAG_MEDIA_ADDRESS(x)  SOATAG_ADDRESS((x))
+#define NUTAG_MEDIA_ADDRESS_REF(x)   SOATAG_ADDRESS_REF((x))
+
+#define NUTAG_HOLD(x) SOATAG_HOLD((x) ? "*" : NULL)
+
+#define NUTAG_ACTIVE_AUDIO(x) SOATAG_ACTIVE_AUDIO((x))
+#define NUTAG_ACTIVE_AUDIO_REF(x) SOATAG_ACTIVE_AUDIO_REF((x))
+#define NUTAG_ACTIVE_VIDEO(x) SOATAG_ACTIVE_VIDEO((x))
+#define NUTAG_ACTIVE_VIDEO_REF(x) SOATAG_ACTIVE_VIDEO_REF((x))
+#define NUTAG_ACTIVE_IMAGE(x) SOATAG_ACTIVE_IMAGE((x))
+#define NUTAG_ACTIVE_IMAGE_REF(x) SOATAG_ACTIVE_IMAGE_REF((x))
+#define NUTAG_ACTIVE_CHAT(x) SOATAG_ACTIVE_CHAT((x))
+#define NUTAG_ACTIVE_CHAT_REF(x) SOATAG_ACTIVE_CHAT_REF((x))
+
+enum {
+  nua_active_rejected = SOA_ACTIVE_REJECTED,
+  nua_active_disabled = SOA_ACTIVE_DISABLED,
+  nua_active_inactive = SOA_ACTIVE_INACTIVE,
+  nua_active_sendonly = SOA_ACTIVE_SENDONLY,
+  nua_active_recvonly = SOA_ACTIVE_RECVONLY,
+  nua_active_sendrecv = SOA_ACTIVE_SENDRECV
+};
+
+#define NUTAG_SRTP_ENABLE(x)  SOATAG_SRTP_ENABLE((x))
+#define NUTAG_SRTP_ENABLE_REF(x) SOATAG_SRTP_ENABLE_REF((x))
+#define NUTAG_SRTP_CONFIDENTIALITY(x)  SOATAG_SRTP_CONFIDENTIALITY((x))
+#define NUTAG_SRTP_CONFIDENTIALITY_REF(x) SOATAG_SRTP_CONFIDENTIALITY_REF((x))
+#define NUTAG_SRTP_INTEGRITY_PROTECTION(x)  SOATAG_SRTP_INTEGRITY((x))
+#define NUTAG_SRTP_INTEGRITY_PROTECTION_REF(x) SOATAG_SRTP_INTEGRITY_REF((x))
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1594 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_100rel.c
+ * @brief NUA-10 tests: early session, PRACK, UPDATE, precondition.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/auth_common.h>
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+/* ======================================================================== */
+
+/*
+ X  accept_pracked    ep
+ |-------INVITE------>|
+ |        (sdp)       |
+ |                    |
+ |<----100 Trying-----|
+ |                    |
+ |<-------180---------|
+ |       (sdp)        |
+ |-------PRACK------->|
+ |<-------200---------|
+ |                    |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ |                    |
+*/
+int accept_pracked(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_prack:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
+      ep->next_condition = until_ready;
+    }
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int accept_pracked2(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_prack:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_200_OK, 
+	      NUTAG_INCLUDE_EXTRA_SDP(1),
+	      TAG_END());
+      ep->next_condition = until_ready;
+    }
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int test_180rel(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t *sip;
+
+  if (print_headings)
+    printf("TEST NUA-10.1.1: Call with 100rel and 180\n");
+
+/* Test for 100rel:
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-------180---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->a.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_pracked2);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/sdp");
+  TEST_1(sip->sip_payload);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  /* 180 is PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Respond with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.1.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.1.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.1.2: PASSED\n");
+  
+  END();
+}
+
+/*
+ X      INVITE
+ |                    |
+ |-------INVITE------>|
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int authenticate_until_ready(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (status == 401 || status == 407) {
+    AUTHENTICATE(ep, call, nh,
+		 NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"),
+		 TAG_END());
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/** Test authentication for PRACK */
+int test_prack_auth(struct context *ctx)
+{
+  if (!ctx->proxy_tests)
+    return 0;
+
+  BEGIN();
+
+  struct endpoint *c = &ctx->c,  *b = &ctx->b;
+  struct call *c_call = c->call, *b_call = b->call;
+  struct event *e;
+  sip_t *sip;
+  sip_proxy_authenticate_t *au;
+  char const *md5 = NULL, *md5sess = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.1.1: Call with 100rel and 180\n");
+
+/* Test for authentication during 100rel
+
+   C			B
+   |-------INVITE--\    |
+   |<-------407----/    |
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-------180---------|
+   |-------PRACK---\    |
+   |<-------407----/    |
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  c_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->c.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 TAG_END());
+  run_c_until(ctx, nua_r_set_params, until_final_response);
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(c_call->nh = nua_handle(c->nua, c_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(c, c_call, c_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(c_call->sdp),
+	 TAG_END());
+
+  run_bc_until(ctx, -1, accept_pracked, -1, authenticate_until_ready);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 407);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(au = sip->sip_proxy_authenticate); 
+  TEST_1(auth_get_params(NULL, au->au_params, 
+			 "algorithm=md5", &md5,
+			 "algorithm=md5-sess", &md5sess,
+			 NULL) > 0);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  if (md5 && !md5sess) {
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+    TEST(e->data->e_status, 407);
+
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+    TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+    TEST_1(!is_answer_recv(e->data->e_tags));
+    TEST_1(!is_offer_sent(e->data->e_tags));
+  }
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  /* 180 is PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Respond with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.1.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.1.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_bc_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* C: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.1.2: PASSED\n");
+  
+  END();
+}
+
+/*
+ X  ringing_pracked    ep
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<-------183---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ |                    |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ |                    |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ |                    |
+*/
+int ringing_pracked(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_prack:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+      ep->next_condition = accept_pracked;
+    }
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_183rel(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-10.2.1: Call with 100rel, 183 and 180\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, ringing_pracked);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+     PROCEEDING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 183);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+
+  /* Responded with 183 Session Progress */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 183);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  /* 183 is PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 180);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  /* 180 is PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Respond with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 200);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.2.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.2.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.2.2: PASSED\n");
+
+  END();
+}
+
+/*
+ X  ringing_updated   ep
+ |-------INVITE------>|
+ |       (sdp)        |
+ |<----100 Trying-----|
+ |                    |
+ |<-------183---------|
+ |       (sdp)        |
+ |-------PRACK------->|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+ |-------UPDATE------>|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+<using  acccept_pracked>
+ |                    |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ |                    |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ |                    |
+*/
+int ringing_updated(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_update:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+      ep->next_condition = accept_pracked;
+    }
+    return 0;
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+	    SIPTAG_REQUIRE_STR("100rel"),
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_preconditions(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t *sip;
+
+  if (print_headings)
+    printf("TEST NUA-10.3.1: Call with 100rel and preconditions\n");
+
+/* Test for precondition:
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-------183---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |-------UPDATE------>|
+   |<-------200---------|
+   |			|
+   |<-------180---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->a.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_EARLY_MEDIA(0),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
+		 TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_SUPPORTED_STR("100rel"),
+	 SIPTAG_REQUIRE_STR("precondition"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, ringing_updated);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING --> PROCEEDING: nua_r_prack, nua_i_state
+     PROCEEDING --> PROCEEDING: nua_r_update, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 183);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(!is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+  /* Does not have effect on call state */
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  if (ctx->proxy_tests) {
+    TEST_1(sip->sip_session_expires);
+    TEST_S(sip->sip_session_expires->x_refresher, "uas");
+    TEST_1(!sip_has_supported(sip->sip_require, "timer"));
+  }
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY --> EARLY: nua_i_prack, nua_i_state
+   EARLY --> EARLY: nua_i_update, nua_i_state
+   EARLY --> EARLY: nua_r_update, nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+  /* Responded with 183 Session Progress */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 183);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_sent(e->data->e_tags)); 
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(!is_answer_recv(e->data->e_tags));
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 180);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  /* 180 PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Responded with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 200);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.3.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.3.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.3.2: PASSED\n");
+
+  END();
+}
+
+/*
+ X  accept_updated    ep
+ |-------INVITE------>|
+ |       (sdp)        |
+ |<----100 Trying-----|
+ |                    |
+ |<-------183---------|
+ |       (sdp)        |
+ |-------PRACK------->|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+ |-------UPDATE------>|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+ |                    |
+ |<-------180---------|
+ |                    |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ |                    |
+*/
+int accept_updated(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_update:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    }
+    return 0;
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+	    SIPTAG_REQUIRE_STR("100rel"),
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    if (status == 180)
+      RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int test_preconditions2(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-10.4.1: Call with preconditions and non-100rel 180\n");
+
+/* Test 100rel and preconditions with NUTAG_ONLY183_100REL(1):
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-------183---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |<-------180---------|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->a.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 NUTAG_ONLY183_100REL(1),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_SUPPORTED_STR("100rel"),
+	 SIPTAG_REQUIRE_STR("precondition"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_updated);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 183);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  /* Send UPDATE */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(!is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+  /* Responded with 183 Session Progress */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  /* Responded with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.4.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.4.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.4.2: PASSED\n");
+
+  END();
+}
+
+/*
+ X  ringing_updated2  ep
+ |-------INVITE------>|
+ |       (sdp)        |
+ |<----100 Trying-----|
+ |                    |
+ |<-------183---------|
+ |       (sdp)        |
+ |-------PRACK------->|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+ |-------UPDATE------>|
+ |       (sdp)        |
+ |<-------200---------|
+ |       (sdp)        |
+ |                    |
+ |<------UPDATE-------|
+ |       (sdp)        |
+ |--------200-------->|
+ |       (sdp)        |
+ |                    |
+<using  acccept_pracked>
+ |                    |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ |                    |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ |                    |
+*/
+int ringing_updated2(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_update:
+    if (200 <= status && status < 300) {
+      UPDATE(ep, call, nh, TAG_END());
+    }
+    return 0;
+  case nua_r_update:
+    if (200 <= status && status < 300) {
+      RESPOND(ep, call, nh, SIP_180_RINGING, 
+	      SIPTAG_REQUIRE_STR("100rel"),
+	      TAG_END());
+      ep->next_condition = accept_pracked;
+    }
+    else if (300 <= status) {
+      RESPOND(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+    }
+    return 0;
+  default:
+    break;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+	    SIPTAG_REQUIRE_STR("100rel"),
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_update_by_uas(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t *sip;
+
+  /* -------------------------------------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-10.5.1: Call with dual UPDATE\n");
+
+/* Test for precondition:
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-------183---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |-------UPDATE------>|
+   |<-------200---------|
+   |			|
+   |<------UPDATE-------|
+   |--------200-------->|
+   |			|
+   |<-------180---------|
+   |-------PRACK------->|
+   |<-------200---------|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->a.nua,
+		 NUTAG_EARLY_MEDIA(1),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_EARLY_MEDIA(0),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
+		 TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_SUPPORTED_STR("100rel"),
+	 SIPTAG_REQUIRE_STR("precondition"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, ringing_updated2);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING: nua_r_prack, nua_i_state
+     PROCEEDING: nua_r_update, nua_i_state
+     PROCEEDING: nua_i_update, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 183);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(!is_answer_recv(e->data->e_tags));
+  TEST_1(is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!is_offer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+  TEST(e->data->e_status, 200);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+  TEST(e->data->e_status, 200);
+  /* Does not have effect on call state */
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  if (ctx->proxy_tests) {
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(sip->sip_session_expires);
+    TEST_S(sip->sip_session_expires->x_refresher, "uas");
+    TEST_1(!sip_has_supported(sip->sip_require, "timer"));
+  }
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(183), nua_i_state
+   EARLY --> EARLY: nua_i_prack, nua_i_state
+   EARLY --> EARLY: nua_i_update, nua_i_state
+   EARLY --> EARLY: nua_update(), nua_i_state
+   EARLY --> EARLY: nua_r_update, nua_i_state
+   EARLY --> EARLY: nua_respond(180), nua_i_state
+   EARLY --> EARLY: nua_i_prack, nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(200), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+  /* Responded with 183 Session Progress */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 183);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+
+  /* sent UPDATE */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_offer_sent(e->data->e_tags)); 
+  TEST_1(!is_offer_recv(e->data->e_tags));
+  TEST_1(!is_answer_sent(e->data->e_tags));
+  TEST_1(!is_answer_recv(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_sent(e->data->e_tags)); 
+  TEST_1(!is_offer_recv(e->data->e_tags));
+  TEST_1(!is_answer_sent(e->data->e_tags));
+  TEST_1(is_answer_recv(e->data->e_tags));
+
+  /* Responded with 180 Ringing */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 180);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  /* 180 PRACKed */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+  /* Does not have effect on call state */
+
+  /* Responded with 200 OK */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(e->data->e_status, 200);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_offer_answer_done(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-10.5.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-10.5.2: terminate call\n");
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-10.5.2: PASSED\n");
+
+  END();
+}
+ 
+
+int test_100rel(struct context *ctx)
+{
+  int retval;
+  
+  retval = test_180rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+  retval = test_prack_auth(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+  retval = test_183rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+  retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+  retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+  retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,509 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_basic_call.c
+ * @brief Test basic call.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_basic_call"
+#endif
+
+/* ======================================================================== */
+
+int until_terminated(CONDITION_PARAMS)
+{
+  if (!check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  return event == nua_i_state && callstate(tags) == nua_callstate_terminated;
+}
+
+/*
+ X     accept_call    ep
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, 
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+/*
+ X     accept_call    ep
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call_with_early_sdp(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, 
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+/*
+ X      INVITE
+ |                    |
+ |-------INVITE------>|
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int until_ready(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/* ======================================================================== */
+
+/* Basic call:
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK------>|
+   |			|
+
+   Client transitions:
+   INIT -(C1)-> CALLING -(C2a)-> PROCEEDING -(C3+C4)-> READY
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S4)-> READY
+
+   B sends BYE:
+   READY -(T2)-> TERMINATING -(T3)-> TERMINATED
+   A receives BYE:
+   READY -(T1)-> TERMINATED
+
+   See @page nua_call_model in nua.docs for more information
+*/
+
+int test_basic_call_1(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t *sip;
+  sip_replaces_t *repa, *repb;
+  nua_handle_t *nh;
+
+  if (print_headings)
+    printf("TEST NUA-3.1: Basic call\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  TEST_1(!nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call_with_early_sdp);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+  TEST_1(repa = nua_handle_make_replaces(a_call->nh, nua_handle_home(a_call->nh), 0));
+  TEST_1(repb = nua_handle_make_replaces(b_call->nh, nua_handle_home(b_call->nh), 0));
+
+  TEST_S(repa->rp_call_id, repb->rp_call_id);
+
+  TEST_1(!nua_handle_by_replaces(a->nua, repa));
+  TEST_1(!nua_handle_by_replaces(b->nua, repb));
+
+  TEST_1(nh = nua_handle_by_replaces(a->nua, repb));
+  TEST_P(nh, a_call->nh);
+  nua_handle_unref(nh);
+
+  TEST_1(nh = nua_handle_by_replaces(b->nua, repa));
+  TEST_P(nh, b_call->nh);
+  nua_handle_unref(nh);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_S(sip->sip_call_id->i_id, repb->rp_call_id);
+  TEST_S(sip->sip_from->a_tag, repb->rp_to_tag);
+  TEST_S(sip->sip_to->a_tag, repb->rp_from_tag);
+  TEST_1(sip->sip_payload);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip->sip_payload);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  /* Test that B uses application-specific contact */
+  if (ctx->proxy_tests)
+    TEST_1(sip->sip_contact->m_url->url_user);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_S(sip->sip_call_id->i_id, repa->rp_call_id);
+  TEST_S(sip->sip_from->a_tag, repa->rp_from_tag);
+  TEST_S(sip->sip_to->a_tag, repa->rp_to_tag);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head);  TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  TEST_1(!nua_handle_has_active_call(b_call->nh));
+
+  /* A transitions:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-3.1: PASSED\n");
+
+  END();
+}
+
+/*
+  accept_early_answer
+ X                    ep
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_early_answer(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING,
+	    NUTAG_EARLY_ANSWER(1),
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_basic_call_2(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+  if (print_headings)
+    printf("TEST NUA-3.2: Basic call with SDP in 180\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, 
+				 SIPTAG_TO_STR("<sip:b at x.org>"),
+				 TAG_END()));
+
+  TEST_1(!nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  INVITE(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_early_answer);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_content_type); 
+  TEST_S(sip->sip_content_type->c_type, "application/sdp");
+  TEST_1(sip->sip_payload);	/* there is sdp in 200 OK */
+  TEST_1(sip->sip_contact);
+  /* Test that B does not use application-specific contact */
+  TEST_1(!sip->sip_contact->m_url->url_user);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!is_answer_recv(e->data->e_tags)); /* but it is ignored */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head);  TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  TEST_1(!nua_handle_has_active_call(b_call->nh));
+
+  /* A transitions:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-3.2: PASSED\n");
+
+  END();
+}
+
+
+int test_basic_call(struct context *ctx)
+{
+  return test_basic_call_1(ctx) || test_basic_call_2(ctx);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,803 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_call_hold.c
+ * @brief Test re-INVITE, call hold, un-hold.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+int ack_when_completing(CONDITION_PARAMS);
+
+/* ======================================================================== */
+/* test_call_hold message sequence looks like this:
+
+ A                    B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+ :                    :
+ |--INVITE(sendonly)->|
+ |<---200(recvonly)---|
+ |---------ACK------->|
+ :                    :
+ |<-INVITE(inactive)--|
+ |----200(inactive)-->|
+ |<--------ACK--------|
+ :                    :
+ |--INVITE(recvonly)->|
+ |<---200(sendonly)---|
+ |---------ACK------->|
+ :                    :
+ |<-INVITE(sendrecv)--|
+ |----200(sendrecv)-->|
+ |<--------ACK--------|
+ :                    :
+ |--------INFO------->|
+ |<--------200--------|
+ :                    :
+ |---------BYE------->|
+ |<--------200--------|
+*/
+
+int test_call_hold(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  a_call->sdp =
+    "m=audio 5008 RTP/AVP 0 8\n"
+    "m=video 6008 RTP/AVP 30\n";
+  b_call->sdp =
+    "m=audio 5010 RTP/AVP 8\n"
+    "a=rtcp:5011\n"
+    "m=video 6010 RTP/AVP 30\n"
+    "a=rtcp:6011\n";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  /*
+    Client transitions:
+    INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+    CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+    PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+  free_events_in_list(ctx, b->events);
+
+  /*
+ :                    :
+ |--INVITE(sendonly)->|
+ |<---200(recvonly)---|
+ |---------ACK------->|
+ :                    :
+  */
+
+  if (print_headings)
+    printf("TEST NUA-7.1: put B on hold\n");
+
+  /* Put B on hold */
+  INVITE(a, a_call, a_call->nh, SOATAG_HOLD("audio"),
+	 SIPTAG_SUBJECT_STR("hold b"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+  /* Client transitions:
+     READY -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_call_on_hold(a_call->nh));
+
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.1: PASSED\n");
+
+  /* ------------------------------------------------------------------------ */
+  /*
+ :                    :
+ |<-INVITE(inactive)--|
+ |----200(inactive)-->|
+ |<--------ACK--------|
+ :                    :
+  */
+
+  if (print_headings)
+    printf("TEST NUA-7.2: put A on hold\n");
+
+  /* Put A on hold, too. */
+  INVITE(b, b_call, b_call->nh, SOATAG_HOLD("audio"),
+	 SIPTAG_SUBJECT_STR("hold a"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+  /* Client transitions:
+     READY -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(nua_handle_has_call_on_hold(b_call->nh));
+
+  free_events_in_list(ctx, b->events);
+
+  /*
+   Server transitions:
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_call_on_hold(a_call->nh));
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.2: PASSED\n");
+
+  /* ------------------------------------------------------------------------ */
+  /*
+ :                    :
+ |--INVITE(recvonly)->|
+ |<---200(sendonly)---|
+ |---------ACK------->|
+ :                    :
+  */
+
+  if (print_headings)
+    printf("TEST NUA-7.3: resume B\n");
+
+  /* Resume B from hold */
+  INVITE(a, a_call, a_call->nh, SOATAG_HOLD(NULL),
+	 SIPTAG_SUBJECT_STR("resume b"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+  /* Client transitions:
+     READY -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  /*
+   Server transitions:
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(nua_handle_has_call_on_hold(b_call->nh));
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.3: PASSED\n");
+
+  /* ------------------------------------------------------------------------ */
+  /*
+ :                    :
+ |<-INVITE(sendrecv)--|
+ |----200(sendrecv)-->|
+ |<--------ACK--------|
+ :                    :
+  */
+
+  if (print_headings)
+    printf("TEST NUA-7.4: resume A\n");
+
+  /* Resume A on hold, too. */
+  INVITE(b, b_call, b_call->nh, SOATAG_HOLD(""),
+	 SIPTAG_SUBJECT_STR("TEST NUA-7.4: resume A"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+  /* Client transitions:
+     READY -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+  /*
+   Server transitions:
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.4: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+  /*
+ A                    B
+ |--------INFO------->|
+ |<--------200--------|
+   */
+  if (print_headings)
+    printf("TEST NUA-7.5: send INFO\n");
+
+  INFO(a, a_call, a_call->nh, TAG_END());
+  run_a_until(ctx, -1, save_until_final_response);
+  /* XXX - B should get a  nua_i_info event with 405 */
+
+  /* A sent INFO, receives 405 */
+  TEST_1(e = a->events->head);  TEST_E(e->data->e_event, nua_r_info);
+  TEST(e->data->e_status, 405);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+#if 0				/* XXX */
+  /* B received INFO */
+  TEST_1(e = b->events->head);  TEST_E(e->data->e_event, nua_i_info);
+  TEST(e->data->e_status, 405);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+#endif
+
+  /* Add INFO to allowed methods */
+  nua_set_hparams(b_call->nh, NUTAG_ALLOW("INFO, PUBLISH"), TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  INFO(a, a_call, a_call->nh, TAG_END());
+  run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+  /* A sent INFO, receives 200 */
+  TEST_1(e = a->events->head);  TEST_E(e->data->e_event, nua_r_info);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* B received INFO */
+  TEST_1(e = b->events->head);  TEST_E(e->data->e_event, nua_i_info);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.5: PASSED\n");
+
+  /* ------------------------------------------------------------------------ */
+  /*
+ :                    :
+ |<------INVITE-------|
+ |--------200-------->|
+ |<--------ACK--------|
+ :                    :
+  */
+
+  if (print_headings)
+    printf("TEST NUA-7.6: re-INVITE without auto-ack\n");
+
+  /* Turn off auto-ack */
+  nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  INVITE(b, b_call, b_call->nh, SOATAG_HOLD(""),
+	 SIPTAG_SUBJECT_STR("TEST NUA-7.6: re-INVITE without auto-ack"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, ack_when_completing);
+
+  /* Client transitions:
+     READY -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C3a)-> COMPLETING: nua_r_invite, nua_i_state
+     COMPLETING -(C4)-> READY: nua_ack(), nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /*
+   Server transitions:
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.6: PASSED\n");
+
+
+  /* ---------------------------------------------------------------------- */
+  /*
+ A                    B
+ |---------BYE------->|
+ |<--------200--------|
+   */
+
+  if (print_headings)
+    printf("TEST NUA-7.6: terminate call\n");
+
+  BYE(a, a_call, a_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /*
+   Transitions of A:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* Transitions of B:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-7.6: PASSED\n");
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  END();
+}
+
+/*
+ INVITE without auto-ack
+ X
+ |                    |
+ |-------INVITE------>|
+ |<--------200--------|
+ |                    |
+ |---------ACK------->|
+*/
+int ack_when_completing(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_completing:
+    ACK(ep, call, nh, TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/* ======================================================================== */
+/* test_reinvite message sequence looks like this:
+
+ A                    B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+ :                    :
+ |<----re-INVITE------|
+ |<-------BYE---------|
+ |--------200-------->|
+ |-----487-INVITE---->|
+ |<--------ACK--------|
+*/
+
+int accept_no_save(CONDITION_PARAMS);
+int ringing_until_terminated(CONDITION_PARAMS);
+int bye_when_ringing(CONDITION_PARAMS);
+
+int test_reinvite(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+
+  if (print_headings)
+    printf("TEST NUA-7.7: Test re-INVITE and BYE\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n";
+  b_call->sdp = "m=audio 5010 RTP/AVP 8\n";
+
+  TEST_1(a_call->nh = 
+	 nua_handle(a->nua, a_call, 
+		    SIPTAG_FROM_STR("Alice <sip:alice at example.com>"),
+		    SIPTAG_TO(b->to),
+		    NUTAG_AUTOANSWER(0),
+		    TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, accept_no_save, -1, accept_no_save);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+/*
+ A                    B
+ |<----re-INVITE------|
+ |<------CANCEL-------|
+ |<-------BYE---------|
+ |-----200-CANCEL---->|
+ |------200-BYE------>|
+ |-----487-INVITE---->|
+ |<--------ACK--------|
+*/
+
+  /* re-INVITE A, send BYE after receiving 180 */
+  INVITE(b, b_call, b_call->nh, 
+	 SIPTAG_SUBJECT_STR("re-INVITE"),
+	 TAG_END());
+  /* Run until both a and b has terminated their call */
+  run_ab_until(ctx, -1, ringing_until_terminated, -1, bye_when_ringing);
+  
+#if notyet
+  struct event *e;
+
+  /* XXX - check events later - now we are happy that calls get terminated  */
+  /* Client events:
+   READY -(C1)-> CALLING: nua_invite(), nua_i_state
+   CALLING --(C2)--> PROCEEDING: nua_r_invite, nua_i_state, nua_bye()
+   PROCEEDING--((C3a+C4)-> READY: nua_r_invite, nua_i_state
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* READY */
+  /* Now we can receive events, in any possible order */
+  /* XXX */
+  TEST_1(e = e->next); 
+  
+  TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+  /*
+   Server transitions:
+   READY --(T2)--> CTERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+   READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+  TEST_1(!e->next);
+
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+  TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+#endif
+
+  if (print_headings)
+    printf("TEST NUA-7.7: PASSED\n");
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-7.8: PASSED\n");
+
+  END();
+}
+
+/*
+ Accept INVITE 
+ X
+ |                    |
+ |-------INVITE------>|
+ |<--------200--------|
+ |                    |
+ |---------ACK------->|
+*/
+int accept_no_save(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int ringing_until_terminated(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_reinvites(struct context *ctx)
+{
+  int retval = 0;
+
+  if (print_headings)
+    printf("TEST NUA-7: Test call hold and re-INVITEs\n");
+
+  retval = test_call_hold(ctx);
+  
+  if (retval == 0)
+    retval |= test_reinvite(ctx);
+
+  if (print_headings && retval == 0)
+    printf("TEST NUA-7: PASSED\n");
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,946 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_call_reject.c
+ * @brief NUA-4 tests: call reject cases
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_reject"
+#endif
+
+/* ======================================================================== */
+/*
+ A      reject-1      B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<--------486--------|
+ |---------ACK------->|
+*/
+int reject_1(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_486_BUSY_HERE, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int test_reject_a(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+  if (print_headings)
+    printf("TEST NUA-4.1: reject before ringing\n");
+
+  /*
+   A      reject-1      B
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<--------486--------|
+   |---------ACK------->|
+  */
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-1"),
+	 SIPTAG_CONTACT_STR("sip:a at 127.0.0.1"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, reject_1);
+
+  /*
+   Client transitions in reject-1:
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 486);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions in reject-1:
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_contact); TEST_1(!sip->sip_contact->m_next); 
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.1: PASSED\n");
+
+  END();
+}
+
+/*
+ A      reject-2      B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------602--------|
+ |---------ACK------->|
+*/
+int reject_2(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, 602, "Rejected 2", TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_reject_b(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  /* ------------------------------------------------------------------------ */
+  /*
+   A      reject-2      B
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<--------602--------|
+   |---------ACK------->|
+  */
+
+  if (print_headings)
+    printf("TEST NUA-4.2: reject after ringing\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  /* Make call reject-2 */
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-2"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, reject_2);
+
+  /*
+   Client transitions in reject-2:
+   INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 602);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions in reject-2:
+   INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6a)-> TERMINATED
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.2: PASSED\n");
+
+  END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+int reject_302(CONDITION_PARAMS);
+int reject_604(CONDITION_PARAMS);
+
+/*
+ A     reject-302     B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<-----302 Other-----|
+ |--------ACK-------->|
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<---604 Nowhere-----|
+ |--------ACK-------->|
+*/
+int reject_302(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    {
+      sip_contact_t m[1];
+      *m = *ep->contact;
+      m->m_url->url_user = "302";
+      RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY,
+	      SIPTAG_CONTACT(m), TAG_END());
+    }
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    ep->next_condition = reject_604;
+    return 0;
+  default:
+    return 0;
+  }
+}
+
+int reject_604(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_604_DOES_NOT_EXIST_ANYWHERE, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_reject_302(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  /* Make call reject-3 */
+  if (print_headings)
+    printf("TEST NUA-4.3: redirect then reject\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-3"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, reject_302);
+
+  /*
+   A      reject-3      B
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<-----302 Other-----|
+   |--------ACK-------->|
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<---604 Nowhere-----|
+   |--------ACK-------->|
+  */
+
+  /*
+   Client transitions in reject-3:
+   INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED/INIT
+   INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+  */
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 100);
+  TEST(sip_object(e->data->e_msg)->sip_status->st_status, 302);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 604);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED/INIT
+   INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6b)-> TERMINATED
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.3: PASSED\n");
+
+  END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Reject call with 407, then 401 */
+
+int reject_407(CONDITION_PARAMS);
+int reject_401(CONDITION_PARAMS);
+int authenticate_call(CONDITION_PARAMS);
+int reject_403(CONDITION_PARAMS);
+
+/*
+ A     reject-401     B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<--------407--------|
+ |---------ACK------->|
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<----180 Ringing----|
+ |                    |
+ |<--------401--------|
+ |---------ACK------->|
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<-------403---------|
+ |--------ACK-------->|
+*/
+
+int reject_407(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_407_PROXY_AUTH_REQUIRED,
+	    SIPTAG_PROXY_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+					  "nonce=\"nsdhfuds\", algorithm=MD5, "
+					  "qop=\"auth-int\""),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    ep->next_condition = reject_401;
+    return 0;
+  default:
+    return 0;
+  }
+}
+
+int reject_401(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
+	    SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+					"nonce=\"nsdhfuds\", algorithm=MD5, "
+					"qop=\"auth\""),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    ep->next_condition = reject_403;
+    return 0;
+  default:
+    return 0;
+  }
+}
+
+int reject_403(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_403_FORBIDDEN, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    ep->next_condition = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int authenticate_call(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (event == nua_r_invite && status == 401) {
+    AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"test_nua\":jaska:secret"),
+		 SIPTAG_SUBJECT_STR("Got 401"),
+		 TAG_END());
+    return 0;
+  }
+
+  if (event == nua_r_invite && status == 407) {
+    AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"test_nua\":erkki:secret"),
+		 SIPTAG_SUBJECT_STR("Got 407"),
+		 TAG_END());
+    return 0;
+  }
+
+  switch (callstate(tags)) {
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_reject_401(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event const *e;
+  sip_t const *sip;
+
+  if (print_headings)
+    printf("TEST NUA-4.4: challenge then reject\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-401"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+  run_ab_until(ctx, -1, authenticate_call, -1, reject_407);
+
+  /*
+   Client transitions in reject-3:
+   INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED/INIT
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(sip_object(e->data->e_msg)->sip_status->st_status, 407);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 401);
+  TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 403);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED/INIT
+   INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6b)-> TERMINATED/INIT
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subject);
+  TEST_S(sip->sip_subject->g_value, "reject-401");
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subject);
+  TEST_S(sip->sip_subject->g_value, "Got 407");
+  TEST_1(sip->sip_proxy_authorization);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subject);
+  TEST_S(sip->sip_subject->g_value, "Got 401");
+  TEST_1(sip->sip_authorization);
+  TEST_1(sip->sip_proxy_authorization);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.4: PASSED\n");
+
+  END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Reject call with 401 and bad challenge */
+
+/*
+ A   reject-401-aka   B
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<--------401--------|
+ |---------ACK------->|
+*/
+
+int reject_401_aka(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
+	    /* Send a challenge that we do not grok */
+	    SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+					"nonce=\"nsdhfuds\", algorithm=SHA0-AKAv6, "
+					"qop=\"auth\""),
+	    TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_reject_401_aka(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event const *e;
+  sip_t const *sip;
+
+  if (print_headings)
+    printf("TEST NUA-4.6: invalid challenge \n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-401-aka"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_terminated, -1, reject_401_aka);
+
+  /*
+   Client transitions
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED/INIT
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.6: PASSED\n");
+
+  END();
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+int test_mime_negotiation(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+  /* Make call reject-3 */
+  if (print_headings)
+    printf("TEST NUA-4.5: check for rejections of invalid requests\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  if (print_headings)
+    printf("TEST NUA-4.5.1: invalid Content-Type\n");
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-3"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_CONTENT_TYPE_STR("application/xyzzy+xml"),
+	 SIPTAG_CONTENT_DISPOSITION_STR("session;required"),
+	 SIPTAG_PAYLOAD_STR("m=audio 5008 RTP/AVP 8\n"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+  /*
+   A    reject-5.1      B
+   |			|
+   |-------INVITE------>|
+   |<-------415---------|
+   |--------ACK-------->|
+  */
+
+  /*
+   Client transitions in reject-3:
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+  */
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 415);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(sip->sip_status->st_status, 415);
+  TEST_1(sip->sip_accept);
+  TEST_S(sip->sip_accept->ac_type, "application/sdp");
+  TEST_1(sip->sip_accept_encoding);
+  /* No content-encoding is supported */
+  TEST_S(sip->sip_accept_encoding->aa_value, "");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-4.5.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-4.5.2: invalid Content-Encoding\n");
+
+  /*
+   A    reject-5.2      B
+   |			|
+   |-------INVITE------>|
+   |<-------415---------|
+   |--------ACK-------->|
+  */
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-5"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_CONTENT_ENCODING_STR("zyxxy"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+  /*
+   Client transitions in reject-3:
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+  */
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 415);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(sip->sip_status->st_status, 415);
+  TEST_1(sip->sip_accept);
+  TEST_S(sip->sip_accept->ac_type, "application/sdp");
+  TEST_1(sip->sip_accept_encoding);
+  /* No content-encoding is supported */
+  TEST_S(sip->sip_accept_encoding->aa_value, "");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-4.5.2: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-4.5.3: invalid Accept\n");
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("reject-3"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_ACCEPT_STR("application/xyzzy+xml"),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+
+  /*
+   A    reject-5.3      B
+   |			|
+   |-------INVITE------>|
+   |<-------406---------|
+   |--------ACK-------->|
+  */
+
+  /*
+   Client transitions in reject-3:
+   INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED
+  */
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 406);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(sip->sip_status->st_status, 406);
+  TEST_1(sip->sip_accept);
+  TEST_S(sip->sip_accept->ac_type, "application/sdp");
+  TEST_1(sip->sip_accept_encoding);
+  /* No content-encoding is supported */
+  TEST_S(sip->sip_accept_encoding->aa_value, "");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-4.5.3: PASSED\n");
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-4.5: PASSED\n");
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,811 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_cancel_bye.c
+ * @brief Test CANCEL, weird BYE and handle destroy
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_cancel_bye"
+#endif
+
+/* ======================================================================== */
+
+/* Cancel cases:
+
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |------CANCEL------->|
+   |<------200 OK-------|
+   |			|
+   |<-------487---------|
+   |--------ACK-------->|
+   |			|
+   |			|
+
+   Client transitions:
+   INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |------CANCEL------->|
+   |<------200 OK-------|
+   |			|
+   |<-------487---------|
+   |--------ACK-------->|
+   |			|
+   |			|
+
+   Client transitions:
+   INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S6b)-> TERMINATED
+
+*/
+
+int cancel_when_calling(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_calling:
+    CANCEL(ep, call, nh, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int cancel_when_ringing(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_proceeding:
+    CANCEL(ep, call, nh, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int alert_call(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int test_call_cancel(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  if (print_headings)
+    printf("TEST NUA-5.1: cancel call\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, cancel_when_calling, -1, until_terminated);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state, nua_cancel()
+     CALLING -(C6a)-> TERMINATED: nua_r_invite(487), nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 487);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S6a)--> TERMINATED: nua_i_cancel, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.1: PASSED\n");
+
+  /* ------------------------------------------------------------------------ */
+
+  if (print_headings)
+    printf("TEST NUA-5.2: cancel call when ringing\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 /*SIPTAG_REJECT_CONTACT_STR("*;audio=FALSE"),*/
+	 TAG_END());
+
+  run_ab_until(ctx, -1, cancel_when_ringing, -1, alert_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
+     PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 487);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
+   EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+  TEST(e->data->e_status, 200);
+  /* Check for bug #1326727 */
+  TEST_1(e->data->e_msg);
+#if 0
+  TEST_1(sip_object(e->data->e_msg)->sip_reject_contact);
+  TEST_1(sip_object(e->data->e_msg)->sip_reject_contact->cp_params &&
+	 sip_object(e->data->e_msg)->sip_reject_contact->cp_params[0]);
+  TEST_S(sip_object(e->data->e_msg)->sip_reject_contact->cp_params[0],
+	 "audio=FALSE");
+#endif
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.2: PASSED\n");
+
+  END();
+}
+
+/* ======================================================================== */
+/* Destroy call handle */
+
+int destroy_when_calling(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_calling:
+    DESTROY(ep, call, nh);
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int destroy_when_completing(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_completing:
+    DESTROY(ep, call, nh);
+    return 1;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_call_destroy_1(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-5.3: destroy when calling\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, destroy_when_calling, -1, until_terminated);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), ...
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S6a)--> TERMINATED: nua_i_cancel, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.3: PASSED\n");
+
+  END();
+}
+
+int accept_until_terminated(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_completed:
+  case nua_callstate_ready:
+    return 0;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_call_destroy_2(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-5.4: destroy when completing\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 NUTAG_AUTOACK(0),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, destroy_when_completing, -1, accept_until_terminated);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), ...
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.4: PASSED\n");
+
+  END();
+}
+
+int destroy_when_early(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  case nua_callstate_completed:
+  case nua_callstate_ready:
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_call_destroy_3(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-5.5: destroy when early\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 NUTAG_AUTOACK(0),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_terminated, -1, destroy_when_early);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), ...
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 480);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(!e->next);  
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.5: PASSED\n");
+
+  END();
+}
+
+int destroy_when_completed(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+    return 0;
+  case nua_callstate_early:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_completed:
+  case nua_callstate_ready:
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_call_destroy_4(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-5.6: destroy when completed\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 NUTAG_AUTOACK(0),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), ...
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(!e->next);  
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-5.6: PASSED\n");
+
+  END();
+}
+
+int test_call_destroy(struct context *ctx)
+{
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  return 
+    test_call_destroy_1(ctx) ||
+    test_call_destroy_2(ctx) ||
+    test_call_destroy_3(ctx) ||
+    test_call_destroy_4(ctx);
+}
+
+/* ======================================================================== */
+/* Early BYE
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |--------BYE-------->|
+   |<------200 OK-------|
+   |			|
+   |<-------487---------|
+   |--------ACK-------->|
+   |			|
+   |			|
+
+   Client transitions:
+   INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(8)-> TERMINATING -> TERMINATED
+
+   Server transitions:
+   INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S8)-> TERMINATED
+
+*/
+
+int bye_when_ringing(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_proceeding:
+    BYE(ep, call, nh, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_early_bye(struct context *ctx)
+{
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  if (print_headings)
+    printf("TEST NUA-6.1: BYE call when ringing\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, bye_when_ringing, -1, alert_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
+     PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next);
+  if (e->data->e_event == nua_r_bye) {
+    /* We might receive this before or after response to INVITE */
+    /* If afterwards, it will come after nua_i_state and we just ignore it */
+    TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200);
+    TEST_1(e->data->e_msg);
+    /* Forking has not been enabled, so this should be actually a CANCEL */
+    TEST(sip_object(e->data->e_msg)->sip_cseq->cs_method, sip_method_cancel);
+    TEST_1(e = e->next);
+  }
+  TEST_E(e->data->e_event, nua_r_invite); TEST(e->data->e_status, 487);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
+   EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  /* Forking has not been enabled, so this should be actually a CANCEL */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-6.1: PASSED\n");
+
+  END();
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,173 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_extension.c
+ * @brief NUA-12: Test extension methods.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Nov 13 15:37:05 EET 2006
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_extension"
+#endif
+
+
+int respond_to_extension(CONDITION_PARAMS)
+{
+  msg_t *with = nua_current_request(nua);
+
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_method:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    NUTAG_WITH(with),
+	    SIPTAG_SUBJECT_STR("extended"),
+	    TAG_END());
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_extension(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+
+/* Test for EXTENSION 
+
+   A			B
+   |------EXTENSION---->|
+   |<--------501--------| (method not recognized)
+   |			|
+   |------EXTENSION---->|
+   |<-------200---------| (method allowed, responded)
+   |			|
+*/
+
+  if (print_headings)
+    printf("TEST NUA-13.1: EXTENSION\n");
+
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  /* Test first without NUTAG_METHOD() */
+  METHOD(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+  /* Client events:
+     nua_method(), nua_r_method
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+  TEST(e->data->e_status, 900);	/* Internal error */
+  TEST_1(!e->data->e_msg);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  METHOD(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 NUTAG_METHOD("EXTENSION"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+  /* Client events:
+     nua_method(), nua_r_method
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+  TEST(e->data->e_status, 501);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  nua_set_params(b->nua, NUTAG_ALLOW("EXTENSION"), TAG_END());
+
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  METHOD(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 NUTAG_METHOD("EXTENSION"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, respond_to_extension);
+
+  /* Client events:
+     nua_method(), nua_r_method
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(!e->next);
+
+  /*
+   Server events:
+   nua_i_method
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_method);
+  TEST(e->data->e_status, 100);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-13.1: PASSED\n");
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,349 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_init.c
+ * @brief Init nua test context 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+static char passwd_name[] = "tmp_sippasswd.XXXXXX";
+
+static void remove_tmp(void)
+{
+  if (passwd_name[0])
+    unlink(passwd_name);
+}
+
+static char const passwd[] =
+  "alice:secret:\n"
+  "bob:secret:\n"
+  "charlie:secret:\n";
+
+int test_nua_init(struct context *ctx,
+		  int start_proxy,
+		  url_t const *o_proxy,
+		  int start_nat,
+		  tag_type_t tag, tag_value_t value, ...)
+{
+  BEGIN();
+  struct event *e;
+  sip_contact_t const *m = NULL;
+  sip_from_t const *sipaddress = NULL;
+  url_t const *p_uri, *a_uri;		/* Proxy URI */
+  char const *a_bind, *a_bind2;
+
+  a_bind = a_bind2 = "sip:0.0.0.0:*";
+
+#if SU_HAVE_OSX_CF_API
+  if (ctx->osx_runloop)
+    ctx->root = su_root_osx_runloop_create(NULL);
+  else
+#endif
+  ctx->root = su_root_create(NULL);
+  TEST_1(ctx->root);
+
+  /* Disable threading by command line switch -s */
+  su_root_threading(ctx->root, ctx->threading);
+
+  if (start_proxy && !o_proxy) {
+    int temp;
+
+    if (print_headings)
+      printf("TEST NUA-2.1.1: init proxy P\n");
+
+#ifndef _WIN32
+    temp = mkstemp(passwd_name);
+#else
+    temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
+#endif
+    TEST_1(temp != -1);
+    atexit(remove_tmp);		/* Make sure temp file is unlinked */
+
+    TEST_SIZE(write(temp, passwd, strlen(passwd)), strlen(passwd));
+
+    TEST_1(close(temp) == 0);
+
+    ctx->p = test_proxy_create(ctx->root,
+			       AUTHTAG_METHOD("Digest"),
+			       AUTHTAG_REALM("test-proxy"),
+			       AUTHTAG_OPAQUE("kuik"),
+			       AUTHTAG_DB(passwd_name),
+			       AUTHTAG_QOP("auth-int"),
+			       AUTHTAG_ALGORITHM("md5-sess"),
+			       TAG_END());
+
+    ctx->proxy_tests = ctx->p != NULL;
+
+    if (print_headings)
+      printf("TEST NUA-2.1.1: PASSED\n");
+  }
+
+  p_uri = a_uri = test_proxy_uri(ctx->p);
+
+  if (start_nat && p_uri == NULL)
+    p_uri = url_hdup(ctx->home, (void *)o_proxy);
+
+  if (start_nat && p_uri != NULL) {
+    int family = 0;
+    su_sockaddr_t su[1];
+    socklen_t sulen = sizeof su;
+    char b[64];
+    size_t len;
+    ta_list ta;
+
+    if (print_headings)
+      printf("TEST NUA-2.1.2: creating test NAT\n");
+
+    /* Try to use different family than proxy. */
+    if (p_uri->url_host[0] == '[')
+      family = AF_INET;
+#if defined(SU_HAVE_IN6)
+    else
+      family = AF_INET6;
+#endif
+
+    ta_start(ta, tag, value);
+    ctx->nat = test_nat_create(ctx->root, family, ta_tags(ta));
+    ta_end(ta);
+
+    /*
+     * NAT thingy works so that we set the outgoing proxy URI to point
+     * towards its "private" address and give the real address of the proxy
+     * as its "public" address. If we use different IP families here, we may
+     * even manage to test real connectivity problems as proxy and endpoint
+     * can not talk to each other.
+     */
+
+    if (test_nat_private(ctx->nat, su, &sulen) < 0) {
+      printf("%s:%u: NUA-2.1.2: failed to get private NAT address\n",
+	     __FILE__, __LINE__);
+    }
+
+#if defined(SU_HAVE_IN6)
+    else if (su->su_family == AF_INET6) {
+      a_uri = (void *)
+	su_sprintf(ctx->home, "sip:[%s]:%u",
+		   inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
+		   ntohs(su->su_port));
+      a_bind = "sip:[::]:*";
+    }
+#endif
+    else if (su->su_family == AF_INET) {
+      a_uri = (void *)
+	su_sprintf(ctx->home, "sip:%s:%u",
+		   inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
+		   ntohs(su->su_port));
+    }
+
+#if defined(SU_HAVE_IN6)
+    if (p_uri->url_host[0] == '[') {
+      su->su_len = sulen = (sizeof su->su_sin6), su->su_family = AF_INET6;
+      len = strcspn(p_uri->url_host + 1, "]"); assert(len < sizeof b);
+      memcpy(b, p_uri->url_host + 1, len); b[len] = '\0';
+      inet_pton(su->su_family, b, SU_ADDR(su));
+    }
+    else {
+      su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
+      inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
+    }
+#else
+    su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
+    inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
+#endif
+
+    su->su_port = htons(strtoul(url_port(p_uri), NULL, 10));
+
+    if (test_nat_public(ctx->nat, su, sulen) < 0) {
+      printf("%s:%u: NUA-2.1.2: failed to set public address\n",
+	     __FILE__, __LINE__);
+      a_uri = NULL;
+    }
+
+    if (print_headings) {
+      if (ctx->nat && a_uri) {
+	printf("TEST NUA-2.1.2: PASSED\n");
+      } else {
+	printf("TEST NUA-2.1.2: FAILED\n");
+      }
+    }
+  }
+
+  if (print_headings)
+    printf("TEST NUA-2.2.1: init endpoint A\n");
+
+  if (a_uri == NULL)
+    a_uri = p_uri;
+
+  ctx->a.instance = nua_generate_instance_identifier(ctx->home);
+
+  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
+			  NUTAG_PROXY(a_uri ? a_uri : o_proxy),
+			  SIPTAG_FROM_STR("sip:alice at example.com"),
+			  NUTAG_URL(a_bind),
+			  TAG_IF(a_bind != a_bind2, NUTAG_SIPS_URL(a_bind2)),
+			  SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
+			  NTATAG_SIP_T1X64(4000),
+			  NUTAG_INSTANCE(ctx->a.instance),
+			  TAG_END());
+  TEST_1(ctx->a.nua);
+
+  nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+  run_a_until(ctx, nua_r_get_params, save_until_final_response);
+  TEST_1(e = ctx->a.events->head);
+  TEST(tl_gets(e->data->e_tags,
+	       NTATAG_CONTACT_REF(m),
+	       SIPTAG_FROM_REF(sipaddress),
+	       TAG_END()), 2); TEST_1(m);
+  TEST_1(ctx->a.contact = sip_contact_dup(ctx->home, m));
+  TEST_1(ctx->a.to = sip_to_dup(ctx->home, sipaddress));
+
+  free_events_in_list(ctx, ctx->a.events);
+
+  if (print_headings)
+    printf("TEST NUA-2.2.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.2.2: init endpoint B\n");
+
+  ctx->b.instance = nua_generate_instance_identifier(ctx->home);
+
+  ctx->b.nua = nua_create(ctx->root, b_callback, ctx,
+			  NUTAG_PROXY(p_uri ? p_uri : o_proxy),
+			  SIPTAG_FROM_STR("sip:bob at example.org"),
+			  NUTAG_URL("sip:0.0.0.0:*"),
+			  SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
+			  NUTAG_INSTANCE(ctx->b.instance),
+			  TAG_END());
+  TEST_1(ctx->b.nua);
+
+  nua_get_params(ctx->b.nua, TAG_ANY(), TAG_END());
+  run_b_until(ctx, nua_r_get_params, save_until_final_response);
+  TEST_1(e = ctx->b.events->head);
+  TEST(tl_gets(e->data->e_tags,
+	       NTATAG_CONTACT_REF(m),
+	       SIPTAG_FROM_REF(sipaddress),
+	       TAG_END()), 2); TEST_1(m);
+  TEST_1(ctx->b.contact = sip_contact_dup(ctx->home, m));
+  TEST_1(ctx->b.to = sip_to_dup(ctx->home, sipaddress));
+  free_events_in_list(ctx, ctx->b.events);
+
+  if (print_headings)
+    printf("TEST NUA-2.2.2: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.2.3: init endpoint C\n");
+
+  /* ctx->c.instance = nua_generate_instance_identifier(ctx->home); */
+
+  ctx->c.nua = nua_create(ctx->root, c_callback, ctx,
+			  NUTAG_PROXY(p_uri ? p_uri : o_proxy),
+			  SIPTAG_FROM_STR("sip:charlie at example.net"),
+			  NUTAG_URL("sip:0.0.0.0:*"),
+			  SOATAG_USER_SDP_STR("m=audio 5400 RTP/AVP 8 0"),
+			  NUTAG_INSTANCE(ctx->c.instance),
+			  TAG_END());
+  TEST_1(ctx->c.nua);
+
+  nua_get_params(ctx->c.nua, TAG_ANY(), TAG_END());
+  run_c_until(ctx, nua_r_get_params, save_until_final_response);
+  TEST_1(e = ctx->c.events->head);
+  TEST(tl_gets(e->data->e_tags,
+	       NTATAG_CONTACT_REF(m),
+	       SIPTAG_FROM_REF(sipaddress),
+	       TAG_END()), 2); TEST_1(m);
+  TEST_1(ctx->c.contact = sip_contact_dup(ctx->home, m));
+  TEST_1(ctx->c.to = sip_to_dup(ctx->home, sipaddress));
+  free_events_in_list(ctx, ctx->c.events);
+
+  if (print_headings)
+    printf("TEST NUA-2.2.3: PASSED\n");
+
+  END();
+}
+
+
+/* ====================================================================== */
+
+int test_deinit(struct context *ctx)
+{
+  BEGIN();
+
+  struct call *call;
+
+  if (!ctx->threading)
+    su_root_step(ctx->root, 100);
+
+  if (ctx->a.nua) {
+    for (call = ctx->a.call; call; call = call->next)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+
+    nua_shutdown(ctx->a.nua);
+    run_a_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->a.specials);
+    nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
+  }
+
+  if (ctx->b.nua) {
+    for (call = ctx->b.call; call; call = call->next)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+
+    nua_shutdown(ctx->b.nua);
+    run_b_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->b.specials);
+    nua_destroy(ctx->b.nua), ctx->b.nua = NULL;
+  }
+
+  if (ctx->c.nua) {
+    for (call = ctx->c.call; call; call = call->next)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+
+    nua_shutdown(ctx->c.nua);
+    run_c_until(ctx, nua_r_shutdown, until_final_response);
+    free_events_in_list(ctx, ctx->c.specials);
+    nua_destroy(ctx->c.nua), ctx->c.nua = NULL;
+  }
+
+  test_proxy_destroy(ctx->p), ctx->p = NULL;
+
+  test_nat_destroy(ctx->nat), ctx->nat = NULL;
+
+  su_root_destroy(ctx->root);
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,884 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nat.c
+ * @brief Simulated NAT for testing
+ *
+ * NAT thing works so that we set the outgoing proxy URI to point
+ * towards its "private" address and give the real address of the proxy
+ * as its "public" address. If we use different IP families here, we may
+ * even manage to test real connectivity problems as proxy and endpoint
+ * can not talk to each other.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 19:54:28 EET 2006
+ */
+
+#include "config.h"
+
+struct nat;
+struct binding;
+
+#define SU_ROOT_MAGIC_T struct nat
+#define SU_WAKEUP_ARG_T struct binding
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+#include <sofia-sip/su_log.h>
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#define LIST_PROTOS(STORAGE, PREFIX, T)			 \
+STORAGE void PREFIX ##_insert(T **list, T *node),	 \
+        PREFIX ##_remove(T *node)
+
+#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV)	  \
+STORAGE void PREFIX ##_insert(T **list, T *node)   \
+{							 \
+  if ((node->NEXT = *list)) {				 \
+    node->PREV = node->NEXT->PREV;			 \
+    node->NEXT->PREV = &node->NEXT;			 \
+  }							 \
+  else							 \
+    node->PREV = list;					 \
+  *list = node;						 \
+}							 \
+STORAGE void PREFIX ##_remove(T *node)			 \
+{							 \
+  if (node->PREV)					 \
+    if ((*node->PREV = node->NEXT))			 \
+      node->NEXT->PREV = node->PREV;			 \
+  node->PREV = NULL;					 \
+}							 \
+extern int LIST_DUMMY_VARIABLE
+
+#include <test_nat.h>
+
+struct nat {
+  su_home_t    home[1];
+  su_root_t   *parent;
+  su_clone_r   clone;
+  tagi_t      *tags;
+
+  su_root_t   *root;
+
+  struct binding *bindings;
+
+  /* True if we act in symmetric way */
+  int symmetric;
+  /* True if we do logging */
+  int logging;
+
+  /* Everything sent to in_address will be forwarded to out_address */
+  su_sockaddr_t in_address[1], out_address[1];
+  socklen_t in_addrlen, out_addrlen;
+
+  int family;			/* Preferred private family */
+
+  /* ...but source address will be "fake" */
+  su_localinfo_t *localinfo, *private, *fake;
+
+  su_socket_t udp_socket, tcp_socket;
+  int udp_register, tcp_register;
+
+  char buffer[65536];
+};
+
+LIST_PROTOS(static, nat_binding, struct binding);
+
+struct binding
+{
+  struct binding *next, **prev;
+  struct nat *nat;		/* backpointer */
+  int socktype, protocol;
+  su_socket_t in_socket, out_socket;
+  int in_register, out_register;
+  int in_closed, out_closed;
+  char in_name[64], out_name[64];
+};
+
+static struct binding *nat_binding_new(struct nat *nat,
+				       char const *protoname,
+				       int socktype, int protocol, 
+				       int connected,
+				       su_socket_t in_socket,
+				       su_sockaddr_t *from,
+				       socklen_t fromlen);
+static void nat_binding_destroy(struct binding *);
+
+static int binding_init(struct binding *b,
+			char const *protoname,
+			int connected,
+			su_localinfo_t *li,
+			su_sockaddr_t *from,
+			socklen_t fromlen);
+
+static void flush_bindings(struct nat *nat);
+static int invalidate_bindings(void *nat);
+
+static int new_udp(struct nat *, su_wait_t *wait, struct binding *dummy);
+static int udp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);
+static int udp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);
+
+static int new_tcp(struct nat *, su_wait_t *wait, struct binding *dummy);
+static int tcp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);
+static int tcp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);
+
+static int invalidate_binding(struct binding *b);
+
+/* nat entry point */
+static int
+test_nat_init(su_root_t *root, struct nat *nat)
+{
+  su_localinfo_t *li, hints[1] = {{ 0 }};
+  int error;
+  unsigned port = 0, port0 = 0;
+  su_sockaddr_t su[1];
+  socklen_t sulen;
+  su_wait_t wait[1];
+
+  nat->root = root;
+  nat->udp_socket = INVALID_SOCKET, nat->tcp_socket = INVALID_SOCKET;
+
+  tl_gets(nat->tags, 
+	  TESTNATTAG_SYMMETRIC_REF(nat->symmetric),
+	  TESTNATTAG_LOGGING_REF(nat->logging),
+	  TAG_END());
+
+  hints->li_scope = LI_SCOPE_HOST | LI_SCOPE_SITE | LI_SCOPE_GLOBAL;
+
+  error = su_getlocalinfo(hints, &nat->localinfo);
+  if (error) {
+    fprintf(stderr, "test_nat: su_getlocalinfo: %s\n", su_gli_strerror(error));
+    return -1;
+  }
+
+  /* We must have two different IP addresses. */
+  if (!nat->localinfo || !nat->localinfo->li_next) {
+    fprintf(stderr, "test_nat: only one IP address available\n");
+    return -1;
+  }
+
+  for (li = nat->localinfo; li; li = li->li_next) {
+    if (nat->family == 0 || nat->family == li->li_family)
+      break;
+  }
+  if (li == NULL)
+    li = nat->localinfo;
+
+  memcpy(su, li->li_addr, sulen = li->li_addrlen);
+  memset(SU_ADDR(su), 0, SU_ADDRLEN(su));
+
+  nat->private = li;
+
+  /* Bind TCP and UDP to same port */
+  for (;;) {
+    nat->udp_socket = su_socket(li->li_family, SOCK_DGRAM, IPPROTO_UDP);
+    if (nat->udp_socket == INVALID_SOCKET)
+      return -1;
+
+    if (bind(nat->udp_socket, (void *)su, sulen) < 0) {
+      if (port0 == 0) {
+	su_perror("nat: bind(udp_socket)");
+	return -1;
+      }
+
+      fprintf(stderr, "test_nat: port %u: %s\n",
+	      port, su_strerror(su_errno()));
+      su_close(nat->udp_socket);
+
+      nat->udp_socket = INVALID_SOCKET;
+
+      if (++port > 65535)
+	port = 1024;
+      if (port == port0) {
+	fprintf(stderr, "test_nat: could not find free port pairt\n");
+	return -1;
+      }
+
+      continue;
+    }
+
+    if (getsockname(nat->udp_socket, (void *)su, &sulen) < 0) {
+      su_perror("nat: getsockname(udp_socket)");
+      return -1;
+    }
+
+    if (port0 == 0) {
+      port = port0 = ntohs(su->su_port);
+      if (port0 == 0) {
+	fprintf(stderr, "test_nat: bind did not return port\n");
+	return -1;
+      }
+    }
+
+    nat->tcp_socket = su_socket(li->li_family, SOCK_STREAM, IPPROTO_TCP);
+    if (nat->tcp_socket == INVALID_SOCKET)
+      return -1;
+
+    if (bind(nat->tcp_socket, (void *)su, sulen) < 0) {
+      su_close(nat->tcp_socket);
+      nat->tcp_socket = INVALID_SOCKET;
+
+      fprintf(stderr, "test_nat: port %u: %s\n",
+	      port, su_strerror(su_errno()));
+
+      if (++port > 65535)
+	port = 1024;
+      if (port == port0) {
+	fprintf(stderr, "test_nat: could not find free port pair\n");
+	return -1;
+      }
+
+      continue;
+    }
+
+    break;
+  }
+
+  memcpy(nat->in_address, li->li_addr, nat->in_addrlen = li->li_addrlen);
+  nat->in_address->su_port = su->su_port;
+
+  if (su_setreuseaddr(nat->udp_socket, 1) < 0) {
+    su_perror("nat: su_setreuseaddr(udp_socket)");
+    return -1;
+  }
+
+  if (listen(nat->tcp_socket, 5) < 0) {
+    su_perror("nat: listen(tcp_socket)");
+    return -1;
+  }
+
+  if (su_wait_create(wait, nat->udp_socket, SU_WAIT_IN) < 0) {
+    su_perror("nat: su_wait_create");
+    return -1;
+  }
+
+  nat->udp_register = su_root_register(root, wait, new_udp, NULL, 0);
+  if (nat->udp_register < 0) {
+    su_perror("nat: su_root_register");
+    return -1;
+  }
+
+  if (su_wait_create(wait, nat->tcp_socket, SU_WAIT_IN) < 0) {
+    su_perror("nat: su_wait_create");
+    return -1;
+  }
+
+  nat->tcp_register = su_root_register(root, wait, new_tcp, NULL, 0);
+  if (nat->tcp_register < 0) {
+    su_perror("nat: su_root_register");
+    return -1;
+  }
+
+  return 0;
+}
+
+static void
+test_nat_deinit(su_root_t *root, struct nat *nat)
+{
+  flush_bindings(nat);
+
+  if (nat->tcp_register)
+    su_root_deregister(root, nat->tcp_register);
+  if (nat->udp_register)
+    su_root_deregister(root, nat->udp_register);
+
+  if (nat->udp_socket != INVALID_SOCKET)
+    su_close(nat->udp_socket);
+  if (nat->tcp_socket != INVALID_SOCKET)
+    su_close(nat->tcp_socket);
+
+  su_freelocalinfo(nat->localinfo);
+
+  free(nat->tags);
+}
+
+struct nat *test_nat_create(su_root_t *root,
+			    int family,
+			    tag_type_t tag, tag_value_t value, ...)
+{
+  struct nat *nat = su_home_new(sizeof *nat);
+
+  if (nat) {
+    ta_list ta;
+
+    nat->parent = root;
+    nat->family = family;
+
+    ta_start(ta, tag, value);
+    nat->tags = tl_llist(ta_tags(ta));
+    ta_end(ta);
+
+    if (su_clone_start(root,
+		       nat->clone,
+		       nat,
+		       test_nat_init,
+		       test_nat_deinit) == -1)
+      su_home_unref(nat->home), nat = NULL;
+  }
+
+  return nat;
+}
+
+void test_nat_destroy(struct nat *nat)
+{
+  if (nat) {
+    su_clone_wait(nat->parent, nat->clone);
+    su_home_unref(nat->home);
+  }
+}
+
+/** Get "private" address. */
+int test_nat_private(struct nat *nat, void *address, socklen_t *return_addrlen)
+{
+  if (nat == NULL || address == NULL || return_addrlen == NULL)
+    return su_seterrno(EFAULT);
+
+  if (*return_addrlen < nat->in_addrlen)
+    return su_seterrno(EINVAL);
+
+  memcpy(address, nat->in_address, *return_addrlen = nat->in_addrlen);
+
+  return 0;
+}
+
+/** Set "public" address. */
+int test_nat_public(struct nat *nat, void const *address, int addrlen)
+{
+  su_sockaddr_t const *su = address;
+  su_localinfo_t *li;
+
+  if (nat == NULL)
+    return su_seterrno(EFAULT);
+
+  if (address == NULL) {
+    nat->fake = NULL;
+    return 0;
+  }
+
+  if ((size_t)addrlen > sizeof nat->out_address)
+    return su_seterrno(EINVAL);
+
+  for (li = nat->localinfo; li; li = li->li_next) {
+    if (li != nat->private &&
+	li->li_scope == LI_SCOPE_HOST &&
+	li->li_family == su->su_family)
+      break;
+  }
+
+  if (li == NULL)
+    for (li = nat->localinfo; li; li = li->li_next) {
+      if (li != nat->private && li->li_family == su->su_family)
+	break;
+    }
+
+  if (li == NULL)
+    return su_seterrno(EADDRNOTAVAIL);
+
+  su_clone_pause(nat->clone);
+  memcpy(nat->out_address, address, nat->out_addrlen = addrlen);
+  nat->fake = li;
+  su_clone_resume(nat->clone);
+
+  return 0;
+}
+
+int test_nat_flush(struct nat *nat)
+{
+  if (nat == NULL)
+    return su_seterrno(EFAULT);
+
+  return su_task_execute(su_clone_task(nat->clone), 
+			 invalidate_bindings, nat, NULL);
+}
+
+/* ====================================================================== */
+
+struct binding *nat_binding_new(struct nat *nat,
+				char const *protoname,
+				int socktype,
+				int protocol,
+				int connected,
+				su_socket_t in_socket,
+				su_sockaddr_t *from,
+				socklen_t fromlen)
+{
+  struct binding *b;
+
+  if (nat->fake == NULL) {	/* Xyzzy */
+    fprintf(stderr, "test_nat: fake address missing\n");
+    su_close(in_socket);
+    return NULL;
+  }
+
+  b = su_zalloc(nat->home, sizeof *b);
+  if (b == NULL) {
+    su_perror("nat_binding_new: su_zalloc");
+    su_close(in_socket);
+    return 0;
+  }
+
+  b->nat = nat;
+  b->socktype = socktype;
+  b->protocol = protocol;
+  b->in_socket = in_socket, b->out_socket = INVALID_SOCKET;
+  b->in_register = -1, b->out_register = -1;
+
+  if (binding_init(b, protoname, connected, nat->fake, from, fromlen) < 0)
+    nat_binding_destroy(b), b = NULL;
+
+  return b;
+}
+
+static int binding_init(struct binding *b,
+			char const *protoname,
+			int connected,
+			su_localinfo_t *li,
+			su_sockaddr_t *from,
+			socklen_t fromlen)
+{
+  struct nat *nat = b->nat;
+  su_socket_t out_socket;
+  su_sockaddr_t addr[1];
+  socklen_t addrlen = (sizeof addr);
+  char ipname[64];
+  su_wait_t wait[1];
+  su_wakeup_f in_to_out, out_to_in;
+
+  if (b->socktype == SOCK_STREAM)
+    in_to_out = tcp_in_to_out, out_to_in = tcp_out_to_in;    
+  else
+    in_to_out = udp_in_to_out, out_to_in = udp_out_to_in;    
+  
+  if (b->in_socket == INVALID_SOCKET) {
+    int in_socket;
+
+    in_socket = su_socket(from->su_family, b->socktype, b->protocol);
+    if (in_socket == INVALID_SOCKET) {
+      su_perror("nat_binding_new: socket");
+      return -1;
+    }
+    b->in_socket = in_socket;
+    if (su_setreuseaddr(in_socket, 1) < 0) {
+      su_perror("nat_binding_new: su_setreuseaddr(in_socket)");
+      return -1;
+    }
+    if (bind(in_socket, (void *)nat->in_address, nat->in_addrlen) < 0) {
+      su_perror("nat_binding_new: bind(in_socket)");
+      return -1;
+    }
+    if (connect(in_socket, (void *)from, fromlen) < 0) {
+      su_perror("nat_binding_new: connect(in_socket)");
+      return -1;
+    }
+  }
+
+  out_socket = su_socket(li->li_family, b->socktype, b->protocol);
+  if (out_socket == INVALID_SOCKET) {
+    su_perror("nat_binding_new: socket");
+    return -1;
+  }
+  b->out_socket = out_socket;
+
+  if (bind(out_socket, (void *)li->li_addr, li->li_addrlen) < 0) {
+    su_perror("nat_binding_new: bind(to)");
+    return -1;
+  }
+
+  if (connected)
+    if (connect(out_socket, (void *)nat->out_address, nat->out_addrlen) < 0) {
+      su_perror("nat_binding_new: connect(to)");
+      return -1;
+    }
+
+  getpeername(b->in_socket, (void *)addr, &addrlen);
+  inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
+  snprintf(b->in_name, sizeof b->in_name,
+	   addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+	   ipname, ntohs(addr->su_port));
+
+  getsockname(out_socket, (void *)addr, &addrlen);
+  inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
+  snprintf(b->out_name, sizeof b->out_name,
+	   addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+	   ipname, ntohs(addr->su_port));
+
+  if (su_wait_create(wait, b->in_socket, SU_WAIT_IN) < 0) {
+    su_perror("nat_binding_new: su_wait_create");
+    return -1;
+  }
+  b->in_register = su_root_register(nat->root, wait, in_to_out, b, 0);
+  if (b->in_register < 0) {
+    su_perror("nat_binding_new: su_root_register");
+    su_wait_destroy(wait); 
+    return -1;
+  }
+
+  if (su_wait_create(wait, out_socket, SU_WAIT_IN) < 0) {
+    su_perror("nat_binding_new: su_wait_create");
+    return -1;
+  }
+  b->out_register = su_root_register(nat->root, wait, out_to_in, b, 0);
+  if (b->out_register < 0) {
+    su_perror("nat_binding_new: su_root_register");
+    su_wait_destroy(wait);
+    return -1;
+  }
+
+  nat_binding_insert(&nat->bindings, b);
+
+  if (nat->logging)
+    printf("nat: new %s binding %s <=> %s\n",
+	   protoname, b->in_name, b->out_name);
+
+  return 0;
+}
+
+static void nat_binding_destroy(struct binding *b)
+{
+  nat_binding_remove(b);
+  if (b->in_register != -1)
+    su_root_deregister(b->nat->root, b->in_register);
+  if (b->out_register != -1)
+    su_root_deregister(b->nat->root, b->out_register);
+  su_close(b->in_socket), su_close(b->out_socket);
+}
+
+static void flush_bindings(struct nat *nat)
+{
+  struct binding *b;
+
+  for (b = nat->bindings; b; b = b->next) {
+    if (b->in_register)
+      su_root_deregister(nat->root, b->in_register);
+    su_close(b->in_socket);
+    if (b->out_register)
+      su_root_deregister(nat->root, b->out_register);
+    su_close(b->out_socket);
+  }
+}
+
+static int invalidate_bindings(void *arg)
+{
+  struct nat *nat = arg;
+  struct binding *b;
+
+  for (b = nat->bindings; b; b = b->next) {
+    invalidate_binding(b);
+  }
+  return 0;
+}
+
+#if 0
+static struct binding *nat_binding_find(struct nat *nat,
+					su_sockaddr_t *from, 
+					int fromlen)
+{
+  char name[64], ipname[64];
+  size_t namelen;
+  struct binding *b;
+				       
+  inet_ntop(from->su_family, SU_ADDR(from), ipname, sizeof ipname);
+  snprintf(name, sizeof name,
+	   from->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+	   ipname, ntohs(from->su_port));
+  namelen = strlen(name) + 1;
+
+  for (b = nat->bindings; b; b = b->next) {
+    if (memcmp(name, b->in_name, namelen) == 0)
+      return b;
+  }
+
+  if (b == NULL)
+    b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric, 
+			INVALID_SOCKET, from, fromlen);
+
+  return b;
+}
+#endif
+
+/* ====================================================================== */
+
+LIST_BODIES(static, nat_binding, struct binding, next, prev);
+
+/* ====================================================================== */
+
+static int new_udp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
+{
+  int events;
+  su_sockaddr_t from[1];
+  socklen_t fromlen = (sizeof from);
+  struct binding *b;
+  ssize_t n, m;
+
+  events = su_wait_events(wait, nat->udp_socket);
+
+  n = su_recvfrom(nat->udp_socket, nat->buffer, sizeof nat->buffer, 0,
+		  from, &fromlen);
+  if (n < 0) {
+    su_perror("new_udp: recvfrom");
+    return 0;
+  }
+
+  b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric, 
+		      INVALID_SOCKET, from, fromlen);
+  if (b == NULL)
+    return 0;
+
+  if (nat->symmetric)
+    m = su_send(b->out_socket, nat->buffer, n, 0);
+  else
+    m = su_sendto(b->out_socket, nat->buffer, n, 0, 
+		  nat->out_address, nat->out_addrlen);
+
+  if (nat->logging)
+    printf("nat: udp out %d/%d %s => %s\n",
+	   (int)m, (int)n, b->in_name, b->out_name);
+
+  return 0;
+}
+
+static int udp_in_to_out(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+  int events;
+  ssize_t n, m;
+
+  events = su_wait_events(wait, b->in_socket);
+
+  n = su_recv(b->in_socket, nat->buffer, sizeof nat->buffer, 0);
+  if (n < 0) {
+    su_perror("udp_in_to_out: recv");
+    return 0;
+  }
+
+  if (nat->symmetric)
+    m = su_send(b->out_socket, nat->buffer, n, 0);
+  else
+    m = su_sendto(b->out_socket, nat->buffer, n, 0,
+		  nat->out_address, nat->out_addrlen);
+
+  if (nat->logging)
+    printf("nat: udp out %d/%d %s => %s\n",
+	   (int)m, (int)n, b->in_name, b->out_name);
+
+  return 0;
+}
+
+static int udp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+  int events;
+  ssize_t n, m;
+
+  events = su_wait_events(wait, b->out_socket);
+
+  n = su_recv(b->out_socket, nat->buffer, sizeof nat->buffer, 0);
+  if (n < 0) {
+    su_perror("udp_out_to_out: recv");
+    return 0;
+  }
+
+  m = su_send(b->in_socket, nat->buffer, n, 0);
+
+  if (nat->logging)
+    printf("nat: udp in %d/%d %s => %s\n",
+	   (int)m, (int)n, b->out_name, b->in_name);
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+static int new_tcp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
+{
+  int events;
+  su_socket_t in_socket;
+  su_sockaddr_t from[1];
+  socklen_t fromlen = (sizeof from);
+  struct binding *b;
+
+  events = su_wait_events(wait, nat->tcp_socket);
+
+  in_socket = accept(nat->tcp_socket, (void *)from, &fromlen);
+  if (in_socket == INVALID_SOCKET) {
+    su_perror("new_tcp: accept");
+    return 0;
+  }
+
+  b = nat_binding_new(nat, "TCP", SOCK_STREAM, IPPROTO_TCP, 1,
+		      in_socket, from, fromlen);
+  if (b == NULL)
+    return 0;
+
+  return 0;
+}
+
+static int tcp_in_to_out(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+  int events;
+  ssize_t n, m, o;
+
+  events = su_wait_events(wait, b->in_socket);
+
+  n = su_recv(b->in_socket, nat->buffer, sizeof nat->buffer, 0);
+  if (n < 0) {
+    su_perror("tcp_in_to_out: recv");
+    return 0;
+  }
+
+  if (n == 0) {
+    if (nat->logging)
+      printf("nat: tcp out FIN %s => %s\n", b->in_name, b->out_name);
+    shutdown(b->out_socket, 1);
+    su_root_eventmask(nat->root, b->in_register, b->in_socket, 0);
+    b->in_closed = 1;
+    if (b->out_closed && b->in_closed)
+      nat_binding_destroy(b);
+    return 0;
+  }
+
+  for (m = 0; m < n; m += o) {
+    o = su_send(b->out_socket, nat->buffer + m, n - m, 0);
+    if (o < 0) {
+      su_perror("tcp_in_to_out: send");
+      break;
+    }
+  }
+
+  if (nat->logging)
+    printf("nat: tcp out %d/%d %s => %s\n",
+	   (int)m, (int)n, b->in_name, b->out_name);
+
+  return 0;
+}
+
+static int tcp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+  int events;
+  ssize_t n, m, o;
+
+  events = su_wait_events(wait, b->out_socket);
+
+  n = su_recv(b->out_socket, nat->buffer, sizeof nat->buffer, 0);
+  if (n < 0) {
+    su_perror("tcp_out_to_in: recv");
+    return 0;
+  }
+
+  if (n == 0) {
+    if (nat->logging)
+      printf("nat: tcp out FIN %s => %s\n", b->out_name, b->in_name);
+    shutdown(b->in_socket, 1);
+    su_root_eventmask(nat->root, b->in_register, b->out_socket, 0);
+    b->out_closed = 1;
+    if (b->out_closed && b->in_closed)
+      nat_binding_destroy(b);
+    return 0;
+  }
+
+  for (m = 0; m < n; m += o) {
+    o = su_send(b->in_socket, nat->buffer + m, n - m, 0);
+    if (o < 0) {
+      if (su_errno() != EPIPE)
+	su_perror("tcp_in_to_out: send");
+      break;
+    }
+  }
+
+  if (nat->logging)
+    printf("nat: tcp in %d/%d %s => %s\n",
+	   (int)m, (int)n, b->out_name, b->in_name);
+
+  return 0;
+}
+
+static int invalidate_binding(struct binding *b)
+{
+  struct nat *nat = b->nat;
+  su_sockaddr_t addr[1];
+  socklen_t addrlen = (sizeof addr);
+  su_socket_t out;
+  int out_register;
+  su_wait_t wout[1];
+  char name[64];
+
+  out = su_socket(nat->fake->li_family, b->socktype, 0);
+  if (out == INVALID_SOCKET) {
+    su_perror("new_udp: socket");
+    return -1;
+  }
+  if (bind(out, (void *)nat->fake->li_addr, nat->fake->li_addrlen) < 0) {
+    su_perror("new_udp: bind(to)");
+    su_close(out);
+    return -1;
+  }
+
+  if (nat->symmetric)
+    if (connect(out, (void *)nat->out_address, nat->out_addrlen) < 0) {
+      su_perror("new_udp: connect(to)");
+      su_close(out);
+      return -1;
+    }
+
+  if (su_wait_create(wout, out, SU_WAIT_IN) < 0) {
+    su_perror("new_udp: su_wait_create");
+    su_close(out);
+    return -1;
+  }
+
+  if (b->socktype == SOCK_DGRAM)
+    out_register = su_root_register(nat->root, wout, udp_out_to_in, b, 0);
+  else
+    out_register = su_root_register(nat->root, wout, tcp_out_to_in, b, 0);
+
+  if (out_register < 0) {
+    su_perror("new_udp: su_root_register");
+    su_wait_destroy(wout);
+    su_close(out);
+    return -1;
+  }
+
+  su_root_deregister(nat->root, b->out_register);
+  su_close(b->out_socket);
+
+  b->out_socket = out;
+  b->out_register = out_register;
+
+  getsockname(out, (void *)addr, &addrlen);
+  inet_ntop(addr->su_family, SU_ADDR(addr), name, sizeof name);
+  snprintf(b->out_name, sizeof b->out_name,
+	   addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+	   name, ntohs(addr->su_port));
+
+  if (nat->logging)
+    printf("nat: flushed binding %s <=> %s\n", b->in_name, b->out_name);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_NAT_H
+#define TEST_NAT_H
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+
+SOFIA_BEGIN_DECLS
+
+struct nat;
+
+struct nat *test_nat_create(su_root_t *, int family, 
+			    tag_type_t, tag_value_t, ...);
+
+void test_nat_destroy(struct nat *);
+
+int test_nat_private(struct nat *nat, void *address, socklen_t *return_addrlen);
+int test_nat_public(struct nat *nat, void const *address, int addrlen);
+
+int test_nat_flush(struct nat *nat);
+
+/* Tags */
+
+/** If true, act as symmetric nat. */
+#define TESTNATTAG_SYMMETRIC(x) testnattag_symmetric, tag_bool_v((x))
+#define TESTNATTAG_SYMMETRIC_REF(x) testnattag_symmetric_ref, tag_bool_vr(&(x))
+extern tag_typedef_t testnattag_symmetric;
+extern tag_typedef_t testnattag_symmetric_ref;
+
+/** If true, print information about connections. */
+#define TESTNATTAG_LOGGING(x) testnattag_logging, tag_bool_v((x))
+#define TESTNATTAG_LOGGING_REF(x) testnattag_logging_ref, tag_bool_vr(&(x))
+extern tag_typedef_t testnattag_logging;
+extern tag_typedef_t testnattag_logging_ref;
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nat_tags.c
+ * @brief Tags for simulated NAT
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar  8 19:54:28 EET 2006
+ */
+
+#include "config.h"
+
+#include "test_nat.h"
+
+tag_typedef_t testnattag_symmetric = BOOLTAG_TYPEDEF(symmetric);
+tag_typedef_t testnattag_symmetric_ref = REFTAG_TYPEDEF(testnattag_symmetric);
+tag_typedef_t testnattag_logging = BOOLTAG_TYPEDEF(symmetric);
+tag_typedef_t testnattag_logging_ref = REFTAG_TYPEDEF(testnattag_logging);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua.c
+ * @brief High-level tester for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_ALARM
+#include <signal.h>
+#endif
+
+#if defined(_WIN32)
+#include <fcntl.h>
+#endif
+
+SOFIAPUBVAR su_log_t nua_log[];
+SOFIAPUBVAR su_log_t soa_log[];
+SOFIAPUBVAR su_log_t nea_log[];
+SOFIAPUBVAR su_log_t nta_log[];
+SOFIAPUBVAR su_log_t tport_log[];
+SOFIAPUBVAR su_log_t su_log_default[];
+
+char const name[] = "test_nua";
+int print_headings = 1;
+int tstflags = 0;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+static char const options_usage[] =
+  "   -v | --verbose    be verbose\n"
+  "   -q | --quiet      be quiet\n"
+  "   -s                use only single thread\n"
+  "   -l level          set logging level (0 by default)\n"
+  "   -e | --events     print nua events\n"
+  "   -A                print nua events for A\n"
+  "   -B                print nua events for B\n"
+  "   -C                print nua events for C\n"
+  "   --attach          print pid, wait for a debugger to be attached\n"
+  "   --no-proxy        do not use internal proxy\n"
+  "   --no-nat          do not use internal \"nat\"\n"
+  "   --symmetric       run internal \"nat\" in symmetric mode\n"
+  "   -N                print events from internal \"nat\"\n"
+  "   --no-alarm        don't ask for guard ALARM\n"
+  "   -p uri            specify uri of outbound proxy (implies --no-proxy)\n"
+  "   --proxy-tests     run tests involving proxy, too\n"
+  "   -k                do not exit after first error\n"
+  ;
+
+void usage(int exitcode)
+{
+  fprintf(stderr, "usage: %s OPTIONS\n   where OPTIONS are\n%s",
+	    name, options_usage);
+  exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i, o_quiet = 0, o_attach = 0, o_alarm = 1;
+  int o_events_init = 0, o_events_a = 0, o_events_b = 0, o_events_c = 0;
+  int o_iproxy = 1, o_inat = 1;
+  int o_inat_symmetric = 0, o_inat_logging = 0, o_expensive = 0;
+  url_t const *o_proxy = NULL;
+  int level = 0;
+
+  struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
+
+  if (getenv("EXPENSIVE_CHECKS"))
+    o_expensive = 1;
+
+  ctx->threading = 1;
+  ctx->quit_on_single_failure = 1;
+
+  endpoint_init(ctx, &ctx->a, 'a');
+  endpoint_init(ctx, &ctx->b, 'b');
+  endpoint_init(ctx, &ctx->c, 'c');
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
+      tstflags |= tst_abort;
+    else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
+      tstflags &= ~tst_verbatim, o_quiet = 1;
+    else if (strcmp(argv[i], "-k") == 0)
+      ctx->quit_on_single_failure = 0;
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage(1);
+
+      su_log_set_level(nua_log, level);
+      su_log_soft_set_level(soa_log, level);
+      su_log_soft_set_level(nea_log, level);
+      su_log_soft_set_level(nta_log, level);
+      su_log_soft_set_level(tport_log, level);
+    }
+    else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--events") == 0) {
+      o_events_init = o_events_a = o_events_b = o_events_c = 1;
+    }
+    else if (strcmp(argv[i], "-I") == 0) {
+      o_events_init = 1;
+    }
+    else if (strcmp(argv[i], "-A") == 0) {
+      o_events_a = 1;
+    }
+    else if (strcmp(argv[i], "-B") == 0) {
+      o_events_b = 1;
+    }
+    else if (strcmp(argv[i], "-C") == 0) {
+      o_events_c = 1;
+    }
+    else if (strcmp(argv[i], "-s") == 0) {
+      ctx->threading = 0;
+    }
+    else if (strcmp(argv[i], "--attach") == 0) {
+      o_attach = 1;
+    }
+    else if (strncmp(argv[i], "-p", 2) == 0) {
+      if (argv[i][2])
+	o_proxy = URL_STRING_MAKE(argv[i] + 2)->us_url;
+      else if (!argv[++i] || argv[i][0] == '-')
+	usage(1);
+      else
+	o_proxy = URL_STRING_MAKE(argv[i])->us_url;
+    }
+    else if (strcmp(argv[i], "--proxy-tests") == 0) {
+      ctx->proxy_tests = 1;
+    }
+    else if (strcmp(argv[i], "--no-proxy") == 0) {
+      o_iproxy = 0;
+    }
+    else if (strcmp(argv[i], "--no-nat") == 0) {
+      o_inat = 0;
+    }
+    else if (strcmp(argv[i], "--nat") == 0) {
+      o_inat = 1;
+    }
+    else if (strcmp(argv[i], "--symmetric") == 0) {
+      o_inat_symmetric = 1;
+    }
+    else if (strcmp(argv[i], "-N") == 0) {
+      o_inat_logging = 1;
+    }
+    else if (strcmp(argv[i], "--expensive") == 0) {
+      o_expensive = 1;
+    }
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+#if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
+    else if (strcmp(argv[i], "--osx-runloop") == 0) {
+      ctx->osx_runloop = 1;
+    }
+#endif
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (argv[i][0] != '-') {
+      break;
+    }
+    else
+      usage(1);
+  }
+
+  if (o_attach) {
+    char line[10], *l;
+    printf("%s: pid %lu\n", name, (unsigned long)getpid());
+    printf("<Press RETURN to continue>\n");
+    l = fgets(line, sizeof line, stdin);
+  }
+#if HAVE_ALARM
+  else if (o_alarm) {
+    alarm(o_expensive ? 60 : 120);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  su_init();
+
+  if (!(TSTFLAGS & tst_verbatim)) {
+    if (level == 0 && !o_quiet)
+      level = 1;
+    su_log_soft_set_level(nua_log, level);
+    su_log_soft_set_level(soa_log, level);
+    su_log_soft_set_level(nea_log, level);
+    su_log_soft_set_level(nta_log, level);
+    su_log_soft_set_level(tport_log, level);
+  }
+
+  if (!o_quiet || (TSTFLAGS & tst_verbatim)
+      || o_events_a || o_events_b || o_events_c)
+    print_headings = 1;
+
+#define SINGLE_FAILURE_CHECK()						\
+  do { fflush(stdout);							\
+    if (retval && ctx->quit_on_single_failure) {			\
+      su_deinit(); return retval; }					\
+  } while(0)
+
+  ctx->a.printer = o_events_init ? print_event : NULL;
+
+  retval |= test_nua_api_errors(ctx); SINGLE_FAILURE_CHECK();
+  retval |= test_tag_filter(); SINGLE_FAILURE_CHECK();
+  retval |= test_nua_params(ctx); SINGLE_FAILURE_CHECK();
+
+  retval |= test_nua_init(ctx, o_iproxy, o_proxy, o_inat,
+			  TESTNATTAG_SYMMETRIC(o_inat_symmetric),
+			  TESTNATTAG_LOGGING(o_inat_logging),
+			  TAG_END());
+
+  ctx->expensive = o_expensive;
+
+  if (retval == 0) {
+    ctx->a.printer = o_events_a ? print_event : NULL;
+    if (o_events_b)
+      ctx->b.printer = print_event;
+    if (o_events_c)
+      ctx->c.printer = print_event;
+
+    retval |= test_stack_errors(ctx); SINGLE_FAILURE_CHECK();
+
+    retval |= test_register(ctx);
+
+    if (retval == 0)
+      retval |= test_connectivity(ctx);
+
+    if (retval == 0 && o_inat)
+      retval |= test_nat_timeout(ctx);
+
+    if (retval == 0) {
+      retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_basic_call(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reject_a(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reject_b(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reject_302(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reject_401(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_mime_negotiation(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reject_401_aka(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_call_destroy(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_reinvites(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_refer(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_simple(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
+    }
+
+    if (ctx->proxy_tests && (retval == 0 || !ctx->p))
+      retval |= test_unregister(ctx); SINGLE_FAILURE_CHECK();
+  }
+  retval |= test_deinit(ctx);
+
+  su_home_deinit(ctx->home);
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua.h
+ * @brief High-level tester framework for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#ifndef TEST_NUA_H
+#define TEST_NUA_H
+
+struct context;
+#define NUA_MAGIC_T struct context
+
+struct call;
+#define NUA_HMAGIC_T struct call
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/sip_status.h"
+
+#include <sofia-sip/sdp.h>
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_tag_io.h>
+
+#if __APPLE_CC__
+#include <sofia-sip/su_osx_runloop.h>
+#endif
+
+#include <test_proxy.h>
+#include <test_nat.h>
+#include <sofia-sip/auth_module.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#include <unistd.h>
+
+extern char const name[];
+
+extern int print_headings;
+extern int tstflags;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#define TEST_E(a, b) TEST_S(nua_event_name(a), nua_event_name(b))
+
+#define NONE ((void*)-1)
+
+struct endpoint;
+
+typedef
+int condition_function(nua_event_t event,
+		       int status, char const *phrase,
+		       nua_t *nua, struct context *ctx,
+		       struct endpoint *ep,
+		       nua_handle_t *nh, struct call *call,
+		       sip_t const *sip,
+		       tagi_t tags[]);
+
+typedef
+void printer_function(nua_event_t event,
+		      char const *operation,
+		      int status, char const *phrase,
+		      nua_t *nua, struct context *ctx,
+		      struct endpoint *ep,
+		      nua_handle_t *nh, struct call *call,
+		      sip_t const *sip,
+		      tagi_t tags[]);
+
+struct proxy_transaction;
+struct registration_entry;
+
+enum { event_is_extra, event_is_normal, event_is_special };
+
+struct eventlist
+{
+  nua_event_t kind;
+  struct event *head, **tail;
+};
+
+struct event 
+{
+  struct event *next, **prev;
+  struct call *call;
+  nua_saved_event_t saved_event[1];
+  nua_event_data_t const *data;
+};
+
+
+struct context
+{
+  su_home_t home[1];
+  su_root_t *root;
+
+  int threading, proxy_tests, expensive, quit_on_single_failure, osx_runloop;
+  char const *external_proxy;
+
+  struct endpoint {
+    char name[4];
+    struct context *ctx;	/* Backpointer */
+
+    int running;
+
+    condition_function *next_condition;
+    nua_event_t next_event, last_event;
+    nua_t *nua;
+    sip_contact_t *contact;
+    sip_from_t *to;
+
+    printer_function *printer;
+
+    char const *instance;
+
+    /* Per-call stuff */
+    struct call {
+      struct call *next;
+      nua_handle_t *nh;
+      char const *sdp;
+      struct eventlist *events;
+    } call[1], reg[1];
+
+    int (*is_special)(nua_event_t e);
+
+    /* Normal events are saved here */
+    struct eventlist events[1];
+    /* Special events are saved here */
+    struct eventlist specials[1];
+
+    /* State flags for complex scenarios */
+    union {
+      struct {
+	unsigned bit0:1, bit1:1, bit2:1, bit3:1;
+	unsigned bit4:1, bit5:1, bit6:1, bit7:1;
+      } b;
+      unsigned n;
+    } flags;
+
+  } a, b, c;
+
+  struct proxy *p;
+  struct nat *nat;
+};
+
+#define RETURN_ON_SINGLE_FAILURE(retval)			  \
+  do {								  \
+    fflush(stdout);						  \
+    if (retval && ctx->quit_on_single_failure) { return retval; } \
+  } while(0)
+
+
+int save_event_in_list(struct context *,
+		       nua_event_t nevent,
+		       struct endpoint *,
+		       struct call *);
+void free_events_in_list(struct context *,
+			 struct eventlist *);
+
+#define CONDITION_PARAMS			\
+  nua_event_t event,				\
+  int status, char const *phrase,		\
+  nua_t *nua, struct context *ctx,		\
+  struct endpoint *ep,				\
+  nua_handle_t *nh, struct call *call,		\
+  sip_t const *sip,				\
+  tagi_t tags[]
+
+int save_events(CONDITION_PARAMS);
+int until_final_response(CONDITION_PARAMS);
+int save_until_final_response(CONDITION_PARAMS);
+int save_until_received(CONDITION_PARAMS);
+int save_until_special(CONDITION_PARAMS);
+
+int until_terminated(CONDITION_PARAMS);
+int until_ready(CONDITION_PARAMS);
+int accept_call(CONDITION_PARAMS);
+
+void a_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[]);
+void b_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[]);
+void c_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[]);
+
+void run_abc_until(struct context *ctx,
+		   nua_event_t a_event, condition_function *a_condition,
+		   nua_event_t b_event, condition_function *b_condition,
+		   nua_event_t c_event, condition_function *c_condition);
+
+void run_ab_until(struct context *ctx,
+		  nua_event_t a_event, condition_function *a_condition,
+		  nua_event_t b_event, condition_function *b_condition);
+
+void run_bc_until(struct context *ctx,
+		  nua_event_t b_event, condition_function *b_condition,
+		  nua_event_t c_event, condition_function *c_condition);
+
+int run_a_until(struct context *, nua_event_t, condition_function *);
+int run_b_until(struct context *, nua_event_t, condition_function *);
+int run_c_until(struct context *, nua_event_t, condition_function *);
+
+typedef int operation_f(struct endpoint *ep, struct call *call, 
+			nua_handle_t *nh, tag_type_t tag, tag_value_t value,
+			...);
+
+operation_f INVITE, ACK, BYE, CANCEL, AUTHENTICATE, UPDATE, INFO, PRACK,
+  REFER, MESSAGE, METHOD, OPTIONS, PUBLISH, UNPUBLISH, REGISTER, UNREGISTER,
+  SUBSCRIBE, UNSUBSCRIBE, NOTIFY, NOTIFIER, TERMINATE, AUTHORIZE;
+
+int RESPOND(struct endpoint *ep,
+	    struct call *call,
+	    nua_handle_t *nh,
+	    int status, char const *phrase,
+	    tag_type_t tag, tag_value_t value,
+	    ...);
+
+int DESTROY(struct endpoint *ep,
+	    struct call *call,
+	    nua_handle_t *nh);
+
+struct call *check_handle(struct endpoint *ep,
+			  struct call *call,
+			  nua_handle_t *nh,
+			  int status, char const *phrase);
+
+int is_special(nua_event_t e);
+int callstate(tagi_t const *tags);
+int is_offer_sent(tagi_t const *tags);
+int is_answer_sent(tagi_t const *tags);
+int is_offer_recv(tagi_t const *tags);
+int is_answer_recv(tagi_t const *tags);
+int is_offer_answer_done(tagi_t const *tags);
+int audio_activity(tagi_t const *tags);
+int video_activity(tagi_t const *tags);
+
+void print_event(nua_event_t event,
+		 char const *operation,
+		 int status, char const *phrase,
+		 nua_t *nua, struct context *ctx,
+		 struct endpoint *ep,
+		 nua_handle_t *nh, struct call *call,
+		 sip_t const *sip,
+		 tagi_t tags[]);
+
+static inline
+void eventlist_init(struct eventlist *list)
+{
+  list->tail = &list->head;
+}
+
+static inline
+void call_init(struct call *call)
+{
+}
+
+void endpoint_init(struct context *ctx, struct endpoint *e, char id);
+
+int test_nua_init(struct context *ctx,
+		  int start_proxy,
+		  url_t const *o_proxy,
+		  int start_nat,
+		  tag_type_t tag, tag_value_t value, ...);
+
+int test_deinit(struct context *ctx);
+
+int test_nua_api_errors(struct context *ctx);
+int test_stack_errors(struct context *ctx);
+int test_tag_filter(void);
+int test_nua_params(struct context *ctx);
+
+int test_register(struct context *ctx);
+int test_connectivity(struct context *ctx);
+int test_nat_timeout(struct context *ctx);
+int test_unregister(struct context *ctx);
+
+int test_basic_call(struct context *ctx);
+int test_reject_a(struct context *ctx);
+int test_reject_b(struct context *ctx);
+int test_reject_302(struct context *ctx);
+int test_reject_401(struct context *ctx);
+int test_mime_negotiation(struct context *ctx);
+int test_reject_401_aka(struct context *ctx);
+int test_call_cancel(struct context *ctx);
+int test_call_destroy(struct context *ctx);
+int test_early_bye(struct context *ctx);
+int test_call_hold(struct context *ctx);
+int test_reinvites(struct context *ctx);
+int test_session_timer(struct context *ctx);
+int test_refer(struct context *ctx);
+int test_100rel(struct context *ctx);
+int test_simple(struct context *ctx);
+int test_events(struct context *ctx);
+
+int test_extension(struct context *ctx);
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,280 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_api.c
+ * @brief NUA API tester.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_nua_api_errors"
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* API tests */
+
+SOFIAPUBVAR su_log_t nua_log[];
+
+int check_set_status(int status, char const *phrase)
+{
+  return status == 200 && strcmp(phrase, sip_200_OK) == 0;
+}
+
+int test_nua_api_errors(struct context *ctx)
+{
+  BEGIN();
+
+  /* Invoke every API function with invalid arguments */
+
+  int level;
+
+  int status; char const *phrase;
+
+  if (print_headings)
+    printf("TEST NUA-1.0: test API\n");
+
+  /* This is a nasty macro. Test it. */
+#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))
+  TEST_1(check_set_status(SET_STATUS1(SIP_200_OK)));
+  TEST(status, 200); TEST_S(phrase, sip_200_OK);
+
+  su_log_init(nua_log);
+  if (!(tstflags & tst_verbatim))
+    su_log_set_level(nua_log, 0);  /* Log at level 0 by default */
+  level = nua_log->log_level;
+
+  TEST_1(!nua_create(NULL, NULL, NULL, TAG_END()));
+  TEST_VOID(nua_shutdown(NULL));
+  TEST_VOID(nua_destroy(NULL));
+  TEST_VOID(nua_set_params(NULL, TAG_END()));
+  TEST_VOID(nua_get_params(NULL, TAG_END()));
+  TEST_1(!nua_default(NULL));
+  TEST_1(!nua_handle(NULL, NULL, TAG_END()));
+  TEST_VOID(nua_handle_destroy(NULL));
+  TEST_VOID(nua_handle_bind(NULL, NULL));
+  TEST_1(!nua_handle_has_invite(NULL));
+  TEST_1(!nua_handle_has_subscribe(NULL));
+  TEST_1(!nua_handle_has_register(NULL));
+  TEST_1(!nua_handle_has_active_call(NULL));
+  TEST_1(!nua_handle_has_call_on_hold(NULL));
+  TEST_1(!nua_handle_has_events(NULL));
+  TEST_1(!nua_handle_has_registrations(NULL));
+  TEST_1(!nua_handle_remote(NULL));
+  TEST_1(!nua_handle_local(NULL));
+  TEST_S(nua_event_name(-1), "NUA_UNKNOWN");
+  TEST_VOID(nua_register(NULL, TAG_END()));
+  TEST_VOID(nua_unregister(NULL, TAG_END()));
+  TEST_VOID(nua_invite(NULL, TAG_END()));
+  TEST_VOID(nua_ack(NULL, TAG_END()));
+  TEST_VOID(nua_prack(NULL, TAG_END()));
+  TEST_VOID(nua_options(NULL, TAG_END()));
+  TEST_VOID(nua_publish(NULL, TAG_END()));
+  TEST_VOID(nua_message(NULL, TAG_END()));
+  TEST_VOID(nua_chat(NULL, TAG_END()));
+  TEST_VOID(nua_info(NULL, TAG_END()));
+  TEST_VOID(nua_subscribe(NULL, TAG_END()));
+  TEST_VOID(nua_unsubscribe(NULL, TAG_END()));
+  TEST_VOID(nua_notify(NULL, TAG_END()));
+  TEST_VOID(nua_notifier(NULL, TAG_END()));
+  TEST_VOID(nua_terminate(NULL, TAG_END()));
+  TEST_VOID(nua_refer(NULL, TAG_END()));
+  TEST_VOID(nua_update(NULL, TAG_END()));
+  TEST_VOID(nua_bye(NULL, TAG_END()));
+  TEST_VOID(nua_cancel(NULL, TAG_END()));
+  TEST_VOID(nua_authenticate(NULL, TAG_END()));
+  TEST_VOID(nua_redirect(NULL, TAG_END()));
+  TEST_VOID(nua_respond(NULL, 0, "", TAG_END()));
+
+  TEST_1(!nua_handle_home(NULL));
+  TEST_1(!nua_save_event(NULL, NULL));
+  TEST_1(!nua_event_data(NULL));
+  TEST_VOID(nua_destroy_event(NULL));
+
+  {
+    nua_saved_event_t event[1];
+
+    memset(event, 0, sizeof event);
+
+    TEST_1(!nua_save_event(NULL, event));
+    TEST_1(!nua_event_data(event));
+    TEST_VOID(nua_destroy_event(event));
+  }
+
+  su_log_set_level(nua_log, level);
+
+  if (print_headings)
+    printf("TEST NUA-1.0: PASSED\n");
+
+  END();
+}
+
+/* ======================================================================== */
+
+int test_stack_errors(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a, *b = &ctx->b;
+  struct call *a_call = a->call;
+  struct event *e;
+
+  int internal_error = 900;
+
+  if (print_headings)
+    printf("TEST NUA-1.2: Stack error handling\n");
+
+  if (print_headings)
+    printf("TEST NUA-1.2.1: CANCEL without INVITE\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  CANCEL(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_cancel);
+  TEST(e->data->e_status, 481);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-1.2.1: PASSED\n");
+
+  /* -BYE without INVITE--------------------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-1.2.2: BYE without INVITE\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  BYE(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST(e->data->e_status, internal_error);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-1.2.2: PASSED\n");
+
+  if (!ctx->proxy_tests)
+    goto nua_1_2_5;
+
+  /* -Un-register without REGISTER--------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-1.2.3: unregister without register\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(a->to), TAG_END()));
+
+  UNREGISTER(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unregister);
+  TEST(e->data->e_status, 401);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-1.2.3: PASSED\n");
+
+  /* -Un-publish without publish--------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-1.2.4: unpublish without publish\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  UNPUBLISH(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unpublish);
+  TEST(e->data->e_status, 404);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-1.2.4: PASSED\n");
+
+  /* -terminate without notifier--------------------------------------- */
+
+ nua_1_2_5:
+  if (print_headings)
+    printf("TEST NUA-1.2.5: terminate without notifier\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  TERMINATE(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_terminate);
+  TEST(e->data->e_status, internal_error);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  AUTHORIZE(a, a_call, a_call->nh, TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_authorize);
+  TEST(e->data->e_status, internal_error);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-1.2.5: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-1.2: PASSED\n");
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,598 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_params.c
+ * @brief Test NUA parameter handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_nua_params"
+#endif
+
+int test_tag_filter(void)
+{
+  BEGIN();
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "test"
+  tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+#define TAG_A(s)      tag_a, tag_str_v((s))
+  tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+#define TAG_B(s)      tag_b, tag_str_v((s))
+
+  tagi_t filter[2] = {{ NUTAG_ANY() }, { TAG_END() }};
+
+  tagi_t *lst, *result;
+
+  lst = tl_list(TAG_A("X"),
+		TAG_SKIP(2),
+		NUTAG_URL((void *)"urn:foo"),
+		TAG_B("Y"),
+		NUTAG_URL((void *)"urn:bar"),
+		TAG_NULL());
+
+  TEST_1(lst);
+
+  result = tl_afilter(NULL, filter, lst);
+
+  TEST_1(result);
+  TEST_P(result[0].t_tag, nutag_url);
+  TEST_P(result[1].t_tag, nutag_url);
+
+  tl_vfree(lst);
+  free(result);
+
+  END();
+}
+
+int test_nua_params(struct context *ctx)
+{
+  BEGIN();
+
+  char const Alice[] = "Alice <sip:a at wonderland.org>";
+  sip_from_t const *from;
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+  nua_handle_t *nh;
+  struct event *e;
+  tagi_t const *t;
+  int n;
+
+  su_home_auto(tmphome, sizeof(tmphome));
+
+  if (print_headings)
+    printf("TEST NUA-1.1: PARAMETERS\n");
+
+#if SU_HAVE_OSX_CF_API
+  if (ctx->osx_runloop)
+    ctx->root = su_root_osx_runloop_create(NULL);
+  else
+#endif
+  ctx->root = su_root_create(NULL);
+  TEST_1(ctx->root);
+
+  /* Disable threading by command line switch? */
+  su_root_threading(ctx->root, ctx->threading);
+
+  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
+			  SIPTAG_FROM_STR("sip:alice at example.com"),
+			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
+			  TAG_END());
+
+  TEST_1(ctx->a.nua);
+
+  nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+  run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+  TEST_1(e = ctx->a.events->head);
+  TEST_E(e->data->e_event, nua_r_get_params);
+  for (n = 0, t = e->data->e_tags; t; n++, t = tl_next(t))
+    ;
+  TEST_1(n > 32);
+  free_events_in_list(ctx, ctx->a.events);
+
+  nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
+  nua_handle_unref(nh);
+
+  nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
+  nua_handle_destroy(nh);
+
+  from = sip_from_make(tmphome, Alice);
+
+  nh = nua_handle(ctx->a.nua, NULL, TAG_END());
+
+  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  /* Modify all pointer values */
+  nua_set_params(ctx->a.nua,
+		 SIPTAG_FROM_STR(Alice),
+
+		 NUTAG_MEDIA_ENABLE(0),
+		 NUTAG_SOA_NAME("test"),
+
+		 NUTAG_REGISTRAR("sip:openlaboratory.net"),
+
+		 SIPTAG_SUPPORTED_STR("test"),
+		 SIPTAG_ALLOW_STR("DWIM, OPTIONS, INFO"),
+		 SIPTAG_ALLOW_EVENTS_STR("reg"),
+		 SIPTAG_USER_AGENT_STR("test_nua/1.0"),
+
+		 SIPTAG_ORGANIZATION_STR("Open Laboratory"),
+		 
+		 NUTAG_M_DISPLAY("XXX"),
+		 NUTAG_M_USERNAME("xxx"),
+		 NUTAG_M_PARAMS("user=ip"),
+		 NUTAG_M_FEATURES("language=\"fi\""),
+		 NUTAG_INSTANCE("urn:uuid:3eb007b1-6d7f-472e-8b64-29e482795da8"),
+		 NUTAG_OUTBOUND("bar"),
+
+		 TAG_END());
+
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  /* Modify everything from their default value */
+  nua_set_params(ctx->a.nua,
+		 SIPTAG_FROM(from),
+		 NUTAG_RETRY_COUNT(9),
+		 NUTAG_MAX_SUBSCRIPTIONS(6),
+
+		 NUTAG_ENABLEINVITE(0),
+		 NUTAG_AUTOALERT(1),
+		 NUTAG_EARLY_MEDIA(1),
+		 NUTAG_AUTOANSWER(1),
+		 NUTAG_AUTOACK(0),
+		 NUTAG_INVITE_TIMER(60),
+
+		 NUTAG_SESSION_TIMER(600),
+		 NUTAG_MIN_SE(35),
+		 NUTAG_SESSION_REFRESHER(nua_remote_refresher),
+		 NUTAG_UPDATE_REFRESH(1),
+
+		 NUTAG_ENABLEMESSAGE(0),
+		 NUTAG_ENABLEMESSENGER(1),
+		 /* NUTAG_MESSAGE_AUTOANSWER(0), */
+
+		 NUTAG_CALLEE_CAPS(1),
+		 NUTAG_MEDIA_FEATURES(1),
+		 NUTAG_SERVICE_ROUTE_ENABLE(0),
+		 NUTAG_PATH_ENABLE(0),
+		 NUTAG_REFER_EXPIRES(333),
+		 NUTAG_REFER_WITH_ID(0),
+		 NUTAG_SUBSTATE(nua_substate_pending),
+
+		 NUTAG_KEEPALIVE(66),
+		 NUTAG_KEEPALIVE_STREAM(33),
+
+		 NUTAG_INSTANCE("urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c"),
+		 NUTAG_M_DISPLAY("Joe"),
+		 NUTAG_M_USERNAME("joe"),
+		 NUTAG_M_PARAMS("user=phone"),
+		 NUTAG_M_FEATURES("language=\"en\""),
+		 NUTAG_OUTBOUND("foo"),
+		 SIPTAG_SUPPORTED(sip_supported_make(tmphome, "foo")),
+		 NUTAG_SUPPORTED("foo, bar"),
+		 SIPTAG_SUPPORTED_STR(",baz,"),
+
+		 SIPTAG_ALLOW_STR("OPTIONS"),
+		 SIPTAG_ALLOW(sip_allow_make(tmphome, "INFO")),
+		 NUTAG_ALLOW("ACK, INFO"),
+
+		 SIPTAG_ALLOW_EVENTS_STR("reg"),
+		 SIPTAG_ALLOW_EVENTS(sip_allow_events_make(tmphome, "presence")),
+		 NUTAG_ALLOW_EVENTS("presence.winfo"),
+
+		 SIPTAG_USER_AGENT(sip_user_agent_make(tmphome, "test_nua")),
+
+		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
+
+		 NUTAG_MEDIA_ENABLE(0),
+		 NUTAG_REGISTRAR(url_hdup(tmphome, (url_t *)"sip:sip.wonderland.org")),
+
+		 TAG_END());
+
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  /* Modify something... */
+  nua_set_params(ctx->a.nua,
+		 NUTAG_RETRY_COUNT(5),
+		 TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  {
+    sip_from_t const *from = NONE;
+    char const *from_str = "NONE";
+
+    unsigned retry_count = (unsigned)-1;
+    unsigned max_subscriptions = (unsigned)-1;
+
+    char const *soa_name = "NONE";
+    int media_enable = -1;
+    int invite_enable = -1;
+    int auto_alert = -1;
+    int early_media = -1;
+    int only183_100rel = -1;
+    int auto_answer = -1;
+    int auto_ack = -1;
+    unsigned invite_timeout = (unsigned)-1;
+
+    unsigned session_timer = (unsigned)-1;
+    unsigned min_se = (unsigned)-1;
+    int refresher = -1;
+    int update_refresh = -1;
+
+    int message_enable = -1;
+    int win_messenger_enable = -1;
+    int message_auto_respond = -1;
+
+    int callee_caps = -1;
+    int media_features = -1;
+    int service_route_enable = -1;
+    int path_enable = -1;
+    unsigned refer_expires = (unsigned)-1;
+    int refer_with_id = -1;
+    int substate = -1;
+
+    sip_allow_t const *allow = NONE;
+    char const *allow_str = "NONE";
+    sip_allow_events_t const *allow_events = NONE;
+    char const *allow_events_str = "NONE";
+    sip_supported_t const *supported = NONE;
+    char const *supported_str = "NONE";
+    sip_user_agent_t const *user_agent = NONE;
+    char const *user_agent_str = "NONE";
+    char const *ua_name = "NONE";
+    sip_organization_t const *organization = NONE;
+    char const *organization_str = "NONE";
+
+    char const *outbound = "NONE";
+    char const *m_display = "NONE";
+    char const *m_username = "NONE";
+    char const *m_params = "NONE";
+    char const *m_features = "NONE";
+    char const *instance = "NONE";
+    
+    url_string_t const *registrar = NONE;
+    unsigned keepalive = (unsigned)-1, keepalive_stream = (unsigned)-1;
+
+    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+    run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+    TEST_1(e = ctx->a.events->head);
+    TEST_E(e->data->e_event, nua_r_get_params);
+
+    n = tl_gets(e->data->e_tags,
+	       	SIPTAG_FROM_REF(from),
+	       	SIPTAG_FROM_STR_REF(from_str),
+
+	       	NUTAG_RETRY_COUNT_REF(retry_count),
+	       	NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),
+
+		NUTAG_SOA_NAME_REF(soa_name),
+		NUTAG_MEDIA_ENABLE_REF(media_enable),
+	       	NUTAG_ENABLEINVITE_REF(invite_enable),
+	       	NUTAG_AUTOALERT_REF(auto_alert),
+	       	NUTAG_EARLY_MEDIA_REF(early_media),
+		NUTAG_ONLY183_100REL_REF(only183_100rel),
+	       	NUTAG_AUTOANSWER_REF(auto_answer),
+	       	NUTAG_AUTOACK_REF(auto_ack),
+	       	NUTAG_INVITE_TIMER_REF(invite_timeout),
+
+	       	NUTAG_SESSION_TIMER_REF(session_timer),
+	       	NUTAG_MIN_SE_REF(min_se),
+	       	NUTAG_SESSION_REFRESHER_REF(refresher),
+	       	NUTAG_UPDATE_REFRESH_REF(update_refresh),
+
+	       	NUTAG_ENABLEMESSAGE_REF(message_enable),
+	       	NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
+	       	/* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */
+
+	       	NUTAG_CALLEE_CAPS_REF(callee_caps),
+	       	NUTAG_MEDIA_FEATURES_REF(media_features),
+	       	NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
+	       	NUTAG_PATH_ENABLE_REF(path_enable),
+	       	NUTAG_REFER_EXPIRES_REF(refer_expires),
+	       	NUTAG_REFER_WITH_ID_REF(refer_with_id),
+	       	NUTAG_SUBSTATE_REF(substate),
+
+	       	SIPTAG_SUPPORTED_REF(supported),
+	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
+	       	SIPTAG_ALLOW_REF(allow),
+	       	SIPTAG_ALLOW_STR_REF(allow_str),
+		SIPTAG_ALLOW_EVENTS_REF(allow_events),
+		SIPTAG_ALLOW_EVENTS_STR_REF(allow_events_str),
+	       	SIPTAG_USER_AGENT_REF(user_agent),
+	       	SIPTAG_USER_AGENT_STR_REF(user_agent_str),
+		NUTAG_USER_AGENT_REF(ua_name),
+
+	       	SIPTAG_ORGANIZATION_REF(organization),
+	       	SIPTAG_ORGANIZATION_STR_REF(organization_str),
+
+	       	NUTAG_REGISTRAR_REF(registrar),
+		NUTAG_KEEPALIVE_REF(keepalive),
+		NUTAG_KEEPALIVE_STREAM_REF(keepalive_stream),
+
+		NUTAG_OUTBOUND_REF(outbound),
+		NUTAG_M_DISPLAY_REF(m_display),
+		NUTAG_M_USERNAME_REF(m_username),
+		NUTAG_M_PARAMS_REF(m_params),
+		NUTAG_M_FEATURES_REF(m_features),
+		NUTAG_INSTANCE_REF(instance),
+
+		TAG_END());
+    TEST(n, 46);
+
+    TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
+    TEST_S(from_str, Alice);
+
+    TEST(retry_count, 5);
+    TEST(max_subscriptions, 6);
+
+    TEST_S(soa_name, "test");
+    TEST(media_enable, 0);
+    TEST(invite_enable, 0);
+    TEST(auto_alert, 1);
+    TEST(early_media, 1);
+    TEST(auto_answer, 1);
+    TEST(auto_ack, 0);
+    TEST(invite_timeout, 60);
+
+    TEST(session_timer, 600);
+    TEST(min_se, 35);
+    TEST(refresher, nua_remote_refresher);
+    TEST(update_refresh, 1);
+
+    TEST(message_enable, 0);
+    TEST(win_messenger_enable, 1);
+    TEST(message_auto_respond, -1); /* XXX */
+
+    TEST(callee_caps, 1);
+    TEST(media_features, 1);
+    TEST(service_route_enable, 0);
+    TEST(path_enable, 0);
+    TEST(refer_expires, 333);
+    TEST(refer_with_id, 0);
+    TEST(substate, nua_substate_pending);
+
+    TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO, ACK");
+    TEST_S(allow_str, "OPTIONS, INFO, ACK");
+    TEST_S(sip_header_as_string(tmphome, (void *)allow_events), 
+	   "reg, presence, presence.winfo");
+    TEST_S(allow_events_str, "reg, presence, presence.winfo");
+    TEST_S(sip_header_as_string(tmphome, (void *)supported), 
+	   "foo, bar, baz");
+    TEST_S(supported_str, "foo, bar, baz");
+    TEST_S(sip_header_as_string(tmphome, (void *)user_agent), "test_nua");
+    TEST_S(user_agent_str, "test_nua");
+    TEST_S(sip_header_as_string(tmphome, (void *)organization),
+	   "Pussy Galore's Flying Circus");
+    TEST_S(organization_str, "Pussy Galore's Flying Circus");
+
+    TEST_S(url_as_string(tmphome, registrar->us_url),
+	   "sip:sip.wonderland.org");
+    TEST(keepalive, 66);
+    TEST(keepalive_stream, 33);
+
+    TEST_S(instance, "urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c");
+    TEST_S(m_display, "Joe");
+    TEST_S(m_username, "joe");
+    TEST_S(m_params, "user=phone");
+    { char const *expect_m_features = "language=\"en\"";
+    TEST_S(m_features, expect_m_features); }
+    TEST_S(outbound, "foo");
+
+    free_events_in_list(ctx, ctx->a.events);
+  }
+
+  /* Test that only those tags that have been set per handle are returned by nua_get_hparams() */
+
+  {
+    sip_from_t const *from = NONE;
+    char const *from_str = "NONE";
+
+    unsigned retry_count = (unsigned)-1;
+    unsigned max_subscriptions = (unsigned)-1;
+
+    int invite_enable = -1;
+    int auto_alert = -1;
+    int early_media = -1;
+    int auto_answer = -1;
+    int auto_ack = -1;
+    unsigned invite_timeout = (unsigned)-1;
+
+    unsigned session_timer = (unsigned)-1;
+    unsigned min_se = (unsigned)-1;
+    int refresher = -1;
+    int update_refresh = -1;
+
+    int message_enable = -1;
+    int win_messenger_enable = -1;
+    int message_auto_respond = -1;
+
+    int callee_caps = -1;
+    int media_features = -1;
+    int service_route_enable = -1;
+    int path_enable = -1;
+    unsigned refer_expires = (unsigned)-1;
+    int refer_with_id = -1;
+    int substate = -1;
+
+    sip_allow_t const *allow = NONE;
+    char const   *allow_str = "NONE";
+    sip_supported_t const *supported = NONE;
+    char const *supported_str = "NONE";
+    sip_user_agent_t const *user_agent = NONE;
+    char const *user_agent_str = "NONE";
+    sip_organization_t const *organization = NONE;
+    char const *organization_str = "NONE";
+
+    url_string_t const *registrar = NONE;
+
+    char const *outbound = "NONE";
+    char const *m_display = "NONE";
+    char const *m_username = "NONE";
+    char const *m_params = "NONE";
+    char const *m_features = "NONE";
+    char const *instance = "NONE";
+
+    int n;
+    struct event *e;
+
+    nua_get_hparams(nh, TAG_ANY(), TAG_END());
+    run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+    TEST_1(e = ctx->a.events->head);
+    TEST_E(e->data->e_event, nua_r_get_params);
+
+    n = tl_gets(e->data->e_tags,
+	       	SIPTAG_FROM_REF(from),
+	       	SIPTAG_FROM_STR_REF(from_str),
+
+	       	NUTAG_RETRY_COUNT_REF(retry_count),
+	       	NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),
+
+	       	NUTAG_ENABLEINVITE_REF(invite_enable),
+	       	NUTAG_AUTOALERT_REF(auto_alert),
+	       	NUTAG_EARLY_MEDIA_REF(early_media),
+	       	NUTAG_AUTOANSWER_REF(auto_answer),
+	       	NUTAG_AUTOACK_REF(auto_ack),
+	       	NUTAG_INVITE_TIMER_REF(invite_timeout),
+
+	       	NUTAG_SESSION_TIMER_REF(session_timer),
+	       	NUTAG_MIN_SE_REF(min_se),
+	       	NUTAG_SESSION_REFRESHER_REF(refresher),
+	       	NUTAG_UPDATE_REFRESH_REF(update_refresh),
+
+	       	NUTAG_ENABLEMESSAGE_REF(message_enable),
+	       	NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
+	       	/* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */
+
+	       	NUTAG_CALLEE_CAPS_REF(callee_caps),
+	       	NUTAG_MEDIA_FEATURES_REF(media_features),
+	       	NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
+	       	NUTAG_PATH_ENABLE_REF(path_enable),
+	       	NUTAG_SUBSTATE_REF(substate),
+
+	       	SIPTAG_SUPPORTED_REF(supported),
+	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
+	       	SIPTAG_ALLOW_REF(allow),
+	       	SIPTAG_ALLOW_STR_REF(allow_str),
+	       	SIPTAG_USER_AGENT_REF(user_agent),
+	       	SIPTAG_USER_AGENT_STR_REF(user_agent_str),
+
+	       	SIPTAG_ORGANIZATION_REF(organization),
+	       	SIPTAG_ORGANIZATION_STR_REF(organization_str),
+
+		NUTAG_OUTBOUND_REF(outbound),
+		NUTAG_M_DISPLAY_REF(m_display),
+		NUTAG_M_USERNAME_REF(m_username),
+		NUTAG_M_PARAMS_REF(m_params),
+		NUTAG_M_FEATURES_REF(m_features),
+		NUTAG_INSTANCE_REF(instance),
+
+	       	NUTAG_REGISTRAR_REF(registrar),
+
+		TAG_END());
+    TEST(n, 3);
+
+    TEST(invite_timeout, 90);
+
+    TEST_1(from != NULL && from != NONE);
+    TEST_1(strcmp(from_str, "NONE"));
+
+    /* Nothing else should be set */
+    TEST(retry_count, (unsigned)-1);
+    TEST(max_subscriptions, (unsigned)-1);
+
+    TEST(invite_enable, -1);
+    TEST(auto_alert, -1);
+    TEST(early_media, -1);
+    TEST(auto_answer, -1);
+    TEST(auto_ack, -1);
+
+    TEST(session_timer, (unsigned)-1);
+    TEST(min_se, (unsigned)-1);
+    TEST(refresher, -1);
+    TEST(update_refresh, -1);
+
+    TEST(message_enable, -1);
+    TEST(win_messenger_enable, -1);
+    TEST(message_auto_respond, -1); /* XXX */
+
+    TEST(callee_caps, -1);
+    TEST(media_features, -1);
+    TEST(service_route_enable, -1);
+    TEST(path_enable, -1);
+    TEST(refer_expires, (unsigned)-1);
+    TEST(refer_with_id, -1);
+    TEST(substate, -1);
+
+    TEST_P(allow, NONE);
+    TEST_S(allow_str, "NONE");
+    TEST_P(supported, NONE);
+    TEST_S(supported_str, "NONE");
+    TEST_P(user_agent, NONE);
+    TEST_S(user_agent_str, "NONE");
+    TEST_P(organization, NONE);
+    TEST_S(organization_str, "NONE");
+
+    TEST_S(outbound, "NONE");
+    TEST_S(m_display, "NONE");
+    TEST_S(m_username, "NONE");
+    TEST_S(m_params, "NONE");
+    TEST_S(m_features, "NONE");
+    TEST_S(instance, "NONE");
+
+    TEST_P(registrar->us_url, NONE);
+
+    free_events_in_list(ctx, ctx->a.events);
+  }
+
+  nua_handle_destroy(nh);
+
+  nua_shutdown(ctx->a.nua);
+  run_a_until(ctx, nua_r_shutdown, until_final_response);
+  nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
+
+  su_root_destroy(ctx->root), ctx->root = NULL;
+
+  su_home_deinit(tmphome);
+
+  if (print_headings)
+    printf("TEST NUA-1.1: PASSED\n");
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_ops.c
+ * @brief High-level test framework for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+int save_events(CONDITION_PARAMS)
+{
+  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
+}
+
+int until_final_response(CONDITION_PARAMS)
+{ 
+  return status >= 200;
+}
+
+int save_until_final_response(CONDITION_PARAMS)
+{
+  save_event_in_list(ctx, event, ep, ep->call);
+  return event >= nua_r_set_params && status >= 200;
+}
+
+/** Save events.
+ *
+ * Terminate when a event is saved.
+ */
+int save_until_received(CONDITION_PARAMS)
+{
+  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
+}
+
+/** Save events until nua_i_outbound is received.  */
+int save_until_special(CONDITION_PARAMS)
+{
+  return save_event_in_list(ctx, event, ep, ep->call) == event_is_special;
+}
+
+/* Return call state from event tag list */
+int callstate(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, nutag_callstate);
+  return ti ? ti->t_value : -1;
+}
+
+/* Return true if offer is sent */
+int is_offer_sent(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, nutag_offer_sent);
+  return ti ? ti->t_value : 0;
+}
+
+/* Return true if answer is sent */
+int is_answer_sent(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, nutag_answer_sent);
+  return ti ? ti->t_value : 0;
+}
+
+/* Return true if offer is recv */
+int is_offer_recv(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, nutag_offer_recv);
+  return ti ? ti->t_value : 0;
+}
+
+/* Return true if answer is recv */
+int is_answer_recv(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, nutag_answer_recv);
+  return ti ? ti->t_value : 0;
+}
+
+/* Return true if offer/answer is sent/recv */
+int is_offer_answer_done(tagi_t const *tags)
+{
+  tagi_t const *ti;
+
+  return 
+    ((ti = tl_find(tags, nutag_answer_recv)) && ti->t_value) ||
+    ((ti = tl_find(tags, nutag_offer_sent)) && ti->t_value) ||
+    ((ti = tl_find(tags, nutag_offer_recv)) && ti->t_value) ||
+    ((ti = tl_find(tags, nutag_answer_sent)) && ti->t_value);
+}
+
+/* Return audio state from event tag list */
+int audio_activity(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, soatag_active_audio);
+  return ti ? ti->t_value : -1;
+}
+
+/* Return video state from event tag list */
+int video_activity(tagi_t const *tags)
+{
+  tagi_t const *ti = tl_find(tags, soatag_active_video);
+  return ti ? ti->t_value : -1;
+}
+
+void print_event(nua_event_t event,
+		 char const *operation,
+		 int status, char const *phrase,
+		 nua_t *nua, struct context *ctx,
+		 struct endpoint *ep,
+		 nua_handle_t *nh, struct call *call,
+		 sip_t const *sip,
+		 tagi_t tags[])
+{
+  if (event == nua_i_state) {
+    fprintf(stderr, "%s.nua(%p): event %s %s\n",
+	    ep->name, nh, nua_event_name(event),
+	    nua_callstate_name(callstate(tags)));
+  }
+  else if ((int)event >= nua_r_set_params) {
+    fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
+	    ep->name, nh, nua_event_name(event), status, phrase);
+  }
+  else if ((int)event >= 0) {
+    fprintf(stderr, "%s.nua(%p): event %s %s\n",
+	    ep->name, nh, nua_event_name(event), phrase);
+  }
+  else if (status > 0) {
+    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
+	    ep->name, nh, operation, status, phrase);
+  }
+  else {
+    tagi_t const *t;
+    t = tl_find(tags, siptag_subject_str);
+    if (t && t->t_value) {
+      char const *subject = (char const *)t->t_value;
+      fprintf(stderr, "%s.nua(%p): call %s() \"%s\"\n",
+	      ep->name, nh, operation, subject);
+    }
+    else
+      fprintf(stderr, "%s.nua(%p): call %s()\n",
+	      ep->name, nh, operation);
+  }
+
+  if ((tstflags & tst_verbatim) && tags)
+    tl_print(stderr, "", tags);
+}
+
+void ep_callback(nua_event_t event,
+		 int status, char const *phrase,
+		 nua_t *nua, struct context *ctx,
+		 struct endpoint *ep,
+		 nua_handle_t *nh, struct call *call,
+		 sip_t const *sip,
+		 tagi_t tags[])
+{
+  if (ep->printer)
+    ep->printer(event, "", status, phrase, nua, ctx, ep, nh, call, sip, tags);
+
+  if (call == NULL && nh) {
+    for (call = ep->call; call; call = call->next) {
+      if (!call->nh)
+	break;
+      if (nh == call->nh)
+	break;
+    }
+
+    if (call && call->nh == NULL) {
+      call->nh = nh;
+      nua_handle_bind(nh, call);
+    }
+  }
+
+  if ((ep->next_event == -1 || ep->next_event == event) &&
+      (ep->next_condition == NULL ||
+       ep->next_condition(event, status, phrase,
+			  nua, ctx, ep, nh, call, sip, tags)))
+    ep->running = 0;
+
+  ep->last_event = event;
+
+  if (call == NULL && nh)
+    nua_handle_destroy(nh);
+}
+
+void a_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[])
+{
+  ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
+}
+
+void b_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[])
+{
+  ep_callback(event, status, phrase, nua, ctx, &ctx->b, nh, call, sip, tags);
+}
+
+void c_callback(nua_event_t event,
+		int status, char const *phrase,
+		nua_t *nua, struct context *ctx,
+		nua_handle_t *nh, struct call *call,
+		sip_t const *sip,
+		tagi_t tags[])
+{
+  ep_callback(event, status, phrase, nua, ctx, &ctx->c, nh, call, sip, tags);
+}
+
+void run_abc_until(struct context *ctx,
+		   nua_event_t a_event, condition_function *a_condition,
+		   nua_event_t b_event, condition_function *b_condition,
+		   nua_event_t c_event, condition_function *c_condition)
+{
+  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+
+  a->next_event = a_event;
+  a->next_condition = a_condition;
+  a->last_event = -1;
+  a->running = a_condition != NULL && a_condition != save_events;
+  a->running |= a_event != -1;
+  a->flags.n = 0;
+
+  b->next_event = b_event;
+  b->next_condition = b_condition;
+  b->last_event = -1;
+  b->running = b_condition != NULL && b_condition != save_events;
+  b->running |= b_event != -1;
+  b->flags.n = 0;
+
+  c->next_event = c_event;
+  c->next_condition = c_condition;
+  c->last_event = -1;
+  c->running = c_condition != NULL && c_condition != save_events;
+  c->running |= c_event != -1;
+  c->flags.n = 0;
+
+  for (; a->running || b->running || c->running;) {
+    su_root_step(ctx->root, 1000);
+  }
+}
+
+void run_ab_until(struct context *ctx,
+		  nua_event_t a_event, condition_function *a_condition,
+		  nua_event_t b_event, condition_function *b_condition)
+{
+  run_abc_until(ctx, a_event, a_condition, b_event, b_condition, -1, NULL);
+}
+
+void run_bc_until(struct context *ctx,
+		  nua_event_t b_event, condition_function *b_condition,
+		  nua_event_t c_event, condition_function *c_condition)
+{
+  run_abc_until(ctx, -1, NULL, b_event, b_condition, c_event, c_condition);
+}
+
+int run_a_until(struct context *ctx,
+		nua_event_t a_event,
+		condition_function *a_condition)
+{
+  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
+  return ctx->a.last_event;
+}
+
+int run_b_until(struct context *ctx,
+		nua_event_t b_event,
+		condition_function *b_condition)
+{
+  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
+  return ctx->b.last_event;
+}
+
+int run_c_until(struct context *ctx,
+		nua_event_t event,
+		condition_function *condition)
+{
+  run_abc_until(ctx, -1, NULL, -1, NULL, event, condition);
+  return ctx->c.last_event;
+}
+
+#define OPERATION(X, x)	   \
+int X(struct endpoint *ep, \
+      struct call *call, nua_handle_t *nh, \
+      tag_type_t tag, tag_value_t value, \
+      ...) \
+{ \
+  ta_list ta; \
+  ta_start(ta, tag, value); \
+\
+  if (ep->printer) \
+    ep->printer(-1, "nua_" #x, 0, "", ep->nua, ep->ctx, ep, \
+		nh, call, NULL, ta_args(ta)); \
+\
+  nua_##x(nh, ta_tags(ta)); \
+\
+  ta_end(ta); \
+  return 0; \
+} extern int dummy
+
+OPERATION(INVITE, invite);
+OPERATION(ACK, ack);
+OPERATION(BYE, bye);
+OPERATION(CANCEL, cancel);
+OPERATION(AUTHENTICATE, authenticate);
+OPERATION(UPDATE, update);
+OPERATION(INFO, info);
+OPERATION(PRACK, prack);
+OPERATION(REFER, refer);
+OPERATION(MESSAGE, message);
+OPERATION(METHOD, method);
+OPERATION(OPTIONS, options);
+OPERATION(PUBLISH, publish);
+OPERATION(UNPUBLISH, unpublish);
+OPERATION(REGISTER, register);
+OPERATION(UNREGISTER, unregister);
+OPERATION(SUBSCRIBE, subscribe);
+OPERATION(UNSUBSCRIBE, unsubscribe);
+OPERATION(NOTIFY, notify);
+OPERATION(NOTIFIER, notifier);
+OPERATION(TERMINATE, terminate);
+OPERATION(AUTHORIZE, authorize);
+
+/* Respond via endpoint and handle */
+int RESPOND(struct endpoint *ep,
+	    struct call *call,
+	    nua_handle_t *nh,
+	    int status, char const *phrase,
+	    tag_type_t tag, tag_value_t value,
+	    ...)
+{
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  if (ep->printer)
+    ep->printer(-1, "nua_respond", status, phrase, ep->nua, ep->ctx, ep,
+		nh, call, NULL, ta_args(ta));
+
+  nua_respond(nh, status, phrase, ta_tags(ta));
+  ta_end(ta);
+
+  return 0;
+}
+
+/* Destroy an handle */
+int DESTROY(struct endpoint *ep,
+	    struct call *call,
+	    nua_handle_t *nh)
+{
+  if (ep->printer)
+    ep->printer(-1, "nua_handle_destroy", 0, "", ep->nua, ep->ctx, ep,
+		nh, call, NULL, NULL);
+
+  nua_handle_destroy(nh);
+
+  if (call->nh == nh)
+    call->nh = NULL;
+
+  return 0;
+}
+
+
+/* Reject all but currently used handles */
+struct call *check_handle(struct endpoint *ep,
+			  struct call *call,
+			  nua_handle_t *nh,
+			  int status, char const *phrase)
+{
+  if (call)
+    return call;
+
+  if (status)
+    RESPOND(ep, call, nh, status, phrase, TAG_END());
+
+  nua_handle_destroy(nh);
+  return NULL;
+}
+
+/* Save nua event in call-specific list */
+int save_event_in_list(struct context *ctx,
+		       nua_event_t nevent,
+		       struct endpoint *ep,
+		       struct call *call)
+
+{
+  struct eventlist *list;
+  struct event *e;
+  int action = ep->is_special(nevent);
+
+  if (action == event_is_extra)
+    return 0;
+  else if (action == event_is_special || call == NULL)
+    list = ep->specials;
+  else if (call->events)
+    list = call->events;
+  else
+    list = ep->events;
+
+  e = su_zalloc(ctx->home, sizeof *e);
+
+  if (!e) { perror("su_zalloc"), abort(); }
+
+  if (!nua_save_event(ep->nua, e->saved_event)) {
+    su_free(ctx->home, e);
+    return -1;
+  }
+
+  *(e->prev = list->tail) = e; list->tail = &e->next;
+
+  e->call = call;
+  e->data = nua_event_data(e->saved_event);
+
+  return action;
+}
+
+/* Save nua event in endpoint list */
+void free_events_in_list(struct context *ctx,
+			 struct eventlist *list)
+{
+  struct event *e;
+
+  while ((e = list->head)) {
+    if ((*e->prev = e->next))
+      e->next->prev = e->prev;
+    nua_destroy_event(e->saved_event);
+    su_free(ctx->home, e);
+  }
+
+  list->tail = &list->head;
+}
+
+int is_special(nua_event_t e)
+{
+  if (e == nua_i_active || e == nua_i_terminated)
+    return event_is_extra;
+  if (e == nua_i_outbound)
+    return event_is_special;
+
+  return event_is_normal;
+}
+
+void
+endpoint_init(struct context *ctx, struct endpoint *e, char id)
+{
+  e->name[0] = id;
+  e->ctx = ctx;
+
+  e->is_special = is_special;
+
+  call_init(e->call);
+  call_init(e->reg);
+  eventlist_init(e->events);
+  eventlist_init(e->specials);
+}
+
+void nolog(void *stream, char const *fmt, va_list ap) {}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1056 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_proxy.c
+ * @brief Extremely simple proxy and registrar for testing nua
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Nov  3 22:49:46 EET 2005
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+struct proxy;
+struct proxy_transaction;
+struct registration_entry;
+struct binding;
+
+#define SU_ROOT_MAGIC_T struct proxy
+#define NTA_LEG_MAGIC_T struct proxy
+#define NTA_OUTGOING_MAGIC_T struct proxy_transaction
+#define NTA_INCOMING_MAGIC_T struct proxy_transaction
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/auth_module.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/msg_addr.h>
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define LIST_PROTOS(STORAGE, PREFIX, T)			 \
+STORAGE void PREFIX ##_insert(T **list, T *node),	 \
+        PREFIX ##_remove(T *node)			 
+
+#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV)	  \
+STORAGE void PREFIX ##_insert(T **list, T *node)   \
+{							 \
+  if ((node->NEXT = *list)) {				 \
+    node->PREV = node->NEXT->PREV;			 \
+    node->NEXT->PREV = &node->NEXT;			 \
+  }							 \
+  else							 \
+    node->PREV = list;					 \
+  *list = node;						 \
+}							 \
+STORAGE void PREFIX ##_remove(T *node)			 \
+{							 \
+  if (node->PREV)					 \
+    if ((*node->PREV = node->NEXT))			 \
+      node->NEXT->PREV = node->PREV;			 \
+  node->PREV = NULL;					 \
+}							 \
+extern int LIST_DUMMY_VARIABLE
+
+#include <test_proxy.h>
+
+struct proxy {
+  su_home_t    home[1];
+  su_root_t   *parent;
+  su_clone_r   clone;
+  tagi_t      *tags;
+
+  su_root_t   *root;
+  auth_mod_t  *auth;
+ 
+  nta_agent_t *agent;
+  url_t const *uri;
+  
+  nta_leg_t *defleg;
+
+  nta_leg_t *example_net;
+  nta_leg_t *example_org;
+  nta_leg_t *example_com;
+
+  sip_contact_t *transport_contacts;
+
+  struct proxy_transaction *stateless;
+  struct proxy_transaction *transactions;
+  struct registration_entry *entries;
+
+  struct {
+    sip_time_t min_expires, expires, max_expires;
+    
+    sip_time_t session_expires, min_se;
+  } prefs;
+}; 
+
+LIST_PROTOS(static, registration_entry, struct registration_entry);
+static struct registration_entry *registration_entry_new(struct proxy *,
+							 url_t const *);
+static void registration_entry_destroy(struct registration_entry *e);
+
+
+struct registration_entry
+{
+  struct registration_entry *next, **prev;
+  struct proxy *proxy;		/* backpointer */
+  url_t *aor;			/* address-of-record */
+  struct binding *bindings;	/* list of bindings */
+  sip_contact_t *contacts;
+};
+
+struct binding
+{
+  struct binding *next, **prev;
+  sip_contact_t *contact;	/* bindings */
+  sip_time_t registered, expires; /* When registered and when expires */
+  sip_call_id_t *call_id;	
+  uint32_t cseq;
+};
+
+static struct binding *binding_new(su_home_t *home, 
+				   sip_contact_t *contact,
+				   sip_call_id_t *call_id,
+				   uint32_t cseq,
+				   sip_time_t registered, 
+				   sip_time_t expires);
+static void binding_destroy(su_home_t *home, struct binding *b);
+static int binding_is_active(struct binding const *b)
+{
+  return b->expires > sip_now();
+}
+
+LIST_PROTOS(static, proxy_transaction, struct proxy_transaction);
+struct proxy_transaction *proxy_transaction_new(struct proxy *);
+static void proxy_transaction_destroy(struct proxy_transaction *t);
+
+struct proxy_transaction
+{
+  struct proxy_transaction *next, **prev;
+
+  struct proxy *proxy;		/* backpointer */
+  sip_request_t *rq;		/* request line */
+  nta_incoming_t *server;	/* server transaction */
+  nta_outgoing_t *client;	/* client transaction */
+};
+
+static sip_contact_t *create_transport_contacts(struct proxy *p);
+
+static int proxy_request(struct proxy *proxy,
+			 nta_leg_t *leg,
+			 nta_incoming_t *irq,
+			 sip_t const *sip);
+
+static int proxy_ack_cancel(struct proxy_transaction *t,
+			    nta_incoming_t *irq,
+			    sip_t const *sip);
+
+static int proxy_response(struct proxy_transaction *t,
+			  nta_outgoing_t *client,
+			  sip_t const *sip);
+
+static int process_register(struct proxy *proxy,
+			    nta_incoming_t *irq,
+			    sip_t const *sip);
+
+static int domain_request(struct proxy *proxy,
+			  nta_leg_t *leg,
+			  nta_incoming_t *irq,
+			  sip_t const *sip);
+
+static int process_options(struct proxy *proxy,
+			   nta_incoming_t *irq,
+			   sip_t const *sip);
+
+static struct registration_entry *
+registration_entry_find(struct proxy const *proxy, url_t const *uri);
+
+static auth_challenger_t registrar_challenger[1];
+static auth_challenger_t proxy_challenger[1];
+
+/* Proxy entry point */
+static int 
+test_proxy_init(su_root_t *root, struct proxy *proxy)
+{
+  struct proxy_transaction *t;
+
+  auth_challenger_t _proxy_challenger[1] = 
+  {{ 
+      SIP_407_PROXY_AUTH_REQUIRED,
+      sip_proxy_authenticate_class,
+      sip_proxy_authentication_info_class
+    }};
+
+  auth_challenger_t _registrar_challenger[1] = 
+  {{ 
+      SIP_401_UNAUTHORIZED,
+      sip_www_authenticate_class,
+      sip_authentication_info_class
+    }};
+
+  *proxy_challenger = *_proxy_challenger;
+  *registrar_challenger = *_registrar_challenger;
+
+  proxy->root = root;
+
+  proxy->auth = auth_mod_create(root, TAG_NEXT(proxy->tags));
+
+  proxy->agent = nta_agent_create(root,
+				  URL_STRING_MAKE("sip:0.0.0.0:*"),
+				  NULL, NULL,
+				  NTATAG_UA(0),
+				  NTATAG_SERVER_RPORT(1),
+				  NTATAG_CLIENT_RPORT(1),
+				  TAG_END());
+
+  proxy->transport_contacts = create_transport_contacts(proxy);
+
+  proxy->defleg = nta_leg_tcreate(proxy->agent,
+				  proxy_request,
+				  proxy,
+				  NTATAG_NO_DIALOG(1),
+				  TAG_END());
+
+  proxy->example_net = nta_leg_tcreate(proxy->agent,
+				       domain_request,
+				       proxy,
+				       NTATAG_NO_DIALOG(1),
+				       URLTAG_URL("sip:example.net"),
+				       TAG_END());
+  proxy->example_org = nta_leg_tcreate(proxy->agent,
+				       domain_request,
+				       proxy,
+				       NTATAG_NO_DIALOG(1),
+				       URLTAG_URL("sip:example.org"),
+				       TAG_END());
+  proxy->example_com = nta_leg_tcreate(proxy->agent,
+				       domain_request,
+				       proxy,
+				       NTATAG_NO_DIALOG(1),
+				       URLTAG_URL("sip:example.com"),
+				       TAG_END());
+
+  proxy->prefs.min_expires = 30;
+  proxy->prefs.expires = 3600;
+  proxy->prefs.max_expires = 3600;
+
+  proxy->prefs.session_expires = 180;
+  proxy->prefs.min_se = 90;
+
+  if (!proxy->defleg || 
+      !proxy->example_net || !proxy->example_org || !proxy->example_com)
+    return -1;
+
+  t = su_zalloc(proxy->home, sizeof *t); 
+
+  if (!t)
+    return -1;
+
+  proxy->stateless = t;
+  t->proxy = proxy;
+  t->server = nta_incoming_default(proxy->agent);
+  t->client = nta_outgoing_default(proxy->agent, proxy_response, t);
+
+  if (!t->client || !t->server)
+    return -1;
+
+  proxy->uri = nta_agent_contact(proxy->agent)->m_url;
+				  
+  return 0;
+}
+
+static void
+test_proxy_deinit(su_root_t *root, struct proxy *proxy)
+{
+  struct proxy_transaction *t;
+  
+  auth_mod_destroy(proxy->auth);
+
+  if ((t = proxy->stateless)) {
+    nta_incoming_destroy(t->server), t->server = NULL;
+    nta_outgoing_destroy(t->client), t->client = NULL;
+  }
+
+  nta_agent_destroy(proxy->agent);
+
+  while (proxy->entries)
+    registration_entry_destroy(proxy->entries);
+
+  free(proxy->tags);
+}
+
+/* Create tst proxy object */
+struct proxy *test_proxy_create(su_root_t *root,
+				tag_type_t tag, tag_value_t value, ...)
+{
+  struct proxy *p = su_home_new(sizeof *p);
+
+  if (p) {
+    ta_list ta;
+
+    p->parent = root;
+
+    ta_start(ta, tag, value);
+    p->tags = tl_llist(ta_tags(ta));
+    ta_end(ta);
+    
+    if (su_clone_start(root,
+		       p->clone,
+		       p,
+		       test_proxy_init,
+		       test_proxy_deinit) == -1)
+      su_home_unref(p->home), p = NULL;
+  }
+
+  return p;
+}
+
+/* Destroy the proxy object */
+void test_proxy_destroy(struct proxy *p)
+{
+  if (p) {
+    su_clone_wait(p->parent, p->clone);
+    su_home_unref(p->home);
+  }
+}
+
+/* Return the proxy URI */
+url_t const *test_proxy_uri(struct proxy const *p)
+{
+  return p ? p->uri : NULL;
+}
+
+void test_proxy_set_expiration(struct proxy *p,
+			       sip_time_t min_expires, 
+			       sip_time_t expires, 
+			       sip_time_t max_expires)
+{
+  if (p) {
+    p->prefs.min_expires = min_expires;
+    p->prefs.expires = expires;
+    p->prefs.max_expires = max_expires;
+  }
+}
+
+void test_proxy_get_expiration(struct proxy *p,
+			       sip_time_t *return_min_expires,
+			       sip_time_t *return_expires,
+			       sip_time_t *return_max_expires)
+{
+  if (p) {
+    if (return_min_expires) *return_min_expires = p->prefs.min_expires;
+    if (return_expires) *return_expires = p->prefs.expires;
+    if (return_max_expires) *return_max_expires = p->prefs.max_expires;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static sip_contact_t *create_transport_contacts(struct proxy *p)
+{
+  su_home_t *home = p->home;
+  sip_via_t *v;
+  sip_contact_t *retval = NULL, **mm = &retval;
+
+  if (!p->agent)
+    return NULL;
+
+  for (v = nta_agent_via(p->agent); v; v = v->v_next) {
+    char const *proto = v->v_protocol;
+
+    if (v->v_next && 
+	strcasecmp(v->v_host, v->v_next->v_host) == 0 &&
+	str0cmp(v->v_port, v->v_next->v_port) == 0 &&
+	((proto == sip_transport_udp &&
+	  v->v_next->v_protocol == sip_transport_tcp) ||
+	 (proto == sip_transport_tcp &&
+	  v->v_next->v_protocol == sip_transport_udp)))
+      /* We have udp/tcp pair, insert URL without tport parameter */
+      *mm = sip_contact_create_from_via_with_transport(home, v, NULL, NULL);
+    if (*mm) mm = &(*mm)->m_next;
+
+    *mm = sip_contact_create_from_via_with_transport(home, v, NULL, proto);
+
+    if (*mm) mm = &(*mm)->m_next;
+  }
+
+  return retval;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int challenge_request(struct proxy *, nta_incoming_t *, sip_t const *);
+
+/** Forward request */
+static
+int proxy_request(struct proxy *proxy,
+		  nta_leg_t *leg,
+		  nta_incoming_t *irq,
+		  sip_t const *sip)
+{
+  url_t const *request_uri, *target;
+  struct proxy_transaction *t = NULL;
+  sip_request_t *rq = NULL;
+  sip_max_forwards_t *mf;
+  sip_method_t method = sip->sip_request->rq_method;
+
+  sip_session_expires_t *x = NULL, x0[1];
+  sip_min_se_t *min_se = NULL, min_se0[1];
+
+  mf = sip->sip_max_forwards;
+
+  if (mf && mf->mf_count <= 1) {
+    if (sip->sip_request->rq_method == sip_method_options) {
+      return process_options(proxy, irq, sip);
+    }
+    nta_incoming_treply(irq, SIP_483_TOO_MANY_HOPS, TAG_END());
+    return 483;
+  }
+
+  if (method != sip_method_ack && method != sip_method_cancel && 
+      str0casecmp(sip->sip_from->a_url->url_host, "example.net") == 0) {
+    /* Challenge everything but CANCEL and ACK coming from Mr. C */
+    int status = challenge_request(proxy, irq, sip);
+    if (status)
+      return status;
+  }
+
+  if (method == sip_method_invite) {
+    if (!sip->sip_min_se || 
+	sip->sip_min_se->min_delta < proxy->prefs.min_se) {
+      min_se = sip_min_se_init(min_se0);
+      min_se->min_delta = proxy->prefs.min_se;
+    }
+
+    if (!sip->sip_session_expires) {
+      x = sip_session_expires_init(x0);
+      x->x_delta = proxy->prefs.session_expires;
+    }
+    else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se
+	     && sip_has_supported(sip->sip_supported, "timer")) {
+      if (min_se == NULL)
+	min_se = sip->sip_min_se; assert(min_se);
+      nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
+			  SIPTAG_MIN_SE(min_se),
+			  TAG_END());
+      return 422;
+    }
+  }
+
+  /* We don't do any route processing */
+  request_uri = sip->sip_request->rq_url;
+
+  if (!request_uri->url_host || 
+      (strcasecmp(request_uri->url_host, "example.org") &&
+       strcasecmp(request_uri->url_host, "example.net") &&
+       strcasecmp(request_uri->url_host, "example.com"))) {
+    target = request_uri;
+  }
+  else {
+    struct registration_entry *e;
+    struct binding *b;
+
+    if (sip->sip_request->rq_method == sip_method_register) 
+      return process_register(proxy, irq, sip);
+
+    e = registration_entry_find(proxy, request_uri);
+    if (e == NULL) {
+      nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END());
+      return 404;
+    }
+
+    for (b = e->bindings; b; b = b->next)
+      if (binding_is_active(b))
+	break;
+
+    if (b == NULL) {
+      nta_incoming_treply(irq, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
+      return 480;
+    }
+    
+    target = b->contact->m_url;
+  }
+
+  t = proxy_transaction_new(proxy);
+  if (t == NULL) {
+    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+    return 500;
+  }
+  nta_incoming_bind(t->server = irq, proxy_ack_cancel, t);
+  
+  rq = sip_request_create(proxy->home,
+			  sip->sip_request->rq_method,
+			  sip->sip_request->rq_method_name,
+			  (url_string_t *)target,
+			  NULL);
+  if (rq == NULL) {
+    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+    proxy_transaction_destroy(t);
+    return 500;
+  }
+  t->rq = rq;
+
+  /* Forward request */
+  t->client = nta_outgoing_mcreate(proxy->agent, proxy_response, t, NULL,
+				   nta_incoming_getrequest(irq),
+				   /* rewrite request */
+				   SIPTAG_REQUEST(rq),
+				   SIPTAG_SESSION_EXPIRES(x),
+				   SIPTAG_MIN_SE(min_se),
+				   TAG_END());
+  if (t->client == NULL) {
+    proxy_transaction_destroy(t);
+    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+    return 500;
+  }
+  else if (sip->sip_request->rq_method == sip_method_ack)
+    proxy_transaction_destroy(t);
+
+  return 0;
+}
+
+static
+int challenge_request(struct proxy *p,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  int status;
+  auth_status_t *as;
+  msg_t *msg;
+
+  as = auth_status_new(p->home);
+  if (!as)
+    return 500;
+
+  as->as_method = sip->sip_request->rq_method_name;
+  msg = nta_incoming_getrequest(irq);
+  as->as_source = msg_addrinfo(msg);
+
+  as->as_user_uri = sip->sip_from->a_url;
+  as->as_display = sip->sip_from->a_display;
+
+  if (sip->sip_payload)
+    as->as_body = sip->sip_payload->pl_data,
+      as->as_bodylen = sip->sip_payload->pl_len;
+
+  auth_mod_check_client(p->auth, as, sip->sip_proxy_authorization,
+			proxy_challenger);
+
+  if ((status = as->as_status)) {
+    nta_incoming_treply(irq,
+			as->as_status, as->as_phrase,
+			SIPTAG_HEADER((void *)as->as_info),
+			SIPTAG_HEADER((void *)as->as_response),
+			TAG_END());
+  }
+  else if (as->as_match) {
+    msg_header_remove(msg, NULL, as->as_match);
+  }
+
+  msg_destroy(msg);
+  su_home_unref(as->as_home);
+
+  return status;
+}		      
+
+int proxy_ack_cancel(struct proxy_transaction *t,
+		     nta_incoming_t *irq,
+		     sip_t const *sip)
+{
+  if (sip == NULL) {
+    proxy_transaction_destroy(t);
+    return 0;
+  }
+
+  if (sip->sip_request->rq_method == sip_method_cancel) {
+    /* We don't care about response to CANCEL (or ACK)
+     * so we give NULL as callback pointer (and nta immediately 
+     * destroys transaction object or marks it disposable)
+     */
+    if (nta_outgoing_tcancel(t->client, NULL, NULL, TAG_END()))
+      return 200;
+    else
+      return 500;
+  }
+  else {
+    return 500;
+  }
+}
+
+int proxy_response(struct proxy_transaction *t,
+		   nta_outgoing_t *client,
+		   sip_t const *sip)
+{
+  int final;
+
+  if (sip) {
+    msg_t *response = nta_outgoing_getresponse(client);
+    final = sip->sip_status->st_status >= 200;
+    sip_via_remove(response, sip_object(response));
+    nta_incoming_mreply(t->server, response);
+  }
+  else {
+    final = 1;
+    nta_incoming_treply(t->server, SIP_408_REQUEST_TIMEOUT, TAG_END());
+  }
+
+  if (final)
+    proxy_transaction_destroy(t);
+
+  return 0;
+}
+
+struct proxy_transaction *
+proxy_transaction_new(struct proxy *proxy)
+{
+  struct proxy_transaction *t;
+
+  t = su_zalloc(proxy->home, sizeof *t);
+  if (t) {
+    t->proxy = proxy;
+    proxy_transaction_insert(&proxy->transactions, t);
+  }
+  return t;
+}
+
+static
+void proxy_transaction_destroy(struct proxy_transaction *t)
+{
+  if (t == t->proxy->stateless)
+    return;
+  proxy_transaction_remove(t);
+  nta_incoming_destroy(t->server);
+  nta_outgoing_destroy(t->client);
+  su_free(t->proxy->home, t->rq);
+  su_free(t->proxy->home, t);
+}
+
+LIST_BODIES(static, proxy_transaction, struct proxy_transaction, next, prev);
+
+/* ---------------------------------------------------------------------- */
+
+
+static
+int domain_request(struct proxy *proxy,
+		   nta_leg_t *leg,
+		   nta_incoming_t *irq,
+		   sip_t const *sip)
+{
+  sip_method_t method = sip->sip_request->rq_method;
+
+  if (method == sip_method_register)
+    return process_register(proxy, irq, sip);
+
+  if (method == sip_method_options) 
+    return process_options(proxy, irq, sip);
+
+  return 501;
+}
+
+static
+int process_options(struct proxy *proxy,
+		    nta_incoming_t *irq,
+		    sip_t const *sip)
+{
+  nta_incoming_treply(irq, SIP_200_OK,
+		      SIPTAG_CONTACT(proxy->transport_contacts),
+		      TAG_END());
+  return 200;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+static int process_register2(struct proxy *p, auth_status_t *as,
+			      nta_incoming_t *irq, sip_t const *sip);
+
+static int set_status(auth_status_t *as, int status, char const *phrase);
+
+static int validate_contacts(struct proxy *p, auth_status_t *as,
+			     sip_t const *sip);
+static int check_out_of_order(struct proxy *p, auth_status_t *as,
+			      struct registration_entry *e, sip_t const *);
+static int binding_update(struct proxy *p,
+       		   auth_status_t *as,
+       		   struct registration_entry *e,
+       		   sip_t const *sip);
+
+sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings);
+
+int process_register(struct proxy *proxy,
+       	      nta_incoming_t *irq,
+       	      sip_t const *sip)
+{
+  auth_status_t *as;
+  msg_t *msg;
+  int status;
+
+  as = auth_status_new(proxy->home);
+  if (!as)
+    return 500;
+
+  as->as_method = sip->sip_request->rq_method_name;
+  msg = nta_incoming_getrequest(irq);
+  as->as_source = msg_addrinfo(msg);
+  msg_destroy(msg);
+
+  as->as_user_uri = sip->sip_from->a_url;
+  as->as_display = sip->sip_from->a_display;
+
+  if (sip->sip_payload)
+    as->as_body = sip->sip_payload->pl_data,
+      as->as_bodylen = sip->sip_payload->pl_len;
+
+  process_register2(proxy, as, irq, sip);
+  assert(as->as_status >= 200);
+
+  nta_incoming_treply(irq,
+       	       as->as_status, as->as_phrase,
+       	       SIPTAG_HEADER((void *)as->as_info),
+       	       SIPTAG_HEADER((void *)as->as_response),
+       	       TAG_END());
+  status = as->as_status;
+
+  su_home_unref(as->as_home);
+
+  return status;
+}
+
+static int process_register2(struct proxy *p,
+			     auth_status_t *as,
+			     nta_incoming_t *irq,
+			     sip_t const *sip)
+{
+  struct registration_entry *e = NULL;
+
+  auth_mod_check_client(p->auth, as, sip->sip_authorization,
+			registrar_challenger);
+  if (as->as_status)
+    return as->as_status;
+  assert(as->as_response == NULL);
+
+  if (validate_contacts(p, as, sip))
+    return as->as_status;
+
+  e = registration_entry_find(p, sip->sip_to->a_url);
+  if (!sip->sip_contact) {
+    as->as_response = (msg_header_t *)e->contacts;
+    return set_status(as, SIP_200_OK);
+  }
+
+  if (e && check_out_of_order(p, as, e, sip))
+    return as->as_status;
+  
+  if (!e) 
+    e = registration_entry_new(p, sip->sip_to->a_url);
+  if (!e)
+    return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+
+  if (binding_update(p, as, e, sip))
+    return as->as_status;
+
+  msg_header_free(p->home, (void *)e->contacts);
+  e->contacts = binding_contacts(p->home, e->bindings);
+
+  as->as_response = (msg_header_t *)e->contacts;
+
+  return set_status(as, SIP_200_OK);
+}
+
+static int set_status(auth_status_t *as, int status, char const *phrase)
+{
+  return as->as_phrase = phrase, as->as_status = status;
+}
+
+static int validate_contacts(struct proxy *p,
+			     auth_status_t *as,
+			     sip_t const *sip)
+{
+  sip_contact_t const *m;
+  sip_time_t expires;
+  sip_time_t now = sip_now();
+
+  for (m = sip->sip_contact; m; m = m->m_next) {
+    if (m->m_url->url_type == url_any) {
+      if (!sip->sip_expires ||
+	  sip->sip_expires->ex_delta || 
+	  sip->sip_expires->ex_time ||
+	  sip->sip_contact->m_next)
+	return set_status(as, SIP_400_BAD_REQUEST);
+      else
+	return 0;
+    }
+
+    expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+				  p->prefs.expires, now);
+    
+    if (expires > 0 && expires < p->prefs.min_expires) {
+      as->as_response = (msg_header_t *)
+	sip_min_expires_format(as->as_home, "%u", 
+			       (unsigned)p->prefs.min_expires);
+      return set_status(as, SIP_423_INTERVAL_TOO_BRIEF);
+    }
+  }
+
+  return 0;
+}
+
+/** Check for out-of-order register request */
+static
+int check_out_of_order(struct proxy *p,
+		       auth_status_t *as,
+		       struct registration_entry *e,
+		       sip_t const *sip)
+{
+  struct binding const *b;
+  sip_call_id_t const *id;
+  sip_contact_t *m;
+
+  if (e == NULL || !sip->sip_contact)
+    return 0;
+
+  id = sip->sip_call_id;
+  
+  /* RFC 3261 subsection 10.3 step 6 and step 7 (p. 66): */
+  /* Check for reordered register requests */
+  for (b = e->bindings; b; b = b->next) {
+    if (binding_is_active(b) &&
+	strcmp(sip->sip_call_id->i_id, b->call_id->i_id) == 0 &&
+	sip->sip_cseq->cs_seq <= b->cseq) {
+      for (m = sip->sip_contact; m; m = m->m_next) {
+	if (m->m_url->url_type == url_any ||
+	    url_cmp_all(m->m_url, b->contact->m_url) == 0)
+	  return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+static struct registration_entry *
+registration_entry_find(struct proxy const *proxy, url_t const *uri)
+{
+  struct registration_entry *e;
+
+  /* Our routing table */
+  for (e = proxy->entries; e; e = e->next) {
+    if (url_cmp(uri, e->aor) == 0)
+      return e;
+  }
+  return NULL;
+}
+
+static struct registration_entry *
+registration_entry_new(struct proxy *proxy, url_t const *aor)
+{
+  struct registration_entry *e;
+
+  e = su_zalloc(proxy->home, sizeof *e); 
+  if (!e) 
+    return NULL;
+
+  e->proxy = proxy;
+  e->aor = url_hdup(proxy->home, aor);
+  if (!e->aor) {
+    su_free(proxy->home, e);
+    return NULL;
+  }
+
+  registration_entry_insert(&proxy->entries, e);
+
+  return e;
+}
+
+static void
+registration_entry_destroy(struct registration_entry *e)
+{
+  if (e) {
+    registration_entry_remove(e);
+    su_free(e->proxy->home, e->aor);
+    while (e->bindings)
+      binding_destroy(e->proxy->home, e->bindings);
+    msg_header_free(e->proxy->home, (void *)e->contacts);
+    su_free(e->proxy->home, e);
+  }
+}
+
+LIST_BODIES(static, registration_entry, struct registration_entry, next, prev);
+
+/* ---------------------------------------------------------------------- */
+/* Bindings */
+
+static
+struct binding *binding_new(su_home_t *home, 
+			    sip_contact_t *contact,
+			    sip_call_id_t *call_id,
+			    uint32_t cseq,
+			    sip_time_t registered, 
+			    sip_time_t expires)
+{
+  struct binding *b;
+  
+  b = su_zalloc(home, sizeof *b);
+
+  if (b) {
+    sip_contact_t m[1];
+    *m = *contact; m->m_next = NULL;
+
+    b->contact = sip_contact_dup(home, m);
+    b->call_id = sip_call_id_dup(home, call_id);
+    b->cseq = cseq;
+    b->registered = registered;
+    b->expires = expires;
+
+    if (!b->contact || !b->call_id)
+      binding_destroy(home, b), b = NULL;
+
+    if (b)
+      msg_header_remove_param(b->contact->m_common, "expires");
+  }
+  
+  return b;
+}
+
+static
+void binding_destroy(su_home_t *home, struct binding *b)
+{
+  if (b->prev) {
+    if ((*b->prev = b->next))
+      b->next->prev = b->prev;
+  }
+  msg_header_free(home, (void *)b->contact);
+  msg_header_free(home, (void *)b->call_id);
+  su_free(home, b);
+}
+
+static
+int binding_update(struct proxy *p,
+		   auth_status_t *as,
+		   struct registration_entry *e,
+		   sip_t const *sip)
+{
+  struct binding *b, *old, *next, *last, *bindings = NULL, **bb = &bindings;
+  sip_contact_t *m;
+  sip_time_t expires;
+
+  sip_time_t now = sip_now();
+
+  assert(sip->sip_contact);
+
+  /* Create new bindings */
+  for (m = sip->sip_contact; m; m = m->m_next) {
+    if (m->m_url->url_type == url_any)
+      break;
+    
+    expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+				  p->prefs.expires, now);
+
+    if (expires > p->prefs.max_expires)
+      expires = p->prefs.max_expires;
+
+    msg_header_remove_param(m->m_common, "expires");
+
+    b = binding_new(p->home, m, sip->sip_call_id, sip->sip_cseq->cs_seq, 
+		    now, now + expires);
+    if (!b)
+      break;
+
+    *bb = b, b->prev = bb, bb = &b->next;
+  }
+
+  last = NULL;
+
+  if (m == NULL) {
+    /* Merge new bindings with old ones */
+    for (old = e->bindings; old; old = next) {
+      next = old->next;
+
+      for (b = bindings; b != last; b = b->next) {
+	if (url_cmp_all(old->contact->m_url, b->contact->m_url) != 0) 
+	  continue;
+
+	if (strcmp(old->call_id->i_id, b->call_id->i_id) == 0) {
+	  b->registered = old->registered;
+	}
+	binding_destroy(p->home, old);
+	break;
+      }
+    }
+
+    for (bb = &e->bindings; *bb; bb = &(*bb)->next)
+      ;
+
+    if ((*bb = bindings))
+      bindings->prev = bb;
+  }
+  else if (m->m_url->url_type == url_any) {
+    /* Unregister all */
+    for (b = e->bindings; b; b = b->next) {
+      b->expires = now;
+    }
+  }
+  else {
+    /* Infernal error */
+
+    for (old = bindings; old; old = next) {
+      next = old->next;
+      binding_destroy(p->home, old);
+    }
+
+    return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+  }
+
+  return 0;
+}
+
+sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings)
+{
+  sip_contact_t *retval = NULL, **mm = &retval; 
+  struct binding *b;
+  sip_time_t now = sip_now();
+
+  for (b = bindings; b; b = b->next) {
+    char const *expires;
+    if (b->expires <= now)
+      continue;
+    *mm = sip_contact_copy(home, b->contact);
+    if (*mm) {
+      expires = su_sprintf(home, "expires=%u", (unsigned)(b->expires - now));
+      msg_header_add_param(home, (*mm)->m_common, expires);
+      mm = &(*mm)->m_next;
+    }
+  }
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_PROXY_H
+#define TEST_PROXY_H
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+
+SOFIA_BEGIN_DECLS
+
+struct proxy;
+
+struct proxy *test_proxy_create(su_root_t *, tag_type_t, tag_value_t, ...);
+
+void test_proxy_destroy(struct proxy *);
+
+url_t const *test_proxy_uri(struct proxy const *);
+
+void test_proxy_set_expiration(struct proxy *,
+			       sip_time_t min_expires, 
+			       sip_time_t expires, 
+			       sip_time_t max_expires);
+
+void test_proxy_get_expiration(struct proxy *,
+			       sip_time_t *return_min_expires, 
+			       sip_time_t *return_expires, 
+			       sip_time_t *return_max_expires);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1026 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_re_invite.c
+ * @brief Test re_inviteing, outbound, nat traversal.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+int accept_call_immediately(CONDITION_PARAMS);
+
+/* ======================================================================== */
+/* NUA-9 tests: REFER */
+
+int test_refer0(struct context *ctx, int refer_with_id, char const *tests);
+int test_refer1(struct context *ctx, int refer_with_id, char const *tests);
+
+int test_refer(struct context *ctx)
+{
+  /* test twice, once without id and once with id */
+  return
+    test_refer0(ctx, 0, "NUA-9.1") ||
+    test_refer0(ctx, 1, "NUA-9.2") ||
+    test_refer1(ctx, 0, "NUA-9.3");
+}
+
+/* Referred call:
+
+   A			B
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<------REFER--------|
+   |-------200 OK------>|			C
+  [|-------NOTIFY------>|]			|
+  [|<------200 OK-------|]			|
+   |			|			|
+   |			|			|
+   |<-----SUBSCRIBE-----|                       |
+   |-------200 OK------>|			|
+   |			|			|
+   |			|			|
+   |-----------------INVITE-------------------->|
+   |			|			|
+   |<------------------180----------------------|
+   |-------NOTIFY------>|			|
+   |<------200 OK-------|			|
+   |			|			|
+   |<------------------200----------------------|
+   |-------NOTIFY------>|			|
+   |<------200 OK-------|			|
+   |-------------------ACK--------------------->|
+   |			|			|
+   |--------BYE-------->|			|
+   |<------200 OK-------|			|
+   |			X			|
+   |			 			|
+   |-------------------BYE--------------------->|
+   |<------------------200----------------------|
+   |						|
+
+*/
+
+int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c;
+  struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+  struct call *a_c2;
+  struct event *e;
+  sip_t const *sip;
+  sip_event_t const *a_event, *b_event;
+  sip_refer_to_t const *refer_to;
+  sip_referred_by_t const *referred_by;
+
+  sip_refer_to_t r0[1];
+  sip_to_t to[1];
+
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+
+  su_home_auto(tmphome, sizeof(tmphome));
+
+  if (print_headings)
+    printf("TEST %s: REFER: refer A to C\n", tests);
+
+  if (print_headings)
+    printf("TEST %s.1: REFER: make a call between A and B\n", tests);
+
+  /* Do (not) include id with first implicit Event: refer */
+  nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
+  call_init(a_c2);
+  a_c2->events = (void *)(a_c2 + 1);
+  eventlist_init(a_c2->events);
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+  a_c2->sdp   = "m=audio 5012 RTP/AVP 8";
+  c_call->sdp = "m=audio 5014 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.1: PASSED\n", tests);
+
+  /* ---------------------------------------------------------------------- */
+  /* REFER (initial NOTIFY is no more sent)
+   A                    B
+   |<------REFER--------|
+   |-------200 OK------>|
+  [|-------NOTIFY------>|]			|
+  [|<------200 OK-------|]			|
+   */
+
+  if (print_headings)
+    printf("TEST %s.2: refer A to C\n", tests);
+
+  *sip_refer_to_init(r0)->r_url = *c->contact->m_url;
+  r0->r_url->url_headers = "subject=referred";
+  r0->r_display = "C";
+
+  REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
+  run_ab_until(ctx, -1, save_until_received,
+	       -1, save_until_final_response);
+
+  /*
+    Events in A:
+    nua_i_refer
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
+  TEST(e->data->e_status, 202);
+  a_event = NULL;
+  TEST(tl_gets(e->data->e_tags,
+	       NUTAG_REFER_EVENT_REF(a_event),
+	       TAG_END()), 1);
+  TEST_1(a_event); TEST_1(a_event = sip_event_dup(tmphome, a_event));
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_refer_to);
+  TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
+  TEST_1(sip->sip_referred_by);
+  TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
+  if (e->next) {
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(!e->next);
+  }
+  free_events_in_list(ctx, a->events);
+
+  /*
+     Events in B after nua_refer():
+     nua_r_refer
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
+  TEST(e->data->e_status, 100);
+  TEST(tl_gets(e->data->e_tags,
+	       NUTAG_REFER_EVENT_REF(b_event),
+	       TAG_END()), 1);
+  TEST_1(b_event); TEST_1(b_event->o_id);
+  TEST_1(b_event = sip_event_dup(tmphome, b_event));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
+  TEST(e->data->e_status, 202);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
+#if 0
+  if (!e->next)
+    run_b_until(ctx, -1, save_until_received);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+  TEST_1(!e->next);
+#endif
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.2: PASSED\n", tests);
+
+#if 0
+  /* ---------------------------------------------------------------------- */
+  /*
+   A                    B
+   |<-----SUBSCRIBE-----|
+   |-------200 OK------>|
+   |-------NOTIFY------>|			|
+   |<------200 OK-------|			|
+   */
+
+  if (print_headings)
+    printf("TEST %s.3: extend expiration time for implied subscription\n", tests);
+
+  SUBSCRIBE(b, b_call, b_call->nh,
+	    SIPTAG_EVENT(b_event),
+	    SIPTAG_EXPIRES_STR("3600"),
+	    TAG_END());
+  run_ab_until(ctx, -1, save_until_final_response,
+	       -1, save_until_final_response);
+
+  /*
+    Events in A:
+    nua_i_subscribe, nua_r_notify
+  */
+  TEST_1(e = a->events->head); 
+  if (e->data->e_event == nua_r_notify)
+    TEST_1(e = e->next);
+  TEST_E(e->data->e_event, nua_i_subscribe);
+  TEST(e->data->e_status, 202);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+     Events in B after nua_subscribe():
+     nua_r_subscribe, nua_i_notify
+  */
+  TEST_1(e = b->events->head); 
+  if (e->data->e_event == nua_i_notify) {
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+  TEST_1(e = e->next);
+  }
+  TEST_E(e->data->e_event, nua_r_subscribe);
+  TEST(e->data->e_status, 202);
+  if (!e->next)
+    run_b_until(ctx, -1, save_until_received);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.3: PASSED\n", tests);
+#endif
+
+  /* ---------------------------------------------------------------------- */
+  /*
+   A                    B                       C
+   |			|			|
+   |-----------------INVITE-------------------->|
+   |			|			|
+  XXX			|			|
+   | 			|			|
+   |<------------------180----------------------|
+   |-------NOTIFY------>|			|
+   |<------200 OK-------|			|
+   | 			|			|
+  XXX			|			|
+   |			|			|
+   |<------------------200----------------------|
+   |-------NOTIFY------>|			|
+   |<------200 OK-------|			|
+   |-------------------ACK--------------------->|
+   */
+
+  if (print_headings)
+    printf("TEST %s.4: A invites C\n", tests);
+
+  *sip_to_init(to)->a_url = *refer_to->r_url;
+  to->a_display = refer_to->r_display;
+
+  a->call->next = a_c2;
+
+  TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
+
+  INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
+	 NUTAG_REFER_EVENT(a_event),
+	 NUTAG_NOTIFY_REFER(a_call->nh),
+	 SOATAG_USER_SDP_STR(a_c2->sdp),
+	 SIPTAG_REFERRED_BY(referred_by),
+	 TAG_END());
+
+  run_abc_until(ctx,
+		-1, until_ready,
+		-1, save_until_received,
+		-1, accept_call_immediately);
+  /* XXX - we should use accept_call instead of accept_call_immediately but
+     nua has a problem with automatically generated NOTIFYs:
+     3rd NOTIFY is not sent because 2nd is still in progress
+  */
+
+  /* Client A transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
+     nua_i_notify
+
+     XXX should be:
+     CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
+     optional: nua_i_notify
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+     nua_i_notify
+     optional: nua_i_notify
+  */
+  TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a_c2->events);
+
+  if (a->events->head == NULL)
+    run_a_until(ctx, -1, save_until_received);
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+     Events in B after nua_refer():
+     nua_i_notify
+  */
+  if (b->events->head == NULL)
+    run_b_until(ctx, -1, save_until_received);
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /*
+   C transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  if (print_headings)
+    printf("TEST %s.4: PASSED\n", tests);
+
+  /* ---------------------------------------------------------------------- */
+  /*
+ A                    B
+ |---------BYE------->|
+ |<--------200--------|
+   */
+
+  if (print_headings)
+    printf("TEST %s.5.1: terminate call between A and B\n", tests);
+
+  BYE(a, a_call, a_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /*
+   Transitions of A:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* Transitions of B:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.5.1: PASSED\n", tests);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+
+  /* ---------------------------------------------------------------------- */
+  /*
+   A                                            C
+   |-------------------BYE--------------------->|
+   |<------------------200----------------------|
+   */
+
+  if (print_headings)
+    printf("TEST %s.5.2: terminate call between A and C\n", tests);
+
+  BYE(a, a_c2, a_c2->nh, TAG_END());
+  run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
+
+  /*
+   Transitions of A:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a_c2->events);
+
+  /* Transitions of B:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  if (print_headings)
+    printf("TEST %s.5.2: PASSED\n", tests);
+
+  nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
+  a->call->next = NULL; free(a_c2);
+
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST %s: PASSED\n", tests);
+
+  su_home_deinit(tmphome);
+
+  END();
+}
+
+
+/*
+ accept_call_immediately
+                      X
+ |                    |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |                    |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call_immediately(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_received:
+    RESPOND(ep, call, nh, SIP_200_OK,
+	    TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+	    TAG_END());
+    return 0;
+  case nua_callstate_ready:
+    return 1;
+  case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/*
+ X      INVITE
+ |                    |
+ |-----------------INVITE-------------------->|
+ |                    |                       |
+ |                    |                       |
+ |<------------------200----------------------|
+ |-------NOTIFY------>|			      |
+ |--------BYE-------->|			      |
+ |-------------------ACK--------------------->|
+
+*/
+int notify_until_terminated(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (event == nua_r_invite) {
+    sip_status_t *st = sip->sip_status;
+    sip_payload_t *pl;
+
+    pl = sip_payload_format(NULL, "SIP/2.0 %u %s\r\n", 
+			    st->st_status, st->st_phrase);
+
+    NOTIFY(ep, ep->call, ep->call->nh,
+	   SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+	   SIPTAG_PAYLOAD(pl),
+	   TAG_IF(st->st_status >= 200,
+		  NUTAG_SUBSTATE(nua_substate_terminated)),
+	   TAG_END());
+
+    BYE(ep, ep->call, ep->call->nh, TAG_END());
+    return 0;
+  }
+
+  if (call != ep->call)
+    return 0;
+
+  switch (callstate(tags)) {
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/* Referred call - NOTIFY and BYE are overlapped
+
+   A			B
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<------REFER--------|
+   |-------200 OK------>|			C
+  [|-------NOTIFY------>|]			|
+  [|<------200 OK-------|]			|
+   |			|			|
+   |			|			|
+   |<-----SUBSCRIBE-----|                       |
+   |-------200 OK------>|			|
+   |			|			|
+   |			|			|
+   |-----------------INVITE-------------------->|
+   |			|			|
+   |			|			|
+   |<------------------200----------------------|
+   |-------NOTIFY------>|			|
+   |--------BYE-------->|			|
+   |-------------------ACK--------------------->|
+   |<------200 OK-------|			|
+   |<------200 OK-------|			|
+   |			X			|
+   |			 			|
+   |-------------------BYE--------------------->|
+   |<------------------200----------------------|
+   |						|
+
+*/
+
+int test_refer1(struct context *ctx, int refer_with_id, char const *tests)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c;
+  struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+  struct call *a_c2;
+  struct event *e;
+  sip_t const *sip;
+  sip_event_t const *a_event, *b_event;
+  sip_refer_to_t const *refer_to;
+  sip_referred_by_t const *referred_by;
+
+  sip_refer_to_t r0[1];
+  sip_to_t to[1];
+
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+
+  su_home_auto(tmphome, sizeof(tmphome));
+
+  if (print_headings)
+    printf("TEST %s: REFER: refer A to C\n", tests);
+
+  if (print_headings)
+    printf("TEST %s.1: REFER: make a call between A and B\n", tests);
+
+  /* Do (not) include id with first implicit Event: refer */
+  nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
+  run_a_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
+  call_init(a_c2);
+  a_c2->events = (void *)(a_c2 + 1);
+  eventlist_init(a_c2->events);
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+  a_c2->sdp   = "m=audio 5012 RTP/AVP 8";
+  c_call->sdp = "m=audio 5014 RTP/AVP 0 8";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.1: PASSED\n", tests);
+
+  /* ---------------------------------------------------------------------- */
+  /* REFER (initial NOTIFY is no more sent)
+   A                    B
+   |<------REFER--------|
+   |-------200 OK------>|
+  [|-------NOTIFY------>|]			|
+  [|<------200 OK-------|]			|
+   */
+
+  if (print_headings)
+    printf("TEST %s.2: refer A to C\n", tests);
+
+  *sip_refer_to_init(r0)->r_url = *c->contact->m_url;
+  r0->r_url->url_headers = "subject=referred";
+  r0->r_display = "C";
+
+  REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
+  run_ab_until(ctx, -1, save_until_received,
+	       -1, save_until_final_response);
+
+  /*
+    Events in A:
+    nua_i_refer
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
+  TEST(e->data->e_status, 202);
+  a_event = NULL;
+  TEST(tl_gets(e->data->e_tags,
+	       NUTAG_REFER_EVENT_REF(a_event),
+	       TAG_END()), 1);
+  TEST_1(a_event); TEST_1(a_event = sip_event_dup(tmphome, a_event));
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_refer_to);
+  TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
+  TEST_1(sip->sip_referred_by);
+  TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
+  if (e->next) {
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(!e->next);
+  }
+  free_events_in_list(ctx, a->events);
+
+  /*
+     Events in B after nua_refer():
+     nua_r_refer
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
+  TEST(e->data->e_status, 100);
+  TEST(tl_gets(e->data->e_tags,
+	       NUTAG_REFER_EVENT_REF(b_event),
+	       TAG_END()), 1);
+  TEST_1(b_event); TEST_1(b_event->o_id);
+  TEST_1(b_event = sip_event_dup(tmphome, b_event));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
+  TEST(e->data->e_status, 202);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
+#if 0
+  if (!e->next)
+    run_b_until(ctx, -1, save_until_received);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+  TEST_1(!e->next);
+#endif
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST %s.2: PASSED\n", tests);
+
+
+  /* ---------------------------------------------------------------------- */
+  /*
+   A                    B                       C
+   |			|			|
+   |-----------------INVITE-------------------->|
+   |			|			|
+  XXX			|			|
+   |			|			|
+   |<------------------200----------------------|
+   |-------NOTIFY------>|			|
+   |---------BYE------->|			|
+   |-------------------ACK--------------------->|
+   |<--------200--------|			|
+   |<------200 OK-------|			|
+   |                    X
+     */
+
+  if (print_headings)
+    printf("TEST %s.4: A invites C\n", tests);
+
+  *sip_to_init(to)->a_url = *refer_to->r_url;
+  to->a_display = refer_to->r_display;
+
+  a->call->next = a_c2;
+
+  TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
+
+  INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
+	 NUTAG_REFER_EVENT(a_event),
+	 /* NUTAG_NOTIFY_REFER(a_call->nh), */
+	 SOATAG_USER_SDP_STR(a_c2->sdp),
+	 SIPTAG_REFERRED_BY(referred_by),
+	 TAG_END());
+
+  run_abc_until(ctx,
+		-1, notify_until_terminated,
+		-1, until_terminated,
+		-1, accept_call_immediately);
+
+  /* XXX - we should use accept_call instead of accept_call_immediately but
+     nua has a problem with automatically generated NOTIFYs:
+     3rd NOTIFY is not sent because 2nd is still in progress
+  */
+
+  /* Client A transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
+     nua_r_notify
+
+     Transitions of first call:
+     READY --(T2)--> TERMINATING: nua_bye()
+     TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+
+     XXX should be:
+     CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
+     optional: nua_i_notify
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+     nua_i_notify
+     optional: nua_i_notify
+  */
+  TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a_c2->events);
+
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /*
+     Events in B after nua_refer():
+     nua_i_notify
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  if (b->events->head == NULL)
+    run_b_until(ctx, -1, save_until_received);
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
+  TEST_1(sip->sip_event);
+  if (refer_with_id)
+    TEST_S(sip->sip_event->o_id, b_event->o_id);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  /*
+   C transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  if (print_headings)
+    printf("TEST %s.4: PASSED\n", tests);
+
+  /* ---------------------------------------------------------------------- */
+  /*
+   A                                            C
+   |-------------------BYE--------------------->|
+   |<------------------200----------------------|
+   */
+
+  if (print_headings)
+    printf("TEST %s.5.2: terminate call between A and C\n", tests);
+
+  BYE(a, a_c2, a_c2->nh, TAG_END());
+  run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
+
+  /*
+   Transitions of A:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a_c2->events);
+
+  /* Transitions of B:
+     READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+  */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  if (print_headings)
+    printf("TEST %s.5.2: PASSED\n", tests);
+
+  nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
+  a->call->next = NULL; free(a_c2);
+
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST %s: PASSED\n", tests);
+
+  su_home_deinit(tmphome);
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,703 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_register.c
+ * @brief Test registering, outbound, nat traversal.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_register"
+#endif
+
+/* ======================================================================== */
+/* Test REGISTER */
+
+int test_register_to_proxy(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c, *x;
+  struct call *a_reg = a->reg, *b_reg = b->reg, *c_reg = c->reg;
+  struct event *e;
+  sip_t const *sip;
+  sip_cseq_t cseq[1];
+
+  if (ctx->p)
+    test_proxy_set_expiration(ctx->p, 5, 5, 10);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.1: un-REGISTER a\n");
+
+  TEST_1(a_reg->nh = nua_handle(a->nua, a_reg, TAG_END()));
+  UNREGISTER(a, a_reg, a_reg->nh, SIPTAG_TO(a->to), 
+	     SIPTAG_CONTACT_STR("*"),
+	     TAG_END());
+  run_a_until(ctx, -1, until_final_response);  
+  AUTHENTICATE(a, a_reg, a_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":alice:secret"), TAG_END());
+  run_a_until(ctx, -1, until_final_response);
+  nua_handle_destroy(a_reg->nh);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.2: un-REGISTER b\n");
+
+  TEST_1(b_reg->nh = nua_handle(b->nua, b_reg, TAG_END()));
+  UNREGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to), 
+	     SIPTAG_CONTACT_STR("*"),
+	     TAG_END());
+  run_b_until(ctx, -1, until_final_response);  
+  AUTHENTICATE(b, b_reg, b_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":bob:secret"), TAG_END());
+  run_b_until(ctx, -1, until_final_response);
+  nua_handle_destroy(b_reg->nh);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.2: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.3: un-REGISTER c\n");
+
+  TEST_1(c_reg->nh = nua_handle(c->nua, c_reg, TAG_END()));
+  UNREGISTER(c, c_reg, c_reg->nh, SIPTAG_TO(c->to), 
+	     SIPTAG_CONTACT_STR("*"),
+	     TAG_END());
+  run_c_until(ctx, -1, until_final_response);  
+  AUTHENTICATE(c, c_reg, c_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+  run_c_until(ctx, -1, until_final_response);
+  nua_handle_destroy(c_reg->nh);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.0.3: PASSED\n");
+
+
+/* REGISTER test
+
+   A			B
+   |------REGISTER----->|
+   |<-------401---------|
+   |------REGISTER----->|
+   |<-------200---------|
+   |			|
+
+*/
+
+  if (print_headings)
+    printf("TEST NUA-2.3.1: REGISTER a\n");
+
+  TEST_1(a_reg->nh = nua_handle(a->nua, a_reg, TAG_END()));
+
+  sip_cseq_init(cseq)->cs_seq = 12;
+  cseq->cs_method = sip_method_register;
+  cseq->cs_method_name = sip_method_name_register;
+
+  REGISTER(a, a_reg, a_reg->nh, SIPTAG_TO(a->to),
+	   NUTAG_OUTBOUND("natify options-keepalive validate"),
+	   NUTAG_KEEPALIVE(1000),
+	   NUTAG_M_DISPLAY("A&A"),
+	   NUTAG_M_USERNAME("a"),
+	   SIPTAG_CSEQ(cseq),
+	   TAG_END());
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(e->data->e_status, 401);
+  TEST(sip->sip_status->st_status, 401);
+  TEST(sip->sip_cseq->cs_seq, 13);
+  TEST_1(!sip->sip_contact);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  AUTHENTICATE(a, a_reg, a_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":alice:secret"), TAG_END());
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_contact);
+  { char const *expect_m_display = "\"A&A\"";
+    /* VC does not dig \" with TEST_S() */
+  TEST_S(sip->sip_contact->m_display, expect_m_display); }
+  TEST_S(sip->sip_contact->m_url->url_user, "a");
+  TEST(sip->sip_cseq->cs_seq, 14);
+
+  if (ctx->nat) {
+    TEST_1(e = a->specials->head);
+  }
+
+  if (print_headings)
+    printf("TEST NUA-2.3.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.3.2: REGISTER b\n");
+
+  TEST_1(b_reg->nh = nua_handle(b->nua, b_reg, TAG_END()));
+
+  /* Test application-supplied contact */
+  {
+    sip_contact_t m[1];
+    sip_contact_init(m)->m_url[0] = b->contact->m_url[0];
+
+    m->m_display = "B";
+    m->m_url->url_user = "b";
+
+    REGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to), 
+	     SIPTAG_CONTACT(m),
+	     TAG_END());
+  }
+  run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
+
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(e->data->e_status, 401);
+  TEST(sip->sip_status->st_status, 401);
+  TEST_1(!sip->sip_contact);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  AUTHENTICATE(b, b_reg, b_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":bob:secret"), TAG_END());
+  run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
+
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_contact);
+  TEST_S(sip->sip_contact->m_display, "B");
+  TEST_S(sip->sip_contact->m_url->url_user, "b");
+
+  if (print_headings)
+    printf("TEST NUA-2.3.2: PASSED\n");
+
+  if (ctx->p)
+    test_proxy_set_expiration(ctx->p, 600, 3600, 36000);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.3: REGISTER c\n");
+
+  TEST_1(c_reg->nh = nua_handle(c->nua, c_reg, TAG_END()));
+
+  REGISTER(c, c_reg, c_reg->nh, SIPTAG_TO(c->to), 
+	   NUTAG_M_DISPLAY("C"),
+	   NUTAG_M_USERNAME("c"),
+	   SIPTAG_EXPIRES_STR("5"), /* Test 423 negotiation */
+	   TAG_END());
+  run_abc_until(ctx, -1, save_events, -1, save_events, 
+		-1, save_until_final_response);
+
+  TEST_1(e = c->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(e->data->e_status, 401);
+  TEST(sip->sip_status->st_status, 401);
+  TEST_1(!sip->sip_contact);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  AUTHENTICATE(c, c_reg, c_reg->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+  run_abc_until(ctx, -1, save_events, -1, save_events, 
+		-1, save_until_final_response);
+
+  TEST_1(e = c->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(sip->sip_status->st_status, 423);
+  TEST_1(e = e->next);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_contact);
+  TEST_S(sip->sip_contact->m_display, "C");
+  TEST_S(sip->sip_contact->m_url->url_user, "c");
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.3: PASSED\n");
+
+  if (!ctx->p) {
+    free_events_in_list(ctx, a->events);
+    free_events_in_list(ctx, b->events);
+    return 0;
+  }
+
+  if (print_headings)
+    printf("TEST NUA-2.3.4: refresh REGISTER\n");
+
+  /* Wait for A and B to refresh their registrations */
+
+  /*
+   * Avoid race condition: if X has already refreshed registration
+   * with expiration time of 3600 seconds, do not wait for new refresh
+   */
+  a->next_condition = save_until_final_response;
+  b->next_condition = save_until_final_response;
+
+  for (x = a; x; x = x == a ? b : NULL) {
+    for (e = x->events->head; e; e = e->next) {
+      if (e->data->e_event == nua_r_register &&
+	  e->data->e_status == 200 &&
+	  (sip = sip_object(e->data->e_msg)) &&
+	  sip->sip_contact &&
+	  sip->sip_contact->m_expires &&
+	  strcmp(sip->sip_contact->m_expires, "3600") == 0) {
+	x->next_condition = NULL;
+	break;
+      }
+    }
+  }
+
+  run_ab_until(ctx, -1, a->next_condition, -1, b->next_condition);
+  
+  for (e = a->events->head; e; e = e->next) {
+    TEST_E(e->data->e_event, nua_r_register);
+    TEST(e->data->e_status, 200);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(sip->sip_contact);
+    if (!e->next)
+      break;
+  }
+  TEST_1(e);
+  TEST_S(sip->sip_contact->m_expires, "3600");
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  for (e = b->events->head; e; e = e->next) {
+    TEST_E(e->data->e_event, nua_r_register);
+    TEST(e->data->e_status, 200);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(sip->sip_contact);
+    if (!e->next)
+      break;
+  }
+  TEST_1(e);
+  TEST_S(sip->sip_contact->m_expires, "3600");
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-2.3.4: PASSED\n");
+
+  END();
+}
+
+int registrar_299(CONDITION_PARAMS)
+{
+  msg_t *request = nua_current_request(nua);
+
+  save_event_in_list(ctx, event, ep, ep->call);
+
+  if (event == nua_i_register) {
+    RESPOND(ep, call, nh, 299, "YES", NUTAG_WITH(request), TAG_END());
+    return 1;
+  }
+
+  return 0;
+}
+
+int test_register_to_c(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *b = &ctx->b, *c = &ctx->c;
+  struct call *b_call = b->call, *c_call = c->call;
+  struct event *e;
+  sip_t const *sip;
+
+  if (print_headings)
+    printf("TEST NUA-2.3.2: REGISTER b to c\n");
+
+  nua_set_params(ctx->c.nua,
+		 NUTAG_ALLOW("REGISTER"),
+		 TAG_END());
+  run_c_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(b_call->nh = nua_handle(b->nua, b_call, TAG_END()));
+
+  REGISTER(b, b_call, b_call->nh, 
+	   NUTAG_REGISTRAR((url_string_t *)c->contact->m_url),
+	   SIPTAG_TO(b->to),
+	   NUTAG_OUTBOUND(NULL),
+	   SIPTAG_CONTACT_STR(NULL),
+	   TAG_END());
+  run_bc_until(ctx, -1, save_until_final_response, -1, registrar_299);
+
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST(e->data->e_status, 299);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(!sip->sip_contact);
+
+  if (print_headings)
+    printf("TEST NUA-2.6.1: PASSED\n");
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  TEST_1(e = c->events->head);
+  TEST_E(e->data->e_event, nua_i_register);
+  TEST(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(!sip->sip_contact);
+
+  free_events_in_list(ctx, c->events);
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-2.3.4: PASSED\n");
+
+  END();
+}
+
+
+int test_register(struct context *ctx)
+{
+  if (test_register_to_c(ctx))
+    return 1;
+
+  if (ctx->proxy_tests)
+    if (test_register_to_proxy(ctx)) return 1;
+
+  return 0;
+}
+
+
+int test_connectivity(struct context *ctx)
+{
+  if (!ctx->proxy_tests)
+    return 0;			/* No proxy */
+
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c;
+  struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+  struct event *e;
+  sip_t const *sip;
+
+  /* Connectivity test using OPTIONS */
+
+  if (print_headings)
+    printf("TEST NUA-2.4.1: OPTIONS from A to B\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  OPTIONS(a, a_call, a_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	  NUTAG_ALLOW("OPTIONS"),
+	  TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+  /* Client events: nua_options(), nua_r_options */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+  /* TEST_1(sip->sip_content_type); */
+  /* TEST_1(sip->sip_payload); */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /* Server events: nua_i_options */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-2.4.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.4.2: OPTIONS from B to C\n");
+
+  TEST_1(b_call->nh = nua_handle(b->nua, b_call, SIPTAG_TO(c->to), TAG_END()));
+
+  OPTIONS(b, b_call, b_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(c->contact->m_url)),
+	  TAG_END());
+
+  run_abc_until(ctx, -1, NULL,
+		-1, save_until_final_response,
+		-1, save_until_received);
+
+  /* Client events: nua_options(), nua_r_options */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+  /* TEST_1(sip->sip_content_type); */
+  /* TEST_1(sip->sip_payload); */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  /* Server events: nua_i_options */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, c->events);
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-2.4.2: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-2.4.3: OPTIONS from C to A\n");
+
+  TEST_1(c_call->nh = nua_handle(c->nua, c_call, SIPTAG_TO(a->to), TAG_END()));
+
+  OPTIONS(c, c_call, c_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(a->contact->m_url)),
+	  TAG_END());
+
+  if (ctx->proxy_tests) {
+    run_abc_until(ctx, -1, NULL, -1, NULL, -1, save_until_final_response);
+
+    /* Client events: nua_options(), nua_r_options */
+    TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_r_options);
+    TEST(e->data->e_status, 407);
+    TEST_1(!e->next);
+
+    free_events_in_list(ctx, c->events);
+
+    AUTHENTICATE(c, c_call, c_call->nh,
+		 NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"),
+		 TAG_END());
+  }
+
+  run_abc_until(ctx, -1, save_until_received,
+		-1, NULL,
+		-1, save_until_final_response);
+
+  /* Client events: nua_options(), nua_r_options */
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_r_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+  /* TEST_1(sip->sip_content_type); */
+  /* TEST_1(sip->sip_payload); */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, c->events);
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  /* Server events: nua_i_options */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_options);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-2.4.3: PASSED\n");
+
+  END();
+}
+
+int test_nat_timeout(struct context *ctx)
+{
+  if (!ctx->proxy_tests || !ctx->nat)
+    return 0;			/* No proxy */
+
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c;
+  struct event *e;
+  sip_t const *sip;
+
+  /* Test what happens when NAT bindings go away */
+
+  if (print_headings)
+    printf("TEST NUA-2.5.1: NAT binding change\n");
+
+  free_events_in_list(ctx, a->specials);
+
+  test_nat_flush(ctx->nat);	/* Break our connections */
+
+  /* Run until we get final response to REGISTER */
+  run_a_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = a->specials->head);
+  TEST_E(e->data->e_event, nua_i_outbound);
+  TEST(e->data->e_status, 102);
+  TEST_S(e->data->e_phrase, "NAT binding changed");
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->specials);
+
+  TEST_1(e = a->events->head);
+  TEST_E(e->data->e_event, nua_r_register);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-2.5.1: PASSED\n");
+  
+  (void)b; (void)c; (void)sip;
+
+  END();
+}
+
+int test_unregister(struct context *ctx)
+{
+  if (!ctx->proxy_tests)
+    return 0;			/* No proxy */
+
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b, *c = &ctx->c;
+  struct event *e;
+  sip_t const *sip;
+
+/* un-REGISTER test
+
+   A			B
+   |----un-REGISTER---->|
+   |<-------200---------|
+   |			|
+
+*/
+  if (print_headings)
+    printf("TEST NUA-13.1: un-REGISTER a\n");
+
+  if (a->reg->nh) {
+    free_events_in_list(ctx, a->events);
+    UNREGISTER(a, NULL, a->reg->nh, TAG_END());
+    run_a_until(ctx, -1, save_until_final_response);
+    TEST_1(e = a->events->head);
+    TEST_E(e->data->e_event, nua_r_unregister);
+    TEST(e->data->e_status, 200);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(!sip->sip_contact);
+    TEST_1(!e->next);
+    free_events_in_list(ctx, a->events);
+    nua_handle_destroy(a->reg->nh), a->reg->nh = NULL;
+  }
+
+  if (print_headings)
+    printf("TEST NUA-13.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-13.2: un-REGISTER b\n");
+
+  if (b->reg->nh) {
+    free_events_in_list(ctx, b->events);
+    UNREGISTER(b, NULL, b->reg->nh, TAG_END());
+    run_b_until(ctx, -1, save_until_final_response);
+    TEST_1(e = b->events->head);
+    TEST_E(e->data->e_event, nua_r_unregister);
+    TEST(e->data->e_status, 200);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(!sip->sip_contact);
+    TEST_1(!e->next);
+    free_events_in_list(ctx, b->events);
+    nua_handle_destroy(b->reg->nh), b->reg->nh = NULL;
+  }
+  if (print_headings)
+    printf("TEST NUA-13.2: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-13.3: un-REGISTER c\n");
+
+  /* Unregister using another handle */
+  free_events_in_list(ctx, c->events);
+  TEST_1(c->call->nh = nua_handle(c->nua, c->call, TAG_END()));
+  UNREGISTER(c, c->call, c->call->nh, SIPTAG_TO(c->to), 
+	     NUTAG_M_DISPLAY("C"),
+	     NUTAG_M_USERNAME("c"),
+	     TAG_END());
+  run_c_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = c->events->head);
+  TEST_E(e->data->e_event, nua_r_unregister);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST(e->data->e_status, 401);
+  TEST(sip->sip_status->st_status, 401);
+  TEST_1(!sip->sip_contact);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+
+  AUTHENTICATE(c, c->call, c->call->nh,
+	       NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+  run_c_until(ctx, -1, save_until_final_response);
+
+  TEST_1(e = c->events->head);
+  TEST_E(e->data->e_event, nua_r_unregister);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(!sip->sip_contact);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, c->events);
+  nua_handle_destroy(c->call->nh), c->call->nh = NULL;
+
+  if (c->reg->nh) {
+    UNREGISTER(c, NULL, c->reg->nh, TAG_END());
+    run_c_until(ctx, -1, save_until_final_response);
+    TEST_1(e = c->events->head);
+    TEST_E(e->data->e_event, nua_r_unregister);
+    TEST(e->data->e_status, 200);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(!sip->sip_contact);
+    TEST_1(!e->next);
+    free_events_in_list(ctx, c->events);
+    nua_handle_destroy(c->reg->nh), c->reg->nh = NULL;
+  }
+
+  if (print_headings)
+    printf("TEST NUA-13.3: PASSED\n");
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,319 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_re_invite.c
+ * @brief NUA-8 tests: Session timer, UPDATE
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+/* ======================================================================== */
+
+int test_session_timer(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+/* Session timer test:
+
+   A	      P		B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |------------------->|
+   |			|
+   |			|
+   |--INVITE->| 	|
+   |<--422----|		|
+   |---ACK--->|		|
+   |			|
+   |-------INVITE------>|
+   |<-------422---------|
+   |--------ACK-------->|
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+
+*/
+
+  if (print_headings)
+    printf("TEST NUA-8.1.1: Session timers\n");
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+  nua_set_params(ctx->b.nua,
+		 NUTAG_SESSION_REFRESHER(nua_any_refresher),
+		 TAG_END());
+
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_SUPPORTED_STR("100rel"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
+  TEST_S(sip->sip_session_expires->x_refresher, "uas");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-8.1.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-8.1.2: Session timers negotiation\n");
+
+  nua_set_hparams(b_call->nh,
+		  NUTAG_AUTOANSWER(0),
+		  NUTAG_MIN_SE(120),
+		  TAG_END());
+
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 SIPTAG_SUPPORTED_STR("100rel, timer"),
+	 NUTAG_SESSION_TIMER(15),
+	 NUTAG_MIN_SE(5),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  /* Client transitions:
+     INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+     CALLING -(C6a)-> (TERMINATED/INIT): nua_r_invite
+     when testing with proxy, second 422 when call reaches UAS:
+       (INIT) -(C1)-> CALLING: nua_i_state
+       CALLING -(C6a)-> (TERMINATED/INIT): nua_r_invite
+     (INIT) -(C1)-> CALLING: nua_i_state
+     CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+     PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 100);
+  TEST(sip_object(e->data->e_msg)->sip_status->st_status, 422);
+
+  if (ctx->proxy_tests) {
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+    TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+    TEST_1(is_offer_sent(e->data->e_tags));
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+    TEST(e->data->e_status, 100);
+    TEST(sip_object(e->data->e_msg)->sip_status->st_status, 422);
+  }
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 180);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
+  TEST(sip->sip_session_expires->x_delta, 120);
+  TEST_S(sip->sip_session_expires->x_refresher, "uac");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server transitions:
+   INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+   RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+   EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+   COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  TEST(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
+  TEST_1(!sip->sip_session_expires->x_refresher);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-8.1: PASSED\n");
+
+  if (print_headings)
+    printf("TEST NUA-8.2: use UPDATE\n");
+
+  UPDATE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+  /* Events from B (who sent UPDATE) */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_offer_sent(e->data->e_tags));
+  if (!e->next)
+    run_b_until(ctx, -1, until_ready);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_answer_recv(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* Events from A (who received UPDATE) */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_update);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST_1(is_offer_recv(e->data->e_tags));
+  TEST_1(is_answer_sent(e->data->e_tags));
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+  /* B transitions:
+   READY --(T2)--> TERMINATING: nua_bye()
+   TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, b->events);
+
+  /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+  TEST(e->data->e_status, 200);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-8.2: PASSED\n");
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,632 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_simple.c
+ * @brief NUA-11: Test SIMPLE methods: MESSAGE, PUBLISH and SUBSCRIBE/NOTIFY.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_simple"
+#endif
+
+int test_message(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+  url_t url[1];
+
+/* Message test
+
+   A			B
+   |-------MESSAGE----->|
+   |<-------200---------|
+   |			|
+
+*/
+  if (print_headings)
+    printf("TEST NUA-11.1: MESSAGE\n");
+
+  if (ctx->proxy_tests)
+    *url = *b->to->a_url;
+  else
+    *url = *b->contact->m_url;
+
+  /* Test that query part is included in request sent to B */
+  url->url_headers = "organization=United%20Testers";
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, TAG_END()));
+
+  MESSAGE(a, a_call, a_call->nh,
+	  NUTAG_URL(url),
+	  SIPTAG_SUBJECT_STR("NUA-11.1"),
+	  SIPTAG_CONTENT_TYPE_STR("text/plain"),
+	  SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
+	  TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+  /* Client events:
+     nua_message(), nua_r_message
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_message);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  /*
+   Server events:
+   nua_i_message
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_message);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subject && sip->sip_subject->g_string);
+  TEST_S(sip->sip_subject->g_string, "NUA-11.1");
+  TEST_1(sip->sip_organization);
+  TEST_S(sip->sip_organization->g_string, "United Testers");
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.1: PASSED\n");
+
+
+/* Message test
+
+   A
+   |-------MESSAGE--\
+   |<---------------/
+   |--------200-----\
+   |<---------------/
+   |
+
+*/
+  if (print_headings)
+    printf("TEST NUA-11.2: MESSAGE to myself\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(a->to), TAG_END()));
+
+  MESSAGE(a, a_call, a_call->nh,
+	  /* We cannot reach us by using our contact! */
+	  NUTAG_URL(!ctx->p && !ctx->proxy_tests ? a->contact->m_url : NULL),
+	  SIPTAG_SUBJECT_STR("NUA-11.1b"),
+	  SIPTAG_CONTENT_TYPE_STR("text/plain"),
+	  SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
+	  TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  /* Events:
+     nua_message(), nua_i_message, nua_r_message
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_message);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subject && sip->sip_subject->g_string);
+  TEST_S(sip->sip_subject->g_string, "NUA-11.1b");
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_message);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.2: PASSED\n");
+
+  END();
+}
+
+int respond_with_etag(CONDITION_PARAMS)
+{
+  msg_t *with = nua_current_request(nua);
+
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+    char const *etag;
+  case nua_i_publish:
+    etag = sip->sip_if_match ? sip->sip_if_match->g_value : NULL;
+    if (sip->sip_if_match && (etag == NULL || strcmp(etag, "tagtag"))) {
+      RESPOND(ep, call, nh, SIP_412_PRECONDITION_FAILED,
+	      NUTAG_WITH(with),
+	      TAG_END());
+    } 
+    else {
+	RESPOND(ep, call, nh, SIP_200_OK,
+		NUTAG_WITH(with),
+		SIPTAG_ETAG_STR("tagtag"),
+		SIPTAG_EXPIRES_STR("3600"),
+		SIPTAG_EXPIRES(sip->sip_expires),	/* overrides 3600 */
+		TAG_END());
+    }
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+int test_publish(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+
+
+/* PUBLISH test
+
+   A			B
+   |-------PUBLISH----->|
+   |<-------405---------| (method not allowed by default)
+   |			|
+   |-------PUBLISH----->|
+   |<-------501---------| (no events allowed)
+   |			|
+   |-------PUBLISH----->|
+   |<-------489---------| (event not allowed by default)
+   |			|
+   |-------PUBLISH----->|
+   |<-------200---------| (event allowed, responded)
+   |			|
+   |-----un-PUBLISH---->|
+   |<-------200---------| (event allowed, responded)
+
+*/
+  if (print_headings)
+    printf("TEST NUA-11.3: PUBLISH\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  PUBLISH(a, a_call, a_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	  SIPTAG_EVENT_STR("presence"),
+	  SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+	  SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+	  TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+  /* Client events:
+     nua_publish(), nua_r_publish
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+  TEST(e->data->e_status, 405);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  nua_set_params(b->nua, NUTAG_ALLOW("PUBLISH"), TAG_END());
+
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  PUBLISH(a, a_call, a_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	  SIPTAG_EVENT_STR("presence"),
+	  SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+	  SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+	  TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  /* Client events:
+     nua_publish(), nua_r_publish
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+  TEST(e->data->e_status, 501);	/* Not implemented */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  /* Allow presence event */
+
+  nua_set_params(b->nua, NUTAG_ALLOW_EVENTS("presence"), TAG_END());
+
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  PUBLISH(a, a_call, a_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	  SIPTAG_EVENT_STR("reg"),
+	  SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+	  SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+	  TAG_END());
+
+  run_a_until(ctx, -1, save_until_final_response);
+
+  /* Client events:
+     nua_publish(), nua_r_publish
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+  TEST(e->data->e_status, 489);	/* Bad Event */
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  PUBLISH(a, a_call, a_call->nh,
+	  TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	  SIPTAG_EVENT_STR("presence"),
+	  SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+	  SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+	  TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, respond_with_etag);
+
+  /* Client events:
+     nua_publish(), nua_r_publish
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_etag);
+  TEST_S(sip->sip_etag->g_string, "tagtag");
+  TEST_1(!e->next);
+
+  /*
+   Server events:
+   nua_i_publish
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_publish);
+  TEST(e->data->e_status, 100);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  UNPUBLISH(a, a_call, a_call->nh, TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response, -1, respond_with_etag);
+
+  /* Client events:
+     nua_publish(), nua_r_publish
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unpublish);
+  TEST(e->data->e_status, 200);
+  TEST_1(!e->next);
+
+  /*
+   Server events:
+   nua_i_publish
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_publish);
+  TEST(e->data->e_status, 100);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.3: PASSED\n");
+  END();
+}
+
+static char const presence_open[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>open</basic></status>\n"
+    "    <contact priority='1.0'>sip:bob at example.org</contact>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+static char const presence_closed[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>closed</basic></status>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+
+int accept_and_notify(CONDITION_PARAMS)
+{
+  msg_t *with = nua_current_request(nua);
+
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_subscribe:
+    if (status < 200) {
+      RESPOND(ep, call, nh, SIP_202_ACCEPTED,
+	      NUTAG_WITH(with),
+	      SIPTAG_EXPIRES_STR("360"),
+	      TAG_END());
+      NOTIFY(ep, call, nh, 
+	     SIPTAG_EVENT(sip->sip_event),
+	     SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	     SIPTAG_PAYLOAD_STR(presence_closed),
+	     NUTAG_SUBSTATE(nua_substate_pending),
+	     TAG_END());
+    }
+    return 0;
+
+  case nua_r_notify:
+    return status >= 200;
+
+  default:
+    return 0;
+  }
+}
+
+extern int save_until_notified_and_responded(CONDITION_PARAMS);
+extern int save_until_notified(CONDITION_PARAMS);
+
+int test_subscribe_notify(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+  tagi_t const *n_tags, *r_tags;
+
+  if (print_headings)
+    printf("TEST NUA-11.4: establishing subscription without notifier\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+	    SIPTAG_EVENT_STR("presence"),
+	    SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified_and_responded,
+	       -1, accept_and_notify);
+
+  /* Client events:
+     nua_subscribe(), nua_i_notify/nua_r_subscribe
+  */
+  TEST_1(e = a->events->head);
+  if (e->data->e_event == nua_i_notify) {
+    TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_subscribe);
+    TEST(e->data->e_status, 202);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+  }
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* Server events: nua_i_subscribe, nua_r_notify */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_i_subscribe);
+  TEST_E(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-11.4: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* NOTIFY with updated content
+
+   A			B
+   |                    |
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  if (print_headings)
+    printf("TEST NUA-11.5: send NOTIFY\n");
+
+  /* Update presence data */
+
+  NOTIFY(b, b_call, b_call->nh,
+	 NUTAG_SUBSTATE(nua_substate_active),
+	 SIPTAG_EVENT_STR("presence"),
+	 SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	 SIPTAG_PAYLOAD_STR(presence_open),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified,
+	       -1, save_until_final_response);
+
+  /* subscriber events:
+     nua_i_notify
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* Notifier events: nua_r_notify */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_notify);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-11.5: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* un-SUBSCRIBE
+
+   A			B
+   |                    |
+   |------SUBSCRIBE---->|
+   |<--------202--------|
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  if (print_headings)
+    printf("TEST NUA-11.6: un-SUBSCRIBE\n");
+
+  UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response,
+	       -1, save_until_final_response);
+
+  /* Client events:
+     nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
+  */
+  TEST_1(e = a->events->head);
+  if (e->data->e_event == nua_i_notify) {
+    TEST_E(e->data->e_event, nua_i_notify);
+    n_tags = e->data->e_tags;
+    TEST_1(sip = sip_object(e->data->e_msg));
+    TEST_1(sip->sip_event);
+    TEST_1(sip->sip_subscription_state);
+    TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+    TEST_1(!sip->sip_subscription_state->ss_expires);
+    TEST_1(tl_find(n_tags, nutag_substate));
+    TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
+    TEST(e->data->e_status, 200);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_unsubscribe);
+    TEST(e->data->e_status, 200);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+  }
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /* Notifier events: nua_r_notify */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_i_subscribe);
+  TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(tl_find(e->data->e_tags, nutag_substate));
+  TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, 
+       nua_substate_terminated);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(e->data->e_status >= 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.6: PASSED\n");
+
+  END();
+}
+
+/* ======================================================================== */
+/* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */
+
+int test_simple(struct context *ctx)
+{
+  return
+    test_message(ctx)
+    || test_publish(ctx)
+    || test_subscribe_notify(ctx)
+    ;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,523 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_sip_events.c
+ * @brief NUA-12 tests: SUBSCRIBE/NOTIFY.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/nea.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+	     const void *needle, size_t needlelen);
+#endif
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_sip_events"
+#endif
+
+/* ======================================================================== */
+/* Test events methods: SUBSCRIBE/NOTIFY */
+
+/**Terminate until received notify.
+ * Save events (except nua_i_active or terminated).
+ */
+int save_until_notified(CONDITION_PARAMS)
+{
+  save_event_in_list(ctx, event, ep, call);
+  return event == nua_i_notify;
+}
+
+int save_until_notified_and_responded(CONDITION_PARAMS)
+{
+  save_event_in_list(ctx, event, ep, call);
+  if (event == nua_i_notify) ep->flags.b.bit0 = 1;
+  if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
+    if (status >= 300)
+      return 1;
+    else if (status >= 200)
+      ep->flags.b.bit1 = 1;
+  }
+
+  return ep->flags.b.bit0 && ep->flags.b.bit1;
+}
+
+
+int save_until_subscription(CONDITION_PARAMS)
+{
+  save_event_in_list(ctx, event, ep, call);
+  return event == nua_i_subscription;
+}
+
+
+int test_events(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+  tagi_t const *n_tags, *r_tags;
+  url_t b_url[1];
+  nea_sub_t *sub = NULL;
+
+  char const open[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>open</basic></status>\n"
+    "    <contact priority='1.0'>sip:bob at example.org</contact>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+  char const closed[] =
+    "<?xml version='1.0' encoding='UTF-8'?>\n"
+    "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+    "   entity='pres:bob at example.org'>\n"
+    "  <tuple id='ksac9udshce'>\n"
+    "    <status><basic>closed</basic></status>\n"
+    "  </tuple>\n"
+    "</presence>\n";
+
+
+/* SUBSCRIBE test
+
+   A			B
+   |------SUBSCRIBE---->|
+   |<--------405--------|
+   |			|
+
+*/
+  if (print_headings)
+    printf("TEST NUA-12.1: SUBSCRIBE without notifier\n");
+
+  nua_set_params(b->nua, SIPTAG_ALLOW_EVENTS(NULL), TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+	    SIPTAG_EVENT_STR("presence"),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_final_response,
+	       -1, NULL /* XXX save_until_received */);
+
+  /* Client events:
+     nua_subscribe(), nua_r_subscribe
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_subscribe);
+  TEST(e->data->e_status, 489);
+  TEST_1(!e->next);
+
+#if 0				/* XXX */
+  /*
+   Server events:
+   nua_i_subscribe
+  */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_i_subscribe);
+  TEST(e->data->e_status, 405);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event);
+  TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(!e->next);
+#endif
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-12.1: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* SUBSCRIBE test using notifier and establishing subscription
+
+   A			B
+   |                    |
+   |------SUBSCRIBE---->|
+   |<--------202--------|
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+
+  if (print_headings)
+    printf("TEST NUA-12.2: using notifier and establishing subscription\n");
+
+  TEST_1(b_call->nh = nua_handle(b->nua, b_call, TAG_END()));
+
+  *b_url = *b->contact->m_url;
+
+  NOTIFIER(b, b_call, b_call->nh,
+	   NUTAG_URL(b_url),
+	   SIPTAG_EVENT_STR("presence"),
+	   SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	   SIPTAG_PAYLOAD_STR(closed),
+	   NEATAG_THROTTLE(1),
+	   TAG_END());
+  run_b_until(ctx, nua_r_notifier, until_final_response);
+
+  SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+	    SIPTAG_EVENT_STR("presence"),
+	    SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified_and_responded,
+	       -1, NULL /* XXX save_until_received */);
+
+  /* Client events:
+     nua_subscribe(), nua_i_notify/nua_r_subscribe
+  */
+  TEST_1(e = a->events->head);
+  if (e->data->e_event == nua_i_notify) {
+    TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_subscribe);
+    TEST(e->data->e_status, 202);
+    r_tags = e->data->e_tags;
+    TEST_1(tl_find(r_tags, nutag_substate));
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+  }
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-12.2: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* NOTIFY with updated content
+
+   A			B
+   |                    |
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  if (print_headings)
+    printf("TEST NUA-12.3: update notifier\n");
+
+  /* Update presence data */
+
+  NOTIFIER(b, b_call, b_call->nh,
+	   SIPTAG_EVENT_STR("presence"),
+	   SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	   SIPTAG_PAYLOAD_STR(open),
+	   TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified,
+	       -1, NULL /* XXX save_until_received */);
+
+  /* subscriber events:
+     nua_i_notify
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value,
+       nua_substate_active);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-12.3: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* un-SUBSCRIBE
+
+   A			B
+   |                    |
+   |------SUBSCRIBE---->|
+   |<--------202--------|
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  if (print_headings)
+    printf("TEST NUA-12.5: un-SUBSCRIBE\n");
+
+  UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified_and_responded,
+	       -1, NULL /* XXX save_until_received */);
+
+  /* Client events:
+     nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
+  */
+  TEST_1(e = a->events->head);
+  if (e->data->e_event == nua_i_notify) {
+    TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
+    TEST_1(tl_find(e->data->e_tags, nutag_substate));
+    TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+	 nua_substate_terminated);
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_unsubscribe);
+    TEST(e->data->e_status, 202);
+    TEST_1(tl_find(e->data->e_tags, nutag_substate));
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+  }
+  TEST_1(sip->sip_event);
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  TEST_1(!sip->sip_subscription_state->ss_expires);
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-12.5: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+/* 2nd SUBSCRIBE with event id
+
+   A			B
+   |                    |
+   |------SUBSCRIBE---->|
+   |<--------202--------|
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  /* XXX - we should do this before unsubscribing first one */
+  if (print_headings)
+    printf("TEST NUA-12.4: establishing 2nd subscription\n");
+
+   NOTIFIER(b, b_call, b_call->nh,
+	    SIPTAG_EVENT_STR("presence"),
+	    SIPTAG_CONTENT_TYPE_STR("application/xpidf+xml"),
+	    SIPTAG_PAYLOAD_STR(open),
+	    NEATAG_THROTTLE(1),
+	    NUTAG_SUBSTATE(nua_substate_pending),
+	    TAG_END());
+  run_b_until(ctx, nua_r_notifier, until_final_response);
+
+  NOTIFIER(b, b_call, b_call->nh,
+	   SIPTAG_EVENT_STR("presence"),
+	   SIPTAG_CONTENT_TYPE_STR("application/xpidf+xml"),
+	   SIPTAG_PAYLOAD_STR(closed),
+	   NEATAG_THROTTLE(1),
+	   NEATAG_FAKE(1),
+	   NUTAG_SUBSTATE(nua_substate_pending),
+	   TAG_END());
+  run_b_until(ctx, nua_r_notifier, until_final_response);
+
+  SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+	    SIPTAG_EVENT_STR("presence;id=1"),
+	    SIPTAG_ACCEPT_STR("application/xpidf+xml"),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified_and_responded,
+	       -1, save_until_subscription);
+
+  /* Client events:
+     nua_subscribe(), nua_i_notify/nua_r_subscribe
+  */
+  TEST_1(e = a->events->head);
+  if (e->data->e_event == nua_i_notify) {
+    TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+    TEST_1(tl_find(e->data->e_tags, nutag_substate));
+    TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+	 nua_substate_pending);
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_subscribe);
+    TEST(e->data->e_status, 202);
+    TEST_1(tl_find(e->data->e_tags, nutag_substate));
+    TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+	 nua_substate_embryonic);
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+    TEST_1(sip = sip_object(e->data->e_msg));
+    n_tags = e->data->e_tags;
+  }
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_S(sip->sip_event->o_id, "1");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/xpidf+xml");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  /* Check that we really got "fake" content */
+  TEST_1(memmem(sip->sip_payload->pl_data, sip->sip_payload->pl_len,
+		"<basic>closed</basic>", strlen("<basic>closed</basic>")));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value,
+       nua_substate_pending);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server events:
+   nua_i_subscription
+  */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_i_subscription);
+  TEST(tl_gets(e->data->e_tags, NEATAG_SUB_REF(sub), TAG_END()), 1);
+  TEST_1(sub);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+
+  /* Authorize user A */
+  AUTHORIZE(b, b_call, b_call->nh,
+	    NUTAG_SUBSTATE(nua_substate_active),
+	    NEATAG_SUB(sub),
+	    NEATAG_FAKE(0),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified,
+	       -1, save_until_final_response);
+
+  /* subscriber events:
+     nua_i_notify with NUTAG_SUBSTATE(nua_substate_active)
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/xpidf+xml");
+  TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+  /* Check that we really got real content */
+  TEST_1(memmem(sip->sip_payload->pl_data, sip->sip_payload->pl_len,
+		"<basic>open</basic>", strlen("<basic>open</basic>")));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  /*
+   Server events:
+   nua_r_authorize
+  */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_r_authorize);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-12.4: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+/* NOTIFY terminating subscription
+
+   A			B
+   |                    |
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+
+  if (print_headings)
+    printf("TEST NUA-12.6: terminate notifier\n");
+
+  TERMINATE(b, b_call, b_call->nh, TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified, -1, until_final_response);
+
+  /* Client events:
+     nua_i_notify
+  */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_S(sip->sip_event->o_id, "1");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  TEST_1(!sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+  free_events_in_list(ctx, a->events);
+
+  if (print_headings)
+    printf("TEST NUA-12.6: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  END();			/* test_events */
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,55 @@
+2005-10-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * In sdp_rtpmap_cmp() use default value "1" for rm_param.
+
+    M ./libsofia-sip-ua/sdp/sdp.c -3 +30
+
+2005-10-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed documentation of sdp_parsing_error() and sdp_parsing_error()
+  contradicting with implementation. Use sdp_session() and sdp_message() to
+  check for error.
+
+    M ./libsofia-sip-ua/sdp/sdp.docs -2 +8
+
+2005-10-03  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sdp_print.c (sdp_printing_error): Fixed return
+	for success to be NULL as defined in function
+	documentation.
+	
+2005-09-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added SDPTAG_TYPEDEF().
+
+    M ./libsofia-sip-ua/sdp/sdp_tag.h +3
+
+  * Not including <sdp.h>.
+
+    M ./libsofia-sip-ua/sdp/sdp_tag.h -7 +12
+
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Handle mode attributes (inactive, sendonly, recvonly, sendrecv).
+
+    M ./libsofia-sip-ua/sdp/sdp.h -1 +5
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -12 +44
+    M ./libsofia-sip-ua/sdp/sdp_print.c -5 +54
+
+  * Setting mode flags on config sdp, too.
+
+    M ./libsofia-sip-ua/sdp/sdp_parse.c -3 +3
+
+  * Added sdp_media_match*(), sdp_media_count*()
+
+    M ./libsofia-sip-ua/sdp/sdp.c +91
+    M ./libsofia-sip-ua/sdp/sdp.h +20
+
+  * Added sdp_list_cmp() and sdp_rtpmap_cmp().
+
+    M ./libsofia-sip-ua/sdp/sdp.c -9 +54
+    M ./libsofia-sip-ua/sdp/sdp.h +6
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+PROJECT_NAME         = "sdp"
+OUTPUT_DIRECTORY     = ../docs/html/sdp
+
+INPUT 		     = sdp.docs .  sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES             += ../docs/su.doxytags=../su
+GENERATE_TAGFILE     = ../docs/sdp.doxytags
+
+ALIASES             +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+#
+# Makefile.am for sdp module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsdp.la
+
+check_PROGRAMS = 	torture_sdp test_sdp
+
+dist_noinst_SCRIPTS =	run_test_sdp
+
+TESTS = 		torture_sdp run_test_sdp
+
+BUILT_SOURCES =		sdp_tag_ref.c
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/sdp.h sofia-sip/sdp_tag.h
+
+libsdp_la_SOURCES = 	sdp.c sdp_parse.c sdp_print.c \
+			sdp_tag.c sdp_tag_ref.c
+
+COVERAGE_INPUT = 	$(libsdp_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libsdp.la \
+			../su/libsu.la
+
+test_sdp_LDFLAGS = 	-static
+torture_sdp_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile sdp.docs $(BUILT_SOURCES) \
+			tests/message-1.sdp \
+			tests/message-2.sdp \
+			tests/message-3.sdp \
+			tests/message-4.sdp \
+			tests/message-5.sdp \
+			tests/message-6.sdp \
+			tests/message-7.sdp \
+			tests/message-8.sdp \
+			tests/message-9.sdp \
+			tests/message-10.sdp
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,722 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sdp module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = torture_sdp$(EXEEXT) test_sdp$(EXEEXT)
+DIST_COMMON = README $(dist_noinst_SCRIPTS) \
+	$(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sdp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsdp_la_LIBADD =
+am_libsdp_la_OBJECTS = sdp.lo sdp_parse.lo sdp_print.lo sdp_tag.lo \
+	sdp_tag_ref.lo
+libsdp_la_OBJECTS = $(am_libsdp_la_OBJECTS)
+test_sdp_SOURCES = test_sdp.c
+test_sdp_OBJECTS = test_sdp.$(OBJEXT)
+test_sdp_LDADD = $(LDADD)
+test_sdp_DEPENDENCIES = libsdp.la ../su/libsu.la
+torture_sdp_SOURCES = torture_sdp.c
+torture_sdp_OBJECTS = torture_sdp.$(OBJEXT)
+torture_sdp_LDADD = $(LDADD)
+torture_sdp_DEPENDENCIES = libsdp.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.c
+DIST_SOURCES = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsdp.la
+dist_noinst_SCRIPTS = run_test_sdp
+TESTS = torture_sdp run_test_sdp
+BUILT_SOURCES = sdp_tag_ref.c
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+			sofia-sip/sdp.h sofia-sip/sdp_tag.h
+
+libsdp_la_SOURCES = sdp.c sdp_parse.c sdp_print.c \
+			sdp_tag.c sdp_tag_ref.c
+
+COVERAGE_INPUT = $(libsdp_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsdp.la \
+			../su/libsu.la
+
+test_sdp_LDFLAGS = -static
+torture_sdp_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile sdp.docs $(BUILT_SOURCES) \
+			tests/message-1.sdp \
+			tests/message-2.sdp \
+			tests/message-3.sdp \
+			tests/message-4.sdp \
+			tests/message-5.sdp \
+			tests/message-6.sdp \
+			tests/message-7.sdp \
+			tests/message-8.sdp \
+			tests/message-9.sdp \
+			tests/message-10.sdp
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/sdp/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/sdp/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsdp.la: $(libsdp_la_OBJECTS) $(libsdp_la_DEPENDENCIES) 
+	$(LINK)  $(libsdp_la_LDFLAGS) $(libsdp_la_OBJECTS) $(libsdp_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_sdp$(EXEEXT): $(test_sdp_OBJECTS) $(test_sdp_DEPENDENCIES) 
+	@rm -f test_sdp$(EXEEXT)
+	$(LINK) $(test_sdp_LDFLAGS) $(test_sdp_OBJECTS) $(test_sdp_LDADD) $(LIBS)
+torture_sdp$(EXEEXT): $(torture_sdp_OBJECTS) $(torture_sdp_DEPENDENCIES) 
+	@rm -f torture_sdp$(EXEEXT)
+	$(LINK) $(torture_sdp_LDFLAGS) $(torture_sdp_OBJECTS) $(torture_sdp_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_parse.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sdp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_sdp.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip $(distdir)/tests
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+SDP Parser and Printer
+======================
+
+	This directory contains SDP parser and printer code.  Parser takes an
+	message and returns a corresponding C structure. Printer takes a C
+	structure and returns a SDP message.
+
+	There is an incomplete documentation in sdp.html on usage of
+	parser and printer.
+
+	Please refer to RFC 2327 for further information.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+RFC 2327 omissions and errors:
+
+* "z=" omitted from zone-adjustments
+
+* protocol on media-field is restricted to alpha-numeric,
+  but example (RTP/AVP!) contains also "/"
+
+* bwtype is restricted to alpha-numeric, but the RFC text discusses
+  extensions like b=x-y:100 
+
+* att-field is restricted to alpha-numeric, but the RFC text discusses
+  extensions like a=x-nokia-foo
+
+* The BNF defintions "key-data" and "safe" are incomplete.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2355 @@
+
+
+
+
+
+
+Network Working Group                                           M. Handley
+Request for Comments: 2327                                     V. Jacobson
+Category: Standards Track                                         ISI/LBNL
+                                                                April 1998
+
+
+                   SDP: Session Description Protocol
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1998).  All Rights Reserved.
+
+Abstract
+
+   This document defines the Session Description Protocol, SDP.  SDP is
+   intended for describing multimedia sessions for the purposes of
+   session announcement, session invitation, and other forms of
+   multimedia session initiation.
+
+   This document is a product of the Multiparty Multimedia Session
+   Control (MMUSIC) working group of the Internet Engineering Task
+   Force. Comments are solicited and should be addressed to the working
+   group's mailing list at confctrl at isi.edu and/or the authors.
+
+1.  Introduction
+
+   On the Internet multicast backbone (Mbone), a session directory tool
+   is used to advertise multimedia conferences and communicate the
+   conference addresses and conference tool-specific information
+   necessary for participation.  This document defines a session
+   description protocol for this purpose, and for general real-time
+   multimedia session description purposes. This memo does not describe
+   multicast address allocation or the distribution of SDP messages in
+   detail.  These are described in accompanying memos.  SDP is not
+   intended for negotiation of media encodings.
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                     [Page 1]
+
+RFC 2327                          SDP                         April 1998
+
+
+2.  Background
+
+   The Mbone is the part of the internet that supports IP multicast, and
+   thus permits efficient many-to-many communication.  It is used
+   extensively for multimedia conferencing.  Such conferences usually
+   have the property that tight coordination of conference membership is
+   not necessary; to receive a conference, a user at an Mbone site only
+   has to know the conference's multicast group address and the UDP
+   ports for the conference data streams.
+
+   Session directories assist the advertisement of conference sessions
+   and communicate the relevant conference setup information to
+   prospective participants.  SDP is designed to convey such information
+   to recipients.  SDP is purely a format for session description - it
+   does not incorporate a transport protocol, and is intended to use
+   different transport protocols as appropriate including the Session
+   Announcement Protocol [4], Session Initiation Protocol [11], Real-
+   Time Streaming Protocol [12], electronic mail using the MIME
+   extensions, and the Hypertext Transport Protocol.
+
+   SDP is intended to be general purpose so that it can be used for a
+   wider range of network environments and applications than just
+   multicast session directories.  However, it is not intended to
+   support negotiation of session content or media encodings - this is
+   viewed as outside the scope of session description.
+
+3.  Glossary of Terms
+
+   The following terms are used in this document, and have specific
+   meaning within the context of this document.
+
+   Conference
+     A multimedia conference is a set of two or more communicating users
+     along with the software they are using to communicate.
+
+   Session
+     A multimedia session is a set of multimedia senders and receivers
+     and the data streams flowing from senders to receivers.  A
+     multimedia conference is an example of a multimedia session.
+
+   Session Advertisement
+     See session announcement.
+
+   Session Announcement
+     A session announcement is a mechanism by which a session
+     description is conveyed to users in a proactive fashion, i.e., the
+     session description was not explicitly requested by the user.
+
+
+
+
+Handley & Jacobson          Standards Track                     [Page 2]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Session Description
+     A well defined format for conveying sufficient information to
+     discover and participate in a multimedia session.
+
+3.1.  Terminology
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119.
+
+4.  SDP Usage
+
+4.1.  Multicast Announcements
+
+   SDP is a session description protocol for multimedia sessions. A
+   common mode of usage is for a client to announce a conference session
+   by periodically multicasting an announcement packet to a well known
+   multicast address and port using the Session Announcement Protocol
+   (SAP).
+
+   SAP packets are UDP packets with the following format:
+
+         |--------------------|
+         | SAP header         |
+         |--------------------|
+         | text payload       |
+         |//////////
+
+
+   The header is the Session Announcement Protocol header.  SAP is
+   described in more detail in a companion memo [4]
+
+   The text payload is an SDP session description, as described in this
+   memo.  The text payload should be no greater than 1 Kbyte in length.
+   If announced by SAP, only one session announcement is permitted in a
+   single packet.
+
+4.2.  Email and WWW Announcements
+
+   Alternative means of conveying session descriptions include
+   electronic mail and the World Wide Web. For both email and WWW
+   distribution, the use of the MIME content type "application/sdp"
+   should be used.  This enables the automatic launching of applications
+   for participation in the session from the WWW client or mail reader
+   in a standard manner.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                     [Page 3]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Note that announcements of multicast sessions made only via email or
+   the World Wide Web (WWW) do not have the property that the receiver
+   of a session announcement can necessarily receive the session because
+   the multicast sessions may be restricted in scope, and access to the
+   WWW server or reception of email is possible outside this scope.  SAP
+   announcements do not suffer from this mismatch.
+
+5.  Requirements and Recommendations
+
+   The purpose of SDP is to convey information about media streams in
+   multimedia sessions to allow the recipients of a session description
+   to participate in the session.  SDP is primarily intended for use in
+   an internetwork, although it is sufficiently general that it can
+   describe conferences in other network environments.
+
+   A multimedia session, for these purposes, is defined as a set of
+   media streams that exist for some duration of time.  Media streams
+   can be many-to-many.  The times during which the session is active
+   need not be continuous.
+
+   Thus far, multicast based sessions on the Internet have differed from
+   many other forms of conferencing in that anyone receiving the traffic
+   can join the session (unless the session traffic is encrypted).  In
+   such an environment, SDP serves two primary purposes.  It is a means
+   to communicate the existence of a session, and is a means to convey
+   sufficient information to enable joining and participating in the
+   session.  In a unicast environment, only the latter purpose is likely
+   to be relevant.
+
+   Thus SDP includes:
+
+   o Session name and purpose
+
+   o Time(s) the session is active
+
+   o The media comprising the session
+
+   o Information to receive those media (addresses, ports, formats and
+     so on)
+
+   As resources necessary to participate in a session may be limited,
+   some additional information may also be desirable:
+
+   o Information about the bandwidth to be used by the conference
+
+   o Contact information for the person responsible for the session
+
+
+
+
+
+Handley & Jacobson          Standards Track                     [Page 4]
+
+RFC 2327                          SDP                         April 1998
+
+
+   In general, SDP must convey sufficient information to be able to join
+   a session (with the possible exception of encryption keys) and to
+   announce the resources to be used to non-participants that may need
+   to know.
+
+5.1.  Media Information
+
+   SDP includes:
+
+   o The type of media (video, audio, etc)
+
+   o The transport protocol (RTP/UDP/IP, H.320, etc)
+
+   o The format of the media (H.261 video, MPEG video, etc)
+
+   For an IP multicast session, the following are also conveyed:
+
+   o Multicast address for media
+
+   o Transport Port for media
+
+   This address and port are the destination address and destination
+   port of the multicast stream, whether being sent, received, or both.
+
+   For an IP unicast session, the following are conveyed:
+
+   o Remote address for media
+
+   o Transport port for contact address
+
+   The semantics of this address and port depend on the media and
+   transport protocol defined.  By default, this is the remote address
+   and remote port to which data is sent, and the remote address and
+   local port on which to receive data.  However, some media may define
+   to use these to establish a control channel for the actual media
+   flow.
+
+5.2.  Timing Information
+
+   Sessions may either be bounded or unbounded in time. Whether or not
+   they are bounded, they may be only active at specific times.
+
+   SDP can convey:
+
+   o An arbitrary list of start and stop times bounding the session
+
+   o For each bound, repeat times such as "every Wednesday at 10am for
+     one hour"
+
+
+
+Handley & Jacobson          Standards Track                     [Page 5]
+
+RFC 2327                          SDP                         April 1998
+
+
+   This timing information is globally consistent, irrespective of local
+   time zone or daylight saving time.
+
+5.3.  Private Sessions
+
+   It is possible to create both public sessions and private sessions.
+   Private sessions will typically be conveyed by encrypting the session
+   description to distribute it.  The details of how encryption is
+   performed are dependent on the mechanism used to convey SDP - see [4]
+   for how this is done for session announcements.
+
+   If a session announcement is private it is possible to use that
+   private announcement to convey encryption keys necessary to decode
+   each of the media in a conference, including enough information to
+   know which encryption scheme is used for each media.
+
+5.4.  Obtaining Further Information about a Session
+
+   A session description should convey enough information to decide
+   whether or not to participate in a session.  SDP may include
+   additional pointers in the form of Universal Resources Identifiers
+   (URIs) for more information about the session.
+
+5.5.  Categorisation
+
+   When many session descriptions are being distributed by SAP or any
+   other advertisement mechanism, it may be desirable to filter
+   announcements that are of interest from those that are not.  SDP
+   supports a categorisation mechanism for sessions that is capable of
+   being automated.
+
+5.6.  Internationalization
+
+   The SDP specification recommends the use of the ISO 10646 character
+   sets in the UTF-8 encoding (RFC 2044) to allow many different
+   languages to be represented.  However, to assist in compact
+   representations, SDP also allows other character sets such as ISO
+   8859-1 to be used when desired.  Internationalization only applies to
+   free-text fields (session name and background information), and not
+   to SDP as a whole.
+
+6.  SDP Specification
+
+   SDP session descriptions are entirely textual using the ISO 10646
+   character set in UTF-8 encoding. SDP field names and attributes names
+   use only the US-ASCII subset of UTF-8, but textual fields and
+   attribute values may use the full ISO 10646 character set.  The
+   textual form, as opposed to a binary encoding such as ASN/1 or XDR,
+
+
+
+Handley & Jacobson          Standards Track                     [Page 6]
+
+RFC 2327                          SDP                         April 1998
+
+
+   was chosen to enhance portability, to enable a variety of transports
+   to be used (e.g, session description in a MIME email message) and to
+   allow flexible, text-based toolkits (e.g., Tcl/Tk ) to be used to
+   generate and to process session descriptions.  However, since the
+   total bandwidth allocated to all SAP announcements is strictly
+   limited, the encoding is deliberately compact.  Also, since
+   announcements may be transported via very unreliable means (e.g.,
+   email) or damaged by an intermediate caching server, the encoding was
+   designed with strict order and formatting rules so that most errors
+   would result in malformed announcements which could be detected
+   easily and discarded. This also allows rapid discarding of encrypted
+   announcements for which a receiver does not have the correct key.
+
+   An SDP session description consists of a number of lines of text of
+   the form <type>=<value> <type> is always exactly one character and is
+   case-significant.  <value> is a structured text string whose format
+   depends on <type>.  It also will be case-significant unless a
+   specific field defines otherwise.  Whitespace is not permitted either
+   side of the `=' sign. In general <value> is either a number of fields
+   delimited by a single space character or a free format string.
+
+   A session description consists of a session-level description
+   (details that apply to the whole session and all media streams) and
+   optionally several media-level descriptions (details that apply onto
+   to a single media stream).
+
+   An announcement consists of a session-level section followed by zero
+   or more media-level sections.  The session-level part starts with a
+   `v=' line and continues to the first media-level section.  The media
+   description starts with an `m=' line and continues to the next media
+   description or end of the whole session description.  In general,
+   session-level values are the default for all media unless overridden
+   by an equivalent media-level value.
+
+   When SDP is conveyed by SAP, only one session description is allowed
+   per packet.  When SDP is conveyed by other means, many SDP session
+   descriptions may be concatenated together (the `v=' line indicating
+   the start of a session description terminates the previous
+   description).  Some lines in each description are required and some
+   are optional but all must appear in exactly the order given here (the
+   fixed order greatly enhances error detection and allows for a simple
+   parser). Optional items are marked with a `*'.
+
+Session description
+        v=  (protocol version)
+        o=  (owner/creator and session identifier).
+        s=  (session name)
+        i=* (session information)
+
+
+
+Handley & Jacobson          Standards Track                     [Page 7]
+
+RFC 2327                          SDP                         April 1998
+
+
+        u=* (URI of description)
+        e=* (email address)
+        p=* (phone number)
+        c=* (connection information - not required if included in all media)
+        b=* (bandwidth information)
+        One or more time descriptions (see below)
+        z=* (time zone adjustments)
+        k=* (encryption key)
+        a=* (zero or more session attribute lines)
+        Zero or more media descriptions (see below)
+
+Time description
+        t=  (time the session is active)
+        r=* (zero or more repeat times)
+
+Media description
+        m=  (media name and transport address)
+        i=* (media title)
+        c=* (connection information - optional if included at session-level)
+        b=* (bandwidth information)
+        k=* (encryption key)
+        a=* (zero or more media attribute lines)
+
+   The set of `type' letters is deliberately small and not intended to
+   be extensible -- SDP parsers must completely ignore any announcement
+   that contains a `type' letter that it does not understand. The
+   `attribute' mechanism ("a=" described below) is the primary means for
+   extending SDP and tailoring it to particular applications or media.
+   Some attributes (the ones listed in this document) have a defined
+   meaning but others may be added on an application-, media- or
+   session-specific basis.  A session directory must ignore any
+   attribute it doesn't understand.
+
+   The connection (`c=') and attribute (`a=') information in the
+   session-level section applies to all the media of that session unless
+   overridden by connection information or an attribute of the same name
+   in the media description.  For instance, in the example below, each
+   media behaves as if it were given a `recvonly' attribute.
+
+   An example SDP description is:
+
+        v=0
+        o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+        s=SDP Seminar
+        i=A Seminar on the session description protocol
+        u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+        e=mjh at isi.edu (Mark Handley)
+        c=IN IP4 224.2.17.12/127
+
+
+
+Handley & Jacobson          Standards Track                     [Page 8]
+
+RFC 2327                          SDP                         April 1998
+
+
+        t=2873397496 2873404696
+        a=recvonly
+        m=audio 49170 RTP/AVP 0
+        m=video 51372 RTP/AVP 31
+        m=application 32416 udp wb
+        a=orient:portrait
+
+   Text records such as the session name and information are bytes
+   strings which may contain any byte with the exceptions of 0x00 (Nul),
+   0x0a (ASCII newline) and 0x0d (ASCII carriage return).  The sequence
+   CRLF (0x0d0a) is used to end a record, although parsers should be
+   tolerant and also accept records terminated with a single newline
+   character.  By default these byte strings contain ISO-10646
+   characters in UTF-8 encoding, but this default may be changed using
+   the `charset' attribute.
+
+   Protocol Version
+
+   v=0
+
+   The "v=" field gives the version of the Session Description Protocol.
+   There is no minor version number.
+
+   Origin
+
+   o=<username> <session id> <version> <network type> <address type>
+   <address>
+
+   The "o=" field gives the originator of the session (their username
+   and the address of the user's host) plus a session id and session
+   version number.
+
+   <username> is the user's login on the originating host, or it is "-"
+   if the originating host does not support the concept of user ids.
+   <username> must not contain spaces.  <session id> is a numeric string
+   such that the tuple of <username>, <session id>, <network type>,
+   <address type> and <address> form a globally unique identifier for
+   the session.
+
+   The method of <session id> allocation is up to the creating tool, but
+   it has been suggested that a Network Time Protocol (NTP) timestamp be
+   used to ensure uniqueness [1].
+
+   <version> is a version number for this announcement.  It is needed
+   for proxy announcements to detect which of several announcements for
+   the same session is the most recent.  Again its usage is up to the
+
+
+
+
+
+Handley & Jacobson          Standards Track                     [Page 9]
+
+RFC 2327                          SDP                         April 1998
+
+
+   creating tool, so long as <version> is increased when a modification
+   is made to the session data.  Again, it is recommended (but not
+   mandatory) that an NTP timestamp is used.
+
+   <network type> is a text string giving the type of network.
+   Initially "IN" is defined to have the meaning "Internet".  <address
+   type> is a text string giving the type of the address that follows.
+   Initially "IP4" and "IP6" are defined.  <address> is the globally
+   unique address of the machine from which the session was created.
+   For an address type of IP4, this is either the fully-qualified domain
+   name of the machine, or the dotted-decimal representation of the IP
+   version 4 address of the machine.  For an address type of IP6, this
+   is either the fully-qualified domain name of the machine, or the
+   compressed textual representation of the IP version 6 address of the
+   machine.  For both IP4 and IP6, the fully-qualified domain name is
+   the form that SHOULD be given unless this is unavailable, in which
+   case the globally unique address may be substituted.  A local IP
+   address MUST NOT be used in any context where the SDP description
+   might leave the scope in which the address is meaningful.
+
+   In general, the "o=" field serves as a globally unique identifier for
+   this version of this session description, and the subfields excepting
+   the version taken together identify the session irrespective of any
+   modifications.
+
+   Session Name
+
+   s=<session name>
+
+   The "s=" field is the session name.  There must be one and only one
+   "s=" field per session description, and it must contain ISO 10646
+   characters (but see also the `charset' attribute below).
+
+   Session and Media Information
+
+   i=<session description>
+
+   The "i=" field is information about the session.  There may be at
+   most one session-level "i=" field per session description, and at
+   most one "i=" field per media. Although it may be omitted, this is
+   discouraged for session announcements, and user interfaces for
+   composing sessions should require text to be entered.  If it is
+   present it must contain ISO 10646 characters (but see also the
+   `charset' attribute below).
+
+   A single "i=" field can also be used for each media definition.  In
+   media definitions, "i=" fields are primarily intended for labeling
+   media streams. As such, they are most likely to be useful when a
+
+
+
+Handley & Jacobson          Standards Track                    [Page 10]
+
+RFC 2327                          SDP                         April 1998
+
+
+   single session has more than one distinct media stream of the same
+   media type.  An example would be two different whiteboards, one for
+   slides and one for feedback and questions.
+
+   URI
+
+   u=<URI>
+
+   o A URI is a Universal Resource Identifier as used by WWW clients
+
+   o The URI should be a pointer to additional information about the
+     conference
+
+   o This field is optional, but if it is present it should be specified
+     before the first media field
+
+   o No more than one URI field is allowed per session description
+
+
+   Email Address and Phone Number
+
+   e=<email address>
+   p=<phone number>
+
+   o These specify contact information for the person responsible for
+     the conference.  This is not necessarily the same person that
+     created the conference announcement.
+
+   o Either an email field or a phone field must be specified.
+     Additional email and phone fields are allowed.
+
+   o If these are present, they should be specified before the first
+     media field.
+
+   o More than one email or phone field can be given for a session
+     description.
+
+   o Phone numbers should be given in the conventional international
+
+     format - preceded by a "+ and the international country code.
+     There must be a space or a hyphen ("-") between the country code
+     and the rest of the phone number.  Spaces and hyphens may be used
+     to split up a phone field to aid readability if desired. For
+     example:
+
+                   p=+44-171-380-7777 or p=+1 617 253 6011
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 11]
+
+RFC 2327                          SDP                         April 1998
+
+
+   o Both email addresses and phone numbers can have an optional free
+     text string associated with them, normally giving the name of the
+     person who may be contacted.  This should be enclosed in
+     parenthesis if it is present.  For example:
+
+                        e=mjh at isi.edu (Mark Handley)
+
+     The alternative RFC822 name quoting convention is also allowed for
+     both email addresses and phone numbers.  For example,
+
+                        e=Mark Handley <mjh at isi.edu>
+
+     The free text string should be in the ISO-10646 character set with
+     UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings
+     if the appropriate charset session-level attribute is set.
+
+   Connection Data
+
+   c=<network type> <address type> <connection address>
+
+   The "c=" field contains connection data.
+
+   A session announcement must contain one "c=" field in each media
+   description (see below) or a "c=" field at the session-level.  It may
+   contain a session-level "c=" field and one additional "c=" field per
+   media description, in which case the per-media values override the
+   session-level settings for the relevant media.
+
+   The first sub-field is the network type, which is a text string
+   giving the type of network.  Initially "IN" is defined to have the
+   meaning "Internet".
+
+   The second sub-field is the address type.  This allows SDP to be used
+   for sessions that are not IP based.  Currently only IP4 is defined.
+
+   The third sub-field is the connection address.  Optional extra
+   subfields may be added after the connection address depending on the
+   value of the <address type> field.
+
+   For IP4 addresses, the connection address is defined as follows:
+
+   o Typically the connection address will be a class-D IP multicast
+
+     group address.  If the session is not multicast, then the
+     connection address contains the fully-qualified domain name or the
+     unicast IP address of the expected data source or data relay or
+     data sink as determined by additional attribute fields. It is not
+     expected that fully-qualified domain names or unicast addresses
+
+
+
+Handley & Jacobson          Standards Track                    [Page 12]
+
+RFC 2327                          SDP                         April 1998
+
+
+     will be given in a session description that is communicated by a
+     multicast announcement, though this is not prohibited.  If a
+     unicast data stream is to pass through a network address
+     translator, the use of a fully-qualified domain name rather than an
+     unicast IP address is RECOMMENDED.  In other cases, the use of an
+     IP address to specify a particular interface on a multi-homed host
+     might be required.  Thus this specification leaves the decision as
+     to which to use up to the individual application, but all
+     applications MUST be able to cope with receiving both formats.
+
+   o Conferences using an IP multicast connection address must also have
+     a time to live (TTL) value present in addition to the multicast
+     address.  The TTL and the address together define the scope with
+     which multicast packets sent in this conference will be sent. TTL
+     values must be in the range 0-255.
+
+     The TTL for the session is appended to the address using a slash as
+     a separator.  An example is:
+
+                           c=IN IP4 224.2.1.1/127
+
+     Hierarchical or layered encoding schemes are data streams where the
+     encoding from a single media source is split into a number of
+     layers.  The receiver can choose the desired quality (and hence
+     bandwidth) by only subscribing to a subset of these layers.  Such
+     layered encodings are normally transmitted in multiple multicast
+     groups to allow multicast pruning.  This technique keeps unwanted
+     traffic from sites only requiring certain levels of the hierarchy.
+     For applications requiring multiple multicast groups, we allow the
+     following notation to be used for the connection address:
+
+            <base multicast address>/<ttl>/<number of addresses>
+
+     If the number of addresses is not given it is assumed to be one.
+     Multicast addresses so assigned are contiguously allocated above
+     the base address, so that, for example:
+
+                          c=IN IP4 224.2.1.1/127/3
+
+     would state that addresses 224.2.1.1, 224.2.1.2 and 224.2.1.3 are
+     to be used at a ttl of 127.  This is semantically identical to
+     including multiple "c=" lines in a media description:
+
+                           c=IN IP4 224.2.1.1/127
+                           c=IN IP4 224.2.1.2/127
+                           c=IN IP4 224.2.1.3/127
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 13]
+
+RFC 2327                          SDP                         April 1998
+
+
+     Multiple addresses or "c=" lines can only be specified on a per-
+     media basis, and not for a session-level "c=" field.
+
+     It is illegal for the slash notation described above to be used for
+     IP unicast addresses.
+
+   Bandwidth
+
+   b=<modifier>:<bandwidth-value>
+
+   o This specifies the proposed bandwidth to be used by the session or
+     media, and is optional.
+
+   o <bandwidth-value> is in kilobits per second
+
+   o <modifier> is a single alphanumeric word giving the meaning of the
+     bandwidth figure.
+
+   o Two modifiers are initially defined:
+
+   CT Conference Total: An implicit maximum bandwidth is associated with
+     each TTL on the Mbone or within a particular multicast
+     administrative scope region (the Mbone bandwidth vs. TTL limits are
+     given in the MBone FAQ). If the bandwidth of a session or media in
+     a session is different from the bandwidth implicit from the scope,
+     a `b=CT:...' line should be supplied for the session giving the
+     proposed upper limit to the bandwidth used. The primary purpose of
+     this is to give an approximate idea as to whether two or more
+     conferences can co-exist simultaneously.
+
+   AS Application-Specific Maximum: The bandwidth is interpreted to be
+     application-specific, i.e., will be the application's concept of
+     maximum bandwidth.  Normally this will coincide with what is set on
+     the application's "maximum bandwidth" control if applicable.
+
+     Note that CT gives a total bandwidth figure for all the media at
+     all sites.  AS gives a bandwidth figure for a single media at a
+     single site, although there may be many sites sending
+     simultaneously.
+
+   o Extension Mechanism: Tool writers can define experimental bandwidth
+     modifiers by prefixing their modifier with "X-". For example:
+
+                                 b=X-YZ:128
+
+     SDP parsers should ignore bandwidth fields with unknown modifiers.
+     Modifiers should be alpha-numeric and, although no length limit is
+     given, they are recommended to be short.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 14]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Times, Repeat Times and Time Zones
+
+   t=<start time>  <stop time>
+
+   o "t=" fields specify the start and stop times for a conference
+     session.  Multiple "t=" fields may be used if a session is active
+     at multiple irregularly spaced times; each additional "t=" field
+     specifies an additional period of time for which the session will
+     be active.  If the session is active at regular times, an "r="
+     field (see below) should be used in addition to and following a
+     "t=" field - in which case the "t=" field specifies the start and
+     stop times of the repeat sequence.
+
+   o The first and second sub-fields give the start and stop times for
+     the conference respectively.  These values are the decimal
+     representation of Network Time Protocol (NTP) time values in
+     seconds [1].  To convert these values to UNIX time, subtract
+     decimal 2208988800.
+
+   o If the stop-time is set to zero, then the session is not bounded,
+     though it will not become active until after the start-time.  If
+     the start-time is also zero, the session is regarded as permanent.
+
+     User interfaces should strongly discourage the creation of
+     unbounded and permanent sessions as they give no information about
+     when the session is actually going to terminate, and so make
+     scheduling difficult.
+
+     The general assumption may be made, when displaying unbounded
+     sessions that have not timed out to the user, that an unbounded
+     session will only be active until half an hour from the current
+     time or the session start time, whichever is the later.  If
+     behaviour other than this is required, an end-time should be given
+     and modified as appropriate when new information becomes available
+     about when the session should really end.
+
+     Permanent sessions may be shown to the user as never being active
+     unless there are associated repeat times which state precisely when
+     the session will be active.  In general, permanent sessions should
+     not be created for any session expected to have a duration of less
+     than 2 months, and should be discouraged for sessions expected to
+     have a duration of less than 6 months.
+
+     r=<repeat interval> <active duration> <list of offsets from start-
+     time>
+
+   o "r=" fields specify repeat times for a session.  For example, if
+     a session is active at 10am on Monday and 11am on Tuesday for one
+
+
+
+Handley & Jacobson          Standards Track                    [Page 15]
+
+RFC 2327                          SDP                         April 1998
+
+
+     hour each week for three months, then the <start time> in the
+     corresponding "t=" field would be the NTP representation of 10am on
+     the first Monday, the <repeat interval> would be 1 week, the
+     <active duration> would be 1 hour, and the offsets would be zero
+     and 25 hours. The corresponding "t=" field stop time would be the
+     NTP representation of the end of the last session three months
+     later. By default all fields are in seconds, so the "r=" and "t="
+     fields might be:
+
+                           t=3034423619 3042462419
+                            r=604800 3600 0 90000
+
+    To make announcements more compact, times may also be given in units
+    of days, hours or minutes. The syntax for these is a number
+    immediately followed by a single case-sensitive character.
+    Fractional units are not allowed - a smaller unit should be used
+    instead.  The following unit specification characters are allowed:
+
+                         d - days (86400 seconds)
+                        h - minutes (3600 seconds)
+                         m - minutes (60 seconds)
+         s - seconds (allowed for completeness but not recommended)
+
+   Thus, the above announcement could also have been written:
+
+                               r=7d 1h 0 25h
+
+     Monthly and yearly repeats cannot currently be directly specified
+     with a single SDP repeat time - instead separate "t" fields should
+     be used to explicitly list the session times.
+
+        z=<adjustment time> <offset> <adjustment time> <offset> ....
+
+   o To schedule a repeated session which spans a change from daylight-
+     saving time to standard time or vice-versa, it is necessary to
+     specify offsets from the base repeat times. This is required
+     because different time zones change time at different times of day,
+     different countries change to or from daylight time on different
+     dates, and some countries do not have daylight saving time at all.
+
+     Thus in order to schedule a session that is at the same time winter
+     and summer, it must be possible to specify unambiguously by whose
+     time zone a session is scheduled.  To simplify this task for
+     receivers, we allow the sender to specify the NTP time that a time
+     zone adjustment happens and the offset from the time when the
+     session was first scheduled.  The "z" field allows the sender to
+     specify a list of these adjustment times and offsets from the base
+     time.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 16]
+
+RFC 2327                          SDP                         April 1998
+
+
+     An example might be:
+
+                        z=2882844526 -1h 2898848070 0
+
+     This specifies that at time 2882844526 the time base by which the
+     session's repeat times are calculated is shifted back by 1 hour,
+     and that at time 2898848070 the session's original time base is
+     restored. Adjustments are always relative to the specified start
+     time - they are not cumulative.
+
+   o    If a session is likely to last several years, it is  expected
+   that
+     the session announcement will be modified periodically rather than
+     transmit several years worth of adjustments in one announcement.
+
+   Encryption Keys
+
+   k=<method>
+   k=<method>:<encryption key>
+
+   o The session description protocol may be used to convey encryption
+     keys.  A key field is permitted before the first media entry (in
+     which case it applies to all media in the session), or for each
+     media entry as required.
+
+   o The format of keys and their usage is outside the scope of this
+     document, but see [3].
+
+   o The method indicates the mechanism to be used to obtain a usable
+     key by external means, or from the encoded encryption key given.
+
+     The following methods are defined:
+
+      k=clear:<encryption key>
+        The encryption key (as described in [3] for  RTP  media  streams
+        under  the  AV  profile)  is  included untransformed in this key
+        field.
+
+      k=base64:<encoded encryption key>
+        The encryption key (as described in [3] for RTP media streams
+        under the AV profile) is included in this key field but has been
+        base64 encoded because it includes characters that are
+        prohibited in SDP.
+
+      k=uri:<URI to obtain key>
+        A Universal Resource Identifier as used by WWW clients is
+        included in this key field.  The URI refers to the data
+        containing the key, and may require additional authentication
+
+
+
+Handley & Jacobson          Standards Track                    [Page 17]
+
+RFC 2327                          SDP                         April 1998
+
+
+        before the key can be returned.  When a request is made to the
+        given URI, the MIME content-type of the reply specifies the
+        encoding for the key in the reply.  The key should not be
+        obtained until the user wishes to join the session to reduce
+        synchronisation of requests to the WWW server(s).
+
+      k=prompt
+        No key is included in this SDP description, but the session or
+        media stream referred to by this key field is encrypted.  The
+        user should be prompted for the key when attempting to join the
+        session, and this user-supplied key should then be used to
+        decrypt the media streams.
+
+   Attributes
+
+   a=<attribute>
+   a=<attribute>:<value>
+
+   Attributes are the primary means for extending SDP.  Attributes may
+   be defined to be used as "session-level" attributes, "media-level"
+   attributes, or both.
+
+   A media description may have any number of attributes ("a=" fields)
+   which are media specific.  These are referred to as "media-level"
+   attributes and add information about the media stream.  Attribute
+   fields can also be added before the first media field; these
+   "session-level" attributes convey additional information that applies
+   to the conference as a whole rather than to individual media; an
+   example might be the conference's floor control policy.
+
+   Attribute fields may be of two forms:
+
+   o property attributes.  A property attribute is simply of the form
+     "a=<flag>".  These are binary attributes, and the presence of the
+     attribute conveys that the attribute is a property of the session.
+     An example might be "a=recvonly".
+
+   o value attributes.  A value attribute is of the form
+     "a=<attribute>:<value>".  An example might be that a whiteboard
+     could have the value attribute "a=orient:landscape"
+
+   Attribute interpretation depends on the media tool being invoked.
+   Thus receivers of session descriptions should be configurable in
+   their interpretation of announcements in general and of attributes in
+   particular.
+
+   Attribute names must be in the US-ASCII subset of ISO-10646/UTF-8.
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 18]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Attribute values are byte strings, and MAY use any byte value except
+   0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default, attribute values
+   are to be interpreted as in ISO-10646 character set with UTF-8
+   encoding.  Unlike other text fields, attribute values are NOT
+   normally affected by the `charset' attribute as this would make
+   comparisons against known values problematic.  However, when an
+   attribute is defined, it can be defined to be charset-dependent, in
+   which case it's value should be interpreted in the session charset
+   rather than in ISO-10646.
+
+   Attributes that will be commonly used can be registered with IANA
+   (see Appendix B).  Unregistered attributes should begin with "X-" to
+   prevent inadvertent collision with registered attributes.  In either
+   case, if an attribute is received that is not understood, it should
+   simply be ignored by the receiver.
+
+   Media Announcements
+
+   m=<media> <port> <transport> <fmt list>
+
+   A session description may contain a number of media descriptions.
+   Each media description starts with an "m=" field, and is terminated
+   by either the next "m=" field or by the end of the session
+   description.  A media field also has several sub-fields:
+
+   o The first sub-field is the media type.  Currently defined media are
+     "audio", "video", "application", "data" and "control", though this
+     list may be extended as new communication modalities emerge (e.g.,
+     telepresense).  The difference between "application" and "data" is
+     that the former is a media flow such as whiteboard information, and
+     the latter is bulk-data transfer such as multicasting of program
+     executables which will not typically be displayed to the user.
+     "control" is used to specify an additional conference control
+     channel for the session.
+
+   o The second sub-field is the transport port to which the media
+     stream will be sent.  The meaning of the transport port depends on
+     the network being used as specified in the relevant "c" field and
+     on the transport protocol defined in the third sub-field.  Other
+     ports used by the media application (such as the RTCP port, see
+     [2]) should be derived algorithmically from the base media port.
+
+     Note: For transports based on UDP, the value should be in the range
+     1024 to 65535 inclusive.  For RTP compliance it should be an even
+     number.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 19]
+
+RFC 2327                          SDP                         April 1998
+
+
+     For applications where hierarchically encoded streams are being
+     sent to a unicast address, it may be necessary to specify multiple
+     transport ports.  This is done using a similar notation to that
+     used for IP multicast addresses in the "c=" field:
+
+          m=<media> <port>/<number of ports> <transport> <fmt list>
+
+     In such a case, the ports used depend on the transport protocol.
+     For RTP, only the even ports are used for data and the
+     corresponding one-higher odd port is used for RTCP.  For example:
+
+                         m=video 49170/2 RTP/AVP 31
+
+     would specify that ports 49170 and 49171 form one RTP/RTCP pair and
+     49172 and 49173 form the second RTP/RTCP pair.  RTP/AVP is the
+     transport protocol and 31 is the format (see below).
+
+     It is illegal for both multiple addresses to be specified in the
+     "c=" field and for multiple ports to be specified in the "m=" field
+     in the same session description.
+
+   o The third sub-field is the transport protocol.  The transport
+     protocol values are dependent on the address-type field in the "c="
+     fields.  Thus a "c=" field of IP4 defines that the transport
+     protocol runs over IP4.  For IP4, it is normally expected that most
+     media traffic will be carried as RTP over UDP.  The following
+     transport protocols are preliminarily defined, but may be extended
+     through registration of new protocols with IANA:
+
+     - RTP/AVP - the IETF's Realtime Transport Protocol using the
+       Audio/Video profile carried over UDP.
+
+     - udp - User Datagram Protocol
+
+     If an application uses a single combined proprietary media format
+     and transport protocol over UDP, then simply specifying the
+     transport protocol as udp and using the format field to distinguish
+     the combined protocol is recommended.  If a transport protocol is
+     used over UDP to carry several distinct media types that need to be
+     distinguished by a session directory, then specifying the transport
+     protocol and media format separately is necessary. RTP is an
+     example of a transport-protocol that carries multiple payload
+     formats that must be distinguished by the session directory for it
+     to know how to start appropriate tools, relays, mixers or
+     recorders.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 20]
+
+RFC 2327                          SDP                         April 1998
+
+
+     The main reason to specify the transport-protocol in addition to
+     the media format is that the same standard media formats may be
+     carried over different transport protocols even when the network
+     protocol is the same - a historical example is vat PCM audio and
+     RTP PCM audio.  In addition, relays and monitoring tools that are
+     transport-protocol-specific but format-independent are possible.
+
+     For RTP media streams operating under the RTP Audio/Video Profile
+     [3], the protocol field is "RTP/AVP".  Should other RTP profiles be
+     defined in the future, their profiles will be specified in the same
+     way.  For example, the protocol field "RTP/XYZ" would specify RTP
+     operating under a profile whose short name is "XYZ".
+
+   o The fourth and subsequent sub-fields are media formats.  For audio
+     and video, these will normally be a media payload type as defined
+     in the RTP Audio/Video Profile.
+
+     When a list of payload formats is given, this implies that all of
+     these formats may be used in the session, but the first of these
+     formats is the default format for the session.
+
+     For media whose transport protocol is not RTP or UDP the format
+     field is protocol specific.  Such formats should be defined in an
+     additional specification document.
+
+     For media whose transport protocol is RTP, SDP can be used to
+     provide a dynamic binding of media encoding to RTP payload type.
+     The encoding names in the RTP AV Profile do not specify unique
+     audio encodings (in terms of clock rate and number of audio
+     channels), and so they are not used directly in SDP format fields.
+     Instead, the payload type number should be used to specify the
+     format for static payload types and the payload type number along
+     with additional encoding information should be used for dynamically
+     allocated payload types.
+
+     An example of a static payload type is u-law PCM coded single
+     channel audio sampled at 8KHz.  This is completely defined in the
+     RTP Audio/Video profile as payload type 0, so the media field for
+     such a stream sent to UDP port 49232 is:
+
+                           m=video 49232 RTP/AVP 0
+
+     An example of a dynamic payload type is 16 bit linear encoded
+     stereo audio sampled at 16KHz.  If we wish to use dynamic RTP/AVP
+     payload type 98 for such a stream, additional information is
+     required to decode it:
+
+                          m=video 49232 RTP/AVP 98
+
+
+
+Handley & Jacobson          Standards Track                    [Page 21]
+
+RFC 2327                          SDP                         April 1998
+
+
+                           a=rtpmap:98 L16/16000/2
+
+     The general form of an rtpmap attribute is:
+
+     a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding
+     parameters>]
+
+     For audio streams, <encoding parameters> may specify the number of
+     audio channels.  This parameter may be omitted if the number of
+     channels is one provided no additional parameters are needed.  For
+     video streams, no encoding parameters are currently specified.
+
+     Additional parameters may be defined in the future, but
+     codecspecific parameters should not be added.  Parameters added to
+     an rtpmap attribute should only be those required for a session
+     directory to make the choice of appropriate media too to
+     participate in a session.  Codec-specific parameters should be
+     added in other attributes.
+
+     Up to one rtpmap attribute can be defined for each media format
+     specified. Thus we might have:
+
+                       m=audio 49230 RTP/AVP 96 97 98
+                             a=rtpmap:96 L8/8000
+                            a=rtpmap:97 L16/8000
+                           a=rtpmap:98 L16/11025/2
+
+     RTP profiles that specify the use of dynamic payload types must
+     define the set of valid encoding names and/or a means to register
+     encoding names if that profile is to be used with SDP.
+
+     Experimental encoding formats can also be specified using rtpmap.
+     RTP formats that are not registered as standard format names must
+     be preceded by "X-".  Thus a new experimental redundant audio
+     stream called GSMLPC using dynamic payload type 99 could be
+     specified as:
+
+                          m=video 49232 RTP/AVP 99
+                          a=rtpmap:99 X-GSMLPC/8000
+
+     Such an experimental encoding requires that any site wishing to
+     receive the media stream has relevant configured state in its
+     session directory to know which tools are appropriate.
+
+     Note that RTP audio formats typically do not include information
+     about the number of samples per packet.  If a non-default (as
+     defined in the RTP Audio/Video Profile) packetisation is required,
+     the "ptime" attribute is used as given below.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 22]
+
+RFC 2327                          SDP                         April 1998
+
+
+     For more details on RTP audio and video formats, see [3].
+
+   o Formats for non-RTP media should be registered as MIME content
+     types as described in Appendix B.  For example, the LBL whiteboard
+     application might be registered as MIME content-type application/wb
+     with encoding considerations specifying that it operates over UDP,
+     with no appropriate file format.  In SDP this would then be
+     expressed using a combination of the "media" field and the "fmt"
+     field, as follows:
+
+                         m=application 32416 udp wb
+
+   Suggested Attributes
+
+   The following attributes are suggested.  Since application writers
+   may add new attributes as they are required, this list is not
+   exhaustive.
+
+   a=cat:<category>
+       This attribute gives the dot-separated hierarchical category of
+       the session.  This is to enable a receiver to filter unwanted
+       sessions by category.  It would probably have been a compulsory
+       separate field, except for its experimental nature at this time.
+       It is a session-level attribute, and is not dependent on charset.
+
+   a=keywds:<keywords>
+       Like the cat attribute, this is to assist identifying wanted
+       sessions at the receiver.  This allows a receiver to select
+       interesting session based on keywords describing the purpose of
+       the session.  It is a session-level attribute. It is a charset
+       dependent attribute, meaning that its value should be interpreted
+       in the charset specified for the session description if one is
+       specified, or by default in ISO 10646/UTF-8.
+
+   a=tool:<name and version of tool>
+       This gives the name and version number of the tool used to create
+       the session description.  It is a session-level attribute, and is
+       not dependent on charset.
+
+   a=ptime:<packet time>
+       This gives the length of time in milliseconds represented by the
+       media in a packet. This is probably only meaningful for audio
+       data.  It should not be necessary to know ptime to decode RTP or
+       vat audio, and it is intended as a recommendation for the
+       encoding/packetisation of audio.  It is a media attribute, and is
+       not dependent on charset.
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 23]
+
+RFC 2327                          SDP                         April 1998
+
+
+   a=recvonly
+       This specifies that the tools should be started in receive-only
+       mode where applicable. It can be either a session or media
+       attribute, and is not dependent on charset.
+
+   a=sendrecv
+       This specifies that the tools should be started in send and
+       receive mode.  This is necessary for interactive conferences with
+       tools such as wb which defaults to receive only mode. It can be
+       either a session or media attribute, and is not dependent on
+       charset.
+
+   a=sendonly
+       This specifies that the tools should be started in send-only
+       mode.  An example may be where a different unicast address is to
+       be used for a traffic destination than for a traffic source. In
+       such a case, two media descriptions may be use, one sendonly and
+       one recvonly. It can be either a session or media attribute, but
+       would normally only be used as a media attribute, and is not
+       dependent on charset.
+
+   a=orient:<whiteboard orientation>
+       Normally this is only used in a whiteboard media specification.
+       It specifies the orientation of a the whiteboard on the screen.
+       It is a media attribute. Permitted values are `portrait',
+       `landscape' and `seascape' (upside down landscape). It is not
+       dependent on charset
+
+   a=type:<conference type>
+       This specifies the type of the conference.  Suggested values are
+       `broadcast', `meeting', `moderated', `test' and `H332'.
+       `recvonly' should be the default for `type:broadcast' sessions,
+       `type:meeting' should imply `sendrecv' and `type:moderated'
+       should indicate the use of a floor control tool and that the
+       media tools are started so as to "mute" new sites joining the
+       conference.
+
+       Specifying the attribute type:H332 indicates that this loosely
+       coupled session is part of a H.332 session as defined in the ITU
+       H.332 specification [10].  Media tools should be started
+       `recvonly'.
+
+       Specifying the attribute type:test is suggested as a hint that,
+       unless explicitly requested otherwise, receivers can safely avoid
+       displaying this session description to users.
+
+       The type attribute is a session-level attribute, and is not
+       dependent on charset.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 24]
+
+RFC 2327                          SDP                         April 1998
+
+
+   a=charset:<character set>
+       This specifies the character set to be used to display the
+       session name and information data.  By default, the ISO-10646
+       character set in UTF-8 encoding is used. If a more compact
+       representation is required, other character sets may be used such
+       as ISO-8859-1 for Northern European languages.  In particular,
+       the ISO 8859-1 is specified with the following SDP attribute:
+
+                             a=charset:ISO-8859-1
+
+       This is a session-level attribute; if this attribute is present,
+       it must be before the first media field.  The charset specified
+       MUST be one of those registered with IANA, such as ISO-8859-1.
+       The character set identifier is a US-ASCII string and MUST be
+       compared against the IANA identifiers using a case-insensitive
+       comparison.  If the identifier is not recognised or not
+       supported, all strings that are affected by it SHOULD be regarded
+       as byte strings.
+
+       Note that a character set specified MUST still prohibit the use
+       of bytes 0x00 (Nul), 0x0A (LF) and 0x0d (CR). Character sets
+       requiring the use of these characters MUST define a quoting
+       mechanism that prevents these bytes appearing within text fields.
+
+   a=sdplang:<language tag>
+       This can be a session level attribute or a media level attribute.
+       As a session level attribute, it specifies the language for the
+       session description.  As a media level attribute, it specifies
+       the language for any media-level SDP information field associated
+       with that media.  Multiple sdplang attributes can be provided
+       either at session or media level if multiple languages in the
+       session description or media use multiple languages, in which
+       case the order of the attributes indicates the order of
+       importance of the various languages in the session or media from
+       most important to least important.
+
+       In general, sending session descriptions consisting of multiple
+       languages should be discouraged.  Instead, multiple descriptions
+       should be sent describing the session, one in each language.
+       However this is not possible with all transport mechanisms, and
+       so multiple sdplang attributes are allowed although not
+       recommended.
+
+       The sdplang attribute value must be a single RFC 1766 language
+       tag in US-ASCII.  It is not dependent on the charset attribute.
+       An sdplang attribute SHOULD be specified when a session is of
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 25]
+
+RFC 2327                          SDP                         April 1998
+
+
+       sufficient scope to cross geographic boundaries where the
+       language of recipients cannot be assumed, or where the session is
+       in a different language from the locally assumed norm.
+
+   a=lang:<language tag>
+       This can be a session level attribute or a media level attribute.
+       As a session level attribute, it specifies the default language
+       for the session being described.  As a media level attribute, it
+       specifies the language for that media, overriding any session-
+       level language specified.  Multiple lang attributes can be
+       provided either at session or media level if multiple languages
+       if the session description or media use multiple languages, in
+       which case the order of the attributes indicates the order of
+       importance of the various languages in the session or media from
+       most important to least important.
+
+       The lang attribute value must be a single RFC 1766 language tag
+       in US-ASCII. It is not dependent on the charset attribute.  A
+       lang attribute SHOULD be specified when a session is of
+       sufficient scope to cross geographic boundaries where the
+       language of recipients cannot be assumed, or where the session is
+       in a different language from the locally assumed norm.
+
+   a=framerate:<frame rate>
+       This gives the maximum video frame rate in frames/sec.  It is
+       intended as a recommendation for the encoding of video data.
+       Decimal representations of fractional values using the notation
+       "<integer>.<fraction>" are allowed.  It is a media attribute, is
+       only defined for video media, and is not dependent on charset.
+
+   a=quality:<quality>
+       This gives a suggestion for the quality of the encoding as an
+       integer value.
+
+       The intention of the quality attribute for video is to specify a
+       non-default trade-off between frame-rate and still-image quality.
+       For video, the value in the range 0 to 10, with the following
+       suggested meaning:
+
+       10 - the best still-image quality the compression scheme can
+       give.
+
+       5 - the default behaviour given no quality suggestion.
+
+       0 - the worst still-image quality the codec designer thinks is
+           still usable.
+
+       It is a media attribute, and is not dependent on charset.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 26]
+
+RFC 2327                          SDP                         April 1998
+
+
+   a=fmtp:<format> <format specific parameters>
+       This attribute allows parameters that are specific to a
+       particular format to be conveyed in a way that SDP doesn't have
+       to understand them.  The format must be one of the formats
+       specified for the media.  Format-specific parameters may be any
+       set of parameters required to be conveyed by SDP and given
+       unchanged to the media tool that will use this format.
+
+       It is a media attribute, and is not dependent on charset.
+
+6.1.  Communicating Conference Control Policy
+
+   There is some debate over the way conference control policy should be
+   communicated.  In general, the authors believe that an implicit
+   declarative style of specifying conference control is desirable where
+   possible.
+
+   A simple declarative style uses a single conference attribute field
+   before the first media field, possibly supplemented by properties
+   such as `recvonly' for some of the media tools.  This conference
+   attribute conveys the conference control policy. An example might be:
+
+                             a=type:moderated
+
+   In some cases, however, it is possible that this may be insufficient
+   to communicate the details of an unusual conference control policy.
+   If this is the case, then a conference attribute specifying external
+   control might be set, and then one or more "media" fields might be
+   used to specify the conference control tools and configuration data
+   for those tools. An example is an ITU H.332 session:
+
+                c=IN IP4 224.5.6.7
+                a=type:H332
+                m=audio 49230 RTP/AVP 0
+                m=video 49232 RTP/AVP 31
+                m=application 12349 udp wb
+                m=control 49234 H323 mc
+                c=IN IP4 134.134.157.81
+
+   In this example, a general conference attribute (type:H332) is
+   specified stating that conference control will be provided by an
+   external H.332 tool, and a contact addresses for the H.323 session
+   multipoint controller is given.
+
+   In this document, only the declarative style of conference control
+   declaration is specified.  Other forms of conference control should
+   specify an appropriate type attribute, and should define the
+   implications this has for control media.
+
+
+
+Handley & Jacobson          Standards Track                    [Page 27]
+
+RFC 2327                          SDP                         April 1998
+
+
+7.  Security Considerations
+
+   SDP is a session description format that describes multimedia
+   sessions.  A session description should not be trusted unless it has
+   been obtained by an authenticated transport protocol from a trusted
+   source.  Many different transport protocols may be used to distribute
+   session description, and the nature of the authentication will differ
+   from transport to transport.
+
+   One transport that will frequently be used to distribute session
+   descriptions is the Session Announcement Protocol (SAP).  SAP
+   provides both encryption and authentication mechanisms but due to the
+   nature of session announcements it is likely that there are many
+   occasions where the originator of a session announcement cannot be
+   authenticated because they are previously unknown to the receiver of
+   the announcement and because no common public key infrastructure is
+   available.
+
+   On receiving a session description over an unauthenticated transport
+   mechanism or from an untrusted party, software parsing the session
+   should take a few precautions. Session description contain
+   information required to start software on the receivers system.
+   Software that parses a session description MUST not be able to start
+   other software except that which is specifically configured as
+   appropriate software to participate in multimedia sessions.  It is
+   normally considered INAPPROPRIATE for software parsing a session
+   description to start, on a user's system, software that is
+   appropriate to participate in multimedia sessions, without the user
+   first being informed that such software will be started and giving
+   their consent.  Thus a session description arriving by session
+   announcement, email, session invitation, or WWW page SHOULD not
+   deliver the user into an {it interactive} multimedia session without
+   the user being aware that this will happen.  As it is not always
+   simple to tell whether a session is interactive or not, applications
+   that are unsure should assume sessions are interactive.
+
+   In this specification, there are no attributes which would allow the
+   recipient of a session description to be informed to start multimedia
+   tools in a mode where they default to transmitting.  Under some
+   circumstances it might be appropriate to define such attributes.  If
+   this is done an application parsing a session description containing
+   such attributes SHOULD either ignore them, or inform the user that
+   joining this session will result in the automatic transmission of
+   multimedia data.  The default behaviour for an unknown attribute is
+   to ignore it.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 28]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Session descriptions may be parsed at intermediate systems such as
+   firewalls for the purposes of opening a hole in the firewall to allow
+   the participation in multimedia sessions.  It is considered
+   INAPPROPRIATE for a firewall to open such holes for unicast data
+   streams unless the session description comes in a request from inside
+   the firewall.
+
+   For multicast sessions, it is likely that local administrators will
+   apply their own policies, but the exclusive use of "local" or "site-
+   local" administrative scope within the firewall and the refusal of
+   the firewall to open a hole for such scopes will provide separation
+   of global multicast sessions from local ones.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 29]
+
+RFC 2327                          SDP                         April 1998
+
+
+Appendix A: SDP Grammar
+
+   This appendix provides an Augmented BNF grammar for SDP. ABNF is
+   defined in RFC 2234.
+
+
+   announcement =        proto-version
+                         origin-field
+                         session-name-field
+                         information-field
+                         uri-field
+                         email-fields
+                         phone-fields
+                         connection-field
+                         bandwidth-fields
+                         time-fields
+                         key-field
+                         attribute-fields
+                         media-descriptions
+
+   proto-version =       "v=" 1*DIGIT CRLF
+                         ;this memo describes version 0
+
+   origin-field =        "o=" username space
+                         sess-id space sess-version space
+                         nettype space addrtype space
+                         addr CRLF
+
+   session-name-field =  "s=" text CRLF
+
+   information-field =   ["i=" text CRLF]
+
+   uri-field =           ["u=" uri CRLF]
+
+   email-fields =        *("e=" email-address CRLF)
+
+   phone-fields =        *("p=" phone-number CRLF)
+
+
+   connection-field =    ["c=" nettype space addrtype space
+                         connection-address CRLF]
+                         ;a connection field must be present
+                         ;in every media description or at the
+                         ;session-level
+
+
+   bandwidth-fields =    *("b=" bwtype ":" bandwidth CRLF)
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 30]
+
+RFC 2327                          SDP                         April 1998
+
+
+   time-fields =         1*( "t=" start-time space stop-time
+                         *(CRLF repeat-fields) CRLF)
+                         [zone-adjustments CRLF]
+
+
+   repeat-fields =       "r=" repeat-interval space typed-time
+                         1*(space typed-time)
+
+
+   zone-adjustments =    time space ["-"] typed-time
+                         *(space time space ["-"] typed-time)
+
+
+   key-field =           ["k=" key-type CRLF]
+
+
+   key-type =            "prompt" |
+                         "clear:" key-data |
+                         "base64:" key-data |
+                         "uri:" uri
+
+
+   key-data =            email-safe | "~" | "
+
+
+   attribute-fields =    *("a=" attribute CRLF)
+
+
+   media-descriptions =  *( media-field
+                         information-field
+                         *(connection-field)
+                         bandwidth-fields
+                         key-field
+                         attribute-fields )
+
+
+   media-field =         "m=" media space port ["/" integer]
+                         space proto 1*(space fmt) CRLF
+
+
+   media =               1*(alpha-numeric)
+                         ;typically "audio", "video", "application"
+                         ;or "data"
+
+   fmt =                 1*(alpha-numeric)
+                         ;typically an RTP payload type for audio
+                         ;and video media
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 31]
+
+RFC 2327                          SDP                         April 1998
+
+
+   proto =               1*(alpha-numeric)
+                         ;typically "RTP/AVP" or "udp" for IP4
+
+
+   port =                1*(DIGIT)
+                         ;should in the range "1024" to "65535" inclusive
+                         ;for UDP based media
+
+
+   attribute =           (att-field ":" att-value) | att-field
+
+
+   att-field =           1*(alpha-numeric)
+
+
+   att-value =           byte-string
+
+
+   sess-id =             1*(DIGIT)
+                         ;should be unique for this originating username/host
+
+
+   sess-version =        1*(DIGIT)
+                         ;0 is a new session
+
+
+   connection-address =  multicast-address
+                         | addr
+
+
+   multicast-address =   3*(decimal-uchar ".") decimal-uchar "/" ttl
+                         [ "/" integer ]
+                         ;multicast addresses may be in the range
+                         ;224.0.0.0 to 239.255.255.255
+
+   ttl =                 decimal-uchar
+
+   start-time =          time | "0"
+
+   stop-time =           time | "0"
+
+   time =                POS-DIGIT 9*(DIGIT)
+                         ;sufficient for 2 more centuries
+
+
+   repeat-interval =     typed-time
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 32]
+
+RFC 2327                          SDP                         April 1998
+
+
+   typed-time =          1*(DIGIT) [fixed-len-time-unit]
+
+
+   fixed-len-time-unit = "d" | "h" | "m" | "s"
+
+
+   bwtype =              1*(alpha-numeric)
+
+   bandwidth =           1*(DIGIT)
+
+
+   username =            safe
+                         ;pretty wide definition, but doesn't include space
+
+
+   email-address =       email | email "(" email-safe ")" |
+                         email-safe "<" email ">"
+
+
+   email =               ;defined in RFC822
+
+
+   uri =                 ;defined in RFC1630
+
+
+   phone-number =        phone | phone "(" email-safe ")" |
+                         email-safe "<" phone ">"
+
+
+   phone =               "+" POS-DIGIT 1*(space | "-" | DIGIT)
+                         ;there must be a space or hyphen between the
+                         ;international code and the rest of the number.
+
+
+   nettype =             "IN"
+                         ;list to be extended
+
+
+   addrtype =            "IP4" | "IP6"
+                         ;list to be extended
+
+
+   addr =                FQDN | unicast-address
+
+
+   FQDN =                4*(alpha-numeric|"-"|".")
+                         ;fully qualified domain name as specified in RFC1035
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 33]
+
+RFC 2327                          SDP                         April 1998
+
+
+   unicast-address =     IP4-address | IP6-address
+
+
+   IP4-address =         b1 "." decimal-uchar "." decimal-uchar "." b4
+   b1 =                  decimal-uchar
+                         ;less than "224"; not "0" or "127"
+   b4 =                  decimal-uchar
+                         ;not "0"
+
+   IP6-address =         ;to be defined
+
+
+   text =                byte-string
+                         ;default is to interpret this as IS0-10646 UTF8
+                         ;ISO 8859-1 requires a "a=charset:ISO-8859-1"
+                         ;session-level attribute to be used
+
+
+   byte-string =         1*(0x01..0x09|0x0b|0x0c|0x0e..0xff)
+                         ;any byte except NUL, CR or LF
+
+
+   decimal-uchar =       DIGIT
+                         | POS-DIGIT DIGIT
+                         | ("1" 2*(DIGIT))
+                         | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
+                         | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
+
+
+   integer =             POS-DIGIT *(DIGIT)
+
+
+   alpha-numeric =       ALPHA | DIGIT
+
+
+   DIGIT =               "0" | POS-DIGIT
+
+
+   POS-DIGIT =           "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+
+
+   ALPHA =               "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"|
+                         "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"|
+                         "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"|
+                         "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"|
+                         "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 34]
+
+RFC 2327                          SDP                         April 1998
+
+
+   email-safe =          safe | space | tab
+
+
+   safe =                alpha-numeric |
+                         "'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
+                         "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
+                         "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
+                         "~" | "
+
+
+   space =               %d32
+   tab =                 %d9
+   CRLF =                %d13.10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 35]
+
+RFC 2327                          SDP                         April 1998
+
+
+Appendix B: Guidelines for registering SDP names with IANA
+
+   There are seven field names that may be registered with IANA. Using
+   the terminology in the SDP specification BNF, they are "media",
+   "proto", "fmt", "att-field", "bwtype", "nettype" and "addrtype".
+
+   "media" (eg, audio, video, application, data).
+
+       Packetized media types, such as those used by RTP, share the
+       namespace used by media types registry [RFC 2048] (i.e. "MIME
+       types").  The list of valid media names is the set of top-level
+       MIME content types.  The set of media is intended to be small and
+       not to be extended except under rare circumstances.  (The MIME
+       subtype corresponds to the "fmt" parameter below).
+
+   "proto"
+
+       In general this should be an IETF standards-track transport
+       protocol identifier such as RTP/AVP (rfc 1889 under the rfc 1890
+       profile).
+
+       However, people will want to invent their own proprietary
+       transport protocols.  Some of these should be registered as a
+       "fmt" using "udp" as the protocol and some of which probably
+       can't be.
+
+       Where the protocol and the application are intimately linked,
+       such as with the LBL whiteboard wb which used a proprietary and
+       special purpose protocol over UDP, the protocol name should be
+       "udp" and the format name that should be registered is "wb".  The
+       rules for formats (see below) apply to such registrations.
+
+       Where the proprietary transport protocol really carries many
+       different data formats, it is possible to register a new protocol
+       name with IANA. In such a case, an RFC MUST be produced
+       describing the protocol and referenced in the registration.  Such
+       an RFC MAY be informational, although it is preferable if it is
+       standards-track.
+
+   "fmt"
+
+       The format namespace is dependent on the context of the "proto"
+       field, so a format cannot be registered without specifying one or
+       more transport protocols that it applies to.
+
+       Formats cover all the possible encodings that might want to be
+       transported in a multimedia session.
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 36]
+
+RFC 2327                          SDP                         April 1998
+
+
+       For RTP formats that have been assigned static payload types, the
+       payload type number is used.  For RTP formats using a dynamic
+       payload type number, the dynamic payload type number is given as
+       the format and an additional "rtpmap" attribute specifies the
+       format and parameters.
+
+       For non-RTP formats, any unregistered format name may be
+       registered through the MIME-type registration process [RFC 2048].
+       The type given here is the MIME subtype only (the top-level MIME
+       content type is specified by the media parameter).  The MIME type
+       registration SHOULD reference a standards-track RFC which
+       describes the transport protocol for this media type.  If there
+       is an existing MIME type for this format, the MIME registration
+       should be augmented to reference the transport specification for
+       this media type.  If there is not an existing MIME type for this
+       format, and there exists no appropriate file format, this should
+       be noted in the encoding considerations as "no appropriate file
+       format".
+
+   "att-field" (Attribute names)
+
+       Attribute field names MAY be registered with IANA, although this
+       is not compulsory, and unknown attributes are simply ignored.
+
+       When an attribute is registered, it must be accompanied by a
+       brief specification stating the following:
+
+       o contact name, email address and telephone number
+
+       o attribute-name (as it will appear in SDP)
+
+       o long-form attribute name in English
+
+       o type of attribute (session level, media level, or both)
+
+       o whether the attribute value is subject to the charset
+       attribute.
+
+       o a one paragraph explanation of the purpose of the attribute.
+
+       o a specification of appropriate attribute values for this
+         attribute.
+
+       IANA will not sanity check such attribute registrations except to
+       ensure that they do not clash with existing registrations.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 37]
+
+RFC 2327                          SDP                         April 1998
+
+
+       Although the above is the minimum that IANA will accept, if the
+       attribute is expected to see widespread use and interoperability
+       is an issue, authors are encouraged to produce a standards-track
+       RFC that specifies the attribute more precisely.
+
+       Submitters of registrations should ensure that the specification
+       is in the spirit of SDP attributes, most notably that the
+       attribute is platform independent in the sense that it makes no
+       implicit assumptions about operating systems and does not name
+       specific pieces of software in a manner that might inhibit
+       interoperability.
+
+   "bwtype" (bandwidth specifiers)
+
+       A proliferation of bandwidth specifiers is strongly discouraged.
+
+       New bandwidth specifiers may be registered with IANA.  The
+       submission MUST reference a standards-track RFC specifying the
+       semantics of the bandwidth specifier precisely, and indicating
+       when it should be used, and why the existing registered bandwidth
+       specifiers do not suffice.
+
+   "nettype" (Network Type)
+
+       New network types may be registered with IANA if SDP needs to be
+       used in the context of non-internet environments. Whilst these
+       are not normally the preserve of IANA, there may be circumstances
+       when an Internet application needs to interoperate with a non-
+       internet application, such as when gatewaying an internet
+       telephony call into the PSTN.  The number of network types should
+       be small and should be rarely extended.  A new network type
+       cannot be registered without registering at least one address
+       type to be used with that network type.  A new network type
+       registration MUST reference an RFC which gives details of the
+       network type and address type and specifies how and when they
+       would be used.  Such an RFC MAY be Informational.
+
+   "addrtype" (Address Type)
+
+       New address types may be registered with IANA.  An address type
+       is only meaningful in the context of a network type, and any
+       registration of an address type MUST specify a registered network
+       type, or be submitted along with a network type registration.  A
+       new address type registration MUST reference an RFC giving
+       details of the syntax of the address type.  Such an RFC MAY be
+       Informational.  Address types are not expected to be registered
+       frequently.
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 38]
+
+RFC 2327                          SDP                         April 1998
+
+
+   Registration Procedure
+
+   To register a name the above guidelines should be followed regarding
+   the required  level  of  documentation  that  is required.  The
+   registration itself should be sent to IANA.  Attribute registrations
+   should  include the  information  given  above.   Other registrations
+   should include the following additional information:
+
+   o contact name, email address and telephone number
+
+   o name being registered (as it will appear in SDP)
+
+   o long-form name in English
+
+   o type of name ("media", "proto", "fmt", "bwtype", "nettype", or
+     "addrtype")
+
+   o a one paragraph explanation of the purpose of the registered name.
+
+   o a reference to the specification (eg RFC number) of the registered
+     name.
+
+   IANA may refer any registration to the IESG or to any appropriate
+   IETF working group for review, and may request revisions to be made
+   before a registration will be made.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 39]
+
+RFC 2327                          SDP                         April 1998
+
+
+Appendix C: Authors' Addresses
+
+   Mark Handley
+   Information Sciences Institute
+   c/o MIT Laboratory for Computer Science
+   545 Technology Square
+   Cambridge, MA 02139
+   United States
+   electronic mail: mjh at isi.edu
+
+   Van Jacobson
+   MS 46a-1121
+   Lawrence Berkeley Laboratory
+   Berkeley, CA 94720
+   United States
+   electronic mail: van at ee.lbl.gov
+
+Acknowledgments
+
+   Many people in the IETF MMUSIC working group have made comments and
+   suggestions contributing to this document.  In particular, we would
+   like to thank Eve Schooler, Steve Casner, Bill Fenner, Allison
+   Mankin, Ross Finlayson, Peter Parnes, Joerg Ott, Carsten Bormann, Rob
+   Lanphier and Steve Hanna.
+
+References
+
+   [1] Mills, D., "Network Time Protocol (version 3) specification and
+   implementation", RFC 1305, March 1992.
+
+   [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP:
+   A Transport Protocol for Real-Time Applications", RFC 1889, January
+   1996.
+
+   [3] Schulzrinne, H., "RTP Profile for Audio and Video Conferences
+   with Minimal Control", RFC 1890, January 1996
+
+   [4] Handley, M., "SAP - Session Announcement Protocol", Work in
+   Progress.
+
+   [5] V. Jacobson, S. McCanne, "vat - X11-based audio teleconferencing
+   tool" vat manual page, Lawrence Berkeley Laboratory, 1994.
+
+   [6] The Unicode Consortium, "The Unicode Standard -- Version 2.0",
+   Addison-Wesley, 1996.
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 40]
+
+RFC 2327                          SDP                         April 1998
+
+
+   [7] ISO/IEC 10646-1:1993. International Standard -- Information
+   technol- ogy -- Universal Multiple-Octet Coded Character Set (UCS) --
+   Part 1: Architecture and Basic Multilingual Plane.  Five amendments
+   and a techn- ical  corrigendum  have been published up to now.  UTF-8
+   is described in Annex R, published as Amendment 2.
+
+   [8] Goldsmith, D., and M. Davis, "Using Unicode with MIME", RFC 1641,
+   July 1994.
+
+   [9] Yergeau, F., "UTF-8, a transformation format of Unicode and ISO
+   10646", RFC 2044, October 1996.
+
+   [10] ITU-T Recommendation H.332 (1998): "Multimedia Terminal for
+   Receiving Internet-based H.323 Conferences", ITU, Geneva.
+
+   [11] Handley, M., Schooler, E., and H. Schulzrinne, "Session
+   Initiation Protocol (SIP)", Work in Progress.
+
+   [12] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming
+   Protocol (RTSP)", RFC 2326, April 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 41]
+
+RFC 2327                          SDP                         April 1998
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (1998).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson          Standards Track                    [Page 42]
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+#! /bin/sh
+#
+# Run the sdp tests
+#
+# usage: run_test_sdp [test_program] [test-directory]
+#
+
+test_sdp="${1:-./test_sdp}"
+tests="${2:-tests}"
+
+if test -r $tests/message-1.sdp ; then
+
+for n in 1 2 3 4 5 6 7 8 9 10;
+do 
+    echo -n "$n: "
+    "$test_sdp" < "$tests/message-$n.sdp" && echo OK
+done
+
+else 
+    echo "sdp run-tests: no tests found, skipping."
+fi
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+   ; BNF from RFC 2327
+
+   announcement =        proto-version
+                         origin-field
+                         session-name-field
+                         information-field
+                         uri-field
+                         email-fields
+                         phone-fields
+                         connection-field
+                         bandwidth-fields
+                         time-fields
+                         key-field
+                         attribute-fields
+                         media-descriptions
+
+   proto-version =       "v=" 1*DIGIT CRLF
+                         ;this memo describes version 0
+
+   origin-field =        "o=" username space
+                         sess-id space sess-version space
+                         nettype space addrtype space
+                         addr CRLF
+
+   session-name-field =  "s=" text CRLF
+
+   information-field =   ["i=" text CRLF]
+
+   uri-field =           ["u=" uri CRLF]
+
+   email-fields =        *("e=" email-address CRLF)
+
+   phone-fields =        *("p=" phone-number CRLF)
+
+
+   connection-field =    ["c=" nettype space addrtype space
+                         connection-address CRLF]
+                         ;a connection field must be present
+                         ;in every media description or at the
+                         ;session-level
+
+
+   bandwidth-fields =    *("b=" bwtype ":" bandwidth CRLF)
+
+
+   time-fields =         1*( "t=" start-time space stop-time
+                         *(CRLF repeat-fields) CRLF)
+                         [zone-adjustments CRLF]
+
+
+   repeat-fields =       "r=" repeat-interval space typed-time
+                         1*(space typed-time)
+
+
+   zone-adjustments =    "z=" time space ["-"] typed-time
+                         *(space time space ["-"] typed-time)
+
+
+   key-field =           ["k=" key-type CRLF]
+
+
+   key-type =            "prompt" |
+                         "clear:" key-data |
+                         "base64:" key-data |
+                         "uri:" uri
+
+
+   key-data =            email-safe | "~" | "
+
+
+   attribute-fields =    *("a=" attribute CRLF)
+
+
+   media-descriptions =  *( media-field
+                         information-field
+                         *(connection-field)
+                         bandwidth-fields
+                         key-field
+                         attribute-fields )
+
+
+   media-field =         "m=" media space port ["/" integer]
+                         space proto 1*(space fmt) CRLF
+
+
+   media =               1*(alpha-numeric)
+                         ;typically "audio", "video", "application"
+                         ;or "data"
+
+   fmt =                 1*(alpha-numeric)
+                         ;typically an RTP payload type for audio
+                         ;and video media
+
+   proto =               1*(alpha-numeric | "/") ; PPe
+                         ;typically "RTP/AVP" or "udp" for IP4
+
+
+   port =                1*(DIGIT)
+                         ;should in the range "1024" to "65535" inclusive
+                         ;for UDP based media
+
+
+   attribute =           (att-field ":" att-value) | att-field
+
+
+   att-field =           1*(alpha-numeric)
+
+
+   att-value =           byte-string
+
+
+   sess-id =             1*(DIGIT)
+                         ;should be unique for this originating username/host
+
+
+   sess-version =        1*(DIGIT)
+                         ;0 is a new session
+
+
+   connection-address =  multicast-address
+                         | addr
+
+
+   multicast-address =   3*(decimal-uchar ".") decimal-uchar "/" ttl
+                         [ "/" integer ]
+                         ;multicast addresses may be in the range
+                         ;224.0.0.0 to 239.255.255.255
+
+   ttl =                 decimal-uchar
+
+   start-time =          time | "0"
+
+   stop-time =           time | "0"
+
+   time =                POS-DIGIT 9*(DIGIT)
+                         ;sufficient for 2 more centuries
+
+
+   repeat-interval =     typed-time
+
+   typed-time =          1*(DIGIT) [fixed-len-time-unit]
+
+
+   fixed-len-time-unit = "d" | "h" | "m" | "s"
+
+
+   bwtype =              1*(alpha-numeric)
+
+   bandwidth =           1*(DIGIT)
+
+
+   username =            safe
+                         ;pretty wide definition, but doesn't include space
+
+
+   email-address =       email | email "(" email-safe ")" |
+                         email-safe "<" email ">"
+
+
+   email =               ;defined in RFC822
+
+
+   uri=                  ;defined in RFC1630
+
+
+   phone-number =        phone | phone "(" email-safe ")" |
+                         email-safe "<" phone ">"
+
+
+   phone =               "+" POS-DIGIT 1*(space | "-" | DIGIT)
+                         ;there must be a space or hyphen between the
+                         ;international code and the rest of the number.
+
+
+   nettype =             "IN"
+                         ;list to be extended
+
+
+   addrtype =            "IP4" | "IP6"
+                         ;list to be extended
+
+
+   addr =                FQDN | unicast-address
+
+
+   FQDN =                4*(alpha-numeric|"-"|".")
+                         ;fully qualified domain name as specified in RFC1035
+
+   unicast-address =     IP4-address | IP6-address
+
+
+   IP4-address =         b1 "." decimal-uchar "." decimal-uchar "." b4
+   b1 =                  decimal-uchar
+                         ;less than "224"; not "0" or "127"
+   b4 =                  decimal-uchar
+                         ;not "0"
+
+   IP6-address =         ;to be defined
+
+
+   text =                byte-string
+                         ;default is to interpret this as IS0-10646 UTF8
+                         ;ISO 8859-1 requires a "a=charset:ISO-8859-1"
+                         ;session-level attribute to be used
+
+
+   byte-string =         1*(0x01..0x09|0x0b|0x0c|0x0e..0xff)
+                         ;any byte except NUL, CR or LF
+
+
+   decimal-uchar =       DIGIT
+                         | POS-DIGIT DIGIT
+                         | ("1" 2*(DIGIT))
+                         | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
+                         | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
+
+
+   integer =             POS-DIGIT *(DIGIT)
+
+
+   alpha-numeric =       ALPHA | DIGIT
+
+
+   DIGIT =               "0" | POS-DIGIT
+
+
+   POS-DIGIT =           "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+
+
+   ALPHA =               "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"|
+                         "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"|
+                         "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"|
+                         "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"|
+                         "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"
+
+
+   email-safe =          safe | space | tab
+
+
+   safe =                alpha-numeric |
+                         "'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
+                         "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
+                         "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
+                         "~" | "
+
+
+   space =               %d32
+   tab =                 %d9
+   CRLF =                %d13.10

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1877 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sdp.c Simple SDP interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_types.h>
+
+#include "sofia-sip/sdp.h"
+
+struct align { void  *_a; char _b; };
+
+#define ALIGN(v, n) ((n - (intptr_t)(v)) & (n - 1))
+#define STRUCT_ALIGN_  (sizeof(struct align) - offsetof(struct align, _b))
+#define STRUCT_ALIGN(v) ALIGN(v, sizeof(void *))
+#define ASSERT_STRUCT_ALIGN(p) \
+  (STRUCT_ALIGN(p) ? (void)assert(!"STRUCT_ALIGNED(" #p ")") : (void)0)
+
+const unsigned sdp_struct_align_ = sizeof(void *) - STRUCT_ALIGN_;
+
+#define STR_XTRA(rv, s)    ((s) ? rv += strlen((s)) + 1 : 0)
+#define PTR_XTRA(rv, p, f) \
+  ((p) ? (rv += STRUCT_ALIGN(rv) + f(p)) : 0)
+#define LST_XTRA(rv, l, f) \
+  ((l) ? (rv += STRUCT_ALIGN(rv) + list_xtra_all((xtra_f*)f, l)) : 0)
+
+
+#define STRUCT_DUP(p, dst, src) \
+  ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src));	\
+  ((*(int*)(src) >= (int)sizeof(*src)					\
+    ? (dst = memcpy((p), (src), sizeof(*src)))				\
+    : (dst = memcpy((p), (src), *(int*)(src))),				\
+    memset((p)+*(int*)(src), 0, sizeof(*src) - *(int*)(src))), \
+  ((p) += sizeof(*src)))
+
+#define STRUCT_DUP2(p, dst, src) \
+  ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src));	\
+  (dst = memcpy((p), (src), *(int*)(src)), ((p) += *(int*)(src)))
+
+#define STR_DUP(p, dst, src, m) \
+ ((src->m) ? ((dst->m) = strcpy((p), (src->m)), (p) += strlen((p)) + 1) \
+           : ((dst->m) = 0))
+#define PTR_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)), ((dup)(&(p), (src->m)))): 0)
+#define LST_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       list_dup_all((dup_f*)(dup), &(p), src->m)) : 0)
+#define MED_XTRA_EX(rv, l, c) \
+  ((l) ? (rv += STRUCT_ALIGN(rv) + media_xtra_ex(l, c)) : 0)
+#define MED_DUP_EX(p, dst, src, m, dst_c, src_c) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       media_dup_all(&(p), src->m, dst, dst_c, src_c)) : 0)
+
+#define MED_XTRA_ALL(rv, m) \
+  ((m) ? (rv += STRUCT_ALIGN(rv) + media_xtra_all(m)) : 0)
+#define MED_DUP_ALL(p, dst, src, m) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       media_dup_all(&(p), src->m, dst)) : 0)
+
+typedef size_t xtra_f(void const *);
+typedef void *dup_f(char **bb, void const *src);
+
+static size_t list_xtra_all(xtra_f *xtra, void const *v);
+static void *list_dup_all(dup_f *dup, char **bb, void const *vsrc);
+
+static size_t session_xtra(sdp_session_t const *o); 
+static sdp_session_t *session_dup(char **pp, sdp_session_t const *o);
+
+static size_t origin_xtra(sdp_origin_t const *o); 
+static sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *o);
+
+static size_t connection_xtra(sdp_connection_t const *o); 
+static sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *o);
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *o); 
+static sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *o);
+
+static size_t time_xtra(sdp_time_t const *o); 
+static sdp_time_t *time_dup(char **pp, sdp_time_t const *o);
+
+static size_t repeat_xtra(sdp_repeat_t const *o); 
+static sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *o);
+
+static size_t zone_xtra(sdp_zone_t const *o); 
+static sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *o);
+
+static size_t key_xtra(sdp_key_t const *o); 
+static sdp_key_t *key_dup(char **pp, sdp_key_t const *o);
+
+static size_t attribute_xtra(sdp_attribute_t const *o); 
+static sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *o);
+
+static size_t list_xtra(sdp_list_t const *o); 
+static sdp_list_t *list_dup(char **pp, sdp_list_t const *o);
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *o); 
+static sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *o);
+
+static size_t media_xtra(sdp_media_t const *o);
+static sdp_media_t *media_dup(char **pp,
+			      sdp_media_t const *o,
+			      sdp_session_t *sdp);
+#ifdef nomore
+static size_t media_xtra_ex(sdp_media_t const *o,
+			  sdp_connection_t const *c);
+static sdp_media_t *media_dup_ex(char **pp,
+				  sdp_media_t const *o,
+				  sdp_session_t *sdp,
+				  sdp_connection_t *dst_c,
+				  sdp_connection_t const *src_c);
+#endif
+static size_t media_xtra_all(sdp_media_t const *o);
+static sdp_media_t *media_dup_all(char **pp,
+				  sdp_media_t const *o,
+				  sdp_session_t *sdp);
+
+
+/** Define a function body duplicating an SDP structure. */
+#define SDP_DUP(type, name) \
+  sdp_##type##_t *rv; size_t size; char *p, *end; \
+  if (!name) return NULL; \
+  size = type##_xtra(name); \
+  p = su_alloc(h, size); end = p + size; \
+  rv = type##_dup(&p, name); \
+  assert(p == end); \
+  return rv;
+
+/** Define a function body duplicating a list of SDP structures. */
+#define SDP_LIST_DUP(type, name) \
+  sdp_##type##_t *rv; size_t size; char *p, *end; \
+  if (!name) return NULL; \
+  size = list_xtra_all((xtra_f*)type##_xtra, name); \
+  rv = su_alloc(h, size); p = (char *)rv; end = p + size; \
+  list_dup_all((dup_f*)type##_dup, &p, name); \
+  assert(p == end); \
+  return rv;
+
+/**Duplicate an SDP origin description.
+ *
+ * The function sdp_origin_dup() duplicates (deeply copies) an SDP origin
+ * description @a o allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param o     SDP origin description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_origin_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_origin_t *sdp_origin_dup(su_home_t *h, sdp_origin_t const *o)
+{ 
+  SDP_DUP(origin, o);
+}
+
+/**Duplicate an SDP connection description.
+ *
+ * The function sdp_connection_dup() duplicates (deeply copies) an SDP
+ * connection description @a c allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param c     SDP connection description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_connection_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_connection_t *sdp_connection_dup(su_home_t *h, sdp_connection_t const *c)
+{ 
+  SDP_LIST_DUP(connection, c);
+}
+
+/**Duplicate an SDP bandwidth description.
+ *
+ * The function sdp_bandwidth_dup() duplicates (deeply copies) an SDP
+ * bandwidth description @a b allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param b     SDP bandwidth description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_bandwidth_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_bandwidth_t *sdp_bandwidth_dup(su_home_t *h, sdp_bandwidth_t const *b)
+{ 
+  SDP_LIST_DUP(bandwidth, b);
+}
+
+/**Duplicate an SDP time description.
+ *
+ * The function sdp_time_dup() duplicates (deeply copies) an SDP time
+ * description @a t allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param t  SDP time description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_time_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_time_t *sdp_time_dup(su_home_t *h, sdp_time_t const *t)
+{ 
+  SDP_LIST_DUP(time, t);
+}
+
+/**Duplicate an SDP repeat description.
+ *
+ * The function sdp_repeat_dup() duplicates (deeply copies) an SDP repeat
+ * description @a r allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param r  SDP repeat description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_repeat_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_repeat_t *sdp_repeat_dup(su_home_t *h, sdp_repeat_t const *r)
+{ 
+  SDP_DUP(repeat, r);
+}
+
+/**Duplicate an SDP zone description.
+ *
+ * The function sdp_zone_dup() duplicates (deeply copies) an SDP zone
+ * description @a z allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param z  SDP zone description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_zone_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_zone_t *sdp_zone_dup(su_home_t *h, sdp_zone_t const *z)
+{ 
+  SDP_DUP(zone, z);
+}
+
+/**Duplicate an SDP key description.
+ *
+ * The function sdp_key_dup() duplicates (deeply copies) an SDP key
+ * description @a k allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param k  SDP key description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_key_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_key_t *sdp_key_dup(su_home_t *h, sdp_key_t const *k)
+{ 
+  SDP_DUP(key, k);
+}
+
+/**Duplicate an SDP attribute list.
+ *
+ * The function sdp_attribute_dup() duplicates (deeply copies) an SDP
+ * attribute list @a a allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param a  SDP attribute description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_attribute_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_attribute_t *sdp_attribute_dup(su_home_t *h, sdp_attribute_t const *a)
+{ 
+  SDP_LIST_DUP(attribute, a);
+}
+
+/**Duplicate an SDP list of text.
+ *
+ * The function sdp_list_dup() duplicates (deeply copies) an SDP text
+ * list @a l allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param l  SDP list description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_list_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_list_t *sdp_list_dup(su_home_t *h, sdp_list_t const *l)
+{ 
+  SDP_LIST_DUP(list, l);
+}
+
+/**Duplicate an SDP rtpmap list.
+ *
+ * The function sdp_rtpmap_dup() duplicates (deeply copies) an SDP rtpmap
+ * list @a rm allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param rm SDP rtpmap description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_rtpmap_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_rtpmap_t *sdp_rtpmap_dup(su_home_t *h, sdp_rtpmap_t const *rm)
+{ 
+  SDP_LIST_DUP(rtpmap, rm);
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup() duplicates (deeply copies) an SDP media
+ * description @a m allocating memory using memory @a home.
+ *
+ * @param h   Memory home
+ * @param m   SDP media description to be duplicated
+ * @param sdp SDP session description to which the newly allocated
+ *            media description is linked
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup(su_home_t *h, sdp_media_t const *m, 
+			   sdp_session_t *sdp)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra(m);
+  p = su_alloc(h, size); end = p + size;
+  rv = media_dup(&p, m, sdp);
+  assert(p == end);
+  return rv;
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup_all() duplicates (deeply copies) a list of SDP
+ * media descriptions @a m allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param m     list of SDP media descriptions to be duplicated
+ * @param sdp   SDP session description to which the newly allocated
+ *              media descriptions are linked
+ *
+ * @return 
+ * If successful, a pointer to a newly allocated list of sdp_media_t
+ * structures is returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup_all(su_home_t *h, sdp_media_t const *m, 
+			       sdp_session_t *sdp)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra_all(m);
+  p = su_alloc(h, size); end = p + size;
+  rv = media_dup_all(&p, m, sdp);
+  assert(p == end);
+  return rv;
+}
+
+#ifdef nomore			/* really deprecated */
+/**Duplicate media description with common address.
+ *
+ * This function is provided in order to avoid duplicate @c c= lines.  If
+ * the @c c= line in media description equals to @a src_c, it is not
+ * duplicated but replaced with @a dst_c instead.
+ *
+ * @param home  Memory home
+ * @param src   SDP media description to be duplicated
+ * @param sdp   SDP session description to which the newly allocated
+ *              media description is linked
+ * @param dst_c Connection description used instead of duplicate of @a src_c.
+ * @param src_c Connection description not to be duplicated
+
+ * @return 
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ *
+ * @deprecated
+ * This function is deprecated. Use sdp_media_dup() instead.
+ */
+sdp_media_t *sdp_media_dup_ex(su_home_t *home, 
+			      sdp_media_t const *src,
+			      sdp_session_t *sdp,
+			      sdp_connection_t *dst_c,
+			      sdp_connection_t const *src_c)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra_all(src, src_c);
+  p = su_alloc(home, size); end = p + size;
+  rv = media_dup_all(&p, src, sdp, dst_c, src_c);
+  assert(p == end);
+  return rv;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static size_t origin_xtra(sdp_origin_t const *o)
+{
+  size_t rv = sizeof(*o);
+  STR_XTRA(rv, o->o_username);
+  PTR_XTRA(rv, o->o_address, connection_xtra);
+  return rv;
+}
+
+static
+sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *src)
+{
+  char *p;
+  sdp_origin_t *o;
+
+  p = *pp; 
+  STRUCT_DUP(p, o, src);
+  STR_DUP(p, o, src, o_username);
+  PTR_DUP(p, o, src, o_address, connection_dup);
+
+  assert((size_t)(p - *pp) == origin_xtra(src));
+  *pp = p;
+  return o;
+}
+
+static size_t connection_xtra(sdp_connection_t const *c)
+{
+  size_t rv = sizeof(*c);
+  STR_XTRA(rv, c->c_address);
+  return rv;
+}
+
+static
+sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *src)
+{
+  char *p;
+  sdp_connection_t *c;
+
+  p = *pp; 
+  STRUCT_DUP(p, c, src); 
+  c->c_next = NULL;
+  STR_DUP(p, c, src, c_address);
+
+  assert((size_t)(p - *pp) == connection_xtra(src));
+  *pp = p;
+  return c;
+}
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *b)
+{
+  size_t rv = sizeof(*b);
+  STR_XTRA(rv, b->b_modifier_name);
+  return rv;
+}
+
+static
+sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *src)
+{
+  char *p;
+  sdp_bandwidth_t *b;
+
+  p = *pp;
+  STRUCT_DUP(p, b, src);
+  b->b_next = NULL;
+  STR_DUP(p, b, src, b_modifier_name);
+
+  assert((size_t)(p - *pp) == bandwidth_xtra(src));
+  *pp = p;
+  return b;
+}
+
+
+static size_t time_xtra(sdp_time_t const *t)
+{
+  size_t rv = sizeof(*t);
+  PTR_XTRA(rv, t->t_repeat, repeat_xtra);
+  PTR_XTRA(rv, t->t_zone, zone_xtra);
+  return rv;
+}
+
+static
+sdp_time_t *time_dup(char **pp, sdp_time_t const *src)
+{
+  char *p;
+  sdp_time_t *t;
+
+  p = *pp;
+  STRUCT_DUP(p, t, src);
+  t->t_next = NULL;
+  PTR_DUP(p, t, src, t_repeat, repeat_dup);
+  PTR_DUP(p, t, src, t_zone, zone_dup);
+
+  assert((size_t)(p - *pp) == time_xtra(src));
+  *pp = p;
+  return t;
+}
+
+
+static size_t repeat_xtra(sdp_repeat_t const *r)
+{
+  return (size_t)r->r_size;
+}
+
+static
+sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *src)
+{
+  char *p;
+  sdp_repeat_t *r;
+
+  p = *pp;
+  STRUCT_DUP2(p, r, src);
+
+  assert((size_t)(p - *pp) == repeat_xtra(src));
+  *pp = p;
+  return r;
+}
+
+
+static size_t zone_xtra(sdp_zone_t const *z)
+{
+  return z->z_size;
+}
+
+static
+sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *src)
+{
+  char *p;
+  sdp_zone_t *z;
+
+  p = *pp;
+  STRUCT_DUP2(p, z, src);
+
+  assert((size_t)(p - *pp) == zone_xtra(src));
+  *pp = p;
+  return z;
+}
+
+
+static size_t key_xtra(sdp_key_t const *k)
+{
+  size_t rv = sizeof(*k);
+  STR_XTRA(rv, k->k_method_name);
+  STR_XTRA(rv, k->k_material);
+  return rv;
+}
+
+static
+sdp_key_t *key_dup(char **pp, sdp_key_t const *src)
+{
+  char *p;
+  sdp_key_t *k;
+
+  p = *pp;
+  STRUCT_DUP(p, k, src);
+  STR_DUP(p, k, src, k_method_name);
+  STR_DUP(p, k, src, k_material);
+
+  assert((size_t)(p - *pp) == key_xtra(src));
+  *pp = p;
+  return k;
+}
+
+
+static size_t attribute_xtra(sdp_attribute_t const *a)
+{
+  size_t rv = sizeof(*a);
+  STR_XTRA(rv, a->a_name);
+  STR_XTRA(rv, a->a_value);
+  return rv;
+}
+
+static
+sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *src)
+{
+  char *p;
+  sdp_attribute_t *a;
+
+  p = *pp;
+  STRUCT_DUP(p, a, src);
+  a->a_next = NULL;
+  STR_DUP(p, a, src, a_name);
+  STR_DUP(p, a, src, a_value);
+
+  assert((size_t)(p - *pp) == attribute_xtra(src));
+  *pp = p;
+  return a;
+}
+
+
+static size_t media_xtra(sdp_media_t const *m)
+{
+  size_t rv = sizeof(*m);
+
+  STR_XTRA(rv, m->m_type_name);
+  STR_XTRA(rv, m->m_proto_name);
+  LST_XTRA(rv, m->m_format, list_xtra);
+  LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+  STR_XTRA(rv, m->m_information);
+  LST_XTRA(rv, m->m_connections, connection_xtra);
+  LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+  PTR_XTRA(rv, m->m_key, key_xtra);
+  LST_XTRA(rv, m->m_attributes, attribute_xtra);
+  
+  return rv;
+}
+
+static
+sdp_media_t *media_dup(char **pp, 
+		       sdp_media_t const *src,
+		       sdp_session_t *sdp)
+{
+  char *p;
+  sdp_media_t *m;
+
+  p = *pp;
+  STRUCT_DUP(p, m, src);
+  m->m_next = NULL;
+
+  STR_DUP(p, m, src, m_type_name);
+  STR_DUP(p, m, src, m_proto_name);
+  LST_DUP(p, m, src, m_format, list_dup);
+  LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+  STR_DUP(p, m, src, m_information);
+  LST_DUP(p, m, src, m_connections, connection_dup);
+  LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+  PTR_DUP(p, m, src, m_key, key_dup);
+  LST_DUP(p, m, src, m_attributes, attribute_dup);
+
+  /* note! we must not implicitly use 'src->m_session' as it 
+           might point to a temporary session */
+  m->m_session = sdp;
+    
+  m->m_rejected = src->m_rejected; 
+  m->m_mode = src->m_mode;
+
+  assert((size_t)(p - *pp) == media_xtra(src));
+  *pp = p;
+  return m;
+}
+
+#ifdef nomore
+static
+int media_xtra_ex(sdp_media_t const *m, sdp_connection_t const *c)
+{
+  int rv = 0;
+
+  for (; m; m = m->m_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += sizeof(*m);
+
+    STR_XTRA(rv, m->m_type_name);
+    STR_XTRA(rv, m->m_proto_name);
+    LST_XTRA(rv, m->m_format, list_xtra);
+    LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+    STR_XTRA(rv, m->m_information);
+    if (c != m->m_connections)
+      LST_XTRA(rv, m->m_connections, connection_xtra);
+    LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+    PTR_XTRA(rv, m->m_key, key_xtra);
+    LST_XTRA(rv, m->m_attributes, attribute_xtra);
+  }
+
+  return rv;
+}
+
+static
+sdp_media_t *media_dup_ex(char **pp, 
+			  sdp_media_t const *src,
+			  sdp_session_t *sdp,
+			  sdp_connection_t *dst_c,
+			  sdp_connection_t const *src_c)
+{
+  char *p;
+  sdp_media_t *retval = NULL, *m, **mm = &retval;
+  int xtra = media_xtra_ex(src, src_c);
+
+  p = *pp;
+
+  for (; src; src = src->m_next) {
+    p += STRUCT_ALIGN(p);
+    STRUCT_DUP(p, m, src);
+    m->m_next = NULL;
+
+    STR_DUP(p, m, src, m_type_name);
+    STR_DUP(p, m, src, m_proto_name);
+    LST_DUP(p, m, src, m_format, list_dup);
+    LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+    STR_DUP(p, m, src, m_information);
+    if (src_c != src->m_connections)
+      LST_DUP(p, m, src, m_connections, connection_dup);
+    else
+      m->m_connections = dst_c;
+    LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+    PTR_DUP(p, m, src, m_key, key_dup);
+    LST_DUP(p, m, src, m_attributes, attribute_dup);
+    
+    /* note! we must not implicitly use 'src->m_session' as it 
+       might point to a temporary session */
+    m->m_session = sdp;
+    
+    m->m_rejected = src->m_rejected; 
+    m->m_mode = src->m_mode;
+
+    assert(m);
+    *mm = m; mm = &m->m_next;
+  }
+
+  assert(p - *pp == xtra);
+
+
+  *pp = p;
+
+  return retval;
+}
+#endif
+
+static size_t media_xtra_all(sdp_media_t const *m)
+{
+  size_t rv = 0;
+
+  for (; m; m = m->m_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += media_xtra(m);
+  }
+
+  return rv;
+}
+
+static
+sdp_media_t *media_dup_all(char **pp, 
+			   sdp_media_t const *src,
+			   sdp_session_t *sdp)
+{
+  char *p;
+  sdp_media_t *retval = NULL, *m, **mm = &retval;
+
+  p = *pp;
+
+  for (; src; src = src->m_next) {
+    p += STRUCT_ALIGN(p);
+    m = media_dup(&p, src, sdp);
+    assert(m);
+    *mm = m; mm = &m->m_next;
+  }
+
+  *pp = p;
+
+  return retval;
+}
+
+static size_t list_xtra(sdp_list_t const *l)
+{
+  size_t rv = sizeof(*l);
+  rv += strlen(l->l_text) + 1;
+  return rv;
+}
+
+static
+sdp_list_t *list_dup(char **pp, sdp_list_t const *src)
+{
+  char *p;
+  sdp_list_t *l;
+
+  p = *pp; 
+  STRUCT_DUP(p, l, src);
+  l->l_next = NULL;
+  STR_DUP(p, l, src, l_text);
+
+  assert((size_t)(p - *pp) == list_xtra(src));
+  *pp = p;
+  return l;
+}
+
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *rm)
+{
+  size_t rv = sizeof(*rm);
+  STR_XTRA(rv, rm->rm_encoding);
+  STR_XTRA(rv, rm->rm_params);
+  STR_XTRA(rv, rm->rm_fmtp);
+  return rv;
+}
+
+static
+sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *src)
+{
+  char *p;
+  sdp_rtpmap_t *rm;
+
+  p = *pp; 
+  STRUCT_DUP(p, rm, src);
+  rm->rm_next = NULL;
+  STR_DUP(p, rm, src, rm_encoding);
+  STR_DUP(p, rm, src, rm_params);
+  STR_DUP(p, rm, src, rm_fmtp);
+
+  assert((size_t)(p - *pp) == rtpmap_xtra(src));
+  *pp = p;
+  return rm;
+}
+
+/** Return total size of a list, including size of all nodes */
+static size_t list_xtra_all(xtra_f *xtra, void const *v)
+{
+  size_t rv = 0;
+  sdp_list_t const *l;
+
+  for (l = v; l; l = l->l_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += xtra(l);
+  }
+
+  return rv;
+}
+
+static
+void *list_dup_all(dup_f *dup, char **pp, void const *vsrc)
+{
+  char *p;
+  sdp_list_t const *src;
+  sdp_list_t *retval = NULL, *l, **ll = &retval;
+
+  p = *pp;
+
+  for (src = vsrc; src; src = src->l_next) {
+    p += STRUCT_ALIGN(p);
+    l = dup(&p, src);
+    assert(l);
+    *ll = l; ll = &l->l_next;
+  }
+
+  *pp = p;
+
+  return retval;
+}
+
+#if 0
+static size_t XXX_xtra(sdp_XXX_t const *YYY)
+{
+  size_t rv = sizeof(*YYY);
+  rv += strlen(YYY->YYY_encoding) + 1;
+  if (YYY->YYY_params);
+    rv += strlen(YYY->YYY_params) + 1;
+  return rv;
+}
+
+static
+sdp_XXX_t *XXX_dup(char **pp, sdp_XXX_t const *src)
+{
+  char *p;
+  sdp_XXX_t *YYY;
+
+  p = *pp; ASSERT_STRUCT_ALIGN(p);
+  YYY = memcpy(p, src, src->YYY_size);
+  p += src->YYY_size;
+  YYY->YYY_next = NULL;
+  ZZZ
+  *pp = p;
+  return YYY;
+}
+
+#endif
+
+static size_t session_xtra(sdp_session_t const *sdp)
+{
+  size_t rv = sizeof(*sdp);
+
+  PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+  STR_XTRA(rv, sdp->sdp_subject);
+  STR_XTRA(rv, sdp->sdp_information);
+  STR_XTRA(rv, sdp->sdp_uri);
+  LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+  LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+  LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+  LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+  LST_XTRA(rv, sdp->sdp_time, time_xtra);
+  PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+  LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+  STR_XTRA(rv, sdp->sdp_charset);
+  MED_XTRA_ALL(rv, sdp->sdp_media);
+
+  return rv;
+}
+
+static
+sdp_session_t *session_dup(char **pp, sdp_session_t const *src)
+{
+  char *p;
+  sdp_session_t *sdp;
+
+  p = *pp; 
+  STRUCT_DUP(p, sdp, src);
+  sdp->sdp_next = NULL;
+
+  PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+  STR_DUP(p, sdp, src, sdp_subject);
+  STR_DUP(p, sdp, src, sdp_information);
+  STR_DUP(p, sdp, src, sdp_uri);
+  LST_DUP(p, sdp, src, sdp_emails, list_dup);
+  LST_DUP(p, sdp, src, sdp_phones, list_dup);
+  LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+  LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+  LST_DUP(p, sdp, src, sdp_time, time_dup);
+  PTR_DUP(p, sdp, src, sdp_key, key_dup);
+  LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+  STR_DUP(p, sdp, src, sdp_charset);
+  MED_DUP_ALL(p, sdp, src, sdp_media);
+
+  assert((size_t)(p - *pp) == session_xtra(src));
+  *pp = p;
+  return sdp;
+}
+
+/**Duplicate an SDP session description.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP
+ * session description @a sdp allocating memory using memory @a home.
+ *
+ * @param h   Memory home
+ * @param sdp SDP session description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup(su_home_t *h, sdp_session_t const *sdp)
+{ 
+  SDP_DUP(session, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static size_t session_without_media_xtra(sdp_session_t const *sdp)
+{
+  size_t rv = sizeof(*sdp);
+
+  PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+  STR_XTRA(rv, sdp->sdp_subject);
+  STR_XTRA(rv, sdp->sdp_information);
+  STR_XTRA(rv, sdp->sdp_uri);
+  LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+  LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+  LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+  LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+  LST_XTRA(rv, sdp->sdp_time, time_xtra);
+  PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+  LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+  STR_XTRA(rv, sdp->sdp_charset);
+
+  return rv;
+}
+
+static
+sdp_session_t *session_without_media_dup(char **pp, sdp_session_t const *src)
+{
+  char *p;
+  sdp_session_t *sdp;
+
+  p = *pp; 
+  STRUCT_DUP(p, sdp, src);
+  sdp->sdp_next = NULL;
+
+  PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+  STR_DUP(p, sdp, src, sdp_subject);
+  STR_DUP(p, sdp, src, sdp_information);
+  STR_DUP(p, sdp, src, sdp_uri);
+  LST_DUP(p, sdp, src, sdp_emails, list_dup);
+  LST_DUP(p, sdp, src, sdp_phones, list_dup);
+  LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+  LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+  LST_DUP(p, sdp, src, sdp_time, time_dup);
+  PTR_DUP(p, sdp, src, sdp_key, key_dup);
+  LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+  STR_DUP(p, sdp, src, sdp_charset);
+
+  sdp->sdp_media = NULL;
+  
+  assert((size_t)(p - *pp) == session_without_media_xtra(src));
+  *pp = p;
+  return sdp;
+}
+
+/* SDP_DUP macro requires this */
+typedef sdp_session_t sdp_session_without_media_t;
+
+/**Duplicate an SDP session description without media descriptions.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP session
+ * description @a sdp allocating memory using memory @a home. It does not
+ * copy the media descriptions, however.
+ *
+ * @param h     memory h
+ * @param sdp   SDP session description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup_without_media(su_home_t *h, 
+					     sdp_session_t const *sdp)
+{ 
+  SDP_DUP(session_without_media, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+/* SDP Tag classes */
+
+#include <sofia-sip/su_tag_class.h>
+
+size_t sdptag_session_xtra(tagi_t const *t, size_t offset)
+{
+  sdp_session_t const *sdp = (sdp_session_t *)t->t_value;
+
+  if (sdp) 
+    return STRUCT_ALIGN(offset) + session_xtra(sdp);
+  else
+    return 0;
+}
+
+tagi_t *sdptag_session_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  sdp_session_t *sdp;
+  sdp_session_t const *srcsdp;
+  char *b;
+
+  assert(src); assert(*bb); 
+
+  b = *bb;
+  b += STRUCT_ALIGN(b);
+  srcsdp = (sdp_session_t *)src->t_value;
+
+  sdp = session_dup(&b, srcsdp);
+
+  dst->t_tag = src->t_tag;
+  dst->t_value = (tag_value_t)sdp;
+
+  *bb = b;
+
+  return dst + 1;
+}
+
+int sdptag_session_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  sdp_session_t const *sdp;
+  sdp_printer_t *print;
+  size_t retval;
+
+  assert(t);
+
+  if (!t || !t->t_value) { 
+    if (size && b) b[0] = 0; 
+    return 0; 
+  }
+
+  sdp = (sdp_session_t const *)t->t_value;
+
+  print = sdp_print(NULL, sdp, b, size, 0);
+
+  retval = sdp_message_size(print);
+  
+  sdp_printer_free(print);
+
+  return (int)retval;
+}
+
+/** Tag class for SDP tags. @HIDE */
+tag_class_t sdptag_session_class[1] = 
+  {{
+    sizeof(sdptag_session_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     sdptag_session_xtra,
+    /* tc_dup */      sdptag_session_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ sdptag_session_snprintf,
+    /* tc_filter */   NULL /* msgtag_str_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+  }};
+
+
+/* ---------------------------------------------------------------------- */
+
+/* Compare two string pointers */
+static inline 
+int str0cmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcmp(a, b);
+}
+
+/* Compare two string pointers ignoring case. */
+static inline 
+int str0casecmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcasecmp(a, b);
+}
+
+/** Compare two session descriptions 
+ */
+int sdp_session_cmp(sdp_session_t const *a, sdp_session_t const *b)
+{
+  int rv; 
+  sdp_bandwidth_t const *ab, *bb;
+  sdp_attribute_t const *aa, *ba;
+  sdp_media_t const *am, *bm;
+ 
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+  if (a == b)
+    return 0;
+  if ((rv = (a->sdp_version[0] - b->sdp_version[0])))
+    return rv;
+  if ((rv = sdp_origin_cmp(a->sdp_origin, b->sdp_origin)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_subject, b->sdp_subject)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_information, b->sdp_information)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_uri, b->sdp_uri)))
+    return rv;
+  if ((rv = sdp_list_cmp(a->sdp_emails, b->sdp_emails)))
+    return rv;
+  if ((rv = sdp_list_cmp(a->sdp_phones, b->sdp_phones)))
+    return rv;
+  if ((rv = sdp_connection_cmp(a->sdp_connection, b->sdp_connection)))
+    return rv;
+
+  for (ab = a->sdp_bandwidths, bb = b->sdp_bandwidths; 
+       ab || bb; 
+       ab = ab->b_next, bb = bb->b_next)
+    if ((rv = sdp_bandwidth_cmp(a->sdp_bandwidths, b->sdp_bandwidths)))
+      return rv;
+
+  if ((rv = sdp_time_cmp(a->sdp_time, b->sdp_time)))
+    return rv;
+  if ((rv = sdp_key_cmp(a->sdp_key, b->sdp_key)))
+    return rv;
+
+  for (aa = a->sdp_attributes, ba = b->sdp_attributes; 
+       aa || bb; 
+       aa = aa->a_next, ba = ba->a_next)
+    if ((rv = sdp_attribute_cmp(aa, ba)))
+      return rv;
+
+  for (am = a->sdp_media, bm = b->sdp_media; 
+       am || bb; 
+       am = am->m_next, bm = bm->m_next)
+    if ((rv = sdp_media_cmp(am, bm)))
+      return rv;
+
+  return 0;
+}
+
+/** Compare two origin fields 
+ */
+int sdp_origin_cmp(sdp_origin_t const *a, sdp_origin_t const *b)
+{
+  int rv;
+
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+  if (a == b)
+    return 0;
+  if (a->o_version != b->o_version)
+    return a->o_version < b->o_version ? -1 : 1;
+  if (a->o_id != b->o_id)
+    return a->o_id < b->o_id ? -1 : 1;
+  if ((rv = strcasecmp(a->o_username, b->o_username)))
+    return rv;
+  if ((rv = strcasecmp(a->o_address->c_address, b->o_address->c_address)))
+    return rv;
+
+  return 0;
+}
+
+/** Compare two connection fields 
+ */
+int sdp_connection_cmp(sdp_connection_t const *a, sdp_connection_t const *b)
+{
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->c_nettype != b->c_nettype)
+    return a->c_nettype < b->c_nettype ? -1 : 1;
+  if (a->c_addrtype != b->c_addrtype)
+    return a->c_addrtype < b->c_addrtype ? -1 : 1;
+  if (a->c_ttl != b->c_ttl)
+    return a->c_ttl < b->c_ttl ? -1 : 1;
+  if (a->c_groups != b->c_groups)
+    return a->c_groups < b->c_groups ? -1 : 1;
+
+  return strcmp(a->c_address, b->c_address);
+}
+
+/** Compare two bandwidth (b=) fields */
+int sdp_bandwidth_cmp(sdp_bandwidth_t const *a, sdp_bandwidth_t const *b)
+{
+  int rv;
+
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->b_modifier != b->b_modifier)
+    return a->b_modifier < b->b_modifier ? -1 : 1;
+  if (a->b_modifier == sdp_bw_x && 
+      (rv = strcmp(a->b_modifier_name, b->b_modifier_name)))
+    return rv;
+
+  if (a->b_value != b->b_value)
+    return a->b_value < b->b_value ? -1 : 1;
+
+  return 0;
+}
+
+/** Compare two time fields */
+int sdp_time_cmp(sdp_time_t const *a, sdp_time_t const *b)
+{
+  int rv; 
+
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+  if (a == b)
+    return 0;
+  if (a->t_start != b->t_start)
+    return a->t_start < b->t_start ? -1 : 1;
+  if (a->t_stop != b->t_stop)
+    return a->t_stop < b->t_stop ? -1 : 1;
+  if ((rv = sdp_zone_cmp(a->t_zone, b->t_zone)))
+    return rv;
+  if ((rv = sdp_repeat_cmp(a->t_repeat, b->t_repeat)))
+    return rv;
+  return 0;
+}
+
+/** Compare two repeat (r=) fields */
+int sdp_repeat_cmp(sdp_repeat_t const *a, sdp_repeat_t const *b)
+{
+  int i, n;
+  
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->r_interval != b->r_interval)
+    return a->r_interval < b->r_interval ? -1 : 1;
+  if (a->r_duration != b->r_duration)
+    return a->r_duration < b->r_duration ? -1 : 1;
+  n = a->r_number_of_offsets < b->r_number_of_offsets 
+    ? a->r_number_of_offsets : b->r_number_of_offsets;
+  for (i = 0; i < n; i++)
+    if (a->r_offsets[i] != b->r_offsets[i])
+      return a->r_offsets[i] < b->r_offsets[i] ? -1 : 1;
+  
+  if (a->r_number_of_offsets != b->r_number_of_offsets)
+    return a->r_number_of_offsets < b->r_number_of_offsets ? -1 : 1;
+
+  return 0;
+ }
+
+/** Compare two zone (z=) fields */
+int sdp_zone_cmp(sdp_zone_t const *a, sdp_zone_t const *b)
+{
+  int i, n;
+  
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  n = a->z_number_of_adjustments < b->z_number_of_adjustments
+    ? a->z_number_of_adjustments : b->z_number_of_adjustments;
+  for (i = 0; i < n; i++) {
+    if (a->z_adjustments[i].z_at != b->z_adjustments[i].z_at)
+      return a->z_adjustments[i].z_at < b->z_adjustments[i].z_at ? -1 : 1;
+    if (a->z_adjustments[i].z_offset != b->z_adjustments[i].z_offset)
+      return a->z_adjustments[i].z_offset < b->z_adjustments[i].z_offset
+	? -1 : 1;
+  }
+
+  if (a->z_number_of_adjustments != b->z_number_of_adjustments)
+    return a->z_number_of_adjustments < b->z_number_of_adjustments ? -1 : 1;
+
+  return 0;
+}
+
+/** Compare two key (k=) fields */
+int sdp_key_cmp(sdp_key_t const *a, sdp_key_t const *b)
+{
+  int rv;
+
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->k_method != b->k_method)
+    return a->k_method < b->k_method ? -1 : 1;
+  if (a->k_method == sdp_key_x && 
+      (rv = str0cmp(a->k_method_name, b->k_method_name)))
+    return rv;
+  return str0cmp(a->k_material, b->k_material);
+}
+
+/** Compare two attribute (a=) fields */
+int sdp_attribute_cmp(sdp_attribute_t const *a, sdp_attribute_t const *b)
+{
+  int rv;
+
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if ((rv = str0cmp(a->a_name, b->a_name)))
+    return rv;
+  return str0cmp(a->a_value, b->a_value);
+}
+
+/** Compare two rtpmap structures. */
+int sdp_rtpmap_cmp(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
+{
+  int rv;
+
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->rm_pt != b->rm_pt)
+    return a->rm_pt < b->rm_pt ? -1 : 1;
+
+  /* Case insensitive encoding */
+  if ((rv = str0cmp(a->rm_encoding, b->rm_encoding)))
+    return rv;
+  /* Rate */
+  if (a->rm_rate != b->rm_rate)
+    return a->rm_rate < b->rm_rate ? -1 : 1;
+
+  {
+    char const *a_param = "1", *b_param = "1";
+
+    if (a->rm_params)
+      a_param = a->rm_params;
+    if (b->rm_params)
+      b_param = b->rm_params;
+    
+    rv = strcasecmp(a_param, b_param);
+
+    if (rv)
+      return rv;
+  }
+
+  return str0casecmp(a->rm_fmtp, b->rm_fmtp);
+}
+
+/** Compare two lists. */
+int sdp_list_cmp(sdp_list_t const *a, sdp_list_t const *b)
+{
+  int rv;
+
+  for (;a || b; a = a->l_next, b = b->l_next) {
+    if (a == b)
+      return 0;
+    if ((a != NULL) != (b != NULL))
+      return (a != NULL) < (b != NULL) ? -1 : 1;
+    if ((rv = str0cmp(a->l_text, b->l_text)))
+      return rv;
+  }
+
+  return 0;
+}
+
+/** Compare two media (m=) fields */
+int sdp_media_cmp(sdp_media_t const *a, sdp_media_t const *b)
+{
+  int rv; 
+
+  sdp_connection_t const *ac, *bc;
+  sdp_bandwidth_t const *ab, *bb;
+  sdp_rtpmap_t const *arm, *brm;
+  sdp_attribute_t const *aa, *ba;
+
+  if (a == b)
+    return 0;
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+
+  if (a->m_type != b->m_type)
+    return a->m_type < b->m_type ? -1 : 1;
+  if (a->m_type == sdp_media_x)
+    if ((rv = str0cmp(a->m_type_name, b->m_type_name)))
+      return rv;
+  if (a->m_port != b->m_port)
+    return a->m_port < b->m_port ? -1 : 1;
+
+  if (a->m_port == 0 /* && b->m_port == 0 */)
+    /* Ignore transport protocol and media list if media has been rejected */
+    return 0;
+
+  if (a->m_number_of_ports != b->m_number_of_ports)
+    return a->m_number_of_ports < b->m_number_of_ports ? -1 : 1;
+
+  if (a->m_proto != b->m_proto)
+    return a->m_proto < b->m_proto ? -1 : 1;
+  if (a->m_proto == sdp_media_x)
+    if ((rv = str0cmp(a->m_proto_name, b->m_proto_name)))
+      return rv;
+
+  if (a->m_mode != b->m_mode)
+    return a->m_mode < b->m_mode ? -1 : 1;
+
+  for (arm = a->m_rtpmaps, brm = b->m_rtpmaps; 
+       arm || brm; 
+       arm = arm->rm_next, brm = brm->rm_next)
+    if ((rv = sdp_rtpmap_cmp(arm, brm)))
+      return rv;
+
+  if ((rv = sdp_list_cmp(a->m_format, b->m_format)))
+    return rv;
+
+  if ((rv = str0cmp(a->m_information, b->m_information)))
+    return rv;
+
+  for (ac = a->m_connections, bc = b->m_connections; 
+       ac || bc; 
+       ac = ac->c_next, bc = bc->c_next)
+  if ((rv = sdp_connection_cmp(ac, bc)))
+    return rv;
+
+  for (ab = a->m_bandwidths, bb = b->m_bandwidths; 
+       ab || bb; 
+       ab = ab->b_next, bb = bb->b_next)
+    if ((rv = sdp_bandwidth_cmp(a->m_bandwidths, b->m_bandwidths)))
+      return rv;
+
+  if ((rv = sdp_key_cmp(a->m_key, b->m_key)))
+    return rv;
+
+  for (aa = a->m_attributes, ba = b->m_attributes; 
+       aa || bb; 
+       aa = aa->a_next, ba = ba->a_next)
+    if ((rv = sdp_attribute_cmp(aa, ba)))
+      return rv;
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+sdp_connection_t *sdp_media_connections(sdp_media_t const *m)
+{
+  if (m) {
+    if (m->m_connections)
+      return m->m_connections;
+    if (m->m_session)
+      return m->m_session->sdp_connection;
+  }
+  return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Find named attribute from given list. */
+sdp_attribute_t *sdp_attribute_find(sdp_attribute_t const *a, char const *name)
+{
+  for (; a; a = a->a_next) {
+    if (strcasecmp(a->a_name, name) == 0)
+      break;
+  }
+
+  return (sdp_attribute_t *)a;
+}
+
+/** Find named attribute from given lists (a or a2). */
+sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a, 
+				     sdp_attribute_t const *a2, 
+				     char const *name)
+{
+  for (; a; a = a->a_next) {
+    if (strcasecmp(a->a_name, name) == 0)
+      break;
+  }
+
+  if (a == 0)
+    for (a = a2; a; a = a->a_next) {
+      if (strcasecmp(a->a_name, name) == 0)
+	break;
+    }
+
+  return (sdp_attribute_t *)a;
+}
+
+/** Get session mode from attribute list. */
+sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a, sdp_mode_t defmode)
+{
+  for (; a; a = a->a_next) {
+    if (strcasecmp(a->a_name, "sendrecv") == 0)
+      return sdp_sendrecv;
+    if (strcasecmp(a->a_name, "inactive") == 0)
+      return sdp_inactive;
+    if (strcasecmp(a->a_name, "recvonly") == 0)
+      return sdp_recvonly;
+    if (strcasecmp(a->a_name, "sendonly") == 0)
+      return sdp_sendonly;
+  }
+
+  return defmode;
+}
+
+/** Convert session mode as #sdp_attribute_t structure. */
+sdp_attribute_t *sdp_attribute_by_mode(su_home_t *home, sdp_mode_t mode)
+{
+  sdp_attribute_t *a;
+  char const *name;
+
+  if (mode == sdp_inactive)
+    name = "inactive";
+  else if (mode == sdp_sendonly)
+    name = "sendonly";
+  else if (mode == sdp_recvonly)
+    name = "recvonly";
+  else if (mode == sdp_sendrecv)
+    name = "sendrecv";
+  else
+    return NULL;
+  
+  a = su_salloc(home, sizeof(*a));
+  if (a)
+    a->a_name = name;
+
+  return a;
+}
+
+/** Find a mapped attribute. 
+ *
+ * A mapped attribute has form 'a=<name>:<pt> <value>' where pt is a RTP
+ * payload type, integer in range 0..127. For example, "a=atmmap" [@RFC3108]
+ * is a mapped attribute. Note that common mapped attributes, "a=rtpmap" and
+ * "a=fmtp" are already parsed as list of #sdp_rtpmap_t in #sdp_media_t.
+ *
+ * @param a pointer to first attribute in the list
+ * @param name name of the attribute
+ * @param pt payload type number (must be 0..127)
+ * @param return_result return value parameter for mapped attribute value
+ *
+ * @return Pointer to a matching attribute structure, or NULL. 
+ *
+ * If a matching attribute is found, @a return_result will point to part of
+ * the attribute after the payload type and whitespace.
+ */
+sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a,
+					   char const *name,
+					   int pt, char **return_result)
+{
+  char pt_value[4];
+  size_t pt_len;
+
+  if (return_result)
+    *return_result = NULL;
+
+  if (0 > pt || pt > 127)
+    return NULL;
+
+  snprintf(pt_value, sizeof(pt_value), "%u", (unsigned)pt);
+  pt_len = strlen(pt_value);
+
+  for (; (a = sdp_attribute_find(a, name)); a = a->a_next) {
+    char const *value = a->a_value;
+    size_t wlen;
+
+    if (strncmp(value, pt_value, pt_len))
+      continue;
+
+    wlen = strspn(value + pt_len, " \t");
+
+    if (wlen == 0 || value[pt_len + wlen] == '\0')
+      continue;
+
+    if (return_result)
+      *return_result = (char *)value + pt_len + wlen;
+
+    return (sdp_attribute_t *)a;
+  }
+
+  return NULL;
+}
+
+/** Append a (list of) attribute(s) to a list of attributes. */
+void sdp_attribute_append(sdp_attribute_t **list, 
+			  sdp_attribute_t const *a)
+{
+  assert(list);
+
+  if (list == NULL || a == NULL)
+    return;
+
+  for (;*list; list = &(*list)->a_next)
+    ;
+
+  *list = (sdp_attribute_t *)a;
+}
+
+/**Replace or append a attribute within a list of attributes. 
+ *
+ * @retval 1 if replaced existing attribute
+ * @retval 0 if attribute was appended
+ * @retval -1 upon an error
+ */
+int sdp_attribute_replace(sdp_attribute_t **list, 
+			  sdp_attribute_t *a,
+			  sdp_attribute_t **return_replaced)
+{
+  sdp_attribute_t *replaced;
+
+  assert(list);
+
+  if (return_replaced)
+    *return_replaced = NULL;
+
+  if (list == NULL || a == NULL)
+    return -1;
+
+  assert(a->a_name != NULL); assert(a->a_next == NULL);
+
+  for (; *list; list = &(*list)->a_next) {
+    if (strcasecmp((*list)->a_name, a->a_name) == 0)
+      break;
+  }
+
+  replaced = *list, *list = a;
+  
+  if (replaced) {
+    a->a_next = replaced->a_next;
+    replaced->a_next = NULL;
+
+    if (return_replaced)
+      *return_replaced = replaced;
+
+    return 1;
+  }
+
+  return 0;
+}
+
+/** Remove a named attribute from a list of attributes. */
+sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list, 
+				      char const *name)
+{
+  sdp_attribute_t *a;
+
+  assert(list);
+
+  if (list == NULL)
+    return NULL;
+  if (name == NULL)
+    return NULL;
+
+  for (a = *list; a; list = &a->a_next, a = *list) {
+    if (strcasecmp(name, a->a_name) == 0)
+      break;
+  }
+
+  if (a) {
+    *list = a->a_next;
+    a->a_next = NULL;
+  }
+
+  return a;
+}
+
+/* Return 1 if m= line struct matches with given type and name */
+unsigned sdp_media_match(sdp_media_t const *m,
+			 sdp_media_e type,
+			 sdp_text_t *type_name,
+			 sdp_proto_e proto,
+			 sdp_text_t *proto_name)
+{
+  if (m == NULL)
+    return 0;
+
+  if (type == sdp_media_any || m->m_type == sdp_media_any)
+    return 1;
+
+  if (type_name == NULL)
+    type_name = "";
+
+  if (type != m->m_type ||
+      (type == sdp_media_x && strcasecmp(m->m_type_name, type_name)))
+    return 0;
+
+  if (proto == sdp_proto_any || m->m_proto == sdp_proto_any)
+    return 1;
+
+  if (proto_name == NULL)
+    proto_name = "";
+
+  if (proto != m->m_proto ||
+      (proto == sdp_proto_x && strcasecmp(m->m_proto_name, proto_name)))
+    return 0;
+
+  return 1;
+}
+
+/* Return 1 if media type and protocol of m= line structs matches */
+unsigned sdp_media_match_with(sdp_media_t const *a,
+			      sdp_media_t const *b)
+{
+  if (a == NULL || b == NULL)
+    return a == b;
+
+  if (a->m_type == sdp_media_any || b->m_type == sdp_media_any)
+    return 1;
+
+  if (a->m_type != b->m_type ||
+      (a->m_type == sdp_media_x &&
+       strcasecmp(b->m_type_name, a->m_type_name)))
+    return 0;
+
+  if (a->m_proto == sdp_proto_any || b->m_proto == sdp_proto_any)
+    return 1;
+
+  if (a->m_proto != b->m_proto ||
+      (a->m_proto == sdp_proto_x &&
+       strcasecmp(b->m_proto_name, a->m_proto_name)))
+    return 0;
+
+  return 1;
+}
+
+
+/** Count matching media lines in SDP. */
+unsigned sdp_media_count(sdp_session_t const *sdp,
+			 sdp_media_e type,
+			 sdp_text_t *type_name,
+			 sdp_proto_e proto,
+			 sdp_text_t *proto_name)
+{
+  unsigned count = 0;
+  sdp_media_t const *m;
+
+  if (sdp != NULL)
+    for (m = sdp->sdp_media; m; m = m->m_next)
+      count += sdp_media_match(m, type, type_name, proto, proto_name);
+
+  return count;
+}
+
+/** Count matching media lines in SDP. */
+unsigned sdp_media_count_with(sdp_session_t const *sdp,
+			      sdp_media_t const *m0)
+{
+  unsigned count = 0;
+  sdp_media_t const *m;
+
+  if (sdp != NULL)
+    for (m = sdp->sdp_media; m; m = m->m_next)
+      count += sdp_media_match_with(m, m0);
+
+  return count;
+}
+
+/** Return true if media uses RTP */
+int sdp_media_uses_rtp(sdp_media_t const *m)
+{
+  return m &&
+    (m->m_proto == sdp_proto_rtp ||
+     m->m_proto == sdp_proto_srtp ||
+     (m->m_proto == sdp_proto_x && m->m_proto_name &&
+      strncasecmp(m->m_proto_name, "RTP/", 4) == 0));
+}
+
+/** Check if payload type, rtp rate and parameters match in rtpmaps*/
+int sdp_rtpmap_match(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
+{
+  char const *aparam, *bparam;
+
+  if (a == b)
+    return 1;
+
+  if (a == 0 || b == 0)
+    return 0;
+
+  if (a->rm_rate != b->rm_rate)
+    return 0;
+
+  if (strcasecmp(a->rm_encoding, b->rm_encoding))
+    return 0;
+
+  aparam = a->rm_params; bparam = b->rm_params;
+
+  if (aparam == bparam)
+    return 1;
+
+  if (!aparam) aparam = "1"; if (!bparam) bparam = "1";
+  
+  if (strcasecmp(aparam, bparam))
+    return 0;
+
+  return 1;
+}
+
+/** Search for matching rtpmap from list.
+ *
+ * @note
+ * The a=fmtp: for the codecs are not compared.
+ */
+sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
+				       sdp_rtpmap_t const *rm)
+{
+  char const *lparam, *rparam;
+
+  if (rm == NULL)
+    return NULL;
+
+  for (; list; list = list->rm_next) {
+    if (rm->rm_rate != list->rm_rate)
+      continue;
+
+    if (strcasecmp(rm->rm_encoding, list->rm_encoding) != 0)
+      continue;
+
+    lparam = rm->rm_params; rparam = list->rm_params;
+
+    if (lparam == rparam)
+      break;
+
+    if (!lparam) lparam = "1"; if (!rparam) rparam = "1";
+    if (strcasecmp(lparam, rparam))
+      continue;
+
+    break;
+  }
+
+  return (sdp_rtpmap_t *)list;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,120 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "sdp" - SDP Module
+
+ at section sdp_meta Module Meta Information
+
+The @b sdp module provides a simple "C" parser interface for SDP [@RFC2327],
+<em>Session Description Protocol</em>. The parser also implements support
+for IPv6 addresses as per @RFC3266. The @RFC4566 should be supported, but we
+have not checked since draft-eitf-mmusic-sdp-new-17 or so.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+- Jari Selin <Jari.Selin at nokia.com>
+
+ at section sdp_parser SDP Parser
+
+SDP parser parses an SDP message and converts it to internally used SDP
+structure #sdp_session_t.
+
+Typically, the SDP parser is used as follows:
+
+ at code
+ sdp_parser_t *parser = sdp_parse(home, message, len, 0);
+
+ if (!sdp_session(parser)) {
+   show(sdp_parsing_error(parser));
+ } else {
+   sdp_session_t *sdp = sdp_session(parser);
+ at endcode
+  Act upon session description, then free the parser:
+ at code
+ }
+ sdp_parser_free(parser);
+ at endcode
+
+There are various flags indicating what kind of SDP variants the sdp_parse()
+accepts. The sanity check run after parsing can be disabled by including
+flag #sdp_f_insane. The parser can be used to parse syntactically vague
+configuration files when using flag #sdp_f_config. The parser will then
+accept * for media, protocol and port, for instance.
+
+ at section sdp_printer SDP Printer
+
+SDP printer converts internally used SDP structure #sdp_session_t to the
+standard SDP format.
+
+Typically, the SDP printer is used as follows:
+ at code
+ char buffer[512];
+ sdp_printer_t *printer = sdp_print(home, session, buffer, sizeof(buffer), 0);
+
+ if (sdp_message(printer)) {
+   char const *msg = sdp_message(printer);
+   size_t msgsize = sdp_message_size(printer);
+ at endcode
+
+At this point, application can use the SDP message contents, e.g., it can
+send them to network, and then free the message:
+ at code
+ }
+ else {
+   show_critical_error(sdp_printing_error(printer));
+ }
+ sdp_printer_free(printer);
+ at endcode 
+
+ at section sdp_example Example
+
+Examples on using SDP parser can be found from test_sdp.c and soa.c. Here is
+an simple example, which decodes an SDP text in @a original, increments the
+version number in the origin line, and encodes the SDP description again to
+ at a buf.
+
+ at code
+size_t increment_sdp_version(char buf[], size_t bsize, 
+                             char const *original, size_t osize)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  sdp_parser_t *parser = sdp_parse(home, original, osize, 0);
+  sdp_printer_t *printer;
+  size_t retval = 0;
+
+  if (sdp_session(parser)) {
+    sdp_session_t *sdp = sdp_session(parser);
+    
+    sdp->sdp_origin->o_version++;
+
+    printer = sdp_print(home, sdp, buf, bsize, 0);
+
+    if (sdp_message(printer)) {
+      retval = sdp_message_size(printer);
+    }
+    else {
+      fprintf(stderr, "increment_sdp_version: %s\n", 
+              sdp_printing_error(printer));
+    }
+
+    sdp_printer_free(printer);
+  }
+  else {
+    fprintf(stderr, "increment_sdp_version: %s\n", 
+            sdp_parsing_error(p));
+  }
+
+  sdp_parser_free(parser);
+      
+  su_home_deinit(home);
+
+  return retval;
+}
+ at endcode
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1887 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sdp_parser
+ * @CFILE sdp_parse.c 
+ * @brief Simple SDP parser interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date  Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/sdp.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.h>
+#include <assert.h>
+
+/** @typedef struct sdp_parser_s sdp_parser_t; 
+ *
+ * SDP parser handle.
+ *
+ * The SDP parser handle is returned by sdp_parse(). It contains either
+ * successfully parse SDP session #sdp_session_t or an error message.
+ * If sdp_session() returns non-NULL, parsing was successful.
+ *
+ * @sa #sdp_session_t, sdp_parse(), sdp_session(), sdp_parsing_error(),
+ * sdp_sanity_check(), sdp_parser_home(), sdp_parser_free().
+ */
+
+struct sdp_parser_s {
+  su_home_t       pr_home[1];
+  union {
+    char          pru_error[128];
+    sdp_session_t pru_session[1];
+  } pr_output;
+  char      *pr_message;
+
+  sdp_mode_t pr_session_mode;
+
+  unsigned   pr_ok : 1;
+
+  unsigned   pr_strict : 1;
+  unsigned   pr_anynet : 1;
+  unsigned   pr_mode_0000 : 1;
+  unsigned   pr_mode_manual : 1;
+  unsigned   pr_insane : 1;
+  unsigned   pr_c_missing : 1;
+  unsigned   pr_config : 1;
+};
+
+#define is_posdigit(c) ((c) >= '1' && (c) <= '9')
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+#define is_space(c) ((c) == ' ')
+#define is_tab(c) ((c) == '\t')
+
+#define pr_error   pr_output.pru_error
+#define pr_session pr_output.pru_session
+
+#define STRICT(pr) (pr->pr_strict)
+
+/* Static parser object used when running out of memory */
+static const struct sdp_parser_s no_mem_error =
+{
+  { SU_HOME_INIT(no_mem_error) },
+  { "sdp: not enough memory" }
+};
+
+/* Internal prototypes */
+static void parse_message(sdp_parser_t *p);
+static void parsing_error(sdp_parser_t *p, char const *fmt, ...);
+
+/** Parse an SDP message.
+ *
+ * The function sdp_parse() parses an SDP message @a msg of size @a
+ * msgsize. Parsing is done according to the given @a flags. The SDP message
+ * may not contain a NUL.
+ * 
+ * The parsing result is stored to an #sdp_session_t structure.
+ *
+ * @param home    memory home
+ * @param msg     pointer to message
+ * @param msgsize size of the message (excluding final NUL, if any)
+ * @param flags   flags affecting the parsing.
+ *
+ * The following flags are used by parser:
+ *
+ * @li #sdp_f_strict Parser should accept only messages conforming strictly 
+ *                   to the specification.
+ * @li #sdp_f_anynet Parser accepts unknown network or address types.
+ * @li #sdp_f_insane Do not run sanity check.
+ * @li #sdp_f_c_missing  Sanity check does not require c= for each m= line
+ * @li #sdp_f_mode_0000 Parser regards "c=IN IP4 0.0.0.0" as "a=inactive"
+ *                      (likewise with c=IN IP6 ::)
+ * @li #sdp_f_mode_manual Do not generate or parse SDP mode
+ * @li #sdp_f_config   Parse config files (any line can be missing)
+ *
+ * @return
+ * Always a valid parser handle.
+ *
+ * @todo Parser accepts some non-conforming SDP even with #sdp_f_strict.
+ */
+sdp_parser_t *
+sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
+{
+  sdp_parser_t *p;
+  char *b;
+  size_t len;
+
+  if (msgsize == -1 || msg == NULL) {
+    p = su_home_clone(home, sizeof(*p));
+    if (p) 
+      parsing_error(p, "invalid input message");
+    else
+      p = (sdp_parser_t*)&no_mem_error;
+    return p;
+  }
+
+  if (msgsize == -1 && msg)
+    len = strlen(msg);
+  else
+    len = msgsize;
+
+  if (len > ISSIZE_MAX)
+    len = ISSIZE_MAX;
+
+  p = su_home_clone(home, sizeof(*p) + len + 1);
+
+  if (p) {
+    b = strncpy((void *)(p + 1), msg, len);
+    b[len] = 0;
+
+    p->pr_message = b;
+    p->pr_strict = (flags & sdp_f_strict) != 0;
+    p->pr_anynet = (flags & sdp_f_anynet) != 0;
+    p->pr_mode_0000 = (flags & sdp_f_mode_0000) != 0;
+    p->pr_insane = (flags & sdp_f_insane) != 0;
+    p->pr_c_missing = (flags & sdp_f_c_missing) != 0;
+    if (flags & sdp_f_config)
+      p->pr_c_missing = 1, p->pr_config = 1;
+    p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
+    p->pr_session_mode = sdp_sendrecv;
+
+    parse_message(p);
+    
+    return p;
+  }
+
+  if (p)
+    sdp_parser_free(p);
+
+  return (sdp_parser_t*)&no_mem_error;
+}
+
+
+/** Obtain memory home used by parser */
+su_home_t *sdp_parser_home(sdp_parser_t *parser)
+{
+  if (parser != &no_mem_error)
+    return parser->pr_home;
+  else
+    return NULL;
+}
+
+/** Retrieve an SDP session structure.
+ *
+ * The function sdp_session() returns a pointer to the SDP session
+ * structure associated with the SDP parser @a p. The pointer and all the
+ * data in the structure are valid until sdp_parser_free() is called.
+ *
+ * @param p SDP parser
+ *
+ * @return
+ *   The function sdp_session() returns a pointer to an parsed SDP message
+ *   or NULL, if an error has occurred.  */
+sdp_session_t *
+sdp_session(sdp_parser_t *p)
+{
+  return p && p->pr_ok ? p->pr_session : NULL;
+}
+
+/** Get a parsing error message.
+ *
+ * The function sdp_parsing_error() returns the error message associated
+ * with an SDP parser @a p.
+ *
+ * @param p SDP parser
+ *
+ * @return 
+ * The function sdp_parsing_error() returns a C string describing parsing
+ * error, or NULL if no error occurred.
+ */
+char const *sdp_parsing_error(sdp_parser_t *p)
+{
+  return !p->pr_ok ? p->pr_error : NULL;
+}
+
+/** Free an SDP parser.
+ *
+ * The function sdp_parser_free() frees an SDP parser object along with
+ * the memory blocks associated with it.
+ *
+ * @param p pointer to the SDP parser to be freed 
+ */
+void sdp_parser_free(sdp_parser_t *p)
+{
+  if (p && p != &no_mem_error)
+    su_home_unref(p->pr_home);
+}
+
+/* ========================================================================= */
+
+/* =========================================================================
+ * Private part
+ */
+
+/* Parsing tokens */
+#define SPACE " "
+#define TAB   "\011"
+#define CRLF  "\015\012"
+#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGIT "0123456789"
+
+/* ========================================================================= */
+/* Parsing functions */
+
+static void post_session(sdp_parser_t *p, sdp_session_t *sdp);
+static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result);
+static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result);
+static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result);
+static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result);
+static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result);
+static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result);
+static void parse_repeat(sdp_parser_t *p, char *r, sdp_repeat_t **result);
+static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result);
+static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result);
+static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result);
+static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result);
+static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result);
+static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m, 
+			     sdp_attribute_t **result);
+static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m);
+static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m);
+static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result);
+
+static void parse_descs(sdp_parser_t *p, char *r, char *m, sdp_media_t **result);
+
+static int parse_ul(sdp_parser_t *p, char **r, unsigned long *result, 
+		    unsigned long max_value);
+static int parse_ull(sdp_parser_t *p, char **r, uint64_t *result, 
+		     uint64_t max_value);
+static void parse_alloc_error(sdp_parser_t *p, const char *typename);
+static char *next(char **message, const char *sep, const char *strip);
+static char *token(char **message, const char *sep, const char *legal, 
+		   const char *strip);
+#if 0
+static void check_mandatory(sdp_parser_t *p, sdp_session_t *sdp);
+#endif
+
+/* -------------------------------------------------------------------------
+ * Macro PARSE_ALLOC
+ *
+ * Description:
+ *   This macro declares a pointer (v) of given type (t). It then allocates
+ *   an structure of given type (t). If allocation was succesful, it assigns
+ *   the XX_size member with appropriate value.
+ */
+#define PARSE_ALLOC(p, t, v) \
+ t *v = su_salloc(p->pr_home, sizeof(*v)); \
+ if (!v && (parse_alloc_error(p, #t), 1)) return; 
+
+/* -------------------------------------------------------------------------
+ * Macro PARSE_CHECK_REST
+ *
+ * Description:
+ *   This macro check if there is extra data at the end of field.
+ */
+#define PARSE_CHECK_REST(p, s, n)\
+ if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")", n, s), 1)) \
+    return
+
+/* -------------------------------------------------------------------------
+ * Function parse_message() - parse an SDP message 
+ *
+ * Description:
+ *   This function parses an SDP message, which is copied into the 
+ *   p->pr_message. The p->pr_message is modified during the parsing,
+ *   and parts of it are returned in p->pr_session.
+ *
+ * Parameters:
+ *   p - pointer to SDP parser object
+ */
+static void parse_message(sdp_parser_t *p)
+{
+/*
+   announcement =        proto-version
+                         origin-field
+                         session-name-field
+                         information-field
+                         uri-field
+                         email-fields
+                         phone-fields
+                         connection-field
+                         bandwidth-fields
+                         time-fields
+                         key-field
+                         attribute-fields
+                         media-descriptions
+*/
+
+  sdp_session_t *sdp = p->pr_session;
+  char *record, *rest;
+  char const *strip;
+  char *message = p->pr_message;
+  char field = '\0';
+  sdp_list_t **emails = &sdp->sdp_emails;
+  sdp_list_t **phones = &sdp->sdp_phones;
+  sdp_bandwidth_t **bandwidths = &sdp->sdp_bandwidths;
+  sdp_time_t **times = &sdp->sdp_time;
+  sdp_repeat_t **repeats = NULL;
+  sdp_zone_t **zones = NULL;
+  sdp_attribute_t **attributes = &sdp->sdp_attributes;
+
+  if (!STRICT(p))
+    strip = SPACE TAB;		/* skip initial whitespace */
+  else
+    strip = NULL;
+
+  p->pr_ok = 1;
+  p->pr_session->sdp_size = sizeof(p->pr_session);
+
+  /* Require that version comes first */
+  record = next(&message, CRLF, strip);
+
+  if (!record || strcmp(record, "v=0")) {
+    if (!p->pr_config || !record || record[1] != '=') {
+      parsing_error(p, "bad SDP message");
+      return;
+    }
+  }
+  else {
+    record = next(&message, CRLF, strip);
+  }
+
+  /*
+    XXX - the lines in SDP are in certain order, which we don't check here.
+     For stricter parsing we might want to parse o= and s= next.
+  */
+
+  for (;
+       record && p->pr_ok;
+       record = next(&message, CRLF, strip)) {
+    field = record[0]; 
+
+    rest = record + 2; rest += strspn(rest, strip);
+
+    if (record[1] != '=') {
+      parsing_error(p, "bad line \"%s\"", record);
+      return;
+    }
+
+    switch (field) {
+    case 'o':
+      parse_origin(p, rest, &sdp->sdp_origin);
+      break;
+
+    case 's':
+      parse_subject(p, rest, &sdp->sdp_subject);
+      break;
+
+    case 'i':
+      parse_information(p, rest, &sdp->sdp_information);
+      break;
+
+    case 'u':
+      parse_uri(p, rest, &sdp->sdp_uri);
+      break;
+
+    case 'e':
+      parse_email(p, rest, emails);
+      emails = &(*emails)->l_next;
+      break;
+
+    case 'p':
+      parse_phone(p, rest, phones);
+      phones = &(*phones)->l_next;
+      break;
+
+    case 'c':
+      parse_connection(p, rest, &sdp->sdp_connection);
+      break;
+
+    case 'b':
+      parse_bandwidth(p, rest, bandwidths);
+      bandwidths = &(*bandwidths)->b_next;
+      break;
+
+    case 't':
+      parse_time(p, rest, times);
+      repeats = &(*times)->t_repeat;
+      zones = &(*times)->t_zone;
+      times = &(*times)->t_next;
+      break;
+
+    case 'r':
+      if (repeats)
+	parse_repeat(p, rest, repeats);
+      else
+	parsing_error(p, "repeat field without time field");
+      break;
+
+    case 'z':
+      if (zones)
+	parse_zone(p, rest, zones), zones = NULL;
+      else
+	parsing_error(p, "zone field without time field");
+      break;
+
+    case 'k':
+      parse_key(p, rest, &sdp->sdp_key);
+      break;
+
+    case 'a':
+      parse_session_attr(p, rest, attributes);
+      if (*attributes)
+	attributes = &(*attributes)->a_next;
+      break;
+
+    case 'm':
+      parse_descs(p, record, message, &sdp->sdp_media);
+      post_session(p, sdp);
+      return;
+
+    default:
+      parsing_error(p, "unknown field \"%s\"", record);
+      return;
+    }
+  }
+
+  post_session(p, sdp);
+}
+
+int sdp_connection_is_inaddr_any(sdp_connection_t const *c)
+{
+  return 
+    c && 
+    c->c_nettype == sdp_net_in && 
+    ((c->c_addrtype == sdp_addr_ip4 && strcmp(c->c_address, "0.0.0.0")) ||
+     (c->c_addrtype == sdp_addr_ip6 && strcmp(c->c_address, "::")));
+}
+
+/**Postprocess session description.
+ *
+ * The function post_session() postprocesses the session description. The
+ * postprocessing includes setting the session backpointer for each media.
+ */
+static void post_session(sdp_parser_t *p, sdp_session_t *sdp)
+{
+  sdp_media_t *m;
+  sdp_connection_t const *c;
+
+  if (!p->pr_ok)
+    return;
+
+  /* Set session back-pointer */
+  for (m = sdp->sdp_media; m; m = m->m_next) {
+    m->m_session = sdp;
+  }
+
+  if (p->pr_config) {
+    if (sdp->sdp_version[0] != 0)
+      parsing_error(p, "Incorrect version");
+    return;
+  }
+  
+  /* Go through all media and set mode */
+  for (m = sdp->sdp_media; m; m = m->m_next) {
+    if (m->m_port == 0) {
+      m->m_mode = sdp_inactive;
+      m->m_rejected = 1;
+      continue;
+    }
+
+    c = sdp_media_connections(m);
+
+    if (p->pr_mode_0000 && c) {
+      if (c->c_nettype == sdp_net_in &&
+	  c->c_addrtype == sdp_addr_ip4 &&
+	  strcmp(c->c_address, "0.0.0.0") == 0)
+	/* Reset recvonly flag */
+	m->m_mode &= ~sdp_recvonly;
+    }
+  }
+
+  if (p->pr_insane)
+    return;
+
+  /* Verify that all mandatory fields are present */
+  if (sdp_sanity_check(p) < 0)
+    return;
+}
+
+/** Validates that all mandatory fields exist 
+ *
+ * Checks that all necessary fields (v=, o=) exists in the parsed sdp. If
+ * strict, check that all mandatory fields (c=, o=, s=, t=) are present. 
+ * This function also goes through all media, marks rejected media as such,
+ * and updates the mode accordingly.
+ * 
+ * @retval 0 if parsed SDP description is valid
+ * @retval -1 if some SDP line is missing
+ * @retval -2 if c= line is missing
+ */
+int sdp_sanity_check(sdp_parser_t *p)
+{
+  sdp_session_t *sdp = p->pr_session;
+  sdp_media_t *m;
+
+  if (!p || !p->pr_ok)
+    ;
+  else if (sdp->sdp_version[0] != 0)
+    parsing_error(p, "Incorrect version");
+  else if (!sdp->sdp_origin)
+    parsing_error(p, "No o= present");
+  else if (p->pr_strict && !sdp->sdp_subject)
+    parsing_error(p, "No s= present");
+  else if (p->pr_strict && !sdp->sdp_time)
+    parsing_error(p, "No t= present");
+
+  if (!p->pr_ok)
+    return -1;
+
+  /* If there is no session level c= check that one exists for all media */
+  /* c= line may be missing if this is a RTSP description */
+  if (!p->pr_c_missing && !sdp->sdp_connection) {
+    for (m = sdp->sdp_media ; m ; m = m->m_next) {
+      if (!m->m_connections && !m->m_rejected) {
+	parsing_error(p, "No c= on either session level or all mediums");
+	return -2;
+      }
+    }
+  }
+
+  return 0;
+}
+
+#if 0
+/**
+ * Parse a "v=" field
+ *
+ * The function parser_version() parses the SDP version field.
+ *
+ * @param p      pointer to SDP parser object
+ * @param r      pointer to record data
+ * @param result pointer to which parsed record is assigned
+ */
+static void parse_version(sdp_parser_t *p, char *r, sdp_version_t *result)
+{
+  /*
+   proto-version =       "v=" 1*DIGIT CRLF
+                         ;[RFC2327] describes version 0
+   */
+  if (parse_ul(p, &r, result, 0))
+    parsing_error(p, "version \"%s\" is invalid", r);
+  else if (*result > 0)
+    parsing_error(p, "unknown version v=%s", r);
+}
+#endif
+
+/* -------------------------------------------------------------------------
+ * Function parse_origin() - parse an "o=" field
+ *
+ * Description:
+ *   This function parses an SDP origin field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result)
+{
+  /*
+   origin-field =        "o=" username space
+                         sess-id space sess-version space
+                         nettype space addrtype space
+                         addr CRLF
+
+   username =            safe
+                         ;pretty wide definition, but doesn't include space
+
+   sess-id =             1*(DIGIT)
+                         ;should be unique for this originating username/host
+
+   sess-version =        1*(DIGIT)
+                         ;0 is a new session
+
+			 
+   */
+  PARSE_ALLOC(p, sdp_origin_t, o);
+
+  *result = o;
+
+  o->o_username = token(&r, SPACE TAB, NULL, SPACE TAB);
+  if (!o->o_username) {
+    parsing_error(p, "invalid username");
+    return;
+  }
+  if (parse_ull(p, &r, &o->o_id, 0)) {
+    parsing_error(p, "invalid session id");
+    return;
+  }
+
+  if (parse_ull(p, &r, &o->o_version, 0)) {
+    parsing_error(p, "invalid session version");
+    return;
+  }
+
+  parse_connection(p, r, &o->o_address);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_subject() - parse an "s=" field
+ *
+ * Description:
+ *   This function parses an SDP subject field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+  /*
+   session-name-field =  "s=" text CRLF
+   text =                byte-string
+   */
+  *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_information() - parse an "i=" field
+ *
+ * Description:
+ *   This function parses an SDP information field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+  /*
+   information-field =   ["i=" text CRLF]
+   */
+  *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_uri() - parse an "u=" field
+ *
+ * Description:
+ *   This function parses an SDP URI field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+  /*
+    uri-field =           ["u=" uri CRLF]
+
+    uri=                  ;defined in RFC1630
+  */
+  /* XXX - no syntax checking here */
+  *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_email() - parse an "e=" field
+ *
+ * Description:
+ *   This function parses an SDP email field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+  /*
+   email-fields =        *("e=" email-address CRLF)
+
+   email-address =       email | email "(" email-safe ")" |
+                         email-safe "<" email ">"
+
+   email =               ;defined in RFC822  */
+  parse_text_list(p, r, result);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_phone() - parse an "p=" field
+ *
+ * Description:
+ *   This function parses an SDP phone field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+  /*
+   phone-fields =        *("p=" phone-number CRLF)
+
+   phone-number =        phone | phone "(" email-safe ")" |
+                         email-safe "<" phone ">"
+
+   phone =               "+" POS-DIGIT 1*(space | "-" | DIGIT)
+                         ;there must be a space or hyphen between the
+                         ;international code and the rest of the number.
+  */
+  parse_text_list(p, r, result);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_connection() - parse an "c=" field
+ *
+ * Description:
+ *   This function parses an SDP connection field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result)
+{
+  /*
+   connection-field =    ["c=" nettype space addrtype space
+                         connection-address CRLF]
+                         ;a connection field must be present
+                         ;in every media description or at the
+                         ;session-level
+
+   nettype =             "IN"
+                         ;list to be extended
+
+   addrtype =            "IP4" | "IP6"
+                         ;list to be extended
+
+   connection-address =  multicast-address
+                         | addr
+
+   multicast-address =   3*(decimal-uchar ".") decimal-uchar "/" ttl
+                         [ "/" integer ]
+                         ;multicast addresses may be in the range
+                         ;224.0.0.0 to 239.255.255.255
+
+   ttl =                 decimal-uchar
+
+   addr =                FQDN | unicast-address
+
+   FQDN =                4*(alpha-numeric|"-"|".")
+                         ;fully qualified domain name as specified in RFC1035
+
+   unicast-address =     IP4-address | IP6-address
+
+   IP4-address =         b1 "." decimal-uchar "." decimal-uchar "." b4
+   b1 =                  decimal-uchar
+                         ;less than "224"; not "0" or "127"
+   b4 =                  decimal-uchar
+                         ;not "0"
+
+   IP6-address =         ;to be defined
+   */
+  PARSE_ALLOC(p, sdp_connection_t, c);
+
+  *result = c;
+
+  if (strncasecmp(r, "IN", 2) == 0) {
+    char *s;
+
+    /* nettype is internet */
+    c->c_nettype = sdp_net_in;
+    s = token(&r, SPACE TAB, NULL, NULL);
+
+    /* addrtype */
+    s = token(&r, SPACE TAB, NULL, NULL);
+    if (s && strcasecmp(s, "IP4") == 0)
+      c->c_addrtype = sdp_addr_ip4;
+    else if (s && strcasecmp(s, "IP6") == 0)
+      c->c_addrtype = sdp_addr_ip6;
+    else {
+      parsing_error(p, "unknown IN address type: %s", s);
+      return;
+    }
+
+    /* address */
+    s = next(&r, SPACE TAB, SPACE TAB);
+    c->c_address = s;
+    if (!s || !*s) {
+      parsing_error(p, "invalid address");
+      return;
+    }
+
+    /* ttl */
+    s = strchr(s, '/');
+    if (s) {
+      unsigned long value;
+      *s++ = 0;
+      if (parse_ul(p, &s, &value, 256) ||
+	  (*s && *s != '/')) {
+	parsing_error(p, "invalid ttl");
+	return;
+      }
+      c->c_ttl = value;
+      c->c_mcast = 1;
+
+      /* multiple groups */
+      value = 1;
+      if (*s++ == '/')
+	if (parse_ul(p, &s, &value, 0) || *s) {
+	  parsing_error(p, "invalid number of multicast groups");
+	  return;
+	}
+      c->c_groups = value;
+    }
+    else
+      c->c_groups = 1;
+  }
+  else if (p->pr_anynet) {
+    c->c_nettype = sdp_net_x;
+    c->c_addrtype = sdp_addr_x;
+    c->c_address = r;
+    c->c_ttl = 0;
+    c->c_groups = 1;
+  }
+  else 
+    parsing_error(p, "invalid address");
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_bandwidth() - parse an "b=" field
+ *
+ * Description:
+ *   This function parses an SDP bandwidth field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result)
+{
+  /*
+   bandwidth-fields =    *("b=" bwtype ":" bandwidth CRLF)
+
+   bwtype =              1*(alpha-numeric)
+                         ; CT or AS
+   bandwidth =           1*(DIGIT)
+   */
+  /* NOTE: bwtype can also be like X-barf */
+  sdp_bandwidth_e modifier;
+  char *name;
+  unsigned long value;
+
+  name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB);
+
+  if (name == NULL || parse_ul(p, &r, &value, 0)) {
+    parsing_error(p, "invalid bandwidth");
+    return;
+  }
+
+  if (strcmp(name, "CT") == 0)
+    modifier = sdp_bw_ct, name = NULL;
+  else if (strcmp(name, "AS") == 0)
+    modifier = sdp_bw_as, name = NULL;
+  else
+    modifier = sdp_bw_x;
+
+  if (STRICT(p))
+    PARSE_CHECK_REST(p, r, "b");
+  
+  {
+    PARSE_ALLOC(p, sdp_bandwidth_t, b);
+    *result = b;
+    b->b_modifier = modifier;
+    b->b_modifier_name = name;
+    b->b_value = value;
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_time() - parse an "t=" field
+ *
+ * Description:
+ *   This function parses an SDP time field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result)
+{
+  /*
+   time-fields =         1*( "t=" start-time space stop-time
+                         *(CRLF repeat-fields) CRLF)
+                         [zone-adjustments CRLF]
+
+   start-time =          time | "0"
+
+   stop-time =           time | "0"
+
+   time =                POS-DIGIT 9*(DIGIT)
+                         ;sufficient for 2 more centuries
+   */
+  PARSE_ALLOC(p, sdp_time_t, t);
+  *result = t;
+  if (parse_ul(p, &r, &t->t_start, 0) ||
+      parse_ul(p, &r, &t->t_stop, 0))
+    parsing_error(p, "invalid time");
+  else if (STRICT(p)) {
+    PARSE_CHECK_REST(p, r, "t");
+  }
+}
+
+/**
+ * Parse an "r=" field
+ *
+ * The function parse_repeat() parses an SDP repeat field.
+ *
+ * @param p      pointer to SDP parser object
+ * @param r      pointer to record data
+ * @param result pointer to which parsed record is assigned
+ * 
+ */
+static void parse_repeat(sdp_parser_t *p, char *d, sdp_repeat_t **result)
+{
+  /*
+   repeat-fields =       "r=" repeat-interval space typed-time
+                         1*(space typed-time)
+
+   repeat-interval =     typed-time
+
+   typed-time =          1*(DIGIT) [fixed-len-time-unit]
+
+   fixed-len-time-unit = "d" | "h" | "m" | "s"
+   */
+
+  unsigned long tt, *interval;
+  size_t i;
+  int n, N;
+  char *s;
+  sdp_repeat_t *r;
+
+  /** Count number of intervals */
+  for (N = 0, s = d; *s; ) {
+    if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+      break;
+    do { s++; } while (is_digit(*s));
+    if (*s && strchr("dhms", *s))
+      s++;
+    N++;
+    if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+      break;
+    s += i;
+  }
+
+  PARSE_CHECK_REST(p, s, "r");
+  if (N < 2) {
+    parsing_error(p, "invalid repeat");
+    return;
+  }
+  if (!(r = su_salloc(p->pr_home, offsetof(sdp_repeat_t, r_offsets[N - 1])))) {
+    parse_alloc_error(p, "sdp_repeat_t"); 
+    return;
+  }
+
+  r->r_number_of_offsets = N - 2;
+  r->r_offsets[N - 2] = 0;
+
+  for (n = 0, interval = &r->r_interval; n < N; n++) {
+    tt = strtoul(d, &d, 10);
+
+    switch (*d) {
+    case 'd': tt *= 24;
+    case 'h': tt *= 60;
+    case 'm': tt *= 60;
+    case 's': d++;
+      break;
+    }
+
+    interval[n] = tt;
+
+    while (is_space(*d))
+      d++;
+  } 
+
+  *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_zone() - parse an "z=" field
+ *
+ * Description:
+ *   This function parses an SDP time zone field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ *
+ */
+static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result)
+{
+  char *s;
+  size_t i;
+  int n, N;
+  sdp_zone_t *z;
+
+  /*
+   zone-adjustments =    time space ["-"] typed-time
+                         *(space time space ["-"] typed-time)
+   */
+
+  /** Count number of timezones, check syntax */
+  for (N = 0, s = r; *s;) {
+    if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+      break;
+    do { s++; } while (is_digit(*s));
+    if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+      break;
+    s += i;
+    if (!(*s == '-' || is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+      break;
+    do { s++; } while (is_digit(*s));
+    if (*s && strchr("dhms", *s))
+      s++;
+    N++;
+    if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+      break;
+    s += i;
+  }
+
+  PARSE_CHECK_REST(p, s, "z");
+
+  if (N < 1) {
+    parsing_error(p, "invalid timezone");
+    return;
+  }
+  if (!(z = su_salloc(p->pr_home, offsetof(sdp_zone_t, z_adjustments[N])))) {
+    parse_alloc_error(p, "sdp_zone_t"); 
+    return;
+  }
+
+  z->z_number_of_adjustments = N;
+
+  for (n = 0; n < N; n++) {
+    unsigned long at = strtoul(r, &r, 10);
+    long offset = strtol(r, &r, 10);
+    switch (*r) {
+    case 'd': offset *= 24;
+    case 'h': offset *= 60;
+    case 'm': offset *= 60;
+    case 's': r++;
+      break;
+    }
+
+    z->z_adjustments[n].z_at = at;
+    z->z_adjustments[n].z_offset = offset;
+  } 
+
+  *result = z;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_key() - parse an "k=" field
+ *
+ * Description:
+ *   This function parses an SDP key field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ *
+ */
+static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result)
+{
+  char *s;
+  /*
+   key-field =           ["k=" key-type CRLF]
+
+
+   key-type =            "prompt" |
+                         "clear:" key-data |
+                         "base64:" key-data |
+                         "uri:" uri
+
+
+   key-data =            email-safe | "~" | "
+   */
+
+  s = token(&r, ":", ALPHA DIGIT "-", SPACE TAB);
+  if (!s) {
+    parsing_error(p, "invalid key method");
+    return;
+  }
+
+  {
+    PARSE_ALLOC(p, sdp_key_t, k);
+    *result = k;
+
+    if (strcasecmp(s, "clear") == 0)
+      k->k_method = sdp_key_clear, k->k_method_name = "clear";
+    else if (strcasecmp(s, "base64") == 0)
+      k->k_method = sdp_key_base64, k->k_method_name = "base64";
+    else if (strcasecmp(s, "uri") == 0)
+      k->k_method = sdp_key_uri, k->k_method_name = "uri";
+    else if (strcasecmp(s, "prompt") == 0)
+      k->k_method = sdp_key_prompt, k->k_method_name = "prompt";
+    else
+      k->k_method = sdp_key_x, k->k_method_name = s;
+
+    k->k_material = r;
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_session_attr() - parse a session "a=" field
+ *
+ * Description:
+ *   This function parses an SDP attribute field regarding whole session.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result)
+{
+  /*
+   attribute-fields =    *("a=" attribute CRLF)
+
+   attribute =           (att-field ":" att-value) | att-field
+
+   att-field =           1*(alpha-numeric)
+
+   att-value =           byte-string
+   */
+
+  char *name = NULL, *value = NULL;
+
+  if (!(name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB))) {
+    parsing_error(p,"invalid attribute name");
+    return;
+  }
+
+  if (*r)
+    value = r;
+  else 
+    PARSE_CHECK_REST(p, r, "a");
+
+  if (strcasecmp(name, "charset") == 0) {
+    p->pr_session->sdp_charset = value;
+    return;
+  }
+
+  if (p->pr_mode_manual) 
+    ;
+  else if (strcasecmp(name, "inactive") == 0)
+    p->pr_session_mode = sdp_inactive;
+  else if (strcasecmp(name, "sendonly") == 0)
+    p->pr_session_mode = sdp_sendonly;
+  else if (strcasecmp(name, "recvonly") == 0)
+    p->pr_session_mode = sdp_recvonly;
+  else if (strcasecmp(name, "sendrecv") == 0)
+    p->pr_session_mode = sdp_sendrecv;
+
+  {
+    PARSE_ALLOC(p, sdp_attribute_t, a);
+    *result = a;
+
+    a->a_name  = name;
+    a->a_value = value;
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_media() - parse an "m=" field
+ *
+ * Description:
+ *   This function parses an SDP media field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result)
+{
+  /*
+   media-descriptions =  *( media-field
+                         information-field
+                         *(connection-field)
+                         bandwidth-fields
+                         key-field
+                         attribute-fields )
+
+   media-field =         "m=" media space port ["/" integer]
+                         space proto 1*(space fmt) CRLF
+
+   media =               1*(alpha-numeric)
+                         ;typically "audio", "video", "application"
+                         ;or "data"
+
+   fmt =                 1*(alpha-numeric)
+                         ;typically an RTP payload type for audio
+                         ;and video media
+
+   proto =               1*(alpha-numeric)
+                         ;typically "RTP/AVP" or "udp" for IP4
+
+   port =                1*(DIGIT)
+                         ;should in the range "1024" to "65535" inclusive
+   */
+  char *s;
+  unsigned long value;
+  PARSE_ALLOC(p, sdp_media_t, m);
+
+  *result = m;
+
+  m->m_mode = sdp_sendrecv;
+
+  s = token(&r, SPACE, ALPHA DIGIT, NULL);
+  if (s == NULL && p->pr_config)
+    s = token(&r, SPACE, "*", NULL);
+  if (!s) {
+    parsing_error(p, "m= invalid media field");
+    return;
+  }
+
+  sdp_media_type(m, s);
+
+  /* Accept m=* in configuration file */
+  if (p->pr_config && m->m_type == sdp_media_any) {
+    r += strspn(r, SPACE TAB);
+    if (r[0] == '\0') {
+      m->m_proto = sdp_proto_any, m->m_proto_name = "*";
+      return;
+    }
+  }
+
+  if (parse_ul(p, &r, &value, 0)) {
+    parsing_error(p, "m= invalid port number");
+    return;
+  }
+  m->m_port = value;
+
+  if (*r == '/') {
+    r++;
+    if (parse_ul(p, &r, &value, 0)) {
+      parsing_error(p, "m= invalid port specification");
+      return;
+    }
+    m->m_number_of_ports = value;
+  }
+
+  /* alpha-numeric and "/" */
+  s = token(&r, SPACE, ALPHA DIGIT "/", SPACE);
+  if (s == NULL && p->pr_config) 
+    s = token(&r, SPACE, "*", SPACE);
+  if (s == NULL) {
+    parsing_error(p, "m= missing protocol");
+    return;
+  }
+  
+  if (!STRICT(p) && strcasecmp(s, "RTP") == 0)
+    m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
+  else 
+    sdp_media_transport(m, s);
+
+  /* RTP format list */
+  if (*r && sdp_media_has_rtp(m)) {
+    parse_payload(p, r, &m->m_rtpmaps);
+    return;
+  }
+
+  /* "normal" format list */
+  if (*r) {
+    sdp_list_t **fmt = &m->m_format;
+    
+    while (r && *r) {
+      PARSE_ALLOC(p, sdp_list_t, l);
+      *fmt = l;
+      l->l_text = next(&r, SPACE TAB, SPACE TAB);
+      fmt = &l->l_next;
+    }
+  }
+}
+
+/** Set media type */
+void sdp_media_type(sdp_media_t *m, char const *s)
+{
+  if (strcmp(s, "*") == 0)
+    m->m_type = sdp_media_any, m->m_type_name = "*";
+  else if (strcasecmp(s, "audio") == 0)
+    m->m_type = sdp_media_audio, m->m_type_name = "audio";
+  else if (strcasecmp(s, "video") == 0)
+    m->m_type = sdp_media_video, m->m_type_name = "video";
+  else if (strcasecmp(s, "application") == 0)
+    m->m_type = sdp_media_application, m->m_type_name = "application";
+  else if (strcasecmp(s, "data") == 0)
+    m->m_type = sdp_media_data, m->m_type_name = "data";
+  else if (strcasecmp(s, "control") == 0)
+    m->m_type = sdp_media_control, m->m_type_name = "control";
+  else if (strcasecmp(s, "message") == 0)
+    m->m_type = sdp_media_message, m->m_type_name = "message";
+  else if (strcasecmp(s, "image") == 0)
+    m->m_type = sdp_media_image, m->m_type_name = "image";
+  else if (strcasecmp(s, "red") == 0)
+    m->m_type = sdp_media_red, m->m_type_name = "red";
+  else
+    m->m_type = sdp_media_x, m->m_type_name = s;
+}
+
+void sdp_media_transport(sdp_media_t *m, char const *s)
+{
+  if (strcasecmp(s, "*") == 0)
+    m->m_proto = sdp_proto_any, m->m_proto_name = "*";
+  else if (strcasecmp(s, "RTP/AVP") == 0)
+    m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
+  else if (strcasecmp(s, "RTP/SAVP") == 0)
+    m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP";
+  else if (strcasecmp(s, "UDPTL") == 0)
+    m->m_proto = sdp_proto_udptl, m->m_proto_name = "UDPTL";
+  else if (strcasecmp(s, "UDP") == 0)
+    m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP";
+  else if (strcasecmp(s, "TCP") == 0)
+    m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP";
+  else if (strcasecmp(s, "TLS") == 0)
+    m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS";
+  else 
+    m->m_proto = sdp_proto_x, m->m_proto_name = s;
+}
+
+/** Check if media uses RTP as its transport protocol.  */
+int sdp_media_has_rtp(sdp_media_t const *m)
+{
+  return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp);
+}
+
+#define RTPMAP(pt, encoding, rate, params) \
+  { sizeof(sdp_rtpmap_t), NULL, encoding, rate, (char *)params, NULL, 1, pt, 0 }
+
+/* rtpmaps for well-known codecs */
+static sdp_rtpmap_t const
+  sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0),
+  sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0),
+  sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0),
+  sdp_rtpmap_gsm =  RTPMAP(3, "GSM",  8000, 0),
+  sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0),
+  sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0),
+  sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0),
+  sdp_rtpmap_lpc = RTPMAP(7, "LPC",  8000, 0),
+  sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0),
+  sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0),
+  sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"),
+  sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0),
+  sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0),
+  sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0),
+  sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
+  sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0),
+  sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0),
+  sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0),
+  sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0),
+  sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0),
+  /* video codecs */
+  sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
+  sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
+  sdp_rtpmap_nv = RTPMAP(28, "nv",   90000, 0),
+  sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
+  sdp_rtpmap_mpv = RTPMAP(32, "MPV",  90000, 0),
+  sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
+  sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
+
+/** Table of rtpmap structures by payload type numbers.
+ *
+ * The table of reserved payload numbers is constructed from @RFC3551
+ * and @RFC1890. Note the clock rate of G722.
+ *
+ * Use sdp_rtpmap_dup() to copy these structures.
+ */
+sdp_rtpmap_t const * const sdp_rtpmap_well_known[128] =
+{
+  &sdp_rtpmap_pcmu,		/* 0 */
+  &sdp_rtpmap_1016,		/* 1 */
+  &sdp_rtpmap_g721,		/* 2 */
+  &sdp_rtpmap_gsm,		/* 3 */
+  &sdp_rtpmap_g723,		/* 4 */
+  &sdp_rtpmap_dvi4_8000,	/* 5 */
+  &sdp_rtpmap_dvi4_16000,	/* 6 */
+  &sdp_rtpmap_lpc,		/* 7 */
+  &sdp_rtpmap_pcma,		/* 8 */
+  &sdp_rtpmap_g722,		/* 9 */
+  &sdp_rtpmap_l16_2,		/* 10 */
+  &sdp_rtpmap_l16,		/* 11 */
+  &sdp_rtpmap_qcelp,		/* 12 */
+  &sdp_rtpmap_cn,		/* 13 */
+  &sdp_rtpmap_mpa,		/* 14 */
+  &sdp_rtpmap_g728,		/* 15 */
+  &sdp_rtpmap_dvi4_11025,	/* 16 */
+  &sdp_rtpmap_dvi4_22050,	/* 17 */
+  &sdp_rtpmap_g729,		/* 18 */
+  &sdp_rtpmap_reserved_cn,	/* 19 */
+  NULL,				/* 20 */
+  NULL,				/* 21 */
+  NULL,				/* 22 */
+  NULL,				/* 23 */
+  NULL,				/* 24 */
+  &sdp_rtpmap_celb,		/* 25 */
+  &sdp_rtpmap_jpeg,		/* 26 */
+  NULL,				/* 27 */
+  &sdp_rtpmap_nv,		/* 28 */
+  NULL,				/* 29 */
+  NULL,				/* 30 */
+  &sdp_rtpmap_h261,		/* 31 */
+  &sdp_rtpmap_mpv,		/* 32 */
+  &sdp_rtpmap_mp2t,		/* 33 */
+  &sdp_rtpmap_h263,		/* 34 */
+  NULL,
+};
+
+/**
+ * The function parse_payload() parses an RTP payload type list, and
+ * creates an rtpmap structure for each payload type.
+ *
+ * @param p       pointer to SDP parser object
+ * @param r       pointer to record data
+ * @param result  pointer to which parsed record is assigned
+ */
+static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
+{
+  while (*r) {
+    unsigned long value;
+
+    if (parse_ul(p, &r, &value, 128) == 0) {
+      PARSE_ALLOC(p, sdp_rtpmap_t, rm);
+
+      assert(0 <= value && value < 128);
+
+      *result = rm; result = &rm->rm_next;
+
+      if (sdp_rtpmap_well_known[value]) {
+	*rm = *sdp_rtpmap_well_known[value];
+      }
+      else {
+	rm->rm_predef = 1;
+	rm->rm_pt = value;
+	rm->rm_encoding = "";
+	rm->rm_rate = 0;
+      }
+    }
+    else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
+      PARSE_ALLOC(p, sdp_rtpmap_t, rm);
+
+      *result = rm; result = &rm->rm_next;
+
+      rm->rm_predef = 1;
+      rm->rm_any = 1;
+      rm->rm_encoding = "*";
+      rm->rm_rate = 0;
+
+      return;
+    }
+    else {
+      parsing_error(p, "m= invalid format for RTP/AVT");
+
+      return;
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_media_attr() - parse a media-specific "a=" field
+ *
+ * Description:
+ *   This function parses a media-specific attribute field.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   r      - pointer to record data
+ *   result - pointer to which parsed record is assigned
+ */
+static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
+			     sdp_attribute_t **result)
+{
+  /*
+   attribute-fields =    *("a=" attribute CRLF)
+
+   attribute =           (att-field ":" att-value) | att-field
+
+   att-field =           1*(alpha-numeric) 
+
+   att-value =           byte-string
+
+   a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
+   a=fmtp:<payload type> <parameters>
+   */
+  int rtp = sdp_media_has_rtp(m);
+  char *name = NULL, *value = NULL;
+  int n;
+
+  if (!(name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB))) {
+    parsing_error(p,"invalid attribute name");
+    return;
+  }
+
+  if (*r)
+    value = r;
+  else 
+    PARSE_CHECK_REST(p, r, "a");
+
+  if (p->pr_mode_manual) 
+    ;
+  else if (strcasecmp(name, "inactive") == 0) {
+    m->m_mode = sdp_inactive;
+    return;
+  }
+  else if (strcasecmp(name, "sendonly") == 0) {
+    m->m_mode = sdp_sendonly;
+    return;
+  }
+  else if (strcasecmp(name, "recvonly") == 0) {
+    m->m_mode = sdp_recvonly;
+    return;
+  }
+  else if (strcasecmp(name, "sendrecv") == 0) {
+    m->m_mode = sdp_sendrecv;
+    return;
+  }
+
+  if (rtp && strcasecmp(name, "rtpmap") == 0) {
+    if ((n = parse_rtpmap(p, r, m)) == 0 || n < -1)
+      return;
+  }
+  else if (rtp && strcasecmp(name, "fmtp") == 0) {
+    if ((n = parse_fmtp(p, r, m)) == 0 || n < -1)
+      return;
+  }
+  else {
+    PARSE_ALLOC(p, sdp_attribute_t, a);
+    *result = a;
+
+    a->a_name  = name;
+    a->a_value = value;
+  }
+}
+
+/** Parse rtpmap attribute.
+ *
+ * a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
+ */
+static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m)
+{
+  unsigned long pt, rate;
+  char *encoding, *params;
+  sdp_rtpmap_t *rm;
+
+  int strict = STRICT(p);
+
+  if (parse_ul(p, &r, &pt, 128)) {
+    if (strict)
+      parsing_error(p, "a=rtpmap: invalid payload type");
+    return -1;
+  }
+
+  for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
+    if (rm->rm_pt == pt)
+      break;
+
+  if (!rm) {
+    if (strict)
+      parsing_error(p, "a=rtpmap:%lu: unknown payload type", pt);
+    return -1;
+  }
+
+  encoding = token(&r, "/", ALPHA DIGIT "-", NULL);
+  if (!r) {
+    parsing_error(p, "a=rtpmap:%lu: missing <clock rate>", pt);
+    return -2;
+  }
+  if (parse_ul(p, &r, &rate, 0)) {
+    parsing_error(p, "a=rtpmap:%lu %s: invalid <clock rate>", pt, encoding);
+    return -2;
+  }
+
+  if (*r == '/') 
+    params = ++r;
+  else
+    params = 0;
+    
+  rm->rm_predef = 0;
+  rm->rm_encoding = encoding;
+  rm->rm_rate = rate;
+  rm->rm_params = params;
+
+  return 0;
+}
+
+/** Parse fmtp attribute.
+ *
+ * a=fmtp:<payload type> <parameters>
+ */
+static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m)
+{
+  unsigned long pt;
+  sdp_rtpmap_t *rm;
+
+  int strict = STRICT(p);
+
+  if (parse_ul(p, &r, &pt, 128)) {
+    if (strict)
+      parsing_error(p, "a=rtpmap: invalid payload type");
+    return -1;
+  }
+
+  for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
+    if (rm->rm_pt == pt)
+      break;
+
+  if (!rm) {
+    if (strict)
+      parsing_error(p, "a=fmtp:%lu: unknown payload type", pt);
+    return -1;
+  }
+
+  rm->rm_fmtp = r;
+  return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_descs() - parse media descriptors
+ *
+ * Description:
+ *   This function parses media descriptors at the end of SDP message.
+ *
+ * Parameters:
+ *   p      - pointer to SDP parser object
+ *   record - pointer to first media field
+ *   message - pointer to rest 
+ *   medias - pointer to which parsed media structures are assigned
+ */
+static void parse_descs(sdp_parser_t *p, 
+			char *record, 
+			char *message, 
+			sdp_media_t **medias)
+{
+  char *rest;
+  const char *strip;
+  sdp_media_t *m = NULL;
+  sdp_connection_t **connections = NULL;
+  sdp_bandwidth_t **bandwidths = NULL;
+  sdp_attribute_t **attributes = NULL;
+
+  if (!STRICT(p))
+    strip = SPACE TAB;		/* skip initial whitespace */
+  else
+    strip = NULL;
+  
+  for (;
+       record && p->pr_ok;
+       record = next(&message, CRLF, strip)) {
+    char field = record[0];
+
+    rest = record + 2; rest += strspn(rest, strip);
+
+    if (record[1] == '=') switch (field) {
+    case 'c':
+      assert(connections);
+      parse_connection(p, rest, connections);
+      connections = &(*connections)->c_next;
+      break;
+
+    case 'b':
+      assert(bandwidths);
+      parse_bandwidth(p, rest, bandwidths);
+      bandwidths = &(*bandwidths)->b_next;
+      break;
+
+    case 'k':
+      parse_key(p, rest, &m->m_key);
+      break;
+
+    case 'a':
+      assert(attributes);
+      parse_media_attr(p, rest, m, attributes);
+      if (*attributes)
+	attributes = &(*attributes)->a_next;
+      break;
+
+    case 'm':
+      parse_media(p, rest, medias);
+      m = *medias;
+      if (m) {
+	m->m_mode = p->pr_session_mode;
+	medias = &m->m_next;
+	connections = &m->m_connections;
+	bandwidths = &m->m_bandwidths;
+	attributes = &m->m_attributes;
+      }
+    }
+  }
+}
+
+static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+  PARSE_ALLOC(p, sdp_list_t, l);
+
+  *result = l;
+
+  l->l_text = r;
+}
+
+/*
+ * parse_ul: parse an unsigned long
+ */
+static int parse_ul(sdp_parser_t *p, char **r, 
+		    unsigned long *result, unsigned long max)
+{
+  char *ul = *r; 
+
+  ul += strspn(ul, SPACE TAB);
+
+  *result = strtoul(ul, r, 10);
+  if (ul != *r && !(max && max <= *result)) {
+    *r += strspn(*r, SPACE TAB);
+    return 0;
+  }
+
+  return -1;
+}
+
+#if !HAVE_STRTOULL
+unsigned longlong strtoull(char const *string, char **return_end, int base);
+#endif
+
+/*
+ * parse_ull: parse an unsigned long long
+ */
+static int parse_ull(sdp_parser_t *p, char **r, 
+		     uint64_t *result, uint64_t max)
+{
+  unsigned longlong ull;
+
+  char *s = *r; 
+
+  s += strspn(s, SPACE TAB);
+
+  ull = strtoull(s, r, 10);
+
+  if (s != *r && !(max && max <= ull)) {
+    *result = (uint64_t)ull;
+    *r += strspn(*r, SPACE TAB);
+    return 0;
+  }
+
+  return -1;
+}
+
+static char *token(char **message, 
+		   const char *sep, 
+		   const char *legal, 
+		   const char *strip)
+{
+  size_t n;
+  char *retval = *message;
+
+  if (strip)
+    retval += strspn(retval, strip);
+
+  if (legal)
+    n = strspn(retval, legal);
+  else 
+    n = strcspn(retval, sep);
+
+  if (n == 0)
+    return NULL;
+
+  if (retval[n]) {
+    retval[n++] = '\0';
+    n += strspn(retval + n, sep);
+  }
+
+  *message = retval + n;
+
+  if (*retval == '\0')
+    return NULL;
+
+  return retval;
+}
+
+static char *next(char **message, const char *sep, const char *strip)
+{
+  size_t n;
+  char *retval = *message;
+
+  if (strip)
+    retval += strspn(retval, strip);
+
+  n = strcspn(retval, sep);
+
+  if (n == 0)
+    return NULL;
+
+  if (retval[n]) {
+    retval[n++] = '\0';
+    n += strspn(retval + n, sep);
+  }
+
+  *message = retval + n;
+
+  if (*retval == '\0')
+    return NULL;
+
+  return retval;
+}
+
+static void parsing_error(sdp_parser_t *p, char const *fmt, ...)
+{
+  int n;
+  va_list ap;
+  va_start(ap, fmt); 
+  
+  memset(p->pr_error, 0, sizeof(p->pr_error));
+  n = vsnprintf(p->pr_error, sizeof(p->pr_error), fmt, ap);
+  va_end(ap);
+
+  p->pr_ok = 0;
+}
+
+static void parse_alloc_error(sdp_parser_t *p, const char *typename)
+{
+  parsing_error(p, "memory exhausted (while allocating memory for %s)", 
+		typename);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,734 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sdp_printer 
+ *
+ * @CFILE sdp_print.c  Simple SDP printer interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/sdp.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ========================================================================= */
+/* Printing API */
+/* */
+
+#define SDP_BLOCK   (512)
+
+#define CRLF "\015\012"
+
+typedef unsigned longlong ull;
+
+/** @typedef struct sdp_printer_s sdp_printer_t
+ *
+ * SDP printer handle.
+ *
+ * @sa #sdp_session_t, sdp_print(), sdp_printing_error(),
+ * sdp_message(), sdp_message_size(), sdp_printer_free()
+ */
+
+struct sdp_printer_s {
+  int        pr_size;
+  su_home_t *pr_home;
+  char      *pr_buffer;
+  size_t     pr_bsiz;
+  size_t     pr_used;
+  /* various flags */
+  unsigned   pr_ok : 1;
+  unsigned   pr_strict : 1;
+  unsigned   pr_owns_buffer:1;
+  unsigned   pr_may_realloc:1;
+  unsigned   pr_all_rtpmaps:1;
+  unsigned   pr_mode_manual:1;
+  unsigned   pr_mode_always:1;
+};
+
+static struct sdp_printer_s printer_memory_error = {
+  sizeof(printer_memory_error),
+  NULL,
+  "memory exhausted", 
+  sizeof(printer_memory_error.pr_buffer),
+  sizeof(printer_memory_error.pr_buffer)
+};
+
+static void print_session(sdp_printer_t *p, sdp_session_t const *session);
+
+/** Print a SDP description.
+ *
+ * Encode the contents of the SDP session structure #sdp_session_t 
+ * to the @a msgbuf. The @a msgbuf has size @a msgsize
+ * bytes. If @a msgbuf is @c NULL, the sdp_print() function allocates the
+ * required buffer from the @a home heap.
+ *
+ * @param home     Memory home (may be NULL).
+ * @param session  SDP session description structure to be encoded.
+ * @param msgbuf   Buffer to which encoding is stored (may be NULL). 
+ * @param msgsize  Size of @a msgbuf.
+ * @param flags    Flags specifying the encoding options.
+ *
+ * The @a flags specify encoding options as follows:
+ *
+ * @li #sdp_f_strict - Printer should only emit messages conforming strictly
+ * to the * specification.
+ *
+ * @li #sdp_f_realloc - If this flag is specified, and @a msgbuf is too
+ * small for the resulting SDP message, @c sdp_print() may allocate a new
+ * buffer for it from the heap.
+ *
+ * @li #sdp_f_print_prefix - The buffer provided by caller already contains
+ * valid data. The result will concatenated to the string in the buffer.
+ *
+ * @li #sdp_f_mode_always - Always add mode attributes to media
+ *
+ * @li #sdp_f_mode_manual - Do not generate mode attributes
+ *
+ * @return 
+ * Always return a handle to an #sdp_printer_t object.
+ *
+ * @sa #sdp_printer_t, #sdp_session_t, sdp_printing_error(),
+ * sdp_message(), sdp_message_size(), sdp_printer_free(),
+ * sdp_parse().
+ */
+sdp_printer_t *sdp_print(su_home_t *home, 
+			 sdp_session_t const *session, 
+			 char msgbuf[], 
+			 isize_t msgsize, 
+			 int flags)
+{
+  sdp_printer_t *p = su_salloc(home, sizeof(*p));
+
+  if (p) {
+    p->pr_size = sizeof(p);
+    p->pr_home = home;
+    p->pr_used   = 0;
+    if (msgbuf) {
+      p->pr_may_realloc = (flags & sdp_f_realloc) != 0;
+      p->pr_buffer = msgbuf;
+      p->pr_bsiz   = msgsize;
+      if (flags & sdp_f_print_prefix)
+	p->pr_used = strlen(msgbuf);
+    }
+    else {
+      p->pr_owns_buffer = 1;
+      p->pr_buffer = su_alloc(home, SDP_BLOCK);
+      p->pr_bsiz   = SDP_BLOCK;
+    }
+    p->pr_strict = (flags & sdp_f_strict) != 0;
+    p->pr_all_rtpmaps = (flags & sdp_f_all_rtpmaps) != 0;
+    p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
+    p->pr_mode_always = (flags & sdp_f_mode_always) != 0;
+
+    print_session(p, session);
+
+    return p;
+  }
+  else {
+    return &printer_memory_error;
+  }
+}
+
+/** @brief Get encoding error.
+ *
+ * Return a message describing the encoding error.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return
+ * Return a pointer to C string describing printing errors, or NULL if no
+ * error was encountered.
+ */
+char const *sdp_printing_error(sdp_printer_t *p)
+{
+  if (p)
+    if (!p->pr_ok)
+      return p->pr_buffer;
+    else
+      return NULL;
+  else
+    return "null sdp_printer_t*";
+}
+
+/** @brief Get encoded SDP message.
+ *
+ * Return a pointer to a C string containing the SDP message.
+ * 
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return 
+ * Return a pointer to a C string containing the encoded SDP message, or
+ * NULL upon an error.
+ */
+char const *sdp_message(sdp_printer_t *p)
+{
+  if (p && p->pr_ok)
+    return p->pr_buffer;
+  else
+    return NULL;
+}
+
+/** @brief Get size of encoded SDP message.
+ *
+ * Return the size of the encoded SDP message.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return 
+ * Number of bytes in SDP message excluding final NUL or 0 upon an error.
+ */
+isize_t sdp_message_size(sdp_printer_t *p)
+{
+  if (p && p->pr_ok)
+    return p->pr_used;
+  else
+    return 0;
+}
+
+/** Free a SDP printer.
+ *
+ * Free the printer object @a p and the message buffer possibly associated
+ * with it.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ */
+void sdp_printer_free(sdp_printer_t *p)
+{
+  if (p && p != &printer_memory_error) {
+    if (p->pr_owns_buffer && p->pr_buffer)
+      su_free(p->pr_home, p->pr_buffer), p->pr_buffer = NULL;
+    su_free(p->pr_home, p);
+  }
+}
+
+/* ========================================================================= */
+static void print_version(sdp_printer_t *p, sdp_version_t const *v);
+static void print_origin(sdp_printer_t *p, sdp_origin_t const *o);
+static void print_subject(sdp_printer_t *p, sdp_text_t *s);
+static void print_information(sdp_printer_t *p, sdp_text_t *i);
+static void print_uri(sdp_printer_t *p, sdp_text_t  *u);
+static void print_emails(sdp_printer_t *p, sdp_list_t const *e);
+static void print_phones(sdp_printer_t *p, sdp_list_t const *ph);
+static void print_connection(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b);
+static void print_time(sdp_printer_t *p, sdp_time_t const *t);
+static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r);
+static void print_zone(sdp_printer_t *p, sdp_zone_t const *z);
+static void print_typed_time(sdp_printer_t *p, unsigned long t);
+static void print_key(sdp_printer_t *p, sdp_key_t const *k);
+static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a);
+static void print_charset(sdp_printer_t *p, sdp_text_t *charset);
+static void print_media(sdp_printer_t *p, sdp_session_t const *, 
+			sdp_media_t const *m);
+
+static void print_text_list(sdp_printer_t*, 
+			    const char *, sdp_list_t const *l);
+
+static void sdp_printf(sdp_printer_t *p, const char *fmt, ...);
+static void printing_error(sdp_printer_t *p, const char *fmt, ...);
+
+static void print_session(sdp_printer_t *p, sdp_session_t const *sdp)
+{
+  p->pr_ok = 1;
+
+  if (!sdp)
+    printing_error(p, "NULL session description");
+  if (p->pr_ok && sdp->sdp_version)
+    print_version(p, sdp->sdp_version);
+  if (p->pr_ok && sdp->sdp_origin)
+    print_origin(p, sdp->sdp_origin);
+  if (p->pr_ok && sdp->sdp_subject)
+    print_subject(p, sdp->sdp_subject);
+  if (p->pr_ok && sdp->sdp_information)
+    print_information(p, sdp->sdp_information);
+  if (p->pr_ok && sdp->sdp_uri)
+    print_uri(p, sdp->sdp_uri);
+  if (p->pr_ok && sdp->sdp_emails)
+    print_emails(p, sdp->sdp_emails);
+  if (p->pr_ok && sdp->sdp_phones)
+    print_phones(p, sdp->sdp_phones);
+  if (p->pr_ok && sdp->sdp_connection)
+    print_connection(p, sdp->sdp_connection);
+  if (p->pr_ok && sdp->sdp_bandwidths)
+    print_bandwidths(p, sdp->sdp_bandwidths);
+  if (p->pr_ok)
+    print_time(p, sdp->sdp_time);
+  if (p->pr_ok && sdp->sdp_time) {
+    if (p->pr_ok && sdp->sdp_time->t_repeat)
+      print_repeat(p, sdp->sdp_time->t_repeat);
+    if (p->pr_ok && sdp->sdp_time->t_zone)
+      print_zone(p, sdp->sdp_time->t_zone);
+  }
+  if (p->pr_ok && sdp->sdp_key)
+    print_key(p, sdp->sdp_key);
+  if (p->pr_ok && sdp->sdp_charset)
+    print_charset(p, sdp->sdp_charset);
+  if (p->pr_ok && sdp->sdp_attributes)
+    print_attributes(p, sdp->sdp_attributes);
+  if (p->pr_ok && sdp->sdp_media)
+    print_media(p, sdp, sdp->sdp_media);
+}
+
+static void print_version(sdp_printer_t *p, sdp_version_t const *v)
+{
+  sdp_printf(p, "v=%lu" CRLF, *v);
+}
+
+static void print_origin(sdp_printer_t *p, sdp_origin_t const *o)
+{
+  if (!o->o_address ||
+      !o->o_address->c_address ||
+      o->o_address->c_ttl != 0 ||
+      o->o_address->c_groups > 1) {
+    printing_error(p, "o= address malformed");
+    return;
+  }
+
+  sdp_printf(p, "o=%s "LLU" "LLU" ", 
+	     o->o_username,
+	     (ull)o->o_id,
+	     (ull)o->o_version);
+
+  print_connection2(p, o->o_address);
+}
+
+static void print_subject(sdp_printer_t *p, sdp_text_t *subject)
+{
+  sdp_printf(p, "s=%s" CRLF, subject);
+}
+
+static void print_information(sdp_printer_t *p, sdp_text_t *information)
+{
+  sdp_printf(p, "i=%s" CRLF, information);
+}
+
+static void print_uri(sdp_printer_t *p, sdp_text_t *uri)
+{
+  sdp_printf(p, "u=%s" CRLF, uri);
+}
+
+static void print_emails(sdp_printer_t *p, sdp_list_t const *emails)
+{
+  print_text_list(p, "e=%s" CRLF, emails);
+}
+
+static void print_phones(sdp_printer_t *p, sdp_list_t const *phones)
+{
+  print_text_list(p, "p=%s" CRLF, phones);
+}
+
+static void print_connection(sdp_printer_t *p, sdp_connection_t const *c)
+{
+  sdp_printf(p, "c=");
+  print_connection2(p, c);
+}
+
+static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c)
+{
+  for (; c ; c = c->c_next) {
+    sdp_printf(p, "c=");
+    print_connection2(p, c);
+  }
+}
+
+static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c)
+{
+  const char *nettype;
+  const char *addrtype;
+
+  switch (c->c_nettype) {
+  case sdp_net_x:
+    nettype = NULL;
+    break;
+  case sdp_net_in:
+    nettype = "IN ";
+    break;
+  default:
+    printing_error(p, "unknown nettype %u", c->c_nettype);
+    return;
+  }
+
+  switch (c->c_addrtype) {
+  case sdp_addr_x:
+    addrtype = NULL;
+    break;
+  case sdp_addr_ip4:
+    nettype = "IN ";
+    addrtype = "IP4 ";
+    break;
+  case sdp_addr_ip6:
+    nettype = "IN ";
+    addrtype = "IP6 ";
+    break;
+  default:
+    printing_error(p, "unknown address type %u", c->c_addrtype);
+    return;
+  }
+
+  if (c->c_address == NULL) {
+    printing_error(p, "missing address");
+    return;
+  }
+
+  sdp_printf(p, "%s%s%s", nettype, addrtype, c->c_address);
+  if (c->c_mcast || c->c_ttl) {
+    sdp_printf(p, "/%u", c->c_ttl);
+    if (c->c_groups > 1)
+      sdp_printf(p, "/%u", c->c_groups);
+  }
+  sdp_printf(p, CRLF);
+}
+
+static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b)
+{
+  for (; b ; b = b->b_next) {
+    char const *name;
+    
+    switch (b->b_modifier) {
+    case sdp_bw_ct: name = "CT"; break;
+    case sdp_bw_as: name = "AS"; break;
+    default:        name = b->b_modifier_name; break;
+    }
+    
+    sdp_printf(p, "b=%s:%lu" CRLF, name, b->b_value);
+  }
+}
+
+static void print_time(sdp_printer_t *p, sdp_time_t const *t)
+{
+  if (t || p->pr_strict)
+    sdp_printf(p, "t=%lu %lu" CRLF, t ? t->t_start : 0L, t ? t->t_stop : 0L);
+}
+
+static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r)
+{
+  int i;
+
+  sdp_printf(p, "r=");
+  print_typed_time(p, r->r_interval);
+  sdp_printf(p, " ");
+  print_typed_time(p, r->r_duration);
+  for (i = 0; i < r->r_number_of_offsets; i++) {
+    sdp_printf(p, " ");
+    print_typed_time(p, r->r_offsets[i]);
+  }
+  sdp_printf(p, CRLF);
+}
+
+static void print_zone(sdp_printer_t *p, sdp_zone_t const *z)
+{
+  int i;
+  sdp_printf(p, "z=");
+
+  for (i = 0; i < z->z_number_of_adjustments; i++) {
+    int negative = z->z_adjustments[i].z_offset < 0L;
+    sdp_printf(p, "%s%lu %s", 
+	       i > 0 ? " " : "",
+	       z->z_adjustments[i].z_at, 
+	       negative ? "-" : "");
+    if (negative)
+      print_typed_time(p, -z->z_adjustments[i].z_offset);
+    else
+      print_typed_time(p, z->z_adjustments[i].z_offset);
+  }
+
+  sdp_printf(p, CRLF);
+}
+
+static void  print_typed_time(sdp_printer_t *p, unsigned long t)
+{
+  if (t % 60 || t == 0) {
+    sdp_printf(p, "%lu", t);
+  }
+  else {
+    t /= 60;
+
+    if (t % 60) {
+      sdp_printf(p, "%lum", t); /* minutes */
+    }
+    else {
+      t /= 60;
+
+      if (t % 24) {
+	sdp_printf(p, "%luh", t); /* hours */
+      }
+      else {
+	t /= 24;
+
+	sdp_printf(p, "%lud", t);	/* days */
+      }
+    }
+  }
+}
+
+static void print_key(sdp_printer_t *p, sdp_key_t const *k)
+{
+  const char *method;
+  int have_material = k->k_material != NULL;
+
+  switch (k->k_method) {
+  case sdp_key_x:
+    method = k->k_method_name; break;
+  case sdp_key_clear:
+    method = "clear"; break;
+  case sdp_key_base64:
+    method = "base64"; break;
+  case sdp_key_uri:
+    method = "uri"; break;
+  case sdp_key_prompt:
+    method = "prompt"; break;
+  default:
+    printing_error(p, "unknown key method (%d)", k->k_method);
+    return;
+  }
+
+  sdp_printf(p, "k=%s%s%s" CRLF, method, 
+	     have_material ? ":" : "",
+	     have_material ? k->k_material : "");
+}
+
+static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a)
+{
+  for (;a; a = a->a_next) {
+    char const *name = a->a_name;
+    char const *value = a->a_value;
+    sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
+  }
+}
+
+static void 
+print_attributes_without_mode(sdp_printer_t *p, sdp_attribute_t const *a)
+{
+  for (;a; a = a->a_next) {
+    char const *name = a->a_name;
+    char const *value = a->a_value;
+
+    if (strcasecmp(name, "inactive") == 0 ||
+	strcasecmp(name, "sendonly") == 0 ||
+	strcasecmp(name, "recvonly") == 0 ||
+	strcasecmp(name, "sendrecv") == 0)
+      continue;
+
+    sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
+  }
+}
+
+static void print_charset(sdp_printer_t *p, sdp_text_t *charset)
+{
+  sdp_printf(p, "a=charset%s%s" CRLF, charset ? ":" : "", charset ? charset : "");
+}
+
+static void print_media(sdp_printer_t *p, 
+			sdp_session_t const *sdp,
+			sdp_media_t const *m)
+{
+  char const *media, *proto;
+  sdp_rtpmap_t *rm;
+
+  sdp_mode_t session_mode = sdp_sendrecv;
+
+  if (!p->pr_mode_manual)
+    session_mode = sdp_attribute_mode(sdp->sdp_attributes, sdp_sendrecv);
+
+  for (;m ; m = m->m_next) {
+    switch (m->m_type) {
+    case sdp_media_audio:       media = "audio"; break;
+    case sdp_media_video:       media = "video"; break;
+    case sdp_media_application: media = "application"; break;
+    case sdp_media_data:        media = "data"; break;
+    case sdp_media_control:     media = "control"; break;
+    case sdp_media_message:     media = "message"; break;
+    case sdp_media_image  :     media = "image"; break;
+    default:                    media = m->m_type_name;
+    }
+    
+    switch (m->m_proto) {
+    case sdp_proto_tcp:   proto = "tcp"; break;
+    case sdp_proto_udp:   proto = "udp"; break;
+    case sdp_proto_rtp:   proto = "RTP/AVP"; break;
+    case sdp_proto_srtp:  proto = "RTP/SAVP"; break;
+    case sdp_proto_udptl: proto = "UDPTL"; break;
+    case sdp_proto_tls:   proto = "tls"; break;
+    default:              proto = m->m_proto_name; break;
+    }
+    
+    if (m->m_number_of_ports <= 1)
+      sdp_printf(p, "m=%s %u %s", media, m->m_port, proto);
+    else
+      sdp_printf(p, "m=%s %u/%u %s", 
+		 media, m->m_port, m->m_number_of_ports, proto);
+
+    if (m->m_rtpmaps) {
+      for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
+	if (rm->rm_any)
+	  sdp_printf(p, " *");
+	else
+	  sdp_printf(p, " %u", (unsigned)rm->rm_pt);
+      }
+    }
+    else if (m->m_format) {
+      sdp_list_t *l = m->m_format;
+      for (; l; l = l->l_next)
+	sdp_printf(p, " %s", l->l_text);
+    }
+    else {
+      sdp_printf(p, " 9");      /* SDP syntax requires at least one format.
+				   9 is used by nobody, right?. */
+    }
+
+
+    sdp_printf(p, CRLF);
+
+    if (m->m_information)
+      print_information(p, m->m_information);
+    if (m->m_connections)
+#ifdef nomore
+    if (m->m_connections != sdp->sdp_connection)
+#endif      
+      print_connection_list(p, m->m_connections);
+    if (m->m_bandwidths)
+      print_bandwidths(p, m->m_bandwidths);
+    if (m->m_key)
+      print_key(p, m->m_key);
+
+    for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
+      if (!rm->rm_predef || p->pr_all_rtpmaps)
+	sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF,
+		   rm->rm_pt, rm->rm_encoding, rm->rm_rate,
+		   rm->rm_params ? "/" : "", 
+		   rm->rm_params ? rm->rm_params : "");
+      if (rm->rm_fmtp)
+	sdp_printf(p, "a=fmtp:%u %s" CRLF, 
+		   rm->rm_pt, rm->rm_fmtp);
+    }
+
+    if (!p->pr_mode_manual && !m->m_rejected &&
+	(m->m_mode != (unsigned int)session_mode || p->pr_mode_always)) {
+      switch (m->m_mode) {
+      case sdp_inactive:
+	sdp_printf(p, "a=inactive" CRLF);
+	break;
+      case sdp_sendonly:
+	sdp_printf(p, "a=sendonly" CRLF);
+	break;
+      case sdp_recvonly:
+	sdp_printf(p, "a=recvonly" CRLF);
+	break;
+      case sdp_sendrecv:
+	sdp_printf(p, "a=sendrecv" CRLF);
+	break;
+      default:
+	break;
+      }
+    }
+
+    if (p->pr_mode_manual)
+      print_attributes(p, m->m_attributes);
+    else
+      print_attributes_without_mode(p, m->m_attributes);
+  }
+}
+
+static void print_text_list(sdp_printer_t *p, 
+			    const char *fmt, sdp_list_t const *l)
+{
+  for (;l; l = l->l_next) {
+    sdp_printf(p, fmt, l->l_text);
+  }
+}
+
+static void printing_error(sdp_printer_t *p, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt); 
+  
+  if (p->pr_ok) {
+    int n;
+
+    n = vsnprintf(p->pr_buffer, p->pr_bsiz, fmt, ap);
+    
+    p->pr_ok = 0;
+  }
+
+  va_end(ap);
+}
+
+static void sdp_printf(sdp_printer_t *p, const char *fmt, ...)
+{
+  va_list ap;
+
+  while (p->pr_ok) {
+    int n;
+    
+    va_start(ap, fmt); 
+    n = vsnprintf(p->pr_buffer + p->pr_used, p->pr_bsiz - p->pr_used, fmt, ap);
+    va_end(ap);
+    
+    if (n > -1 && (size_t)n < p->pr_bsiz - p->pr_used) {
+      p->pr_used += n;
+      break;
+    }
+    else {
+      if (p->pr_owns_buffer) {
+	p->pr_buffer = su_realloc(p->pr_home, p->pr_buffer, 2 * p->pr_bsiz);
+	if (p->pr_buffer) {
+	  p->pr_bsiz = 2 * p->pr_bsiz;
+	  continue;
+	}
+	p->pr_owns_buffer = 0;
+      }
+      else if (p->pr_may_realloc) {	
+	char *buffer;
+	size_t size;
+	if (p->pr_bsiz < SDP_BLOCK)
+	  size = SDP_BLOCK;
+	else
+	  size = 2 * p->pr_bsiz;
+	buffer = su_alloc(p->pr_home, size);
+	if (buffer) {
+	  p->pr_owns_buffer = 1;
+	  p->pr_buffer = memcpy(buffer, p->pr_buffer, p->pr_bsiz);
+	  p->pr_bsiz = size;
+	  continue;
+	}
+      }
+      p->pr_ok = 0;
+      p->pr_buffer = "Memory exhausted";
+    }
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file sdp_tag.c
+ * @brief SDP Tags
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Mon May 12 12:11:30 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#define TAG_NAMESPACE "sdp"
+
+#include <sofia-sip/sdp_tag.h>
+
+tag_typedef_t sdptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t sdptag_session = {{
+  TAG_NAMESPACE, "session", sdptag_session_class 
+}};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,562 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SDP_H
+#define SDP_H
+/**@file sofia-sip/sdp.h  Simple SDP (RFC 2327) Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 08:54:48 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** SDP session description */
+typedef struct sdp_session_s     sdp_session_t;
+/** SDP version "v=" line */
+typedef unsigned long            sdp_version_t;
+/** SDP origin "o=" line */
+typedef struct sdp_origin_s      sdp_origin_t;
+/** SDP connection "c=" line */
+typedef struct sdp_connection_s  sdp_connection_t;
+/** SDP bandwidth "b=" line */
+typedef struct sdp_bandwidth_s   sdp_bandwidth_t;
+/** SDP time "t=" line */
+typedef struct sdp_time_s        sdp_time_t;
+/** SDP repeat "r=" line */
+typedef struct sdp_repeat_s      sdp_repeat_t;
+/** SDP timezone "z=" line */
+typedef struct sdp_zone_s        sdp_zone_t;
+/** SDP encryption key "k=" line */
+typedef struct sdp_key_s         sdp_key_t;
+/** SDP attribute "a=" line */
+typedef struct sdp_attribute_s   sdp_attribute_t;
+/** SDP media "m=" line */
+typedef struct sdp_media_s       sdp_media_t;
+/** SDP list ("e=", "p=" lines) */
+typedef struct sdp_list_s        sdp_list_t;
+/** SDP rtpmap attribute */
+typedef struct sdp_rtpmap_s      sdp_rtpmap_t;
+
+/** Message text */
+typedef char const               sdp_text_t;
+
+#define SDP_MIME_TYPE "application/sdp"
+
+enum {
+  SDP_CURRENT_VERSION = 0
+};
+
+/** Session description */
+struct sdp_session_s
+{
+  int                sdp_size;		/**< sizeof sdp_session_t */
+  sdp_session_t     *sdp_next;	        /**< Next description in list */
+  sdp_version_t      sdp_version[1];	/**< SDP version */
+  sdp_origin_t      *sdp_origin;	/**< Owner/creator and session ID */
+  sdp_text_t        *sdp_subject;	/**< Session name */
+  sdp_text_t        *sdp_information;	/**< Session information  */
+  sdp_text_t        *sdp_uri;		/**< URi of description */
+  sdp_list_t   	    *sdp_emails;	/**< E-mail address(s) */
+  sdp_list_t   	    *sdp_phones;	/**< Phone number(s)  */
+  sdp_connection_t  *sdp_connection;	/**< Group (or member) address */
+  sdp_bandwidth_t   *sdp_bandwidths;	/**< Session bandwidth */
+  sdp_time_t        *sdp_time;		/**< Session active time */
+  sdp_key_t         *sdp_key;	        /**< Session key */
+  sdp_attribute_t   *sdp_attributes;    /**< Session attributes */
+  sdp_text_t        *sdp_charset;       /**< SDP charset (default is UTF8) */
+  sdp_media_t       *sdp_media;         /**< Media descriptors */
+};
+
+/** Session description identification */ 
+struct sdp_origin_s
+{
+  int               o_size;		/**< sizeof sdp_origin_t */
+  sdp_text_t       *o_username;		/**< Username of originator */
+  uint64_t          o_id;		/**< Session identification  */
+  uint64_t          o_version;		/**< Version of session description */
+  sdp_connection_t *o_address;		/**< Address of originator */
+};
+
+/** Network type */
+typedef enum
+{
+  sdp_net_x = 0,			/**< Unknown network type */
+  sdp_net_in = 1		        /**< Internet */
+} sdp_nettype_e;
+
+/** Address type */
+typedef enum
+{
+  sdp_addr_x   = 0,			/**< Unknown address type */
+  sdp_addr_ip4 = 1,			/**< IPv4 address */
+  sdp_addr_ip6 = 2,			/**< IPv6 address */
+} sdp_addrtype_e;
+
+/** SDP connection - host or group address */
+struct sdp_connection_s
+{
+  int               c_size;		/**< Size fo sdp_connection_t */
+  sdp_connection_t *c_next;		/**< Next connection in list */
+  sdp_nettype_e     c_nettype;		/**< Network type */
+  sdp_addrtype_e    c_addrtype;		/**< Address type */
+  sdp_text_t       *c_address;		/**< Host or group address */
+  unsigned          c_ttl : 8;		/**< Time to live (scope) */
+  unsigned          c_mcast : 1;        /**< True if multicast */
+  unsigned : 0;
+  unsigned          c_groups;		/**< Number of groups (if multiple) */
+};
+
+/** Bandwdith type */
+typedef enum
+{
+  sdp_bw_x,				/**< Unknown bandwidth type */
+  sdp_bw_ct,				/**< Conference total */
+  sdp_bw_as,				/**< Application-specific */
+} sdp_bandwidth_e;
+
+/** Session or media bandwidth. */
+struct sdp_bandwidth_s
+{
+  int              b_size;		/**< Size fo sdp_bandwidth_t */
+  sdp_bandwidth_t *b_next;		/**< Next bw description in list */
+  sdp_bandwidth_e  b_modifier;		/**< Meaning of value 
+					     (total, or per application).  */
+  sdp_text_t      *b_modifier_name;     /**< Modifier if not well-known */
+  unsigned long    b_value;		/**< Bandwidth in kilobits per second */
+};
+
+/** Active time description. */
+struct sdp_time_s
+{
+  int            t_size;		/**< sizeof sdp_time_t in bytes */
+  sdp_time_t    *t_next;		/**< Next time description in list */
+  unsigned long  t_start;		/**< Start time (seconds since 1900) */
+  unsigned long  t_stop;		/**< Stop time (seconds since 1900) */
+  sdp_repeat_t  *t_repeat;		/**< Repeat information */
+  sdp_zone_t    *t_zone;		/**< Time Zone infromation */
+};
+
+/** Description of repetition. */
+struct sdp_repeat_s
+{
+  int           r_size;			/**< Size of structure including
+					 * r_offsets[r_number_of_offsets]
+					 */
+  int           r_number_of_offsets;	/**< Number of offsets in list */
+  unsigned long r_interval;		/**< Time between activations */
+  unsigned long r_duration;		/**< Duration of activation */
+  unsigned long r_offsets[1];	        /**< List of offsets from start-time */
+};
+
+/** Timezone */
+struct sdp_zone_s
+{
+  /** Size of structure including z_adjustments[z_number_of_adjustments] */
+  int z_size;
+  int z_number_of_adjustments;		/**< Number of adjustments in list  */
+  struct {
+    unsigned long z_at;			/**< Adjustment time  */
+    long          z_offset;		/**< Adjustment offset  */
+  } z_adjustments[1];		        /**< List of timezone adjustments */
+};
+
+/** Mechanism to be used to obtain session key */
+typedef enum {
+  sdp_key_x,				/**< Unknown mechanism */
+  sdp_key_clear,			/**< Key is included untransformed */
+  sdp_key_base64,			/**< Key is encoded with base64 */
+  sdp_key_uri,				/**< URI used to obtain a key */
+  sdp_key_prompt			/**< No key is included, 
+					     prompt user for key */
+} sdp_key_method_e;
+
+/** Session key */
+struct sdp_key_s
+{
+  int              k_size;		/**< sizeof sdp_key_t  */
+  sdp_key_method_e k_method;		/**< Mechanism used to obtain key */
+  sdp_text_t      *k_method_name;	/**< Mechanism if not known  */
+  sdp_text_t      *k_material;		/**< Encryption key  */
+};
+
+/** Session or media attribute */
+struct sdp_attribute_s {
+  int              a_size;		/**< sizeof sdp_attribute_t  */
+  sdp_attribute_t *a_next;		/**< Next attribute in list */
+  sdp_text_t      *a_name;		/**< Attribute name */
+  sdp_text_t      *a_value;		/**< Attribute value */
+};
+
+/** Media type @sa RFC2327 page 18. */
+typedef enum
+{
+  sdp_media_x = 0,			/**< Unknown media */
+  sdp_media_any,		        /**< * wildcard */
+  sdp_media_audio,			/**< Audio */
+  sdp_media_video,			/**< Video */
+  sdp_media_application,		/**< Conferencing */
+  sdp_media_data,			/**< Bulk data transfer */
+  sdp_media_control,			/**< Additional conference control */
+  sdp_media_message,			/**< Messaging sessions*/
+  sdp_media_image,			/**< Image browsing sessions for JPIP, and T.38 */
+  sdp_media_red				/**< Redundancy. @NEW_1_12_4 */
+} sdp_media_e;
+
+/** Media transport protocol. */
+typedef enum
+{
+  sdp_proto_x = 0,			/**< Unknown transport  */
+  sdp_proto_tcp = 6,			/**< TCP  */
+  sdp_proto_udp = 17,			/**< Plain UDP */
+  sdp_proto_rtp = 256,			/**< RTP/AVP */
+  sdp_proto_srtp = 257,			/**< RTP/SAVP  */
+  sdp_proto_udptl = 258,		/**< UDPTL. @NEW_1_12_4  */
+  sdp_proto_tls = 511,			/**< TLS over TCP */
+  sdp_proto_any = 512		        /**< * wildcard */
+} sdp_proto_e;
+
+/** Session mode. @note Identical to rtp_mode_t. */
+typedef enum {
+  sdp_inactive = 0, 
+  sdp_sendonly = 1, 
+  sdp_recvonly = 2, 
+  sdp_sendrecv = sdp_sendonly | sdp_recvonly
+} sdp_mode_t;
+
+/** Media announcement.
+ * 
+ * This structure describes one media type, e.g., audio.  The description
+ * contains the transport address (IP address and port) used for the group,
+ * the transport protocol used, the media formats or RTP payload types, and
+ * optionally media-specific bandwidth specification, encryption key and
+ * attributes. 
+ *
+ * There is a pointer (m_user) for the application data, too.
+ */
+struct sdp_media_s
+{
+  int               m_size;		/**< sizeof sdp_media_t  */
+  sdp_media_t      *m_next;		/**< Next media announcement  */
+  sdp_session_t    *m_session;          /**< Back-pointer to session level */
+
+  sdp_media_e       m_type;		/**< Media type  */
+  sdp_text_t       *m_type_name;	/**< Media type name */
+  unsigned long     m_port;		/**< Transport port number */
+  unsigned long     m_number_of_ports;	/**< Number of ports (if multiple) */
+  sdp_proto_e       m_proto;		/**< Transport protocol  */
+  sdp_text_t       *m_proto_name;	/**< Transport protocol name */
+  sdp_list_t       *m_format;		/**< List of media formats */
+  sdp_rtpmap_t     *m_rtpmaps;		/**< List of RTP maps */
+  sdp_text_t       *m_information;	/**< Media information */
+  sdp_connection_t *m_connections;	/**< List of addresses used */
+  sdp_bandwidth_t  *m_bandwidths;	/**< Bandwidth specification */
+  sdp_key_t        *m_key;		/**< Media key */
+  sdp_attribute_t  *m_attributes;	/**< Media attributes */
+
+  void             *m_user;	        /**< User data. */
+  
+  /** Rejected media */
+  unsigned          m_rejected : 1;     
+  /** Inactive, recvonly, sendonly, sendrecv */
+  /* sdp_mode_t */ unsigned m_mode : 2;
+  unsigned          : 0;
+};
+
+/** Text list */
+struct sdp_list_s
+{
+  int              l_size;		/**< sizeof sdp_list_t  */
+  sdp_list_t      *l_next;		/**< Next text entry in list */
+  sdp_text_t      *l_text;	        /**< Text as C string */
+};
+
+/** Mapping from RTP payload to codec.
+ * 
+ * The sdp_rtpmap_t() structure defines a mapping from an RTP payload to a
+ * particular codec.  In case of well-known payloads, the sdp_rtpmap_t()
+ * structure may be predefined, that is, generated by SDP parser without
+ * corresponding "a" line in the SDP.  The sdp_rtpmap_t() structure may also
+ * contain the @c fmtp attribute, which is used to convey format-specific
+ * parameters.
+ */
+struct sdp_rtpmap_s {
+  int            rm_size;		/**< sizeof sdp_rtpmap_t  */
+  sdp_rtpmap_t  *rm_next;		/**< Next RTP map entry  */
+  sdp_text_t    *rm_encoding;		/**< Codec name */
+  unsigned long  rm_rate;		/**< Sampling rate */
+  sdp_text_t    *rm_params;		/**< Format-specific parameters  */
+  sdp_text_t    *rm_fmtp;	        /**< Contents of fmtp */
+  unsigned       rm_predef : 1;	        /**< is this entry well-known? */
+  unsigned       rm_pt : 7;		/**< Payload type */
+  unsigned       rm_any : 1;	        /**< Wildcard entry */
+  int       :0;
+};
+
+SOFIAPUBVAR sdp_rtpmap_t const * const sdp_rtpmap_well_known[128];
+
+/** Duplicate an SDP session description structure. */
+SOFIAPUBFUN sdp_session_t *sdp_session_dup(su_home_t *, sdp_session_t const *);
+
+/** Duplicate an SDP origin structure. */
+SOFIAPUBFUN
+sdp_origin_t    *sdp_origin_dup(su_home_t *, sdp_origin_t const *);
+
+/** Duplicate an SDP connection structure. */
+SOFIAPUBFUN
+sdp_connection_t *sdp_connection_dup(su_home_t *home, sdp_connection_t const *);
+
+/** Duplicate an SDP bandwidth structure. */
+SOFIAPUBFUN
+sdp_bandwidth_t  *sdp_bandwidth_dup(su_home_t *home, sdp_bandwidth_t const *);
+
+/** Duplicate an SDP time structure. */
+SOFIAPUBFUN
+sdp_time_t       *sdp_time_dup(su_home_t *home, sdp_time_t const *);
+
+/** Duplicate an SDP repeat structure. */
+SOFIAPUBFUN
+sdp_repeat_t     *sdp_repeat_dup(su_home_t *home, sdp_repeat_t const *);
+
+/** Duplicate an SDP timezone structure. */
+SOFIAPUBFUN
+sdp_zone_t       *sdp_zone_dup(su_home_t *home, sdp_zone_t const *);
+
+/** Duplicate an SDP key structure. */
+SOFIAPUBFUN
+sdp_key_t        *sdp_key_dup(su_home_t *home, sdp_key_t const *);
+
+/** Duplicate an SDP attribute structure. */
+SOFIAPUBFUN
+sdp_attribute_t  *sdp_attribute_dup(su_home_t *home, sdp_attribute_t const *);
+
+/** Duplicate an SDP media description structure. */
+SOFIAPUBFUN
+sdp_media_t *sdp_media_dup(su_home_t *, sdp_media_t const *,
+			   sdp_session_t *);
+
+/** Duplicate a list of SDP media description structures. */
+SOFIAPUBFUN
+sdp_media_t *sdp_media_dup_all(su_home_t *, sdp_media_t const *,
+			       sdp_session_t *);
+
+/** Duplicate a list structure. */
+SOFIAPUBFUN
+sdp_list_t       *sdp_list_dup(su_home_t *home, sdp_list_t const *);
+
+/** Duplicate an rtpmap structure. */
+SOFIAPUBFUN
+sdp_rtpmap_t     *sdp_rtpmap_dup(su_home_t *home, sdp_rtpmap_t const *);
+
+/** Compare two session descriptions. */
+SOFIAPUBFUN int sdp_session_cmp(sdp_session_t const *a,
+				sdp_session_t const *b);
+
+/** Compare two origin fields */
+SOFIAPUBFUN int sdp_origin_cmp(sdp_origin_t const *a,
+			       sdp_origin_t const *b);
+
+/** Compare two connection fields */
+SOFIAPUBFUN int sdp_connection_cmp(sdp_connection_t const *,
+				   sdp_connection_t const *b);
+
+/** Compare two bandwidth (b=) fields */
+SOFIAPUBFUN int sdp_bandwidth_cmp(sdp_bandwidth_t const *a,
+				  sdp_bandwidth_t const *b);
+
+/** Compare two time fields */
+SOFIAPUBFUN int sdp_time_cmp(sdp_time_t const *a, sdp_time_t const *b);
+
+/* Compare two repeat (r=) fields */
+SOFIAPUBFUN int sdp_repeat_cmp(sdp_repeat_t const *a, sdp_repeat_t const *b);
+
+/* Compare two zone (z=) fields */
+SOFIAPUBFUN int sdp_zone_cmp(sdp_zone_t const *a, sdp_zone_t const *b);
+
+/** Compare two key (k=) fields. */
+SOFIAPUBFUN int sdp_key_cmp(sdp_key_t const *a, sdp_key_t const *b);
+
+/** Compare two attribute (a=) fields */
+SOFIAPUBFUN int sdp_attribute_cmp(sdp_attribute_t const *,
+				  sdp_attribute_t const *);
+
+/** Compare two media (m=) descriptions */
+SOFIAPUBFUN int sdp_media_cmp(sdp_media_t const *, sdp_media_t const *);
+
+/** Compare two rtpmap structures. */
+SOFIAPUBFUN int sdp_rtpmap_cmp(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b);
+
+/** Compare two text lists */
+SOFIAPUBFUN int sdp_list_cmp(sdp_list_t const *a, sdp_list_t const *b);
+
+/** Get connections of a media description */
+SOFIAPUBFUN sdp_connection_t *sdp_media_connections(sdp_media_t const *m);
+
+/** Check if media uses RTP as its transport protocol  */
+SOFIAPUBFUN int sdp_media_has_rtp(sdp_media_t const *m);
+
+/** Set media type */
+SOFIAPUBFUN void sdp_media_type(sdp_media_t *m, char const *s);
+
+/** Set transport protocol */
+SOFIAPUBFUN void sdp_media_transport(sdp_media_t *m, char const *s);
+
+/** Find named attribute from given list. */
+SOFIAPUBFUN sdp_attribute_t  *sdp_attribute_find(sdp_attribute_t const *a,
+						 char const *name);
+
+/** Find named attribute from given lists. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a, 
+						 sdp_attribute_t const *a2, 
+						 char const *name);
+
+/** Get session mode from attribute list. */
+SOFIAPUBFUN sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a,
+					  sdp_mode_t defmode);
+
+/** Get session mode from attribute list. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_by_mode(su_home_t *, 
+						   sdp_mode_t mode);
+
+/** Find a mapped attribute. */
+SOFIAPUBFUN 
+sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a, 
+					   char const *name, 
+					   int pt, char **return_result);
+
+/** Append a attribute to a list of attributes. */
+SOFIAPUBFUN void sdp_attribute_append(sdp_attribute_t **list, 
+			  sdp_attribute_t const *a);
+
+/** Replace a attribute within a list of attributes. */
+SOFIAPUBFUN int sdp_attribute_replace(sdp_attribute_t **list, 
+				      sdp_attribute_t *a,
+				      sdp_attribute_t **return_replaced);
+
+/** Remove a named attribute from a list of attributes. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list, 
+						  char const *name);
+
+/* Return 1 if m= line struct matches with given type and name */
+SOFIAPUBFUN unsigned sdp_media_match(sdp_media_t const *m,
+				     sdp_media_e type,
+				     sdp_text_t *type_name,
+				     sdp_proto_e proto,
+				     sdp_text_t *proto_name);
+
+SOFIAPUBFUN unsigned sdp_media_match_with(sdp_media_t const *a,
+					  sdp_media_t const *b);
+
+/** Count media lines in SDP. */
+SOFIAPUBFUN unsigned sdp_media_count(sdp_session_t const *sdp,
+				     sdp_media_e type,
+				     sdp_text_t *type_name,
+				     sdp_proto_e proto,
+				     sdp_text_t *proto_name);
+
+SOFIAPUBFUN unsigned sdp_media_count_with(sdp_session_t const *sdp,
+					  sdp_media_t const *m0);
+
+/** Return true if media uses RTP */
+SOFIAPUBFUN int sdp_media_uses_rtp(sdp_media_t const *m);
+
+/** Check if payload type, rtp rate and parameters match in rtpmaps*/
+SOFIAPUBFUN int sdp_rtpmap_match(sdp_rtpmap_t const *, sdp_rtpmap_t const *);
+
+/** Search for matching rtpmap from list */
+SOFIAPUBFUN sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
+						   sdp_rtpmap_t const *rm);
+
+/* ======================================================================== */
+
+/** Flags given to sdp_parse()/sdp_print(). */
+enum sdp_parse_flags_e {
+  /** Accept only conforming SDP */
+  sdp_f_strict = 1,
+  /** Accept any network type. */
+  sdp_f_anynet = 2,		
+  /** Reallocate message. */ 
+  sdp_f_realloc = 4,
+  /** Include well-known rtpmaps in message, too */
+  sdp_f_all_rtpmaps = 8,
+  /** Print buffer already contains a valid prefix */
+  sdp_f_print_prefix = 16,
+  /** Connection line with INADDR_ANY is considered equal to sendonly */
+  sdp_f_mode_0000 = 32,
+  /** Don't run sanity check */
+  sdp_f_insane = 64,
+  /** Don't require c= for each media line */
+  sdp_f_c_missing = 128,
+  /** Parse SDP config files */
+  sdp_f_config = 256,
+  /** Do not generate or parse SDP mode */
+  sdp_f_mode_manual = 512,
+  /** Always generate media-level mode attributes */
+  sdp_f_mode_always = 1024
+};
+
+/** SDP parser handle. */
+typedef struct sdp_parser_s sdp_parser_t;
+typedef sdp_parser_t  *sdp_parser;
+
+SOFIAPUBFUN sdp_parser_t *sdp_parse(su_home_t *,
+				    char const msg[], issize_t msgsize,
+				    int flags);
+SOFIAPUBFUN char const *sdp_parsing_error(sdp_parser_t *p);
+SOFIAPUBFUN sdp_session_t *sdp_session(sdp_parser_t *p);
+SOFIAPUBFUN void sdp_parser_free(sdp_parser_t *p);
+
+SOFIAPUBFUN int sdp_sanity_check(sdp_parser_t *);
+
+SOFIAPUBFUN su_home_t *sdp_parser_home(sdp_parser_t *);
+
+/* ======================================================================== */
+
+/** SDP printer handle */
+typedef struct sdp_printer_s sdp_printer_t;
+typedef sdp_printer_t *sdp_printer;
+
+SOFIAPUBFUN sdp_printer_t *sdp_print(su_home_t *, sdp_session_t const *session, 
+				     char msgbuf[], isize_t maxmsgsize, int flags);
+SOFIAPUBFUN char const *sdp_printing_error(sdp_printer_t *p);
+SOFIAPUBFUN char const *sdp_message(sdp_printer_t *p);
+SOFIAPUBFUN isize_t sdp_message_size(sdp_printer_t *p);
+SOFIAPUBFUN void sdp_printer_free(sdp_printer_t *p);
+
+#define sdp_mapped_attribute_find sdp_attribute_mapped_find
+#define sdp_free_parser  sdp_parser_free
+#define sdp_free_printer sdp_printer_free
+
+SOFIA_END_DECLS
+
+#endif /* SDP_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SDP_TAG_H
+/** Defined when <sofia-sip/sdp_tag.h> has been included. */
+#define SDP_TAG_H
+
+/**@file sofia-sip/sdp_tag.h   
+ * @brief SDP tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon May 12 12:06:20 EEST 2003 ppessi
+ * @{
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct sdp_session_s;
+
+/** Filter tag matching any sdp tag. */
+#define SDPTAG_ANY()         sdptag_any, ((tag_value_t)0)
+SDP_DLL extern tag_typedef_t sdptag_any;
+
+/* Tags for parameters */
+
+SDP_DLL extern tag_typedef_t sdptag_session;
+/** SDP session description. @HI */
+#define SDPTAG_SESSION(x) \
+sdptag_session, sdptag_session_v((x))
+
+SDP_DLL extern tag_typedef_t sdptag_session_ref;
+#define SDPTAG_SESSION_REF(x) \
+sdptag_session_ref, sdptag_session_vr(&(x))
+
+/* Functions for typesafe parameter passing */
+
+#if SU_HAVE_INLINE
+su_inline
+tag_value_t sdptag_session_v(struct sdp_session_s const *v) { 
+  return (tag_value_t)v; 
+}
+su_inline
+tag_value_t sdptag_session_vr(struct sdp_session_s const **vp) { 
+  return (tag_value_t)vp; 
+}
+#else
+#define sdptag_session_v(v)   (tag_value_t)(v)
+#define sdptag_session_vr(vp) (tag_value_t)(vp)
+#endif
+
+/* Tag classes */
+
+extern tag_class_t sdptag_session_class[];
+
+#define SDPTAG_TYPEDEF(name) \
+  {{ TAG_NAMESPACE, #name, sdptag_session_class }}
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SDP_TAG_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE test_sdp.c
+ *
+ * Simple SDP tester
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created      : Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sofia-sip/sdp.h"
+
+int diff(const char *olds, const char *news, int *linep, int *pos)
+{
+  const char *o, *n;
+
+  *linep = 0;
+
+  for (o = olds, n = news; *o && *n && *o == *n ; o++, n++) {
+    if (*o == '\n') ++*linep;
+  }
+
+  *pos = o - olds;
+
+  return *o != *n;
+}
+
+int main(int argc, char *argv[])
+{
+  char buffer[2048];
+  int  n;
+  su_home_t *home = su_home_create();
+  int exitcode = 1; 
+  FILE *f;
+
+  if (argv[1] && strcmp(argv[1], "-"))
+    f = fopen(argv[1], "rb");
+  else
+    f = stdin;
+
+  n = fread(buffer, 1, sizeof(buffer) - 1, f);
+  buffer[n] = 0;
+
+  if (feof(f)) {
+    sdp_parser_t *p = sdp_parse(home, buffer, n + 1, 0);
+
+    su_home_check(home);
+    su_home_check((su_home_t *)p);
+
+    if (sdp_session(p)) {
+      sdp_session_t *sdp, *dup;
+      sdp_printer_t *printer;
+
+      sdp = sdp_session(p);
+      dup = sdp_session_dup(home, sdp);
+      su_home_check(home);
+
+      sdp_parser_free(p), p = NULL;
+      su_home_check(home);
+
+      printer = sdp_print(home, dup, NULL, 0, 0);
+      su_home_check(home);
+
+      if (sdp_message(printer)) {
+	int line, pos;
+
+	if (diff(buffer, sdp_message(printer), &line, &pos)) {
+	  fprintf(stdout, "test_sdp:%d: messages differ:\n", line);
+	  fputs(buffer, stdout);
+	  fprintf(stdout, ">>>new message:\n");
+	  fputs(sdp_message(printer), stdout);
+	}
+	else {
+	  exitcode = 0;
+	}
+      }
+      else {
+	fprintf(stderr, "test_sdp: %s\n", sdp_printing_error(printer));
+      }
+      sdp_printer_free(printer);
+
+      su_home_check(home);
+    }
+    else {
+      fprintf(stderr, "test_sdp: %s\n", sdp_parsing_error(p));
+      sdp_parser_free(p);
+      exit(1);
+    }
+  }
+  else {
+    if (ferror(f)) {
+      perror("test_sdp");
+    }
+    else {
+      fprintf(stderr, "test_sdp: maximum length of sdp messages is %u bytes\n", 
+	      (unsigned)sizeof(buffer));
+    }
+    exit(1);
+  }
+
+  su_home_unref(home);
+
+  return exitcode;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+v=1

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,32 @@
+v=0
+o=ppessi 2890844526 13 IN IP4 126.16.64.4
+s=Testing sdp parser quirks
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+e=mjh at mail.isi.edu (Mark Handley)
+p=+358 9 4376 1
+p=+1 442 555 6782
+c=IN IP4 224.2.17.12/127/2
+b=CT:512
+t=2873397496 2873404696
+r=7d 1h 1d 1d 1d 1d 1d
+z=2882844526 -1h 2898848070 0
+k=uri:shttp://foo.bar.com/session/key
+a=recvonly
+m=audio 49230 RTP/AVP 0 96 97 98 99 100
+b=AS:360
+a=rtpmap:96 L8/8000
+a=rtpmap:97 L16/8000
+a=rtpmap:98 L16/11025/2
+a=rtpmap:99 GSM-EFR/8000
+a=rtpmap:100 X-AMR/8000
+a=fmtp:100 mode-set=4,5,6 interleaving crc vad=on use-redundancy=1
+m=video 51372/2 RTP/AVP 31
+c=IN IP4 224.2.17.12/127
+c=IN IP4 224.2.17.13/127
+b=AS:16
+a=rtpmap:31 H261/90000
+m=application 32416 udp wb
+b=AS:32
+a=orient:portrait

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+v=0
+o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+s=SDP Seminar
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+c=IN IP4 224.2.17.12/127
+t=2873397496 2873404696
+a=recvonly
+m=audio 49170 RTP/AVP 0
+m=video 51372 RTP/AVP 31
+m=application 32416 udp wb
+a=orient:portrait

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+v=0
+o=user1 53655765 2353687637 IN IP4 128.3.4.5
+s=Mbone Audio
+i=Discussion of Mbone Engineering Issues
+e=mbone at somewhere.com
+c=IN IP4 224.2.0.1/127
+t=0 0
+m=audio 3456 RTP/AVP 0

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4 @@
+v=0
+o=bell 53655765 2353687637 IN IP4 128.3.4.5
+c=IN IP4 135.180.144.94
+m=audio 3456 RTP/AVP 0 3 4 5

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,5 @@
+v=0
+o=watson 4858949 4858949 IN IP4 192.1.2.3
+s=I'm on my way
+c=IN IP4 boston.bell-tel.com
+m=audio 5004 RTP/AVP 0 3

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+v=0
+s=Let's talk
+c=IN IP4 north.east.isi.edu
+b=CT:128
+m=audio 3456 RTP/AVP 5 0 7
+m=video 2232 RTP/AVP 31

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+v=0
+o=alice 2890844526 2890844526 IN IP4 host.anywhere.com
+i=First example from RFC 2543 page 136
+c=IN IP4 host.anywhere.com
+m=audio 49170 RTP/AVP 0
+a=rtpmap:0 PCMU/8000
+m=video 51372 RTP/AVP 31
+a=rtpmap:31 H261/90000
+m=video 53000 RTP/AVP 32
+a=rtpmap:32 MPV/90000

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+v=0
+o=bob 2890844730 2890844730 IN IP4 host.example.com
+i=First example from RFC 2543 page 136
+c=IN IP4 host.example.com
+m=audio 47920 RTP/AVP 0 1
+a=rtpmap:0 PCMU/8000
+a=rtpmap:1 1016/8000
+m=video 0 RTP/AVP 31
+m=video 53000 RTP/AVP 32
+a=rtpmap:32 MPV/90000

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,25 @@
+v=0
+o=ppessi 2890844526 0 IN IP4 126.16.64.4
+s=Testing sdp parser quirks
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+c=IN IP4 224.2.17.12/127/2
+b=CT:512
+t=2873397496 2873404696
+a=recvonly
+m=audio 49230 RTP/AVP 0 96 97 98 99 100
+b=AS:360
+a=rtpmap:96 L8/8000
+a=rtpmap:97 L16/8000
+a=rtpmap:98 L16/11025/2
+a=rtpmap:99 GSM-EFR/8000
+a=rtpmap:100 X-AMR/8000
+m=video 51372/2 RTP/AVP 31
+c=IN IP4 224.2.17.12/127
+c=IN IP4 224.2.17.13/127
+b=AS:16
+a=rtpmap:31 H261/90000
+m=application 32416 udp wb
+b=AS:32
+a=orient:portrait

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,886 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE sdp_torture.c  
+ *
+ * Torture testing sdp module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Mar  6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/sdp.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/sdp_tag.h>
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+int tstflags;
+
+char const *name = "torture_sdp.c";
+
+FILE *null;
+
+static char const e0_msg[] = 
+"foo";
+
+static char const e1_msg[] = 
+    "v=1\n"
+    "s=/sdp_torture\n"
+    "o=sdp_torture 0 0 IN IP4 0.0.0.0\n"
+    "m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+    "a=rtpmap:96 X-AMR-WB/16000\n"
+    "a=rtpmap:97 X-AMR/8000\n"
+    "a=rtpmap:98 GSM-EFR/8000\n"
+    "a=rtpmap:10 L16/16000\n"
+    "a=rtpmap:99 G723/8000\n"
+    "a=rtpmap:8 PCMA/8000\n"
+    "a=rtpmap:0 PCMU/8000\n"
+    "m=video 0 *";
+
+static int test_error(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_parser_t *parser;
+
+  BEGIN();
+
+  su_home_check(home); TEST0(home);
+
+  TEST_1((parser = sdp_parse(home, e0_msg, sizeof(e0_msg), 0)));
+  TEST_1(sdp_session(parser) == NULL);
+  TEST_1(sdp_parsing_error(parser));
+  sdp_parser_free(parser);
+
+  TEST_1((parser = sdp_parse(home, e1_msg, sizeof(e1_msg), 0)));
+  TEST_1(sdp_session(parser) == NULL);
+  TEST_1(sdp_parsing_error(parser));
+  sdp_parser_free(parser);
+
+
+  /* destroy the home objects */
+  su_home_check(home); su_home_zap(home);
+
+  END();
+}
+
+static char const s0_msg[] = 
+    "v=0\n"
+    "s=/sdp_torture\n"
+    "o=sdp_torture 0 0 IN IP4 0.0.0.0\n"
+    "m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+    "a=rtpmap:96 X-AMR-WB/16000\n"
+    "a=rtpmap:97 X-AMR/8000\n"
+    "a=rtpmap:98 GSM-EFR/8000\n"
+    "a=rtpmap:10 L16/16000\n"
+    "a=rtpmap:99 G723/8000\n"
+    "a=rtpmap:8 PCMA/8000\n"
+    "a=rtpmap:0 PCMU/8000\n"
+    "m=video 0 *\n"
+    "m=* 0 RTP/AVP *\n"
+  ;
+
+static int test_session(void)
+{
+  su_home_t *home = su_home_create(), *home2 = su_home_create();
+  sdp_session_t *sdp_src, *sdp_target;
+  sdp_session_t const *sdp = NULL;
+  sdp_parser_t *parser;
+  sdp_printer_t *printer;
+  sdp_media_t *m;
+  char buffer[512];
+  tagi_t *lst, *dup;
+
+  BEGIN();
+
+  su_home_check(home);
+  TEST_1(home);
+
+  su_home_check(home2);
+  TEST_1(home2);
+  
+  TEST_1((parser = sdp_parse(home, s0_msg, sizeof(s0_msg), sdp_f_config)));
+  TEST_1((sdp_src = sdp_session(parser)));
+  TEST_1(sdp_src->sdp_media);
+  TEST_1(sdp_src->sdp_media->m_session);
+  TEST_P(sdp_src->sdp_media->m_session, sdp_src);
+
+  /* clone the session using 'home2' */
+  TEST_1((sdp_target = sdp_session_dup(home2, sdp_src)));
+
+  /* Check comparing */
+  TEST(sdp_session_cmp(sdp_src, sdp_target), 0);
+
+  /* check the cloned session */
+  TEST_1(sdp_target->sdp_subject);
+  TEST_S(sdp_target->sdp_subject, "/sdp_torture");
+  strcpy((char*)sdp_target->sdp_subject, "garbage");
+  TEST_S(sdp_src->sdp_subject, "/sdp_torture");
+
+  TEST_1(sdp_target->sdp_origin);
+  TEST_1(sdp_target->sdp_origin->o_username);
+  TEST_S(sdp_target->sdp_origin->o_username, "sdp_torture");
+  strcpy((char*)sdp_target->sdp_origin->o_username, "garbage");
+  TEST_S(sdp_src->sdp_origin->o_username, "sdp_torture");
+
+  TEST_1(m = sdp_target->sdp_media);
+  TEST_P(m->m_session, sdp_target);
+  TEST_1(sdp_src->sdp_media->m_session != sdp_target->sdp_media->m_session);
+
+  TEST(m->m_type, sdp_media_audio);
+  TEST_S(m->m_type_name, "audio");
+  TEST(m->m_port, 0);
+  TEST(m->m_number_of_ports, 0);
+  TEST(m->m_proto, sdp_proto_rtp);
+  TEST_S(m->m_proto_name, "RTP/AVP");
+  /* FIXME: add more tests */
+
+  /* frees all data created by the parser including 'sdp_src' */
+  sdp_parser_free(parser);
+
+  /* destroy the first home instance */
+  su_home_check(home);
+  su_home_unref(home);
+    
+  /* access all cloned data by printing it */
+  printer = sdp_print(home2, sdp_target, buffer, sizeof(buffer), 0);
+  if (printer != NULL) {
+    char const *msg = sdp_message(printer);
+
+    if (tstflags & tst_verbatim) {
+      printf("sdp_torture.c: parsed SDP message:\"%s\".\n", msg);
+    }
+      
+    sdp_printer_free(printer);
+  }
+
+  TEST_1(lst = tl_list(SDPTAG_SESSION(sdp_target), TAG_NULL()));
+
+  TEST_1(dup = tl_adup(home2, lst));
+
+  if (tstflags & tst_verbatim)
+    tl_print(stdout, "dup:\n", dup);
+  else
+    tl_print(null, "dup:\n", dup);
+
+  TEST(tl_gets(dup, SDPTAG_SESSION_REF(sdp), TAG_END()), 1);
+
+  /* access all copied data by printing it */
+  printer = sdp_print(home2, sdp, buffer, sizeof(buffer), 0);
+  if (printer != NULL) {
+    char const *msg = sdp_message(printer);
+    if (tstflags & tst_verbatim) {
+      printf("sdp_torture.c: "
+	     "SDP message passed through tag list:\n\"%s\".\n", msg);
+    }
+    sdp_printer_free(printer);
+  }
+
+  su_free(home2, dup);
+  tl_vfree(lst);
+
+  /* destroy the second home object */
+  su_home_check(home2);
+  su_home_unref(home2);
+
+  END();
+}
+
+static char const s1_msg[] = 
+  "v=0\r\n"
+  "o=- 2435697 2435697 IN IP4 172.21.137.44\r\n"
+  "s=-\r\n"
+  "c=IN IP4 172.21.137.44\r\n"
+  "t=0 0\r\n"
+  "a=sendonly\r\n"
+  "m=video 49154 RTP/AVP 96 24 25 26 28 31 32 33 34\r\n"
+  "a=rtpmap:96 H263-1998/90000\r\n"
+  "m=audio 49152 RTP/AVP 97 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19\r\n"
+  "a=rtpmap 97 AMR/8000\r\n"
+  "a=fmtp:97 mode-set=\"0,1,2,3,4\"\r\n"
+  "a=ptime:400\r\n";
+
+static char const s2_msg[] = 
+  "v=0\r\n"
+  "o=- 308519342 2 IN IP4 172.168.1.55\r\n"
+  "s=-\r\n"
+  "c=IN IP4 172.168.1.55\r\n"
+  "t=0 0\r\n"
+  "a=recvonly\r\n"
+  "m=video 59154 RTP/AVP 96\r\n"
+  "b=AS:64\r\n"
+  "a=rtpmap:96 H263-1998/90000\r\n"
+  "a=framerate:8\r\n"
+  "a=fmtp:96 QCIF=4\r\n"
+  "m=audio 59152 RTP/AVP 97\r\n"
+  "b=AS:8\r\n"
+  "a=rtpmap:97 AMR/8000\r\n"
+  "a=fmtp:97 mode-set=\"0\"\r\n"
+  "a=maxptime:500\r\n";
+
+static int test_session2(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_session_t const *sdp = NULL;
+  sdp_parser_t *parser;
+  sdp_media_t *m;
+  sdp_rtpmap_t *rm;
+
+  BEGIN();
+
+  su_home_check(home); TEST_1(home);
+
+  TEST_1((parser = sdp_parse(home, s1_msg, sizeof(s1_msg), 0)));
+  TEST_1((sdp = sdp_session(parser)));
+  TEST_1(m = sdp->sdp_media);
+  TEST(m->m_mode, sdp_sendonly);
+  TEST_P(m->m_session, sdp);
+  TEST_1(rm = m->m_rtpmaps);
+  TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "H263-1998");
+  TEST(rm->rm_rate, 90000);
+
+  {
+#define RTPMAP(pt, type, rate, params) \
+    { sizeof(sdp_rtpmap_t), NULL, type, rate, (char *)params, NULL, 1, pt, 0 }
+
+    /* rtpmaps for well-known video codecs */
+    static sdp_rtpmap_t const
+      sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
+      sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
+      sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0),
+      sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
+      sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0),
+      sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
+      sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
+
+
+    TEST_1(rm = rm->rm_next);
+    TEST_S(rm->rm_encoding, ""); TEST(rm->rm_rate, 0);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_celb, rm), &sdp_rtpmap_celb);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_jpeg, rm), &sdp_rtpmap_jpeg);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_nv, rm), &sdp_rtpmap_nv);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_h261, rm), &sdp_rtpmap_h261);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mpv, rm), &sdp_rtpmap_mpv);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mp2t, rm), &sdp_rtpmap_mp2t);
+    TEST_1(rm = rm->rm_next);
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_h263, rm), &sdp_rtpmap_h263);
+    TEST_1(!rm->rm_next);
+  }
+
+  TEST_1(m = m->m_next);
+  TEST(m->m_mode, sdp_sendonly);
+  TEST_P(m->m_session, sdp);
+  TEST_1(rm = m->m_rtpmaps);
+  TEST(rm->rm_pt, 97);
+  TEST_S(rm->rm_encoding, "AMR");
+  TEST(rm->rm_rate, 8000);
+  TEST_S(rm->rm_fmtp, "mode-set=\"0,1,2,3,4\"");
+
+  {
+    /* rtpmaps for well-known audio codecs */
+    static sdp_rtpmap_t const
+      sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, "1"),
+      sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, "1"),
+      sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, "1"),
+      sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, "1"),
+      sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, "1"),
+      sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, "1"),
+      sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, "1"),
+      sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, "1"),
+      sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, "1"),
+      sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, "1"),
+      sdp_rtpmap_l16 = RTPMAP(10, "L16", 44100, "2"),
+      sdp_rtpmap_l16_stereo = RTPMAP(11, "L16", 44100, "1"),
+      sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, "1"),
+      sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, "1"),
+      sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
+      sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, "1"),
+      sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, "1"),
+      sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, "1"),
+      sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, "1"),
+      sdp_rtpmap_cn_reserved = RTPMAP(19, "CN", 8000, "1");
+
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcmu, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_pcmu, rm), &sdp_rtpmap_pcmu);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_1016, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_1016, rm), &sdp_rtpmap_1016);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g721, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g721, rm), &sdp_rtpmap_g721);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_gsm, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_gsm, rm), &sdp_rtpmap_gsm);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g723, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g723, rm), &sdp_rtpmap_g723);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_8000, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_8000, rm),
+	   &sdp_rtpmap_dvi4_8000);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_16000, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_16000, rm),
+	   &sdp_rtpmap_dvi4_16000);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_lpc, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_lpc, rm), &sdp_rtpmap_lpc);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcma, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_pcma, rm), &sdp_rtpmap_pcma);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g722, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g722, rm), &sdp_rtpmap_g722);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_l16, rm), &sdp_rtpmap_l16);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16_stereo, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_l16_stereo, rm),
+	   &sdp_rtpmap_l16_stereo);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_qcelp, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_qcelp, rm), &sdp_rtpmap_qcelp);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_cn, rm), &sdp_rtpmap_cn);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_mpa, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mpa, rm), &sdp_rtpmap_mpa);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g728, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g728, rm), &sdp_rtpmap_g728);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_11025, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_11025, rm),
+	   &sdp_rtpmap_dvi4_11025);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_22050, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_22050, rm),
+	   &sdp_rtpmap_dvi4_22050);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g729, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g729, rm), &sdp_rtpmap_g729);
+    TEST_1(rm = rm->rm_next);
+    TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn_reserved, rm));
+    TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_cn_reserved, rm),
+	   &sdp_rtpmap_cn_reserved);
+    TEST_1(!rm->rm_next);
+  }
+  
+  TEST_1((parser = sdp_parse(home, s2_msg, sizeof (s2_msg), 0)));
+  TEST_1((sdp = sdp_session(parser)));
+  TEST_1(m = sdp->sdp_media);
+  TEST(m->m_mode, sdp_recvonly);
+  TEST_P(m->m_session, sdp);
+  TEST_1(m->m_rtpmaps);
+  TEST(m->m_rtpmaps->rm_pt, 96);
+  TEST_S(m->m_rtpmaps->rm_encoding, "H263-1998");
+  TEST(m->m_rtpmaps->rm_rate, 90000);
+  TEST_S(m->m_rtpmaps->rm_fmtp, "QCIF=4");
+  TEST_1(m = sdp->sdp_media->m_next);
+  TEST(m->m_mode, sdp_recvonly);
+  TEST_P(m->m_session, sdp);
+  TEST_1(m->m_rtpmaps);
+  TEST(m->m_rtpmaps->rm_pt, 97);
+  TEST_S(m->m_rtpmaps->rm_encoding, "AMR");
+  TEST(m->m_rtpmaps->rm_rate, 8000);
+  TEST_S(m->m_rtpmaps->rm_fmtp, "mode-set=\"0\"");
+
+  su_home_unref(home);
+
+  END();
+}
+
+static char const s3_msg[] = 
+  "v=0\r\n"
+  "o=- 2435697 2435697 IN IP4 172.21.137.44\r\n"
+  "s=-\r\n"
+  "t=0 0\r\n"
+  "m=video 49154 RTP/AVP 34\r\n"
+  "c=IN IP4 172.21.137.44\r\n"
+  "m=audio 49152 RTP/AVP 8 0\r\n"
+  "c=IN IP4 172.21.137.44\r\n"
+  "m=message 0 MSRP/TCP *\r\n"
+  ;
+
+
+static int test_sanity(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_parser_t *parser;
+
+  BEGIN();
+
+  su_home_check(home); TEST_1(home);
+
+  TEST_1((parser = sdp_parse(home, s3_msg, sizeof(s1_msg), 0)));
+  
+  TEST_1(sdp_sanity_check(parser) == 0);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static sdp_list_t const l0[1] = {{ sizeof(l0), NULL, "foo" }};
+static sdp_list_t const l1[1] = {{ sizeof(l1), (sdp_list_t *)l0, "bar" }};
+
+/** Test list things */
+int test_list(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_list_t *l;
+
+  BEGIN();
+
+  su_home_check(home);
+
+  TEST_1(home);
+
+  TEST_1((l = sdp_list_dup(home, l0)));
+  TEST_P(l->l_next, NULL);
+  TEST_S(l->l_text, "foo");
+
+  TEST_1((l = sdp_list_dup(home, l1)));
+  TEST_1(l->l_next != NULL);
+  TEST_1(l->l_next->l_next == NULL);
+  TEST_S(l->l_text, "bar");
+  TEST_S(l->l_next->l_text, "foo");
+
+  su_home_check(home);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static
+sdp_rtpmap_t const rm0[1] = 
+  {{ 
+      sizeof(rm0), NULL, "AMR", 8000, "1",
+      "mode-set=4,5,6 interleaving crc use-redundancy=1",
+      0, 96, 0
+  }};
+
+static
+sdp_rtpmap_t const rm1[1] = 
+  {{ 
+      sizeof(rm1), (sdp_rtpmap_t *)rm0, "PCMA", 8000, "1",
+      NULL,
+      1, 8, 0,
+  }};
+
+/** Test rtpmap-related things */
+int test_rtpmap(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_rtpmap_t *rm;
+
+  BEGIN();
+
+  su_home_check(home);
+
+  TEST_1(home);
+
+  TEST_1((rm = sdp_rtpmap_dup(home, rm0)));
+  TEST_P(rm->rm_next, NULL);
+  TEST_S(rm->rm_encoding, "AMR");
+  TEST_S(rm->rm_params, "1");
+  TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_fmtp, "mode-set=4,5,6 interleaving crc use-redundancy=1");
+
+  TEST_1((rm = sdp_rtpmap_dup(home, rm1)));
+  TEST_1(rm->rm_next != NULL);
+  TEST_1(rm->rm_next->rm_next == NULL);
+  TEST_S(rm->rm_encoding, "PCMA");
+  TEST_S(rm->rm_params, "1");
+  TEST(rm->rm_pt, 8);
+
+  su_home_check(home);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static sdp_attribute_t const a0[1] =
+  {{ sizeof(a0), NULL, "foo", "2"}};
+static sdp_attribute_t const a1[1] = 
+  {{ sizeof(a1), (sdp_attribute_t *)a0, "bar", "1" }};
+
+static int test_attribute(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_attribute_t *a, *a_new, *list, *replaced;
+
+  BEGIN();
+
+  su_home_check(home);
+
+  TEST_1(home);
+
+  TEST_1((a = sdp_attribute_dup(home, a0)));
+  TEST_P(a->a_next, NULL);
+  TEST_S(a->a_name, "foo");
+  TEST_S(a->a_value, "2");
+
+  strcpy((char *)a->a_name, "FOO");
+  TEST_S(a0->a_name, "foo");
+
+  strcpy((char *)a->a_value, "X");
+  TEST_S(a0->a_value, "2");
+
+  TEST_1((a = sdp_attribute_dup(home, a1)));
+  TEST_1(a->a_next != NULL);
+  TEST_1(a->a_next->a_next == NULL);
+  TEST_S(a->a_name, "bar");
+  TEST_S(a->a_value, "1");
+  TEST_S(a->a_next->a_name, "foo");
+  TEST_S(a->a_next->a_value, "2");
+
+  list = a;
+
+  TEST_P(sdp_attribute_remove(&list, NULL), NULL);
+  TEST_P(sdp_attribute_remove(&list, "kuik"), NULL);
+  TEST_P(sdp_attribute_remove(&list, "barf"), NULL);
+  TEST_P(sdp_attribute_remove(&list, "bar"), a);
+  TEST_1(a_new = sdp_attribute_dup(home, a));
+  replaced = (void *)-1;
+  TEST(sdp_attribute_replace(&list, NULL, &replaced), -1);
+  TEST_P(replaced, NULL);
+  TEST(sdp_attribute_replace(&list, a, &replaced), 0); 
+  TEST_P(replaced, NULL);
+  TEST(sdp_attribute_replace(&list, a_new, &replaced), 1); 
+  TEST_P(replaced, a);
+
+  TEST_VOID(sdp_attribute_append(&list, a)); 
+
+  TEST_P(sdp_attribute_remove(&list, "bAr"), a_new);
+  TEST_P(sdp_attribute_remove(&list, "BAR"), a);
+  TEST_P(sdp_attribute_remove(&list, "bar"), NULL);
+
+  su_home_check(home);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static int test_connection(void)
+{
+  BEGIN();
+  END();
+}
+
+static char const media_msg[] = 
+"v=0\n"
+"s=/sdp_torture\n"
+"o=sdp_torture 0 0 IN IP4 1.2.3.4\n"
+"c=IN IP4 1.2.3.4\n"
+"m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+"a=rtpmap:96 X-AMR-WB/16000\n"
+"a=rtpmap:97 X-AMR/8000\n"
+"a=rtpmap:98 GSM-EFR/8000\n"
+"a=rtpmap:10 L16/16000\n"
+"a=rtpmap:99 G723/8000\n"
+"a=rtpmap:8 PCMA/8000\n"
+"a=rtpmap:0 PCMU/8000\n"
+"m=video 0 RTP/AVP 31\n"
+"c=IN IP4 2.3.4.5\n";
+
+static sdp_media_t const m0[1] =
+  {{ sizeof(m0), 
+     NULL, 
+     NULL,
+     sdp_media_audio,
+     NULL, 
+     1234, 
+     5, 
+     sdp_proto_udp,
+     "udp",
+  }};
+
+static int test_media(void)
+{
+  su_home_t *home = su_home_create();
+  sdp_media_t *media;
+  sdp_session_t *sdp;
+  sdp_parser_t *parser;
+
+  BEGIN();
+
+  su_home_check(home);
+  TEST_1(home);
+
+  TEST_1((parser = sdp_parse(home, media_msg, sizeof(media_msg), 0)));
+  TEST_1((sdp = sdp_session(parser)));
+  TEST_1((media = sdp_media_dup(home, m0, sdp)));
+  /* Check comparing */
+  TEST(sdp_media_cmp(media, m0), 0);
+
+  TEST(media->m_type, sdp_media_audio);
+  TEST(media->m_port, 1234);
+  TEST(media->m_number_of_ports, 5);
+  TEST_P(media->m_session, sdp);
+  /* FIXME: add more tests */
+
+  media->m_next = (sdp_media_t *)m0;
+  TEST_1((media = sdp_media_dup_all(home, media, sdp)));
+  TEST_P(media->m_connections, NULL);
+  TEST_1(media->m_next);
+  TEST_P(media->m_next->m_connections, NULL);
+  TEST_P(sdp_media_connections(media), sdp->sdp_connection);
+  TEST_P(sdp_media_connections(media->m_next), sdp->sdp_connection);
+
+  sdp_parser_free(parser);
+
+  su_home_check(home);
+  su_home_unref(home);
+
+  END();
+}
+
+static int test_origin(void)
+{
+  BEGIN();
+  END();
+}
+
+static int test_bandwidth(void)
+{
+  BEGIN();
+  END();
+}
+
+static char const t_msg[] =
+"v=0\n"
+"s=/sdp_torture\n"
+"o=sdp_torture 1 1 IN IP4 1.2.3.4\n"
+"c=IN IP4 1.2.3.4\n"
+"t=3309789956 3309793556\n"
+"t=3309789956 3309793557\n"
+"t=3309789955 3309793557\n"
+"r=604800 3600 0 90000\n"
+"z=2882844526 -1h 2898848070 0\n"
+"t=3309789955 3309793557\n"
+"r=604800 3600 0 90000\n"
+"z=2882844526 -1h 2898848070 0\n"
+  ;
+
+static int test_time(void)
+{
+  sdp_parser_t *parser;
+  sdp_session_t *sdp;
+  sdp_time_t *t, t1[1], t2[1];
+
+  BEGIN();
+
+  TEST_1((parser = sdp_parse(NULL, t_msg, sizeof(t_msg), 0)));
+  TEST_1((sdp = sdp_session(parser)));
+  TEST_1((t = sdp->sdp_time)); *t1 = *t; t1->t_next = NULL; *t2 = *t1;
+  TEST_1(sdp_time_cmp(t1, t1) == 0);
+  TEST_1(sdp_time_cmp(t1, t2) == 0);
+  TEST_1(sdp_time_cmp(t2, t1) == 0);
+  TEST_1((t = t->t_next)); *t1 = *t; t1->t_next = NULL; 
+  TEST_1(sdp_time_cmp(t1, t2) > 0);
+  TEST_1(sdp_time_cmp(t2, t1) < 0);
+  TEST_1((t = t->t_next)); *t2 = *t; t2->t_next = NULL; 
+  TEST_1(t2->t_zone); TEST_1(t2->t_repeat);
+  TEST_1(sdp_time_cmp(t2, t2) == 0);
+  TEST_1(sdp_time_cmp(t1, t2) > 0);
+  TEST_1(sdp_time_cmp(t2, t1) < 0);
+  TEST_1((t = t->t_next)); *t1 = *t; t1->t_next = NULL; 
+  TEST_1(t1->t_zone); TEST_1(t1->t_repeat);
+  TEST_1(sdp_time_cmp(t1, t1) == 0);
+  TEST_1(sdp_time_cmp(t2, t2) == 0);
+  TEST_1(sdp_time_cmp(t1, t2) == 0);
+  
+  sdp_parser_free(parser);
+
+  END();
+}
+
+static int test_key(void)
+{
+  BEGIN();
+  END();
+}
+
+#include <time.h>
+#include <stdlib.h>
+
+static int test_build(void)
+{
+  sdp_session_t *sdp, *dup;
+  sdp_origin_t *o;
+  sdp_time_t *t;
+  sdp_connection_t *c;
+  sdp_media_t *m, *m1;
+  sdp_rtpmap_t *rm;
+  sdp_list_t *l, *l1;
+  sdp_attribute_t *a;
+  su_home_t *home;
+  sdp_printer_t *printer;
+  char const *data;
+
+  BEGIN();
+
+  srand(time(NULL));
+
+  TEST_1(home = su_home_create());
+
+  /* 
+   * Allocate an SDP structure using su_salloc().
+   * su_salloc() puts memory area size to the beginning of structure 
+   * and zeroes rest of the structure.
+   */
+  TEST_1(sdp = su_salloc(home, sizeof(*sdp)));
+  TEST_1(o = su_salloc(home, sizeof(*o)));
+  TEST_1(t = su_salloc(home, sizeof(*t)));
+  TEST_1(c = su_salloc(home, sizeof(*c)));
+  TEST_1(m = su_salloc(home, sizeof(*m)));
+  TEST_1(rm = su_salloc(home, sizeof(*rm)));
+
+  sdp->sdp_origin = o;
+  sdp->sdp_time = t;		/* zero time is fine for SIP */
+  sdp->sdp_connection = c;
+  sdp->sdp_media = m;
+
+  o->o_username = "test";
+  o->o_id = rand();
+  o->o_version = 1;
+  o->o_address = c;
+  
+  c->c_nettype = sdp_net_in;
+  c->c_addrtype = sdp_addr_ip4;
+  c->c_address = "172.21.40.40";
+
+  m->m_session = sdp;
+  m->m_type = sdp_media_audio; m->m_type_name = "audio";
+  m->m_port = 5004;
+  m->m_proto = sdp_proto_rtp; m->m_proto_name = "RTP/AVP";
+  m->m_rtpmaps = rm;
+  
+  rm->rm_predef = 1;
+  rm->rm_pt = 8;
+  rm->rm_encoding = "PCMA"; 
+  rm->rm_rate = 8000;
+
+  TEST_1(m1 = su_salloc(home, sizeof(*m1)));
+  TEST_1(l = su_salloc(home, sizeof(*l)));
+  TEST_1(l1 = su_salloc(home, sizeof(*l1)));
+  TEST_1(a = su_salloc(home, sizeof(*a)));
+
+  m->m_next = m1;
+
+  m1->m_session = sdp;
+  m1->m_type = sdp_media_message; m->m_type_name = "message";
+  m1->m_port = 5060;
+  m1->m_proto = sdp_proto_tcp; m->m_proto_name = "TCP";
+  m1->m_format = l;
+  m1->m_attributes = a;
+
+  l->l_text = "sip";
+
+  l->l_next = l1;
+  l1->l_text = "cpim";
+
+  a->a_name = "user";
+  a->a_value = "chat-81273845";
+
+  TEST_1(dup = sdp_session_dup(home, sdp));
+
+  TEST_1(printer = sdp_print(home, dup, NULL, 0, 0));
+  TEST_1(data = sdp_message(printer));
+
+  if (tstflags & tst_verbatim)
+    printf("sdp_torture.c: built SDP message:\"%s\".\n", data);
+
+  sdp_printer_free(printer);
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  null = fopen("/dev/null", "ab");
+
+  retval |= test_error(); fflush(stdout);
+  retval |= test_session(); fflush(stdout);
+  retval |= test_session2(); fflush(stdout);
+  retval |= test_sanity(); fflush(stdout);
+  retval |= test_list(); fflush(stdout);
+  retval |= test_rtpmap(); fflush(stdout);
+  retval |= test_origin(); fflush(stdout);
+  retval |= test_connection(); fflush(stdout);
+  retval |= test_bandwidth(); fflush(stdout);
+  retval |= test_time(); fflush(stdout);
+  retval |= test_key(); fflush(stdout);
+  retval |= test_attribute(); fflush(stdout);
+  retval |= test_media(); fflush(stdout);
+  retval |= test_build(); fflush(stdout);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,152 @@
+Description of Adding a SIP Header to Sofia SIP
+===============================================
+
+by Pekka Pessi (2002-08-16, updated 2006-10-03)
+
+There are three ways to extend the Sofia SIP parser, including a standard
+header in sip_t structure, including a standard header in extra headers or
+putting the extension headers into a separate library.
+
+Probalem with extending #sip_t is that it breaks binary compatibility.
+
+In the text below, we use "Example" header as our example with following
+ABNF:
+
+   sip-example = "Example" COLON 1*DIGIT
+
+
+IF YOUR HEADER IS A STANDARD ONE
+--------------------------------
+
+  * In <sip.h>, add:
+
+  - Add typedef to the header structure.
+
+    The typedefs to ordinary headers are in more or less alphabetic
+    order after typedef of sip_unknown_t. You should add a typedef line
+    like this:
+
+     typedef struct sip_example_s sip_example_t;
+	
+    Note that the typedefs are documented together with the
+    implementation in the .c file.
+
+  - Add field to the sip_t structure (struct sip_s)
+    - Remember to add a comment containing the header name
+      after field for benefit of the AWK script autmatically generating
+      boilerplate functions and macros:
+      sip_example_t *sip_example; /**< Example */
+    - The AWK script msg_parser.awk automatically creates the default
+      prototypes and tags for the newly created header when the entry in
+      sip_t structure is formatted like to the example above. 
+      It will complain about mismatches between header name and field name.
+
+  * Add the actual header structure:
+
+    The header structure would look like below. The first field MUST be a
+    sip_common_t structure, second field MUST be a pointer to next header
+    with same name. As a convention, if there can be only one header field
+    of this kind, the type of the "next" pointer is sip_error_t.
+
+    The fields representing the header value are located after the mandatory
+    fields, usually in the order they are present in the header contents. In
+    this case, the Example header consist of a 32-bit integer:
+
+       /**@ingroup sip_example
+        * @brief Structure for Example header.
+        */
+       struct sip_example_s {
+         sip_common_t   ex_common[1];	    /**< Common fragment info. */
+         sip_error_t   *ex_next;	    /**< Link to next (dummy). */
+         unsigned long  ex_value;	    /**< Value of example. */
+       };
+
+  * Write parsing tests for your new headers in torture_sip.c:
+
+    Add all relevant parsing/processing cases you can think of
+    at the end of function sip_header_test() or add a testing
+    function of your own.
+
+  * Add implementation in a suitable ".c" file
+    - For an simple example, see implementation of Date header in sip_basic.c
+    - Add a documentation group with @defgroup
+    - Document the typedef
+    - Add header class structure
+    - Add parsing and printing functions:
+      + sip_example_d(), sip_example_e()
+    - Add functions used when copying the header structure:
+      + sip_example_dup_xtra(), sip_example_dup_one()
+
+  * If you added a .c file, add to the Makefile.am
+    - remember to run autogen.sh unless you have given --enable-maintainer-mode 
+      to configure script
+
+  * Run "make check" after you are ready 
+
+  * Run "make check" after you are ready. Really.
+
+
+IF YOUR HEADERS ARE NON-STANDARD
+--------------------------------
+
+    - There is an example package sofia-sip-2543.tar.gz, available from
+      sofia-sip.sourceforge.net
+
+      See the extension package for 1) 
+
+    - Create a header template for your header just like 
+      sofia-sip/rfc2543.h.in (found in <sofia-sip/rfc2543.h> package), 
+      e.g, sip_example.h.in:
+
+---8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<---
+/**@file sip_example.h.in
+ *
+ * Template for <sip_example.h>.
+ */
+
+#ifndef SIP_EXAMPLE_H 
+/** Defined when <sip_example.h> has been included. */
+#define SIP_EXAMPLE_H 
+
+/**@file sip_example.h 
+*
+ * @brief Example header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+/**@ingroup sip_example
+ * @brief Structure for @b Example header.
+ */
+struct sip_example_s
+{
+  sip_common_t   ex_common[1];    /**< Common fragment info */
+  sip_error_t   *ex_next;	  /**< Link to next (dummy). */
+  uint32_t       ex_value;	  /**< Value of Example */
+};
+
+typedef struct sip_example_s sip_example_t;
+
+struct sip_example_dummy_structure {
+  /* === Headers start here */
+  sip_example_t *sip_example;                            /**< Example */
+  /* === Headers end here */
+};
+
+
+#endif /** !defined(SIP_EXAMPLE_H) */
+--->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,58 @@
+2006-01-25  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Doxyfile (INPUT): Missing sip_dll.c broke refdoc 
+	build. Now changed so that individual are not listed 
+	anymore in INPUT.
+
+2006-01-10  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Doxyfile: References to removed files sip_internal.h
+	and sip_extensions.h caused fatal doxygen error.
+
+2005-10-21  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * sip_contact_create_from_via_with_transport() now converts tport name to lcase.
+
+    M ./libsofia-sip-ua/sip/sip_util.c -10 +25
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Contact generated by nta now contains URL transport parameter.
+  The transport=UDP was left out from contact URL always. Now it is left out
+  only if both UDP and TCP are supported.
+  Added utility function sip_contact_create_from_via_with_transport().
+
+    M ./libsofia-sip-ua/nta/nta.c -2 +14
+    M ./libsofia-sip-ua/sip/sip_util.c -10 +28
+    M ./libsofia-sip-ua/sip/sip_util.h +6
+
+2005-08-01  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Makefile.am: Added sip_bad_mask.
+
+	* sip_mime.c: Fixed sip_accept_encoding_d() and
+	sip_accept_language_d() to accept empty list.
+
+	* sip_util.c: sip_header_as_string() can now return an empty
+	string, too.
+
+	* sip.h: Putting Proxy-Require in the beginning of hte message.
+
+	* torture_sip.c: Added tests for privacy.
+
+	* sip_security.c: Added error checking in Privacy: accept
+	commas-separated list, too.
+
+	* sip_parser.h: Added header classification masks.
+
+	* sip_mime.c: Using apndlist format for various Accept headers.
+
+	* sip_feature.c: Using msg_commalist_d() to decode Allow, Require,
+	Proxy-Require, Supported, and Unsupported.
+
+	* sip_basic.c: Not encoding comment in Contact. Always using
+	name-addr form for Route headers.
+ 
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+PROJECT_NAME         = "sip"
+OUTPUT_DIRECTORY     = ../docs/html/sip
+
+INPUT 		     = sofia-sip sip.docs sip_parser.docs .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += \
+	../docs/su.doxytags=../su \
+	../docs/ipt.doxytags=../ipt \
+	../docs/bnf.doxytags=../bnf \
+	../docs/url.doxytags=../url \
+	../docs/msg.doxytags=../msg \
+	../docs/sdp.doxytags=../sdp \
+	../docs/iptsec.doxytags=../iptsec \
+	../docs/nta.doxytags=../nta \
+	../docs/nua.doxytags=../nua
+
+GENERATE_TAGFILE    = ../docs/sip.doxytags
+
+ALIASES += \
+	"SIP_TAG=@ingroup sip_tag\n" \
+	"SIP_HEADER=@ingroup sip_headers\n at defgroup" \
+        "SIP_PARSER=\n"
+
+ at INCLUDE = sip.doxyaliases
+
+IMAGE_PATH           += images

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,537 @@
+/* SIP grammar from RFC3261
+ * 
+ *    alphanum  =  ALPHA / DIGIT
+ * 
+ *    reserved    =  ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+"
+ *                   / "$" / ","
+ *    unreserved  =  alphanum / mark
+ *    mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
+ *                   / "(" / ")"
+ *    escaped     =  "%" HEXDIG HEXDIG
+ * 
+ *    LWS  =  [*WSP CRLF] 1*WSP ; linear whitespace
+ *    SWS  =  [LWS] ; sep whitespace
+ * 
+ *    HCOLON  =  *( SP / HTAB ) ":" SWS
+ * 
+ *    TEXT-UTF8-TRIM  =  1*TEXT-UTF8char *(*LWS TEXT-UTF8char)
+ *    TEXT-UTF8char   =  %x21-7E / UTF8-NONASCII
+ *    UTF8-NONASCII   =  %xC0-DF 1UTF8-CONT
+ *                    /  %xE0-EF 2UTF8-CONT
+ *                    /  %xF0-F7 3UTF8-CONT
+ *                    /  %xF8-Fb 4UTF8-CONT
+ *                    /  %xFC-FD 5UTF8-CONT
+ *    UTF8-CONT       =  %x80-BF
+ * 
+ *    LHEX  =  DIGIT / %x61-66 ;lowercase a-f
+ * 
+ *    token       =  1*(alphanum / "-" / "." / "!" / "%" / "*"
+ *                   / "_" / "+" / "`" / "'" / "~" )
+ *    separators  =  "(" / ")" / "<" / ">" / "@" /
+ *                   "," / ";" / ":" / "\" / DQUOTE /
+ *                   "/" / "[" / "]" / "?" / "=" /
+ *                   "{" / "}" / SP / HTAB
+ *    word        =  1*(alphanum / "-" / "." / "!" / "%" / "*" /
+ *                   "_" / "+" / "`" / "'" / "~" /
+ *                   "(" / ")" / "<" / ">" /
+ *                   ":" / "\" / DQUOTE /
+ *                   "/" / "[" / "]" / "?" /
+ *                   "{" / "}" )
+ * 
+ *    STAR    =  SWS "*" SWS ; asterisk
+ *    SLASH   =  SWS "/" SWS ; slash
+ *    EQUAL   =  SWS "=" SWS ; equal
+ *    LPAREN  =  SWS "(" SWS ; left parenthesis
+ *    RPAREN  =  SWS ")" SWS ; right parenthesis
+ *    RAQUOT  =  ">" SWS ; right angle quote
+ *    LAQUOT  =  SWS "<"; left angle quote
+ *    COMMA   =  SWS "," SWS ; comma
+ *    SEMI    =  SWS ";" SWS ; semicolon
+ *    COLON   =  SWS ":" SWS ; colon
+ *    LDQUOT  =  SWS DQUOTE; open double quotation mark
+ *    RDQUOT  =  DQUOTE SWS ; close double quotation mark
+ * 
+ *    comment  =  LPAREN *(ctext / quoted-pair / comment) RPAREN
+ *    ctext    =  %x21-27 / %x2A-5B / %x5D-7E / UTF8-NONASCII
+ *                / LWS
+ * 
+ *    quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
+ *    qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
+ *                      / UTF8-NONASCII
+ * 
+ *    quoted-pair  =  "\" (%x00-09 / %x0B-0C
+ *                    / %x0E-7F)
+ * 
+ *    SIP-URI          =  "sip:" [ userinfo ] hostport
+ *                        uri-parameters [ headers ]
+ *    SIPS-URI         =  "sips:" [ userinfo ] hostport
+ *                        uri-parameters [ headers ]
+ *    userinfo         =  ( user / telephone-subscriber ) [ ":" password ] "@"
+ *    user             =  1*( unreserved / escaped / user-unreserved )
+ *    user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
+ *    password         =  *( unreserved / escaped /
+ *                        "&" / "=" / "+" / "$" / "," )
+ *    hostport         =  host [ ":" port ]
+ *    host             =  hostname / IPv4address / IPv6reference
+ *    hostname         =  *( domainlabel "." ) toplabel [ "." ]
+ *    domainlabel      =  alphanum
+ *                        / alphanum *( alphanum / "-" ) alphanum
+ *    toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ *    IPv4address    =  1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
+ *    IPv6reference  =  "[" IPv6address "]"
+ *    IPv6address    =  hexpart [ ":" IPv4address ]
+ *    hexpart        =  hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+ *    hexseq         =  hex4 *( ":" hex4)
+ *    hex4           =  1*4HEXDIG
+ *    port           =  1*DIGIT
+ * 
+ *    uri-parameters    =  *( ";" uri-parameter)
+ *    uri-parameter     =  transport-param / user-param / method-param
+ *                         / ttl-param / maddr-param / lr-param / other-param
+ *    transport-param   =  "transport="
+ *                         ( "udp" / "tcp" / "sctp" / "tls"
+ *                         / other-transport)
+ *    other-transport   =  token
+ *    user-param        =  "user=" ( "phone" / "ip" / other-user)
+ *    other-user        =  token
+ *    method-param      =  "method=" Method
+ *    ttl-param         =  "ttl=" ttl
+ *    maddr-param       =  "maddr=" host
+ *    lr-param          =  "lr"
+ *    other-param       =  pname [ "=" pvalue ]
+ *    pname             =  1*paramchar
+ *    pvalue            =  1*paramchar
+ *    paramchar         =  param-unreserved / unreserved / escaped
+ *    param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
+ * 
+ *    headers         =  "?" header *( "&" header )
+ *    header          =  hname "=" hvalue
+ *    hname           =  1*( hnv-unreserved / unreserved / escaped )
+ *    hvalue          =  *( hnv-unreserved / unreserved / escaped )
+ *    hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
+ * 
+ *    SIP-message    =  Request / Response
+ *    Request        =  Request-Line
+ *                      *( message-header )
+ *                      CRLF
+ *                      [ message-body ]
+ *    Request-Line   =  Method SP Request-URI SP SIP-Version CRLF
+ *    Request-URI    =  SIP-URI / SIPS-URI / absoluteURI
+ *    absoluteURI    =  scheme ":" ( hier-part / opaque-part )
+ *    hier-part      =  ( net-path / abs-path ) [ "?" query ]
+ *    net-path       =  "//" authority [ abs-path ]
+ *    abs-path       =  "/" path-segments
+ *    opaque-part    =  uric-no-slash *uric
+ *    uric           =  reserved / unreserved / escaped
+ *    uric-no-slash  =  unreserved / escaped / ";" / "?" / ":" / "@"
+ *                      / "&" / "=" / "+" / "$" / ","
+ *    path-segments  =  segment *( "/" segment )
+ *    segment        =  *pchar *( ";" param )
+ *    param          =  *pchar
+ *    pchar          =  unreserved / escaped /
+ *                      ":" / "@" / "&" / "=" / "+" / "$" / ","
+ *    scheme         =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ *    authority      =  srvr / reg-name
+ *    srvr           =  [ [ userinfo "@" ] hostport ]
+ *    reg-name       =  1*( unreserved / escaped / "$" / ","
+ *                      / ";" / ":" / "@" / "&" / "=" / "+" )
+ *    query          =  *uric
+ *    SIP-Version    =  "SIP" "/" 1*DIGIT "." 1*DIGIT
+ * 
+ *    message-header  =  (Accept
+ *                    /  Accept-Encoding
+ *                    /  Accept-Language
+ *                    /  Alert-Info
+ *                    /  Allow
+ *                    /  Authentication-Info
+ *                    /  Authorization
+ *                    /  Call-ID
+ *                    /  Call-Info
+ *                    /  Contact
+ *                    /  Content-Disposition
+ *                    /  Content-Encoding
+ *                    /  Content-Language
+ *                    /  Content-Length
+ *                    /  Content-Type
+ *                    /  CSeq
+ *                    /  Date
+ *                    /  Error-Info
+ *                    /  Expires
+ *                    /  From
+ *                    /  In-Reply-To
+ *                    /  Max-Forwards
+ *                    /  MIME-Version
+ *                    /  Min-Expires
+ *                    /  Organization
+ *                    /  Priority
+ *                    /  Proxy-Authenticate
+ *                    /  Proxy-Authorization
+ *                    /  Proxy-Require
+ *                    /  Record-Route
+ *                    /  Reply-To
+ *                    /  Require
+ *                    /  Retry-After
+ *                    /  Route
+ *                    /  Server
+ *                    /  Subject
+ *                    /  Supported
+ *                    /  Timestamp
+ *                    /  To
+ *                    /  Unsupported
+ *                    /  User-Agent
+ *                    /  Via
+ *                    /  Warning
+ *                    /  WWW-Authenticate
+ *                    /  extension-header) CRLF
+ * 
+ *    INVITEm           =  %x49.4E.56.49.54.45 ; INVITE in caps
+ *    ACKm              =  %x41.43.4B ; ACK in caps
+ *    OPTIONSm          =  %x4F.50.54.49.4F.4E.53 ; OPTIONS in caps
+ *    BYEm              =  %x42.59.45 ; BYE in caps
+ *    CANCELm           =  %x43.41.4E.43.45.4C ; CANCEL in caps
+ *    REGISTERm         =  %x52.45.47.49.53.54.45.52 ; REGISTER in caps
+ *    Method            =  INVITEm / ACKm / OPTIONSm / BYEm
+ *                         / CANCELm / REGISTERm
+ *                         / extension-method
+ *    extension-method  =  token
+ *    Response          =  Status-Line
+ *                         *( message-header )
+ *                         CRLF
+ *                         [ message-body ]
+ * 
+ *    Status-Line     =  SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ *    Status-Code     =  Informational
+ *                   /   Redirection
+ *                   /   Success
+ *                   /   Client-Error
+ *                   /   Server-Error
+ *                   /   Global-Failure
+ *                   /   extension-code
+ *    extension-code  =  3DIGIT
+ *    Reason-Phrase   =  *(reserved / unreserved / escaped
+ *                       / UTF8-NONASCII / UTF8-CONT / SP / HTAB)
+ * 
+ *    Informational  =  "100"  ;  Trying
+ *                  /   "180"  ;  Ringing
+ *                  /   "181"  ;  Call Is Being Forwarded
+ *                  /   "182"  ;  Queued
+ *                  /   "183"  ;  Session Progress
+ * 
+ *    Success  =  "200"  ;  OK
+ * 
+ *    Redirection  =  "300"  ;  Multiple Choices
+ *                /   "301"  ;  Moved Permanently
+ *                /   "302"  ;  Moved Temporarily
+ *                /   "305"  ;  Use Proxy
+ *                /   "380"  ;  Alternative Service
+ * 
+ *    Client-Error  =  "400"  ;  Bad Request
+ *                 /   "401"  ;  Unauthorized
+ *                 /   "402"  ;  Payment Required
+ *                 /   "403"  ;  Forbidden
+ *                 /   "404"  ;  Not Found
+ *                 /   "405"  ;  Method Not Allowed
+ *                 /   "406"  ;  Not Acceptable
+ *                 /   "407"  ;  Proxy Authentication Required
+ *                 /   "408"  ;  Request Timeout
+ *                 /   "410"  ;  Gone
+ *                 /   "413"  ;  Request Entity Too Large
+ *                 /   "414"  ;  Request-URI Too Large
+ *                 /   "415"  ;  Unsupported Media Type
+ *                 /   "416"  ;  Unsupported URI Scheme
+ *                 /   "420"  ;  Bad Extension
+ *                 /   "421"  ;  Extension Required
+ *                 /   "423"  ;  Interval Too Brief
+ *                 /   "480"  ;  Temporarily not available
+ *                 /   "481"  ;  Call Leg/Transaction Does Not Exist
+ *                 /   "482"  ;  Loop Detected
+ *                 /   "483"  ;  Too Many Hops
+ *                 /   "484"  ;  Address Incomplete
+ *                 /   "485"  ;  Ambiguous
+ *                 /   "486"  ;  Busy Here
+ *                 /   "487"  ;  Request Terminated
+ *                 /   "488"  ;  Not Acceptable Here
+ *                 /   "491"  ;  Request Pending
+ *                 /   "493"  ;  Undecipherable
+ * 
+ *    Server-Error  =  "500"  ;  Internal Server Error
+ *                 /   "501"  ;  Not Implemented
+ *                 /   "502"  ;  Bad Gateway
+ *                 /   "503"  ;  Service Unavailable
+ *                 /   "504"  ;  Server Time-out
+ *                 /   "505"  ;  SIP Version not supported
+ *                 /   "513"  ;  Message Too Large
+ * 
+ *    Global-Failure  =  "600"  ;  Busy Everywhere
+ *                   /   "603"  ;  Decline
+ *                   /   "604"  ;  Does not exist anywhere
+ *                   /   "606"  ;  Not Acceptable
+ * 
+ *    Accept         =  "Accept" HCOLON
+ *                       [ accept-range *(COMMA accept-range) ]
+ *    accept-range   =  media-range *(SEMI accept-param)
+ *    ; Why not SLASH ? //PPe
+ *    media-range    =  ( "*" "/" "*"
+ *                      / ( m-type SLASH "*" )
+ *                      / ( m-type SLASH m-subtype )
+ *                      ) *( SEMI m-parameter )
+ *    accept-param   =  ("q" EQUAL qvalue) / generic-param
+ *    qvalue         =  ( "0" [ "." 0*3DIGIT ] )
+ *                      / ( "1" [ "." 0*3("0") ] )
+ *    generic-param  =  token [ EQUAL gen-value ]
+ *    gen-value      =  token / host / quoted-string
+ * 
+ *    Accept-Encoding  =  "Accept-Encoding" HCOLON
+ *                         [ encoding *(COMMA encoding) ]
+ *    encoding         =  codings *(SEMI accept-param)
+ *    codings          =  content-coding / "*"
+ *    content-coding   =  token
+ * 
+ *    Accept-Language  =  "Accept-Language" HCOLON
+ *                         [ language *(COMMA language) ]
+ *    language         =  language-range *(SEMI accept-param)
+ *    language-range   =  ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
+ * 
+ *    Alert-Info   =  "Alert-Info" HCOLON alert-param *(COMMA alert-param)
+ *    alert-param  =  LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ * 
+ *    Allow  =  "Allow" HCOLON [Method *(COMMA Method)]
+ * 
+ *    Authorization     =  "Authorization" HCOLON credentials
+ *    credentials       =  ("Digest" LWS digest-response)
+ *                         / other-response
+ *    digest-response   =  dig-resp *(COMMA dig-resp)
+ *    dig-resp          =  username / realm / nonce / digest-uri
+ *                          / dresponse / algorithm / cnonce
+ *                          / opaque / message-qop
+ *                          / nonce-count / auth-param
+ *    username          =  "username" EQUAL username-value
+ *    username-value    =  quoted-string
+ *    digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
+ *    digest-uri-value  =  rquest-uri ; Equal to request-uri as specified
+ *                         by HTTP/1.1
+ *    message-qop       =  "qop" EQUAL qop-value
+ *    cnonce            =  "cnonce" EQUAL cnonce-value
+ *    cnonce-value      =  nonce-value
+ *    nonce-count       =  "nc" EQUAL nc-value
+ *    nc-value          =  8LHEX
+ *    dresponse         =  "response" EQUAL request-digest
+ *    request-digest    =  LDQUOT 32LHEX RDQUOT
+ *    auth-param        =  auth-param-name EQUAL
+ *                         ( token / quoted-string )
+ *    auth-param-name   =  token
+ *    other-response    =  auth-scheme LWS auth-param
+ *                         *(COMMA auth-param)
+ *    auth-scheme       =  token
+ * 
+ *    Authentication-Info  =  "Authentication-Info" HCOLON ainfo
+ *                            *(COMMA ainfo)
+ *    ainfo                =  nextnonce / message-qop
+ *                             / response-auth / cnonce
+ *                             / nonce-count
+ *    nextnonce            =  "nextnonce" EQUAL nonce-value
+ *    response-auth        =  "rspauth" EQUAL response-digest
+ *    response-digest      =  LDQUOT *LHEX RDQUOT
+ * 
+ *    Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
+ *    callid   =  word [ "@" word ]
+ * 
+ *    Call-Info   =  "Call-Info" HCOLON info *(COMMA info)
+ *    info        =  LAQUOT absoluteURI RAQUOT *( SEMI info-param)
+ *    info-param  =  ( "purpose" EQUAL ( "icon" / "info"
+ *                   / "card" / token ) ) / generic-param
+ * 
+ *    Contact        =  ("Contact" / "m" ) HCOLON
+ *                      ( STAR / (contact-param *(COMMA contact-param)))
+ *    contact-param  =  (name-addr / addr-spec) *(SEMI contact-params)
+ *    name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
+ *    addr-spec      =  SIP-URI / SIPS-URI / absoluteURI
+ *    display-name   =  *(token LWS)/ quoted-string
+ * 
+ *    contact-params     =  c-p-q / c-p-expires
+ *                          / contact-extension
+ *    c-p-q              =  "q" EQUAL qvalue
+ *    c-p-expires        =  "expires" EQUAL delta-seconds
+ *    contact-extension  =  generic-param
+ *    delta-seconds      =  1*DIGIT
+ * 
+ *    Content-Disposition   =  "Content-Disposition" HCOLON
+ *                             disp-type *( SEMI disp-param )
+ *    disp-type             =  "render" / "session" / "icon" / "alert"
+ *                             / disp-extension-token
+ *    disp-param            =  handling-param / generic-param
+ *    handling-param        =  "handling" EQUAL
+ *                             ( "optional" / "required"
+ *                             / other-handling )
+ *    other-handling        =  token
+ *    disp-extension-token  =  token
+ * 
+ *    Content-Encoding  =  ( "Content-Encoding" / "e" ) HCOLON
+ *                         content-coding *(COMMA content-coding)
+ * 
+ *    Content-Language  =  "Content-Language" HCOLON
+ *                         language-tag *(COMMA language-tag)
+ *    language-tag      =  primary-tag *( "-" subtag )
+ *    primary-tag       =  1*8ALPHA
+ *    subtag            =  1*8ALPHA
+ * 
+ *    Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ *    Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
+ *    media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
+ *    m-type           =  discrete-type / composite-type
+ *    discrete-type    =  "text" / "image" / "audio" / "video"
+ *                        / "application" / extension-token
+ *    composite-type   =  "message" / "multipart" / extension-token
+ *    extension-token  =  ietf-token / x-token
+ *    ietf-token       =  token
+ *    x-token          =  "x-" token
+ *    m-subtype        =  extension-token / iana-token
+ *    iana-token       =  token
+ *    m-parameter      =  m-attribute EQUAL m-value
+ *    m-attribute      =  token
+ *    m-value          =  token / quoted-string
+ * 
+ *    CSeq  =  "CSeq" HCOLON 1*DIGIT LWS Method
+ * 
+ *    Date          =  "Date" HCOLON SIP-date
+ *    SIP-date      =  rfc1123-date
+ *    rfc1123-date  =  wkday "," SP date1 SP time SP "GMT"
+ *    date1         =  2DIGIT SP month SP 4DIGIT
+ *                     ; day month year (e.g., 02 Jun 1982)
+ *    time          =  2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                     ; 00:00:00 - 23:59:59
+ *    wkday         =  "Mon" / "Tue" / "Wed"
+ *                     / "Thu" / "Fri" / "Sat" / "Sun"
+ *    month         =  "Jan" / "Feb" / "Mar" / "Apr"
+ *                     / "May" / "Jun" / "Jul" / "Aug"
+ *                     / "Sep" / "Oct" / "Nov" / "Dec"
+ * 
+ *    Error-Info  =  "Error-Info" HCOLON error-uri *(COMMA error-uri)
+ *    error-uri   =  LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ * 
+ *    Expires     =  "Expires" HCOLON delta-seconds
+ *    From        =  ( "From" / "f" ) HCOLON from-spec
+ *    from-spec   =  ( name-addr / addr-spec )
+ *                   *( SEMI from-param )
+ *    from-param  =  tag-param / generic-param
+ *    tag-param   =  "tag" EQUAL token
+ * 
+ *    In-Reply-To  =  "In-Reply-To" HCOLON callid *(COMMA callid)
+ * 
+ *    Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
+ * 
+ *    MIME-Version  =  "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
+ * 
+ *    Min-Expires  =  "Min-Expires" HCOLON delta-seconds
+ * 
+ *    Organization  =  "Organization" HCOLON [TEXT-UTF8-TRIM]
+ * 
+ *    Priority        =  "Priority" HCOLON priority-value
+ *    priority-value  =  "emergency" / "urgent" / "normal"
+ *                       / "non-urgent" / other-priority
+ *    other-priority  =  token
+ * 
+ *    Proxy-Authenticate  =  "Proxy-Authenticate" HCOLON challenge
+ *    challenge           =  ("Digest" LWS digest-cln *(COMMA digest-cln))
+ *                           / other-challenge
+ *    other-challenge     =  auth-scheme LWS auth-param
+ *                           *(COMMA auth-param)
+ *    digest-cln          =  realm / domain / nonce
+ *                            / opaque / stale / algorithm
+ *                            / qop-options / auth-param
+ *    realm               =  "realm" EQUAL realm-value
+ *    realm-value         =  quoted-string
+ *    domain              =  "domain" EQUAL LDQUOT URI
+ *                           *( 1*SP URI ) RDQUOT
+ *    URI                 =  absoluteURI / abs-path
+ *    nonce               =  "nonce" EQUAL nonce-value
+ *    nonce-value         =  quoted-string
+ *    opaque              =  "opaque" EQUAL quoted-string
+ *    stale               =  "stale" EQUAL ( "true" / "false" )
+ *    algorithm           =  "algorithm" EQUAL ( "MD5" / "MD5-sess"
+ *                           / token )
+ *    qop-options         =  "qop" EQUAL LDQUOT qop-value
+ *                           *("," qop-value) RDQUOT
+ *    qop-value           =  "auth" / "auth-int" / token
+ * 
+ *    Proxy-Authorization  =  "Proxy-Authorization" HCOLON credentials
+ * 
+ *    Proxy-Require  =  "Proxy-Require" HCOLON option-tag
+ *                      *(COMMA option-tag)
+ *    option-tag     =  token
+ * 
+ *    Record-Route  =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
+ *    rec-route     =  name-addr *( SEMI rr-param )
+ *    rr-param      =  generic-param
+ * 
+ *    Reply-To      =  "Reply-To" HCOLON rplyto-spec
+ *    rplyto-spec   =  ( name-addr / addr-spec )
+ *                     *( SEMI rplyto-param )
+ *    rplyto-param  =  generic-param
+ *    Require       =  "Require" HCOLON option-tag *(COMMA option-tag)
+ * 
+ *    Retry-After  =  "Retry-After" HCOLON delta-seconds
+ *                    [ comment ] *( SEMI retry-param )
+ * 
+ *    retry-param  =  ("duration" EQUAL delta-seconds)
+ *                    / generic-param
+ * 
+ *    Route        =  "Route" HCOLON route-param *(COMMA route-param)
+ *    route-param  =  name-addr *( SEMI rr-param )
+ * 
+ *    Server           =  "Server" HCOLON server-val *(LWS server-val)
+ *    server-val       =  product / comment
+ *    product          =  token [SLASH product-version]
+ *    product-version  =  token
+ * 
+ *    Subject  =  ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
+ * 
+ *    Supported  =  ( "Supported" / "k" ) HCOLON
+ *                  [option-tag *(COMMA option-tag)]
+ * 
+ *    Timestamp  =  "Timestamp" HCOLON 1*(DIGIT)
+ *                   [ "." *(DIGIT) ] [ LWS delay ]
+ *    delay      =  *(DIGIT) [ "." *(DIGIT) ]
+ * 
+ *    To        =  ( "To" / "t" ) HCOLON ( name-addr
+ *                 / addr-spec ) *( SEMI to-param )
+ *    to-param  =  tag-param / generic-param
+ * 
+ *    Unsupported  =  "Unsupported" HCOLON option-tag *(COMMA option-tag)
+ *    User-Agent  =  "User-Agent" HCOLON server-val *(LWS server-val)
+ * 
+ *    Via               =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ *    via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
+ *    via-params        =  via-ttl / via-maddr
+ *                         / via-received / via-branch
+ *                         / via-extension
+ *    via-ttl           =  "ttl" EQUAL ttl
+ *    via-maddr         =  "maddr" EQUAL host
+ *    via-received      =  "received" EQUAL (IPv4address / IPv6address)
+ *    via-branch        =  "branch" EQUAL token
+ *    via-extension     =  generic-param
+ *    sent-protocol     =  protocol-name SLASH protocol-version
+ *                         SLASH transport
+ *    protocol-name     =  "SIP" / token
+ *    protocol-version  =  token
+ *    transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
+ *                         / other-transport
+ *    sent-by           =  host [ COLON port ]
+ *    ttl               =  1*3DIGIT ; 0 to 255
+ * 
+ *    Warning        =  "Warning" HCOLON warning-value *(COMMA warning-value)
+ *    warning-value  =  warn-code SP warn-agent SP warn-text
+ *    warn-code      =  3DIGIT
+ *    warn-agent     =  hostport / pseudonym
+ *                      ;  the name or pseudonym of the server adding
+ *                      ;  the Warning header, for use in debugging
+ *    warn-text      =  quoted-string
+ *    pseudonym      =  token
+ * 
+ *    WWW-Authenticate  =  "WWW-Authenticate" HCOLON challenge
+ * 
+ *    extension-header  =  header-name HCOLON header-value
+ *    header-name       =  token
+ *    header-value      =  *(TEXT-UTF8char / UTF8-CONT / LWS)
+ *    message-body  =  *OCTET
+ */
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,154 @@
+#
+# Makefile.am for sip module
+#
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsip.la
+
+check_PROGRAMS =       torture_sip \
+			sip_test_msg validator date_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+GENERATED_H = 		sofia-sip/sip_hclasses.h \
+			sofia-sip/sip_protos.h sofia-sip/sip_tag.h \
+			sofia-sip/sip_extra.h
+H_IN = 			sofia-sip/sip_hclasses.h.in \
+			sofia-sip/sip_protos.h.in sofia-sip/sip_tag.h.in \
+			sofia-sip/sip_extra.h.in
+
+PUBLIC_H = sofia-sip/sip.h sofia-sip/sip_util.h \
+           sofia-sip/sip_header.h sofia-sip/sip_parser.h \
+	   sofia-sip/sip_tag_class.h sofia-sip/sip_status.h
+
+GENERATED_C = sip_tag.c sip_tag_ref.c sip_parser_table.c
+
+BUILT_SOURCES = 	$(GENERATED_H) $(GENERATED_C)
+
+nobase_include_sofia_HEADERS = $(GENERATED_H) $(PUBLIC_H) $(H_IN)
+
+libsip_la_SOURCES = 	$(INTERNAL_H) \
+			sip_parser.c sip_header.c sip_util.c sip_pref_util.c \
+			sip_basic.c sip_extra.c sip_feature.c sip_mime.c \
+			sip_security.c sip_event.c sip_prack.c \
+			sip_refer.c sip_session.c \
+			sip_caller_prefs.c sip_reason.c \
+			sip_status.c sip_time.c \
+			sip_tag_class.c \
+			$(GENERATED_C)
+
+COVERAGE_INPUT = 	$(libsip_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libsip.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../url/liburl.la \
+			../su/libsu.la
+
+torture_sip_LDFLAGS = 	-static
+sip_test_msg_LDFLAGS = 	-static
+date_test_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+# note: srcdir needs to be specified, otherwise
+#       breaks make distcheck target
+
+EXTRA_DIST =		Doxyfile sip.docs sip_parser.docs sip.doxyaliases \
+			ADD-A-HEADER GRAMMAR sip_bad_mask \
+			sip_parser_table.c.in sip_tag.c.in \
+			sip_extra_headers.txt \
+	images/sip-parser.eps images/sip-parser.gif \
+	images/sip-parser2.eps images/sip-parser2.gif \
+	images/sip-parser3.eps images/sip-parser3.gif \
+	images/sip-parser4.eps images/sip-parser4.gif \
+	tests/own0.txt tests/own1.txt tests/own2.txt tests/own3.txt \
+	tests/own4.txt tests/own5.txt tests/own6.txt tests/own8.txt \
+	tests/test1.txt tests/test-ack-1.txt tests/test2.txt tests/test3.txt \
+	tests/test4.txt tests/test5.txt tests/test6.txt tests/test7.txt	     \
+	tests/test8.txt tests/test9.txt tests/test10.txt tests/test10b.txt   \
+	tests/test10c.txt tests/test11.txt tests/test12.txt tests/test13.txt \
+	tests/test14-req.txt tests/test14.txt tests/test15.txt		     \
+	tests/test16.txt tests/test17.txt tests/test18.txt tests/test19.txt  \
+	tests/test1a.txt tests/test20.txt tests/test21.txt tests/test22.txt  \
+	tests/test23.txt tests/test24.txt tests/test25.txt tests/test26.txt  \
+	tests/test27.txt tests/test28.txt tests/test29.txt tests/test30.txt  \
+	tests/test31.txt tests/test32.txt tests/test33.txt tests/test34.txt  \
+	tests/test35.txt tests/test36.txt tests/test37.txt tests/test38.txt  \
+	tests/test39.txt tests/test40.txt tests/test41.txt tests/test42.txt
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_sip run_sip_test_msg run_date_test
+
+dist_noinst_SCRIPTS = 	run_sip_test_msg run_date_test
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+
+AWK_SIP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=sip
+
+#
+# Note: sip_bad_mask is used by nta to weed out bad messages
+#
+sip_parser_table.c: sip_bad_mask
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip_hclasses.h.in
+sofia-sip/sip_protos.h: sofia-sip/sip_protos.h.in
+sofia-sip/sip_tag.h: sofia-sip/sip_tag.h.in
+
+$(GENERATED_H): $(MSG_PARSER_AWK)
+
+sip_parser_table.c: sip_parser_table.c.in $(MSG_PARSER_AWK)
+sip_tag.c: sip_tag.c.in $(MSG_PARSER_AWK)
+
+EXTRA = $(srcdir)/sip_extra_headers.txt
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_hclasses.h.in $<
+
+sofia-sip/sip_protos.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_protos.h.in $<
+
+sofia-sip/sip_tag.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_tag.h.in $<
+
+sip_tag.c: sofia-sip/sip.h sip_extra_headers.txt
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sip_tag.c.in $< $(EXTRA)
+
+sip_parser_table.c: sip_extra_headers.txt
+
+sip_parser_table.c: sofia-sip/sip.h
+	$(AWK_SIP_AWK) PT=$@ TEMPLATE=$(srcdir)/sip_parser_table.c.in \
+		FLAGFILE=$(srcdir)/sip_bad_mask \
+		MC_HASH_SIZE=127 MC_SHORT_SIZE=26 $< $(EXTRA)
+
+sofia-sip/sip_extra.h: sofia-sip/sip_extra.h.in sip_extra_headers.txt
+	@-mkdir -p sofia-sip 2>/dev/null
+	${AWK_SIP_AWK} PR=$@ NO_FIRST=1 NO_LAST=1 \
+		PACKAGE_NAME="${PACKAGE_NAME}" \
+		PACKAGE_VERSION="${PACKAGE_VERSION}" \
+		TEMPLATE1=${srcdir}/sofia-sip/sip_hclasses.h.in \
+		TEMPLATE2=${srcdir}/sofia-sip/sip_protos.h.in \
+		TEMPLATE=$< $(EXTRA)

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,854 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sip module
+#
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsip_la_SOURCES) date_test.c test_sip_msg.c torture_sip.c validator.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = torture_sip$(EXEEXT) test_sip_msg$(EXEEXT) \
+	validator$(EXEEXT) date_test$(EXEEXT)
+DIST_COMMON = $(dist_noinst_SCRIPTS) $(nobase_include_sofia_HEADERS) \
+	$(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sip
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsip_la_LIBADD =
+am__objects_1 = sip_tag.lo sip_tag_ref.lo sip_parser_table.lo
+am_libsip_la_OBJECTS = sip_parser.lo sip_header.lo sip_util.lo \
+	sip_pref_util.lo sip_basic.lo sip_extra.lo sip_feature.lo \
+	sip_mime.lo sip_security.lo sip_event.lo sip_prack.lo \
+	sip_refer.lo sip_session.lo sip_caller_prefs.lo sip_reason.lo \
+	sip_status.lo sip_time.lo sip_tag_class.lo $(am__objects_1)
+libsip_la_OBJECTS = $(am_libsip_la_OBJECTS)
+date_test_SOURCES = date_test.c
+date_test_OBJECTS = date_test.$(OBJEXT)
+date_test_LDADD = $(LDADD)
+date_test_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+	../url/liburl.la ../su/libsu.la
+test_sip_msg_SOURCES = test_sip_msg.c
+test_sip_msg_OBJECTS = test_sip_msg.$(OBJEXT)
+test_sip_msg_LDADD = $(LDADD)
+test_sip_msg_DEPENDENCIES = libsip.la ../msg/libmsg.la \
+	../bnf/libbnf.la ../url/liburl.la ../su/libsu.la
+torture_sip_SOURCES = torture_sip.c
+torture_sip_OBJECTS = torture_sip.$(OBJEXT)
+torture_sip_LDADD = $(LDADD)
+torture_sip_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+	../url/liburl.la ../su/libsu.la
+validator_SOURCES = validator.c
+validator_OBJECTS = validator.$(OBJEXT)
+validator_LDADD = $(LDADD)
+validator_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+	../url/liburl.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsip_la_SOURCES) date_test.c test_sip_msg.c \
+	torture_sip.c validator.c
+DIST_SOURCES = $(libsip_la_SOURCES) date_test.c test_sip_msg.c \
+	torture_sip.c validator.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../msg -I../msg \
+		-I$(srcdir)/../url -I../url \
+		-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsip.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+GENERATED_H = sofia-sip/sip_hclasses.h \
+			sofia-sip/sip_protos.h sofia-sip/sip_tag.h \
+			sofia-sip/sip_extra.h
+
+H_IN = sofia-sip/sip_hclasses.h.in \
+			sofia-sip/sip_protos.h.in sofia-sip/sip_tag.h.in \
+			sofia-sip/sip_extra.h.in
+
+PUBLIC_H = sofia-sip/sip.h sofia-sip/sip_util.h \
+           sofia-sip/sip_header.h sofia-sip/sip_parser.h \
+	   sofia-sip/sip_tag_class.h sofia-sip/sip_status.h
+
+GENERATED_C = sip_tag.c sip_tag_ref.c sip_parser_table.c
+BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C)
+nobase_include_sofia_HEADERS = $(GENERATED_H) $(PUBLIC_H) $(H_IN)
+libsip_la_SOURCES = $(INTERNAL_H) \
+			sip_parser.c sip_header.c sip_util.c sip_pref_util.c \
+			sip_basic.c sip_extra.c sip_feature.c sip_mime.c \
+			sip_security.c sip_event.c sip_prack.c \
+			sip_refer.c sip_session.c \
+			sip_caller_prefs.c sip_reason.c \
+			sip_status.c sip_time.c \
+			sip_tag_class.c \
+			$(GENERATED_C)
+
+COVERAGE_INPUT = $(libsip_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsip.la \
+			../msg/libmsg.la \
+			../bnf/libbnf.la \
+			../url/liburl.la \
+			../su/libsu.la
+
+torture_sip_LDFLAGS = -static
+sip_test_msg_LDFLAGS = -static
+date_test_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+# note: srcdir needs to be specified, otherwise
+#       breaks make distcheck target
+EXTRA_DIST = Doxyfile sip.docs sip_parser.docs sip.doxyaliases \
+			ADD-A-HEADER GRAMMAR sip_bad_mask \
+			sip_parser_table.c.in sip_tag.c.in \
+			sip_extra_headers.txt \
+	images/sip-parser.eps images/sip-parser.gif \
+	images/sip-parser2.eps images/sip-parser2.gif \
+	images/sip-parser3.eps images/sip-parser3.gif \
+	images/sip-parser4.eps images/sip-parser4.gif \
+	tests/own0.txt tests/own1.txt tests/own2.txt tests/own3.txt \
+	tests/own4.txt tests/own5.txt tests/own6.txt tests/own8.txt \
+	tests/test1.txt tests/test-ack-1.txt tests/test2.txt tests/test3.txt \
+	tests/test4.txt tests/test5.txt tests/test6.txt tests/test7.txt	     \
+	tests/test8.txt tests/test9.txt tests/test10.txt tests/test10b.txt   \
+	tests/test10c.txt tests/test11.txt tests/test12.txt tests/test13.txt \
+	tests/test14-req.txt tests/test14.txt tests/test15.txt		     \
+	tests/test16.txt tests/test17.txt tests/test18.txt tests/test19.txt  \
+	tests/test1a.txt tests/test20.txt tests/test21.txt tests/test22.txt  \
+	tests/test23.txt tests/test24.txt tests/test25.txt tests/test26.txt  \
+	tests/test27.txt tests/test28.txt tests/test29.txt tests/test30.txt  \
+	tests/test31.txt tests/test32.txt tests/test33.txt tests/test34.txt  \
+	tests/test35.txt tests/test36.txt tests/test37.txt tests/test38.txt  \
+	tests/test39.txt tests/test40.txt tests/test41.txt tests/test42.txt
+
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_sip run_sip_test_msg run_date_test
+dist_noinst_SCRIPTS = run_sip_test_msg run_date_test
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+AWK_SIP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=sip
+EXTRA = $(srcdir)/sip_extra_headers.txt
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/sip/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/sip/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsip.la: $(libsip_la_OBJECTS) $(libsip_la_DEPENDENCIES) 
+	$(LINK)  $(libsip_la_LDFLAGS) $(libsip_la_OBJECTS) $(libsip_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+date_test$(EXEEXT): $(date_test_OBJECTS) $(date_test_DEPENDENCIES) 
+	@rm -f date_test$(EXEEXT)
+	$(LINK) $(date_test_LDFLAGS) $(date_test_OBJECTS) $(date_test_LDADD) $(LIBS)
+test_sip_msg$(EXEEXT): $(test_sip_msg_OBJECTS) $(test_sip_msg_DEPENDENCIES) 
+	@rm -f test_sip_msg$(EXEEXT)
+	$(LINK) $(test_sip_msg_LDFLAGS) $(test_sip_msg_OBJECTS) $(test_sip_msg_LDADD) $(LIBS)
+torture_sip$(EXEEXT): $(torture_sip_OBJECTS) $(torture_sip_DEPENDENCIES) 
+	@rm -f torture_sip$(EXEEXT)
+	$(LINK) $(torture_sip_LDFLAGS) $(torture_sip_OBJECTS) $(torture_sip_LDADD) $(LIBS)
+validator$(EXEEXT): $(validator_OBJECTS) $(validator_DEPENDENCIES) 
+	@rm -f validator$(EXEEXT)
+	$(LINK) $(validator_LDFLAGS) $(validator_OBJECTS) $(validator_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/date_test.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_caller_prefs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_event.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_extra.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_feature.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_header.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_mime.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_parser_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_prack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_pref_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_reason.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_refer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_security.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_session.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_status.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag_class.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_time.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sip_msg.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_sip.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/validator.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/images $(distdir)/sofia-sip $(distdir)/tests
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+#
+# Note: sip_bad_mask is used by nta to weed out bad messages
+#
+sip_parser_table.c: sip_bad_mask
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip_hclasses.h.in
+sofia-sip/sip_protos.h: sofia-sip/sip_protos.h.in
+sofia-sip/sip_tag.h: sofia-sip/sip_tag.h.in
+
+$(GENERATED_H): $(MSG_PARSER_AWK)
+
+sip_parser_table.c: sip_parser_table.c.in $(MSG_PARSER_AWK)
+sip_tag.c: sip_tag.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_hclasses.h.in $<
+
+sofia-sip/sip_protos.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_protos.h.in $<
+
+sofia-sip/sip_tag.h: sofia-sip/sip.h
+	@-mkdir sofia-sip 2>/dev/null || true
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_tag.h.in $<
+
+sip_tag.c: sofia-sip/sip.h sip_extra_headers.txt
+	$(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sip_tag.c.in $< $(EXTRA)
+
+sip_parser_table.c: sip_extra_headers.txt
+
+sip_parser_table.c: sofia-sip/sip.h
+	$(AWK_SIP_AWK) PT=$@ TEMPLATE=$(srcdir)/sip_parser_table.c.in \
+		FLAGFILE=$(srcdir)/sip_bad_mask \
+		MC_HASH_SIZE=127 MC_SHORT_SIZE=26 $< $(EXTRA)
+
+sofia-sip/sip_extra.h: sofia-sip/sip_extra.h.in sip_extra_headers.txt
+	@-mkdir -p sofia-sip 2>/dev/null
+	${AWK_SIP_AWK} PR=$@ NO_FIRST=1 NO_LAST=1 \
+		PACKAGE_NAME="${PACKAGE_NAME}" \
+		PACKAGE_VERSION="${PACKAGE_VERSION}" \
+		TEMPLATE1=${srcdir}/sofia-sip/sip_hclasses.h.in \
+		TEMPLATE2=${srcdir}/sofia-sip/sip_protos.h.in \
+		TEMPLATE=$< $(EXTRA)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE date_test.c  
+ *
+ * Tester for SIP date parser
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Wed Mar 21 19:12:13 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <sofia-sip/string0.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/msg_date.h>
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: date_test [SIP-date] "
+	  "[YYYYy][DDd][HHh][MMm][SS[s]]\n");
+  exit(1);
+}
+
+int main(int ac, char *av[])
+{
+  int i;
+  sip_time_t t, delta, t2;
+  char const *s;
+  int verbatim = 0, retval = 0;
+
+  t = ((31 + 27) * 24) * 60 * 60;
+  delta = (365 * 24 + 6) * 60 * 60;
+
+  if (str0cmp(av[1], "-v") == 0)
+    verbatim = 1, av++;
+
+  if ((s = av[1])) {
+    if (msg_date_d(&s, &t) < 0) {
+      fprintf(stderr, "date_test: %s is not valid time\n", s);
+      exit(1);
+    }
+      
+    if ((s = av[2])) {
+      for (delta = 0; *s; ) {
+	t2 = 0;
+	msg_delta_d(&s, &t2);
+
+	switch (*s++) {
+	case 'y': delta += t2 * (365 * 24 + 6) * 60 * 60; break;
+	case 'd': delta += t2 * 24 * 60 * 60; break;
+	case 'h': delta += t2 * 60 * 60; break;
+	case 'm': delta += t2 * 60; break;
+	case '\0': --s;		/* FALLTHROUGH */
+	case 's': delta += t2; break;
+	default:
+	  fprintf(stderr, "date_test: %s is not valid time offset\n" , av[2]);
+	  usage();
+	  break;
+	}
+      }
+    }
+  }
+
+  for (i = 0; i < 20; i++) {
+    char buf[80];
+
+    msg_date_e(buf, sizeof(buf), t);
+    
+    if (verbatim)
+      printf("%08lx is %s\n", t, buf);
+
+    s = buf, t2 = 0;
+    if (msg_date_d(&s, &t2) < 0) {
+      fprintf(stderr, "date_test: decoding %s failed\n", buf);
+      retval = 1;
+      break;
+    }
+    else if (t2 != t) {
+      fprintf(stderr, "date_test: %lu != %lu\n", t, t2);
+      retval = 1;
+      break;
+    }
+    t += delta;
+  }
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif
==============================================================================
Binary file. No diff available.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8564 @@
+
+
+
+
+
+
+Network Working Group                                          M. Handley
+Request for Comments: 2543                                          ACIRI
+Category: Standards Track                                  H. Schulzrinne
+                                                              Columbia U.
+                                                              E. Schooler
+                                                                 Cal Tech
+                                                             J. Rosenberg
+                                                                Bell Labs
+                                                               March 1999
+
+                    SIP: Session Initiation Protocol
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+IESG Note
+
+   The IESG intends to charter, in the near future, one or more working
+   groups to produce standards for "name lookup", where such names would
+   include electronic mail addresses and telephone numbers, and the
+   result of such a lookup would be a list of attributes and
+   characteristics of the user or terminal associated with the name.
+   Groups which are in need of a "name lookup" protocol should follow
+   the development of these new working groups rather than using SIP for
+   this function. In addition it is anticipated that SIP will migrate
+   towards using such protocols, and SIP implementors are advised to
+   monitor these efforts.
+
+Abstract
+
+   The Session Initiation Protocol (SIP) is an application-layer control
+   (signaling) protocol for creating, modifying and terminating sessions
+   with one or more participants. These sessions include Internet
+   multimedia conferences, Internet telephone calls and multimedia
+   distribution. Members in a session can communicate via multicast or
+   via a mesh of unicast relations, or a combination of these.
+
+
+
+
+
+
+Handley, et al.             Standards Track                     [Page 1]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   SIP invitations used to create sessions carry session descriptions
+   which allow participants to agree on a set of compatible media types.
+   SIP supports user mobility by proxying and redirecting requests to
+   the user's current location. Users can register their current
+   location.  SIP is not tied to any particular conference control
+   protocol. SIP is designed to be independent of the lower-layer
+   transport protocol and can be extended with additional capabilities.
+
+Table of Contents
+
+   1          Introduction ........................................    7
+   1.1        Overview of SIP Functionality .......................    7
+   1.2        Terminology .........................................    8
+   1.3        Definitions .........................................    9
+   1.4        Overview of SIP Operation ...........................   12
+   1.4.1      SIP Addressing ......................................   12
+   1.4.2      Locating a SIP Server ...............................   13
+   1.4.3      SIP Transaction .....................................   14
+   1.4.4      SIP Invitation ......................................   15
+   1.4.5      Locating a User .....................................   17
+   1.4.6      Changing an Existing Session ........................   18
+   1.4.7      Registration Services ...............................   18
+   1.5        Protocol Properties .................................   18
+   1.5.1      Minimal State .......................................   18
+   1.5.2      Lower-Layer-Protocol Neutral ........................   18
+   1.5.3      Text-Based ..........................................   20
+   2          SIP Uniform Resource Locators .......................   20
+   3          SIP Message Overview ................................   24
+   4          Request .............................................   26
+   4.1        Request-Line ........................................   26
+   4.2        Methods .............................................   27
+   4.2.1      INVITE ..............................................   28
+   4.2.2      ACK .................................................   29
+   4.2.3      OPTIONS .............................................   29
+   4.2.4      BYE .................................................   30
+   4.2.5      CANCEL ..............................................   30
+   4.2.6      REGISTER ............................................   31
+   4.3        Request-URI .........................................   34
+   4.3.1      SIP Version .........................................   35
+   4.4        Option Tags .........................................   35
+   4.4.1      Registering New Option Tags with IANA ...............   35
+   5          Response ............................................   36
+   5.1        Status-Line .........................................   36
+   5.1.1      Status Codes and Reason Phrases .....................   37
+   6          Header Field Definitions ............................   39
+   6.1        General Header Fields ...............................   41
+   6.2        Entity Header Fields ................................   42
+   6.3        Request Header Fields ...............................   43
+
+
+
+Handley, et al.             Standards Track                     [Page 2]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   6.4        Response Header Fields ..............................   43
+   6.5        End-to-end and Hop-by-hop Headers ...................   43
+   6.6        Header Field Format .................................   43
+   6.7        Accept ..............................................   44
+   6.8        Accept-Encoding .....................................   44
+   6.9        Accept-Language .....................................   45
+   6.10       Allow ...............................................   45
+   6.11       Authorization .......................................   45
+   6.12       Call-ID .............................................   46
+   6.13       Contact .............................................   47
+   6.14       Content-Encoding ....................................   50
+   6.15       Content-Length ......................................   51
+   6.16       Content-Type ........................................   51
+   6.17       CSeq ................................................   52
+   6.18       Date ................................................   53
+   6.19       Encryption ..........................................   54
+   6.20       Expires .............................................   55
+   6.21       From ................................................   56
+   6.22       Hide ................................................   57
+   6.23       Max-Forwards ........................................   59
+   6.24       Organization ........................................   59
+   6.25       Priority ............................................   60
+   6.26       Proxy-Authenticate ..................................   60
+   6.27       Proxy-Authorization .................................   61
+   6.28       Proxy-Require .......................................   61
+   6.29       Record-Route ........................................   62
+   6.30       Require .............................................   63
+   6.31       Response-Key ........................................   63
+   6.32       Retry-After .........................................   64
+   6.33       Route ...............................................   65
+   6.34       Server ..............................................   65
+   6.35       Subject .............................................   65
+   6.36       Timestamp ...........................................   66
+   6.37       To ..................................................   66
+   6.38       Unsupported .........................................   68
+   6.39       User-Agent ..........................................   68
+   6.40       Via .................................................   68
+   6.40.1     Requests ............................................   68
+   6.40.2     Receiver-tagged Via Header Fields ...................   69
+   6.40.3     Responses ...........................................   70
+   6.40.4     User Agent and Redirect Servers .....................   70
+   6.40.5     Syntax ..............................................   71
+   6.41       Warning .............................................   72
+   6.42       WWW-Authenticate ....................................   74
+   7          Status Code Definitions .............................   75
+   7.1        Informational 1xx ...................................   75
+   7.1.1      100 Trying ..........................................   75
+   7.1.2      180 Ringing .........................................   75
+
+
+
+Handley, et al.             Standards Track                     [Page 3]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   7.1.3      181 Call Is Being Forwarded .........................   75
+   7.1.4      182 Queued ..........................................   76
+   7.2        Successful 2xx ......................................   76
+   7.2.1      200 OK ..............................................   76
+   7.3        Redirection 3xx .....................................   76
+   7.3.1      300 Multiple Choices ................................   77
+   7.3.2      301 Moved Permanently ...............................   77
+   7.3.3      302 Moved Temporarily ...............................   77
+   7.3.4      305 Use Proxy .......................................   77
+   7.3.5      380 Alternative Service .............................   78
+   7.4        Request Failure 4xx .................................   78
+   7.4.1      400 Bad Request .....................................   78
+   7.4.2      401 Unauthorized ....................................   78
+   7.4.3      402 Payment Required ................................   78
+   7.4.4      403 Forbidden .......................................   78
+   7.4.5      404 Not Found .......................................   78
+   7.4.6      405 Method Not Allowed ..............................   78
+   7.4.7      406 Not Acceptable ..................................   79
+   7.4.8      407 Proxy Authentication Required ...................   79
+   7.4.9      408 Request Timeout .................................   79
+   7.4.10     409 Conflict ........................................   79
+   7.4.11     410 Gone ............................................   79
+   7.4.12     411 Length Required .................................   79
+   7.4.13     413 Request Entity Too Large ........................   80
+   7.4.14     414 Request-URI Too Long ............................   80
+   7.4.15     415 Unsupported Media Type ..........................   80
+   7.4.16     420 Bad Extension ...................................   80
+   7.4.17     480 Temporarily Unavailable .........................   80
+   7.4.18     481 Call Leg/Transaction Does Not Exist .............   81
+   7.4.19     482 Loop Detected ...................................   81
+   7.4.20     483 Too Many Hops ...................................   81
+   7.4.21     484 Address Incomplete ..............................   81
+   7.4.22     485 Ambiguous .......................................   81
+   7.4.23     486 Busy Here .......................................   82
+   7.5        Server Failure 5xx ..................................   82
+   7.5.1      500 Server Internal Error ...........................   82
+   7.5.2      501 Not Implemented .................................   82
+   7.5.3      502 Bad Gateway .....................................   82
+   7.5.4      503 Service Unavailable .............................   83
+   7.5.5      504 Gateway Time-out ................................   83
+   7.5.6      505 Version Not Supported ...........................   83
+   7.6        Global Failures 6xx .................................   83
+   7.6.1      600 Busy Everywhere .................................   83
+   7.6.2      603 Decline .........................................   84
+   7.6.3      604 Does Not Exist Anywhere .........................   84
+   7.6.4      606 Not Acceptable ..................................   84
+   8          SIP Message Body ....................................   84
+   8.1        Body Inclusion ......................................   84
+
+
+
+Handley, et al.             Standards Track                     [Page 4]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   8.2        Message Body Type ...................................   85
+   8.3        Message Body Length .................................   85
+   9          Compact Form ........................................   85
+   10         Behavior of SIP Clients and Servers .................   86
+   10.1       General Remarks .....................................   86
+   10.1.1     Requests ............................................   86
+   10.1.2     Responses ...........................................   87
+   10.2       Source Addresses, Destination Addresses and
+              Connections .........................................   88
+   10.2.1     Unicast UDP .........................................   88
+   10.2.2     Multicast UDP .......................................   88
+   10.3       TCP .................................................   89
+   10.4       Reliability for BYE, CANCEL, OPTIONS, REGISTER
+              Requests ............................................   90
+   10.4.1     UDP .................................................   90
+   10.4.2     TCP .................................................   91
+   10.5       Reliability for INVITE Requests .....................   91
+   10.5.1     UDP .................................................   92
+   10.5.2     TCP .................................................   95
+   10.6       Reliability for ACK Requests ........................   95
+   10.7       ICMP Handling .......................................   95
+   11         Behavior of SIP User Agents .........................   95
+   11.1       Caller Issues Initial INVITE Request ................   96
+   11.2       Callee Issues Response ..............................   96
+   11.3       Caller Receives Response to Initial Request .........   96
+   11.4       Caller or Callee Generate Subsequent Requests .......   97
+   11.5       Receiving Subsequent Requests .......................   97
+   12         Behavior of SIP Proxy and Redirect Servers ..........   97
+   12.1       Redirect Server .....................................   97
+   12.2       User Agent Server ...................................   98
+   12.3       Proxy Server ........................................   98
+   12.3.1     Proxying Requests ...................................   98
+   12.3.2     Proxying Responses ..................................   99
+   12.3.3     Stateless Proxy: Proxying Responses .................   99
+   12.3.4     Stateful Proxy: Receiving Requests ..................   99
+   12.3.5     Stateful Proxy: Receiving ACKs ......................   99
+   12.3.6     Stateful Proxy: Receiving Responses .................  100
+   12.3.7     Stateless, Non-Forking Proxy ........................  100
+   12.4       Forking Proxy .......................................  100
+   13         Security Considerations .............................  104
+   13.1       Confidentiality and Privacy: Encryption .............  104
+   13.1.1     End-to-End Encryption ...............................  104
+   13.1.2     Privacy of SIP Responses ............................  107
+   13.1.3     Encryption by Proxies ...............................  108
+   13.1.4     Hop-by-Hop Encryption ...............................  108
+   13.1.5     Via field encryption ................................  108
+   13.2       Message Integrity and Access Control:
+              Authentication ......................................  109
+
+
+
+Handley, et al.             Standards Track                     [Page 5]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   13.2.1     Trusting responses ..................................  112
+   13.3       Callee Privacy ......................................  113
+   13.4       Known Security Problems .............................  113
+   14         SIP Authentication using HTTP Basic and Digest
+              Schemes .............................................  113
+   14.1       Framework ...........................................  113
+   14.2       Basic Authentication ................................  114
+   14.3       Digest Authentication ...............................  114
+   14.4       Proxy-Authentication ................................  115
+   15         SIP Security Using PGP ..............................  115
+   15.1       PGP Authentication Scheme ...........................  115
+   15.1.1     The WWW-Authenticate Response Header ................  116
+   15.1.2     The Authorization Request Header ....................  117
+   15.2       PGP Encryption Scheme ...............................  118
+   15.3       Response-Key Header Field for PGP ...................  119
+   16         Examples ............................................  119
+   16.1       Registration ........................................  119
+   16.2       Invitation to a Multicast Conference ................  121
+   16.2.1     Request .............................................  121
+   16.2.2     Response ............................................  122
+   16.3       Two-party Call ......................................  123
+   16.4       Terminating a Call ..................................  125
+   16.5       Forking Proxy .......................................  126
+   16.6       Redirects ...........................................  130
+   16.7       Negotiation .........................................  131
+   16.8       OPTIONS Request .....................................  132
+   A          Minimal Implementation ..............................  134
+   A.1        Client ..............................................  134
+   A.2        Server ..............................................  135
+   A.3        Header Processing ...................................  135
+   B          Usage of the Session Description Protocol (SDP)......  136
+   B.1        Configuring Media Streams ...........................  136
+   B.2        Setting SDP Values for Unicast ......................  138
+   B.3        Multicast Operation .................................  139
+   B.4        Delayed Media Streams ...............................  139
+   B.5        Putting Media Streams on Hold .......................  139
+   B.6        Subject and SDP "s=" Line ...........................  140
+   B.7        The SDP "o=" Line ...................................  140
+   C          Summary of Augmented BNF ............................  141
+   C.1        Basic Rules .........................................  143
+   D          Using SRV DNS Records ...............................  146
+   E          IANA Considerations .................................  148
+   F          Acknowledgments .....................................  149
+   G          Authors' Addresses ..................................  149
+   H          Bibliography ........................................  150
+   I          Full Copyright Statement ............................  153
+
+
+
+
+
+Handley, et al.             Standards Track                     [Page 6]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+1 Introduction
+
+1.1 Overview of SIP Functionality
+
+   The Session Initiation Protocol (SIP) is an application-layer control
+   protocol that can establish, modify and terminate multimedia sessions
+   or calls. These multimedia sessions include multimedia conferences,
+   distance learning, Internet telephony and similar applications. SIP
+   can invite both persons and "robots", such as a media storage
+   service.  SIP can invite parties to both unicast and multicast
+   sessions; the initiator does not necessarily have to be a member of
+   the session to which it is inviting. Media and participants can be
+   added to an existing session.
+
+   SIP can be used to initiate sessions as well as invite members to
+   sessions that have been advertised and established by other means.
+   Sessions can be advertised using multicast protocols such as SAP,
+   electronic mail, news groups, web pages or directories (LDAP), among
+   others.
+
+   SIP transparently supports name mapping and redirection services,
+   allowing the implementation of ISDN and Intelligent Network telephony
+   subscriber services. These facilities also enable personal mobility.
+   In the parlance of telecommunications intelligent network services,
+   this is defined as: "Personal mobility is the ability of end users to
+   originate and receive calls and access subscribed telecommunication
+   services on any terminal in any location, and the ability of the
+   network to identify end users as they move. Personal mobility is
+   based on the use of a unique personal identity (i.e., personal
+   number)." [1]. Personal mobility complements terminal mobility, i.e.,
+   the ability to maintain communications when moving a single end
+   system from one subnet to another.
+
+   SIP supports five facets of establishing and terminating multimedia
+   communications:
+
+   User location: determination of the end system to be used for
+        communication;
+
+   User capabilities: determination of the media and media parameters to
+        be used;
+
+   User availability: determination of the willingness of the called
+        party to engage in communications;
+
+   Call setup: "ringing", establishment of call parameters at both
+        called and calling party;
+
+
+
+
+Handley, et al.             Standards Track                     [Page 7]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Call handling: including transfer and termination of calls.
+
+   SIP can also initiate multi-party calls using a multipoint control
+   unit (MCU) or fully-meshed interconnection instead of multicast.
+   Internet telephony gateways that connect Public Switched Telephone
+   Network (PSTN) parties can also use SIP to set up calls between them.
+
+   SIP is designed as part of the overall IETF multimedia data and
+   control architecture currently incorporating protocols such as RSVP
+   (RFC 2205 [2]) for reserving network resources, the real-time
+   transport protocol (RTP) (RFC 1889 [3]) for transporting real-time
+   data and providing QOS feedback, the real-time streaming protocol
+   (RTSP) (RFC 2326 [4]) for controlling delivery of streaming media,
+   the session announcement protocol (SAP) [5] for advertising
+   multimedia sessions via multicast and the session description
+   protocol (SDP) (RFC 2327 [6]) for describing multimedia sessions.
+   However, the functionality and operation of SIP does not depend on
+   any of these protocols.
+
+   SIP can also be used in conjunction with other call setup and
+   signaling protocols. In that mode, an end system uses SIP exchanges
+   to determine the appropriate end system address and protocol from a
+   given address that is protocol-independent. For example, SIP could be
+   used to determine that the party can be reached via H.323 [7], obtain
+   the H.245 [8] gateway and user address and then use H.225.0 [9] to
+   establish the call.
+
+   In another example, SIP might be used to determine that the callee is
+   reachable via the PSTN and indicate the phone number to be called,
+   possibly suggesting an Internet-to-PSTN gateway to be used.
+
+   SIP does not offer conference control services such as floor control
+   or voting and does not prescribe how a conference is to be managed,
+   but SIP can be used to introduce conference control protocols. SIP
+   does not allocate multicast addresses.
+
+   SIP can invite users to sessions with and without resource
+   reservation.  SIP does not reserve resources, but can convey to the
+   invited system the information necessary to do this.
+
+1.2 Terminology
+
+   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
+   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
+   and "OPTIONAL" are to be interpreted as described in RFC 2119 [10]
+   and indicate requirement levels for compliant SIP implementations.
+
+
+
+
+
+Handley, et al.             Standards Track                     [Page 8]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+1.3 Definitions
+
+   This specification uses a number of terms to refer to the roles
+   played by participants in SIP communications. The definitions of
+   client, server and proxy are similar to those used by the Hypertext
+   Transport Protocol (HTTP) (RFC 2068 [11]). The terms and generic
+   syntax of URI and URL are defined in RFC 2396 [12]. The following
+   terms have special significance for SIP.
+
+   Call: A call consists of all participants in a conference invited by
+        a common source. A SIP call is identified by a globally unique
+        call-id (Section 6.12). Thus, if a user is, for example, invited
+        to the same multicast session by several people, each of these
+        invitations will be a unique call. A point-to-point Internet
+        telephony conversation maps into a single SIP call. In a
+        multiparty conference unit (MCU) based call-in conference, each
+        participant uses a separate call to invite himself to the MCU.
+
+   Call leg: A call leg is identified by the combination of Call-ID, To
+        and From.
+
+   Client: An application program that sends SIP requests. Clients may
+        or may not interact directly with a human user.  User agents and
+        proxies contain clients (and servers).
+
+   Conference: A multimedia session (see below), identified by a common
+        session description. A conference can have zero or more members
+        and includes the cases of a multicast conference, a full-mesh
+        conference and a two-party "telephone call", as well as
+        combinations of these.  Any number of calls can be used to
+        create a conference.
+
+   Downstream: Requests sent in the direction from the caller to the
+        callee (i.e., user agent client to user agent server).
+
+   Final response: A response that terminates a SIP transaction, as
+        opposed to a provisional response that does not. All 2xx, 3xx,
+        4xx, 5xx and 6xx responses are final.
+
+   Initiator, calling party, caller: The party initiating a conference
+        invitation. Note that the calling party does not have to be the
+        same as the one creating the conference.
+
+   Invitation: A request sent to a user (or service) requesting
+        participation in a session. A successful SIP invitation consists
+        of two transactions: an INVITE request followed by an ACK
+        request.
+
+
+
+
+Handley, et al.             Standards Track                     [Page 9]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Invitee, invited user, called party, callee: The person or service
+        that the calling party is trying to invite to a conference.
+
+   Isomorphic request or response: Two requests or responses are defined
+        to be isomorphic for the purposes of this document if they have
+        the same values for the Call-ID, To, From and CSeq header
+        fields. In addition, isomorphic requests have to have the same
+        Request-URI.
+
+   Location server: See location service.
+
+   Location service: A location service is used by a SIP redirect or
+        proxy server to obtain information about a callee's possible
+        location(s). Location services are offered by location servers.
+        Location servers MAY be co-located with a SIP server, but the
+        manner in which a SIP server requests location services is
+        beyond the scope of this document.
+
+   Parallel search: In a parallel search, a proxy issues several
+        requests to possible user locations upon receiving an incoming
+        request.  Rather than issuing one request and then waiting for
+        the final response before issuing the next request as in a
+        sequential search , a parallel search issues requests without
+        waiting for the result of previous requests.
+
+   Provisional response: A response used by the server to indicate
+        progress, but that does not terminate a SIP transaction. 1xx
+        responses are provisional, other responses are considered final.
+
+   Proxy, proxy server: An intermediary program that acts as both a
+        server and a client for the purpose of making requests on behalf
+        of other clients. Requests are serviced internally or by passing
+        them on, possibly after translation, to other servers. A proxy
+        interprets, and, if necessary, rewrites a request message before
+        forwarding it.
+
+   Redirect server: A redirect server is a server that accepts a SIP
+        request, maps the address into zero or more new addresses and
+        returns these addresses to the client. Unlike a proxy server ,
+        it does not initiate its own SIP request. Unlike a user agent
+        server , it does not accept calls.
+
+   Registrar: A registrar is a server that accepts REGISTER requests. A
+        registrar is typically co-located with a proxy or redirect
+        server and MAY offer location services.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 10]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Ringback: Ringback is the signaling tone produced by the calling
+        client's application indicating that a called party is being
+        alerted (ringing).
+
+   Server: A server is an application program that accepts requests in
+        order to service requests and sends back responses to those
+        requests.  Servers are either proxy, redirect or user agent
+        servers or registrars.
+
+   Session: From the SDP specification: "A multimedia session is a set
+        of multimedia senders and receivers and the data streams flowing
+        from senders to receivers. A multimedia conference is an example
+        of a multimedia session." (RFC 2327 [6]) (A session as defined
+        for SDP can comprise one or more RTP sessions.) As defined, a
+        callee can be invited several times, by different calls, to the
+        same session. If SDP is used, a session is defined by the
+        concatenation of the user name , session id , network type ,
+        address type and address elements in the origin field.
+
+   (SIP) transaction: A SIP transaction occurs between a client and a
+        server and comprises all messages from the first request sent
+        from the client to the server up to a final (non-1xx) response
+        sent from the server to the client. A transaction is identified
+        by the CSeq sequence number (Section 6.17) within a single call
+        leg.  The ACK request has the same CSeq number as the
+        corresponding INVITE request, but comprises a transaction of its
+        own.
+
+   Upstream: Responses sent in the direction from the user agent server
+        to the user agent client.
+
+   URL-encoded: A character string encoded according to RFC 1738,
+        Section 2.2 [13].
+
+   User agent client (UAC), calling user agent: A user agent client is a
+        client application that initiates the SIP request.
+
+   User agent server (UAS), called user agent: A user agent server is a
+        server application that contacts the user when a SIP request is
+        received and that returns a response on behalf of the user. The
+        response accepts, rejects or redirects the request.
+
+   User agent (UA): An application which contains both a user agent
+        client and user agent server.
+
+   An application program MAY be capable of acting both as a client and
+   a server. For example, a typical multimedia conference control
+   application would act as a user agent client to initiate calls or to
+
+
+
+Handley, et al.             Standards Track                    [Page 11]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   invite others to conferences and as a user agent server to accept
+   invitations. The properties of the different SIP server types are
+   summarized in Table 1.
+
+
+    property                   redirect  proxy   user agent  registrar
+                                server   server    server
+    __________________________________________________________________
+    also acts as a SIP client     no      yes        no         no
+    returns 1xx status           yes      yes       yes         yes
+    returns 2xx status            no      yes       yes         yes
+    returns 3xx status           yes      yes       yes         yes
+    returns 4xx status           yes      yes       yes         yes
+    returns 5xx status           yes      yes       yes         yes
+    returns 6xx status            no      yes       yes         yes
+    inserts Via header            no      yes        no         no
+    accepts ACK                  yes      yes       yes         no
+
+
+   Table 1: Properties of the different SIP server types
+
+
+1.4 Overview of SIP Operation
+
+   This section explains the basic protocol functionality and operation.
+   Callers and callees are identified by SIP addresses, described in
+   Section 1.4.1. When making a SIP call, a caller first locates the
+   appropriate server (Section 1.4.2) and then sends a SIP request
+   (Section 1.4.3). The most common SIP operation is the invitation
+   (Section 1.4.4). Instead of directly reaching the intended callee, a
+   SIP request may be redirected or may trigger a chain of new SIP
+   requests by proxies (Section 1.4.5). Users can register their
+   location(s) with SIP servers (Section 4.2.6).
+
+1.4.1 SIP Addressing
+
+   The "objects" addressed by SIP are users at hosts, identified by a
+   SIP URL. The SIP URL takes a form similar to a mailto or telnet URL,
+   i.e., user at host.  The user part is a user name or a telephone number.
+   The host part is either a domain name or a numeric network address.
+   See section 2 for a detailed discussion of SIP URL's.
+
+   A user's SIP address can be obtained out-of-band, can be learned via
+   existing media agents, can be included in some mailers' message
+   headers, or can be recorded during previous invitation interactions.
+   In many cases, a user's SIP URL can be guessed from their email
+   address.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 12]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   A SIP URL address can designate an individual (possibly located at
+   one of several end systems), the first available person from a group
+   of individuals or a whole group. The form of the address, for
+   example, sip:sales at example.com , is not sufficient, in general, to
+   determine the intent of the caller.
+
+   If a user or service chooses to be reachable at an address that is
+   guessable from the person's name and organizational affiliation, the
+   traditional method of ensuring privacy by having an unlisted "phone"
+   number is compromised. However, unlike traditional telephony, SIP
+   offers authentication and access control mechanisms and can avail
+   itself of lower-layer security mechanisms, so that client software
+   can reject unauthorized or undesired call attempts.
+
+1.4.2 Locating a SIP Server
+
+   When a client wishes to send a request, the client either sends it to
+   a locally configured SIP proxy server (as in HTTP), independent of
+   the Request-URI, or sends it to the IP address and port corresponding
+   to the Request-URI.
+
+   For the latter case, the client must determine the protocol, port and
+   IP address of a server to which to send the request. A client SHOULD
+   follow the steps below to obtain this information, but MAY follow the
+   alternative, optional procedure defined in Appendix D. At each step,
+   unless stated otherwise, the client SHOULD try to contact a server at
+   the port number listed in the Request-URI. If no port number is
+   present in the Request-URI, the client uses port 5060. If the
+   Request-URI specifies a protocol (TCP or UDP), the client contacts
+   the server using that protocol. If no protocol is specified, the
+   client tries UDP (if UDP is supported). If the attempt fails, or if
+   the client doesn't support UDP but supports TCP, it then tries TCP.
+
+   A client SHOULD be able to interpret explicit network notifications
+   (such as ICMP messages) which indicate that a server is not
+   reachable, rather than relying solely on timeouts. (For socket-based
+   programs: For TCP, connect() returns ECONNREFUSED if the client could
+   not connect to a server at that address. For UDP, the socket needs to
+   be bound to the destination address using connect() rather than
+   sendto() or similar so that a second write() fails with ECONNREFUSED
+   if there is no server listening) If the client finds the server is
+   not reachable at a particular address, it SHOULD behave as if it had
+   received a 400-class error response to that request.
+
+   The client tries to find one or more addresses for the SIP server by
+   querying DNS. The procedure is as follows:
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 13]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        1.   If the host portion of the Request-URI is an IP address,
+             the client contacts the server at the given address.
+             Otherwise, the client proceeds to the next step.
+
+        2.   The client queries the DNS server for address records for
+             the host portion of the Request-URI. If the DNS server
+             returns no address records, the client stops, as it has
+             been unable to locate a server. By address record, we mean
+             A RR's, AAAA RR's, or other similar address records, chosen
+             according to the client's network protocol capabilities.
+
+
+        There are no mandatory rules on how to select a host name
+        for a SIP server. Users are encouraged to name their SIP
+        servers using the sip.domainname (i.e., sip.example.com)
+        convention, as specified in RFC 2219 [16]. Users may only
+        know an email address instead of a full SIP URL for a
+        callee, however. In that case, implementations may be able
+        to increase the likelihood of reaching a SIP server for
+        that domain by constructing a SIP URL from that email
+        address by prefixing the host name with "sip.". In the
+        future, this mechanism is likely to become unnecessary as
+        better DNS techniques, such as the one in Appendix D,
+        become widely available.
+
+   A client MAY cache a successful DNS query result. A successful query
+   is one which contained records in the answer, and a server was
+   contacted at one of the addresses from the answer. When the client
+   wishes to send a request to the same host, it MUST start the search
+   as if it had just received this answer from the name server. The
+   client MUST follow the procedures in RFC1035 [15] regarding DNS cache
+   invalidation when the DNS time-to-live expires.
+
+1.4.3 SIP Transaction
+
+   Once the host part has been resolved to a SIP server, the client
+   sends one or more SIP requests to that server and receives one or
+   more responses from the server. A request (and its retransmissions)
+   together with the responses triggered by that request make up a SIP
+   transaction.  All responses to a request contain the same values in
+   the Call-ID, CSeq, To, and From fields (with the possible addition of
+   a tag in the To field (section 6.37)). This allows responses to be
+   matched with requests. The ACK request following an INVITE is not
+   part of the transaction since it may traverse a different set of
+   hosts.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 14]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   If TCP is used, request and responses within a single SIP transaction
+   are carried over the same TCP connection (see Section 10). Several
+   SIP requests from the same client to the same server MAY use the same
+   TCP connection or MAY use a new connection for each request.
+
+   If the client sent the request via unicast UDP, the response is sent
+   to the address contained in the next Via header field (Section 6.40)
+   of the response. If the request is sent via multicast UDP, the
+   response is directed to the same multicast address and destination
+   port. For UDP, reliability is achieved using retransmission (Section
+   10).
+
+   The SIP message format and operation is independent of the transport
+   protocol.
+
+1.4.4 SIP Invitation
+
+   A successful SIP invitation consists of two requests, INVITE followed
+   by ACK. The INVITE (Section 4.2.1) request asks the callee to join a
+   particular conference or establish a two-party conversation. After
+   the callee has agreed to participate in the call, the caller confirms
+   that it has received that response by sending an ACK (Section 4.2.2)
+   request. If the caller no longer wants to participate in the call, it
+   sends a BYE request instead of an ACK.
+
+   The INVITE request typically contains a session description, for
+   example written in SDP (RFC 2327 [6]) format, that provides the
+   called party with enough information to join the session. For
+   multicast sessions, the session description enumerates the media
+   types and formats that are allowed to be distributed to that session.
+   For a unicast session, the session description enumerates the media
+   types and formats that the caller is willing to use and where it
+   wishes the media data to be sent. In either case, if the callee
+   wishes to accept the call, it responds to the invitation by returning
+   a similar description listing the media it wishes to use. For a
+   multicast session, the callee SHOULD only return a session
+   description if it is unable to receive the media indicated in the
+   caller's description or wants to receive data via unicast.
+
+   The protocol exchanges for the INVITE method are shown in Fig. 1 for
+   a proxy server and in Fig. 2 for a redirect server. (Note that the
+   messages shown in the figures have been abbreviated slightly.) In
+   Fig. 1, the proxy server accepts the INVITE request (step 1),
+   contacts the location service with all or parts of the address (step
+   2) and obtains a more precise location (step 3). The proxy server
+   then issues a SIP INVITE request to the address(es) returned by the
+   location service (step 4). The user agent server alerts the user
+   (step 5) and returns a success indication to the proxy server (step
+
+
+
+Handley, et al.             Standards Track                    [Page 15]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   6). The proxy server then returns the success result to the original
+   caller (step 7). The receipt of this message is confirmed by the
+   caller using an ACK request, which is forwarded to the callee (steps
+   8 and 9). Note that an ACK can also be sent directly to the callee,
+   bypassing the proxy. All requests and responses have the same Call-
+   ID.
+
+
+
+
+
+                                         +....... cs.columbia.edu .......+
+                                         :                               :
+                                         : (~~~~~~~~~~)                  :
+                                         : ( location )                  :
+                                         : ( service  )                  :
+                                         : (~~~~~~~~~~)                  :
+                                         :     ^    |                    :
+                                         :     | hgs at lab                 :
+                                         :    2|   3|                    :
+                                         :     |    |                    :
+                                         : henning  |                    : 
++.. cs.tu-berlin.de ..+ 1: INVITE        :     |    |                    :
+:                     :    henning at cs.col:     |   \/ 4: INVITE  5: ring :
+: cz at cs.tu-berlin.de ========================>(~~~~~~)=========>(~~~~~~) :
+:                    <........................(      )<.........(      ) :
+:                     : 7: 200 OK        :    (      )6: 200 OK (      ) :
+:                     :                  :    ( work )          ( lab  ) :
+:                     : 8: ACK           :    (      )9: ACK    (      ) :
+:                    ========================>(~~~~~~)=========>(~~~~~~) :
++.....................+                  +...............................+
+
+  ====> SIP request                                                         
+  ....> SIP response                                                       
+  
+   ^
+   |    non-SIP protocols                                                  
+   |
+  
+
+   Figure 1: Example of SIP proxy server
+
+
+
+   The redirect server shown in Fig. 2 accepts the INVITE request (step
+   1), contacts the location service as before (steps 2 and 3) and,
+   instead of contacting the newly found address itself, returns the
+   address to the caller (step 4), which is then acknowledged via an ACK
+
+
+
+Handley, et al.             Standards Track                    [Page 16]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   request (step 5). The caller issues a new request, with the same
+   call-ID but a higher CSeq, to the address returned by the first
+   server (step 6). In the example, the call succeeds (step 7). The
+   caller and callee complete the handshake with an ACK (step 8).
+
+
+   The next section discusses what happens if the location service
+   returns more than one possible alternative.
+
+1.4.5 Locating a User
+
+   A callee may move between a number of different end systems over
+   time.  These locations can be dynamically registered with the SIP
+   server (Sections 1.4.7, 4.2.6). A location server MAY also use one or
+   more other protocols, such as finger (RFC 1288 [17]), rwhois (RFC
+   2167 [18]), LDAP (RFC 1777 [19]), multicast-based protocols [20] or
+   operating-system dependent mechanisms to actively determine the end
+   system where a user might be reachable. A location server MAY return
+   several locations because the user is logged in at several hosts
+   simultaneously or because the location server has (temporarily)
+   inaccurate information. The SIP server combines the results to yield
+   a list of a zero or more locations.
+
+   The action taken on receiving a list of locations varies with the
+   type of SIP server. A SIP redirect server returns the list to the
+   client as Contact headers (Section 6.13). A SIP proxy server can
+   sequentially or in parallel try the addresses until the call is
+   successful (2xx response) or the callee has declined the call (6xx
+   response). With sequential attempts, a proxy server can implement an
+   "anycast" service.
+
+   If a proxy server forwards a SIP request, it MUST add itself to the
+   beginning of the list of forwarders noted in the Via (Section 6.40)
+   headers. The Via trace ensures that replies can take the same path
+   back, ensuring correct operation through compliant firewalls and
+   avoiding request loops. On the response path, each host MUST remove
+   its Via, so that routing internal information is hidden from the
+   callee and outside networks. A proxy server MUST check that it does
+   not generate a request to a host listed in the Via sent-by, via-
+   received or via-maddr parameters (Section 6.40). (Note: If a host has
+   several names or network addresses, this does not always work.  Thus,
+   each host also checks if it is part of the Via list.)
+
+   A SIP invitation may traverse more than one SIP proxy server. If one
+   of these "forks" the request, i.e., issues more than one request in
+   response to receiving the invitation request, it is possible that a
+   client is reached, independently, by more than one copy of the
+
+
+
+
+Handley, et al.             Standards Track                    [Page 17]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   invitation request. Each of these copies bears the same Call-ID. The
+   user agent MUST return the same status response returned in the first
+   response. Duplicate requests are not an error.
+
+1.4.6 Changing an Existing Session
+
+   In some circumstances, it is desirable to change the parameters of an
+   existing session. This is done by re-issuing the INVITE, using the
+   same Call-ID, but a new or different body or header fields to convey
+   the new information. This re INVITE MUST have a higher CSeq than any
+   previous request from the client to the server.
+
+   For example, two parties may have been conversing and then want to
+   add a third party, switching to multicast for efficiency.  One of the
+   participants invites the third party with the new multicast address
+   and simultaneously sends an INVITE to the second party, with the new
+   multicast session description, but with the old call identifier.
+
+1.4.7 Registration Services
+
+   The REGISTER request allows a client to let a proxy or redirect
+   server know at which address(es) it can be reached. A client MAY also
+   use it to install call handling features at the server.
+
+1.5 Protocol Properties
+
+1.5.1 Minimal State
+
+   A single conference session or call involves one or more SIP
+   request-response transactions. Proxy servers do not have to keep
+   state for a particular call, however, they MAY maintain state for a
+   single SIP transaction, as discussed in Section 12. For efficiency, a
+   server MAY cache the results of location service requests.
+
+1.5.2 Lower-Layer-Protocol Neutral
+
+   SIP makes minimal assumptions about the underlying transport and
+   network-layer protocols. The lower-layer can provide either a packet
+   or a byte stream service, with reliable or unreliable service.
+
+   In an Internet context, SIP is able to utilize both UDP and TCP as
+   transport protocols, among others. UDP allows the application to more
+   carefully control the timing of messages and their retransmission, to
+   perform parallel searches without requiring TCP connection state for
+   each outstanding request, and to use multicast. Routers can more
+   readily snoop SIP UDP packets. TCP allows easier passage through
+   existing firewalls.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 18]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+
+
+                                         +....... cs.columbia.edu .......+
+                                         :                               :
+                                         : (~~~~~~~~~~)                  :
+                                         : ( location )                  :
+                                         : ( service  )                  :
+                                         : (~~~~~~~~~~)                  :
+                                         :    ^   |                      :
+                                         :    | hgs at lab                  :
+                                         :   2|  3|                      :
+                                         :    |   |                      :
+                                         : henning|                      : 
++.. cs.tu-berlin.de ..+ 1: INVITE        :    |   |                      :
+:                     :    henning at cs.col:    |   \/                     : 
+: cz at cs.tu-berlin.de =======================>(~~~~~~)                    : 
+:       | ^ |        <.......................(      )                    :
+:       | . |         : 4: 302 Moved     :   (      )                    :
+:       | . |         :    hgs at lab       :   ( work )                    :
+:       | . |         :                  :   (      )                    :
+:       | . |         : 5: ACK           :   (      )                    :
+:       | . |        =======================>(~~~~~~)                    :
+:       | . |         :                  :                               :
++.......|...|.........+                  :                               :
+        | . |                            :                               :
+        | . |                            :                               :
+        | . |                            :                               :
+        | . |                            :                               :
+        | . | 6: INVITE hgs at lab.cs.columbia.edu                 (~~~~~~) : 
+        | . ==================================================> (      ) :
+        | ..................................................... (      ) :
+        |     7: 200 OK                  :                      ( lab  ) : 
+        |                                :                      (      ) :
+        |     8: ACK                     :                      (      ) :
+        ======================================================> (~~~~~~) :
+                                         +...............................+ 
+                                                                          
+  ====> SIP request                                                        
+  ....> SIP response                                                       
+    
+    ^
+    |   non-SIP protocols                                                  
+    |
+
+
+
+
+   Figure 2: Example of SIP redirect server
+
+Handley, et al.             Standards Track                    [Page 19]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   When TCP is used, SIP can use one or more connections to attempt to
+   contact a user or to modify parameters of an existing conference.
+   Different SIP requests for the same SIP call MAY use different TCP
+   connections or a single persistent connection, as appropriate.
+
+   For concreteness, this document will only refer to Internet
+   protocols.  However, SIP MAY also be used directly with protocols
+   such as ATM AAL5, IPX, frame relay or X.25. The necessary naming
+   conventions are beyond the scope of this document. User agents SHOULD
+   implement both UDP and TCP transport. Proxy, registrar, and redirect
+   servers MUST implement both UDP and TCP transport.
+
+1.5.3 Text-Based
+
+   SIP is text-based, using ISO 10646 in UTF-8 encoding throughout. This
+   allows easy implementation in languages such as Java, Tcl and Perl,
+   allows easy debugging, and most importantly, makes SIP flexible and
+   extensible. As SIP is used for initiating multimedia conferences
+   rather than delivering media data, it is believed that the additional
+   overhead of using a text-based protocol is not significant.
+
+2 SIP Uniform Resource Locators
+
+   SIP URLs are used within SIP messages to indicate the originator
+   (From), current destination (Request-URI) and final recipient (To) of
+   a SIP request, and to specify redirection addresses (Contact). A SIP
+   URL can also be embedded in web pages or other hyperlinks to indicate
+   that a particular user or service can be called via SIP. When used as
+   a hyperlink, the SIP URL indicates the use of the INVITE method.
+
+   The SIP URL scheme is defined to allow setting SIP request-header
+   fields and the SIP message-body.
+
+
+        This corresponds to the use of mailto: URLs. It makes it
+        possible, for example, to specify the subject, urgency or
+        media types of calls initiated through a web page or as
+        part of an email message.
+
+   A SIP URL follows the guidelines of RFC 2396 [12] and has the syntax
+   shown in Fig. 3. The syntax is described using Augmented Backus-Naur
+   Form (See Section C). Note that reserved characters have to be
+   escaped and that the "set of characters reserved within any given URI
+   component is defined by that component. In general, a character is
+   reserved if the semantics of the URI changes if the character is
+   replaced with its escaped US-ASCII encoding" [12].
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 20]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+  SIP-URL         = "sip:" [ userinfo "@" ] hostport
+                    url-parameters [ headers ]
+  userinfo        = user [ ":" password ]
+  user            = *( unreserved | escaped
+                  | "&" | "=" | "+" | "$" | "," )
+  password        = *( unreserved | escaped
+                  | "&" | "=" | "+" | "$" | "," )
+  hostport        = host [ ":" port ]
+  host            = hostname | IPv4address
+  hostname        = *( domainlabel "." ) toplabel [ "." ]
+  domainlabel     = alphanum | alphanum *( alphanum | "-" ) alphanum
+  toplabel        = alpha | alpha *( alphanum | "-" ) alphanum
+  IPv4address     = 1*digit "." 1*digit "." 1*digit "." 1*digit
+  port            = *digit
+  url-parameters  = *( ";" url-parameter )
+  url-parameter   = transport-param | user-param | method-param
+                  | ttl-param | maddr-param | other-param
+  transport-param = "transport=" ( "udp" | "tcp" )
+  ttl-param       = "ttl=" ttl
+  ttl             = 1*3DIGIT       ; 0 to 255
+  maddr-param     = "maddr=" host
+  user-param      = "user=" ( "phone" | "ip" )
+  method-param    = "method=" Method
+  tag-param       = "tag=" UUID
+  UUID            = 1*( hex | "-" )
+  other-param     = ( token | ( token "=" ( token | quoted-string )))
+  headers         = "?" header *( "&" header )
+  header          = hname "=" hvalue
+  hname           = 1*uric
+  hvalue          = *uric
+  uric            = reserved | unreserved | escaped
+  reserved        = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+                    "$" | ","
+  digits          = 1*DIGIT
+
+
+   Figure 3: SIP URL syntax
+
+
+
+   The URI character classes referenced above are described in Appendix
+   C.
+
+   The components of the SIP URI have the following meanings.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 21]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+telephone-subscriber  = global-phone-number | local-phone-number
+   global-phone-number   = "+" 1*phonedigit [isdn-subaddress]
+                             [post-dial]
+   local-phone-number    = 1*(phonedigit | dtmf-digit | 
+                             pause-character) [isdn-subaddress] 
+                             [post-dial]
+   isdn-subaddress       = ";isub=" 1*phonedigit
+   post-dial             = ";postd=" 1*(phonedigit | dtmf-digit
+                         |  pause-character)
+   phonedigit            = DIGIT | visual-separator
+   visual-separator      = "-" | "."
+   pause-character       = one-second-pause | wait-for-dial-tone
+   one-second-pause      = "p"
+   wait-for-dial-tone    = "w"
+   dtmf-digit            = "*" | "#" | "A" | "B" | "C" | "D"
+
+   Figure 4: SIP URL syntax; telephone subscriber
+
+   user: If the host is an Internet telephony gateway, the user field
+        MAY also encode a telephone number using the notation of
+        telephone-subscriber (Fig. 4). The telephone number is a special
+        case of a user name and cannot be distinguished by a BNF. Thus,
+        a URL parameter, user, is added to distinguish telephone numbers
+        from user names. The phone identifier is to be used when
+        connecting to a telephony gateway. Even without this parameter,
+        recipients of SIP URLs MAY interpret the pre-@ part as a phone
+        number if local restrictions on the name space for user name
+        allow it.
+
+   password: The SIP scheme MAY use the format "user:password" in the
+        userinfo field. The use of passwords in the userinfo is NOT
+        RECOMMENDED, because the passing of authentication information
+        in clear text (such as URIs) has proven to be a security risk in
+        almost every case where it has been used.
+
+   host: The mailto: URL and RFC 822 email addresses require that
+        numeric host addresses ("host numbers") are enclosed in square
+        brackets (presumably, since host names might be numeric), while
+        host numbers without brackets are used for all other URLs. The
+        SIP URL requires the latter form, without brackets.
+
+   The issue of IPv6 literal addresses in URLs is being looked at
+   elsewhere in the IETF. SIP implementers are advised to keep up to
+   date on that activity.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 22]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   port: The port number to send a request to. If not present, the
+        procedures outlined in Section 1.4.2 are used to determine the
+        port number to send a request to.
+
+   URL parameters: SIP URLs can define specific parameters of the
+        request. URL parameters are added after the host component and
+        are separated by semi-colons. The transport parameter determines
+        the the transport mechanism (UDP or TCP). UDP is to be assumed
+        when no explicit transport parameter is included. The maddr
+        parameter provides the server address to be contacted for this
+        user, overriding the address supplied in the host field.  This
+        address is typically a multicast address, but could also be the
+        address of a backup server. The ttl parameter determines the
+        time-to-live value of the UDP multicast packet and MUST only be
+        used if maddr is a multicast address and the transport protocol
+        is UDP. The user parameter was described above. For example, to
+        specify to call j.doe at big.com using multicast to 239.255.255.1
+        with a ttl of 15, the following URL would be used:
+
+
+     sip:j.doe at big.com;maddr=239.255.255.1;ttl=15
+
+
+
+   The transport, maddr, and ttl parameters MUST NOT be used in the From
+   and To header fields and the Request-URI; they are ignored if
+   present.
+
+   Headers: Headers of the SIP request can be defined with the "?"
+        mechanism within a SIP URL. The special hname "body" indicates
+        that the associated hvalue is the message-body of the SIP INVITE
+        request. Headers MUST NOT be used in the From and To header
+        fields and the Request-URI; they are ignored if present.  hname
+        and hvalue are encodings of a SIP header name and value,
+        respectively. All URL reserved characters in the header names
+        and values MUST be escaped.
+
+   Method: The method of the SIP request can be specified with the
+        method parameter.  This parameter MUST NOT be used in the From
+        and To header fields and the Request-URI; they are ignored if
+        present.
+
+   Table 2 summarizes where the components of the SIP URL can be used
+   and what default values they assume if not present.
+
+
+   Examples of SIP URLs are:
+
+
+
+
+Handley, et al.             Standards Track                    [Page 23]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+                     default    Req.-URI  To  From  Contact  external
+      user           --         x         x   x     x        x
+      password       --         x         x         x        x
+      host           mandatory  x         x   x     x        x
+      port           5060       x         x   x     x        x
+      user-param     ip         x         x   x     x        x
+      method         INVITE                         x        x
+      maddr-param    --                             x        x
+      ttl-param      1                              x        x
+      transp.-param  --                             x        x
+      headers        --                             x        x
+
+
+   Table 2: Use and default values of URL components  for  SIP  headers,
+   Request-URI and references
+
+     sip:j.doe at big.com
+     sip:j.doe:secret at big.com;transport=tcp
+     sip:j.doe at big.com?subject=project
+     sip:+1-212-555-1212:1234 at gateway.com;user=phone
+     sip:1212 at gateway.com
+     sip:alice at 10.1.2.3
+     sip:alice at example.com
+     sip:alice%40example.com at gateway.com
+     sip:alice at registrar.com;method=REGISTER
+
+
+
+   Within a SIP message, URLs are used to indicate the source and
+   intended destination of a request, redirection addresses and the
+   current destination of a request. Normally all these fields will
+   contain SIP URLs.
+
+   SIP URLs are case-insensitive, so that for example the two URLs
+   sip:j.doe at example.com and SIP:J.Doe at Example.com are equivalent.  All
+   URL parameters are included when comparing SIP URLs for equality.
+
+   SIP header fields MAY contain non-SIP URLs. As an example, if a call
+   from a telephone is relayed to the Internet via SIP, the SIP From
+   header field might contain a phone URL.
+
+3 SIP Message Overview
+
+   SIP is a text-based protocol and uses the ISO 10646 character set in
+   UTF-8 encoding (RFC 2279 [21]). Senders MUST terminate lines with a
+   CRLF, but receivers MUST also interpret CR and LF by themselves as
+   line terminators.
+
+
+
+Handley, et al.             Standards Track                    [Page 24]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Except for the above difference in character sets, much of the
+   message syntax is and header fields are identical to HTTP/1.1; rather
+   than repeating the syntax and semantics here we use [HX.Y] to refer
+   to Section X.Y of the current HTTP/1.1 specification (RFC 2068 [11]).
+   In addition, we describe SIP in both prose and an augmented Backus-
+   Naur form (ABNF). See section C for an overview of ABNF.
+
+   Note, however, that SIP is not an extension of HTTP.
+
+   Unlike HTTP, SIP MAY use UDP. When sent over TCP or UDP, multiple SIP
+   transactions can be carried in a single TCP connection or UDP
+   datagram. UDP datagrams, including all headers, SHOULD NOT be larger
+   than the path maximum transmission unit (MTU) if the MTU is known, or
+   1500 bytes if the MTU is unknown.
+
+
+        The 1500 bytes accommodates encapsulation within the
+        "typical" ethernet MTU without IP fragmentation. Recent
+        studies [22] indicate that an MTU of 1500 bytes is a
+        reasonable assumption. The next lower common MTU values are
+        1006 bytes for SLIP and 296 for low-delay PPP (RFC 1191
+        [23]). Thus, another reasonable value would be a message
+        size of 950 bytes, to accommodate packet headers within the
+        SLIP MTU without fragmentation.
+
+   A SIP message is either a request from a client to a server, or a
+   response from a server to a client.
+
+
+
+        SIP-message  =  Request | Response
+
+
+   Both Request (section 4) and Response (section 5) messages use the
+   generic-message format of RFC 822 [24] for transferring entities (the
+   body of the message). Both types of messages consist of a start-line,
+   one or more header fields (also known as "headers"), an empty line
+   (i.e., a line with nothing preceding the carriage-return line-feed
+   (CRLF)) indicating the end of the header fields, and an optional
+   message-body. To avoid confusion with similar-named headers in HTTP,
+   we refer to the headers describing the message body as entity
+   headers. These components are described in detail in the upcoming
+   sections.
+
+
+
+        generic-message  =  start-line
+                            *message-header
+
+
+
+Handley, et al.             Standards Track                    [Page 25]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+                            CRLF
+                            [ message-body ]
+
+        start-line       =  Request-Line |     ;Section 4.1
+                            Status-Line        ;Section 5.1
+
+
+
+
+        message-header  =  ( general-header
+                           | request-header
+                           | response-header
+                           | entity-header )
+
+
+
+   In the interest of robustness, any leading empty line(s) MUST be
+   ignored. In other words, if the Request or Response message begins
+   with one or more CRLF, CR, or LFs, these characters MUST be ignored.
+
+4 Request
+
+   The Request message format is shown below:
+
+
+
+        Request  =  Request-Line       ;  Section 4.1
+                    *( general-header
+                    | request-header
+                    | entity-header )
+                    CRLF
+                    [ message-body ]   ;  Section 8
+
+
+4.1 Request-Line
+
+   The Request-Line begins with a method token, followed by the
+   Request-URI and the protocol version, and ending with CRLF. The
+   elements are separated by SP characters.  No CR or LF are allowed
+   except in the final CRLF sequence.
+
+
+
+        Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 26]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+        general-header   =  Accept               ; Section 6.7
+                         |  Accept-Encoding      ; Section 6.8
+                         |  Accept-Language      ; Section 6.9
+                         |  Call-ID              ; Section 6.12
+                         |  Contact              ; Section 6.13
+                         |  CSeq                 ; Section 6.17
+                         |  Date                 ; Section 6.18
+                         |  Encryption           ; Section 6.19
+                         |  Expires              ; Section 6.20
+                         |  From                 ; Section 6.21
+                         |  Record-Route         ; Section 6.29
+                         |  Timestamp            ; Section 6.36
+                         |  To                   ; Section 6.37
+                         |  Via                  ; Section 6.40
+        entity-header    =  Content-Encoding     ; Section 6.14
+                         |  Content-Length       ; Section 6.15
+                         |  Content-Type         ; Section 6.16
+        request-header   =  Authorization        ; Section 6.11
+                         |  Contact              ; Section 6.13
+                         |  Hide                 ; Section 6.22
+                         |  Max-Forwards         ; Section 6.23
+                         |  Organization         ; Section 6.24
+                         |  Priority             ; Section 6.25
+                         |  Proxy-Authorization  ; Section 6.27
+                         |  Proxy-Require        ; Section 6.28
+                         |  Route                ; Section 6.33
+                         |  Require              ; Section 6.30
+                         |  Response-Key         ; Section 6.31
+                         |  Subject              ; Section 6.35
+                         |  User-Agent           ; Section 6.39
+        response-header  =  Allow                ; Section 6.10
+                         |  Proxy-Authenticate   ; Section 6.26
+                         |  Retry-After          ; Section 6.32
+                         |  Server               ; Section 6.34
+                         |  Unsupported          ; Section 6.38
+                         |  Warning              ; Section 6.41
+                         |  WWW-Authenticate     ; Section 6.42
+
+
+   Table 3: SIP headers
+
+4.2 Methods
+
+   The methods are defined below. Methods that are not supported by a
+   proxy or redirect server are treated by that server as if they were
+   an OPTIONS method and forwarded accordingly. Methods that are not
+
+
+
+Handley, et al.             Standards Track                    [Page 27]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   supported by a user agent server or registrar cause a 501 (Not
+   Implemented) response to be returned (Section 7). As in HTTP, the
+   Method token is case-sensitive.
+
+
+
+        Method  =  "INVITE" | "ACK" | "OPTIONS" | "BYE"
+                   | "CANCEL" | "REGISTER"
+
+
+4.2.1 INVITE
+
+   The INVITE method indicates that the user or service is being invited
+   to participate in a session. The message body contains a description
+   of the session to which the callee is being invited. For two-party
+   calls, the caller indicates the type of media it is able to receive
+   and possibly the media it is willing to send as well as their
+   parameters such as network destination. A success response MUST
+   indicate in its message body which media the callee wishes to receive
+   and MAY indicate the media the callee is going to send.
+
+
+        Not all session description formats have the ability to
+        indicate sending media.
+
+   A server MAY automatically respond to an invitation for a conference
+   the user is already participating in, identified either by the SIP
+   Call-ID or a globally unique identifier within the session
+   description, with a 200 (OK) response.
+
+   If a user agent receives an INVITE request for an existing call leg
+   with a higher CSeq sequence number than any previous INVITE for the
+   same Call-ID, it MUST check any version identifiers in the session
+   description or, if there are no version identifiers, the content of
+   the session description to see if it has changed. It MUST also
+   inspect any other header fields for changes. If there is a change,
+   the user agent MUST update any internal state or information
+   generated as a result of that header. If the session description has
+   changed, the user agent server MUST adjust the session parameters
+   accordingly, possibly after asking the user for confirmation.
+   (Versioning of the session description can be used to accommodate the
+   capabilities of new arrivals to a conference, add or delete media or
+   change from a unicast to a multicast conference.)
+
+   This method MUST be supported by SIP proxy, redirect and user agent
+   servers as well as clients.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 28]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+4.2.2 ACK
+
+   The ACK request confirms that the client has received a final
+   response to an INVITE request. (ACK is used only with INVITE
+   requests.) 2xx responses are acknowledged by client user agents, all
+   other final responses by the first proxy or client user agent to
+   receive the response. The Via is always initialized to the host that
+   originates the ACK request, i.e., the client user agent after a 2xx
+   response or the first proxy to receive a non-2xx final response. The
+   ACK request is forwarded as the corresponding INVITE request, based
+   on its Request-URI. See Section 10 for details.
+
+   The ACK request MAY contain a message body with the final session
+   description to be used by the callee. If the ACK message body is
+   empty, the callee uses the session description in the INVITE request.
+
+   A proxy server receiving an ACK request after having sent a 3xx, 4xx,
+   5xx, or 6xx response must make a determination about whether the ACK
+   is for it, or for some user agent or proxy server further downstream.
+   This determination is made by examining the tag in the To field. If
+   the tag in the ACK To header field matches the tag in the To header
+   field of the response, and the From, CSeq and Call-ID header fields
+   in the response match those in the ACK, the ACK is meant for the
+   proxy server. Otherwise, the ACK SHOULD be proxied downstream as any
+   other request.
+
+
+        It is possible for a user agent client or proxy server to
+        receive multiple 3xx, 4xx, 5xx, and 6xx responses to a
+        request along a single branch. This can happen under
+        various error conditions, typically when a forking proxy
+        transitions from stateful to stateless before receiving all
+        responses. The various responses will all be identical,
+        except for the tag in the To field, which is different for
+        each one. It can therefore be used as a means to
+        disambiguate them.
+
+   This method MUST be supported by SIP proxy, redirect and user agent
+   servers as well as clients.
+
+4.2.3 OPTIONS
+
+   The server is being queried as to its capabilities. A server that
+   believes it can contact the user, such as a user agent where the user
+   is logged in and has been recently active, MAY respond to this
+   request with a capability set. A called user agent MAY return a
+   status reflecting how it would have responded to an invitation, e.g.,
+
+
+
+
+Handley, et al.             Standards Track                    [Page 29]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   600 (Busy). Such a server SHOULD return an Allow header field
+   indicating the methods that it supports. Proxy and redirect servers
+   simply forward the request without indicating their capabilities.
+
+   This method MUST be supported by SIP proxy, redirect and user agent
+   servers, registrars and clients.
+
+4.2.4 BYE
+
+   The user agent client uses BYE to indicate to the server that it
+   wishes to release the call. A BYE request is forwarded like an INVITE
+   request and MAY be issued by either caller or callee. A party to a
+   call SHOULD issue a BYE request before releasing a call ("hanging
+   up"). A party receiving a BYE request MUST cease transmitting media
+   streams specifically directed at the party issuing the BYE request.
+
+   If the INVITE request contained a Contact header, the callee SHOULD
+   send a BYE request to that address rather than the From address.
+
+   This method MUST be supported by proxy servers and SHOULD be
+   supported by redirect and user agent SIP servers.
+
+4.2.5 CANCEL
+
+   The CANCEL request cancels a pending request with the same Call-ID,
+   To, From and CSeq (sequence number only) header field values, but
+   does not affect a completed request. (A request is considered
+   completed if the server has returned a final status response.)
+
+   A user agent client or proxy client MAY issue a CANCEL request at any
+   time. A proxy, in particular, MAY choose to send a CANCEL to
+   destinations that have not yet returned a final response after it has
+   received a 2xx or 6xx response for one or more of the parallel-search
+   requests. A proxy that receives a CANCEL request forwards the request
+   to all destinations with pending requests.
+
+   The Call-ID, To, the numeric part of CSeq and From headers in the
+   CANCEL request are identical to those in the original request. This
+   allows a CANCEL request to be matched with the request it cancels.
+   However, to allow the client to distinguish responses to the CANCEL
+   from those to the original request, the CSeq Method component is set
+   to CANCEL. The Via header field is initialized to the proxy issuing
+   the CANCEL request. (Thus, responses to this CANCEL request only
+   reach the issuing proxy.)
+
+   Once a user agent server has received a CANCEL, it MUST NOT issue a
+   2xx response for the cancelled original request.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 30]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   A redirect or user agent server receiving a CANCEL request responds
+   with a status of 200 (OK) if the transaction exists and a status of
+   481 (Transaction Does Not Exist) if not, but takes no further action.
+   In particular, any existing call is unaffected.
+
+
+        The BYE request cannot be used to cancel branches of a
+        parallel search, since several branches may, through
+        intermediate proxies, find the same user agent server and
+        then terminate the call.  To terminate a call instead of
+        just pending searches, the UAC must use BYE instead of or
+        in addition to CANCEL. While CANCEL can terminate any
+        pending request other than ACK or CANCEL, it is typically
+        useful only for INVITE. 200 responses to INVITE and 200
+        responses to CANCEL are distinguished by the method in the
+        Cseq header field, so there is no ambiguity.
+
+   This method MUST be supported by proxy servers and SHOULD be
+   supported by all other SIP server types.
+
+4.2.6 REGISTER
+
+   A client uses the REGISTER method to register the address listed in
+   the To header field with a SIP server.
+
+   A user agent MAY register with a local server on startup by sending a
+   REGISTER request to the well-known "all SIP servers" multicast
+   address "sip.mcast.net" (224.0.1.75). This request SHOULD be scoped
+   to ensure it is not forwarded beyond the boundaries of the
+   administrative system. This MAY be done with either TTL or
+   administrative scopes [25], depending on what is implemented in the
+   network. SIP user agents MAY listen to that address and use it to
+   become aware of the location of other local users [20]; however, they
+   do not respond to the request.  A user agent MAY also be configured
+   with the address of a registrar server to which it sends a REGISTER
+   request upon startup.
+
+   Requests are processed in the order received. Clients SHOULD avoid
+   sending a new registration (as opposed to a retransmission) until
+   they have received the response from the server for the previous one.
+
+
+        Clients may register from different locations, by necessity
+        using different Call-ID values. Thus, the CSeq value cannot
+        be used to enforce ordering. Since registrations are
+        additive, ordering is less of a problem than if each
+        REGISTER request completely replaced all earlier ones.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 31]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The meaning of the REGISTER request-header fields is defined as
+   follows. We define "address-of-record" as the SIP address that the
+   registry knows the registrand, typically of the form "user at domain"
+   rather than "user at host". In third-party registration, the entity
+   issuing the request is different from the entity being registered.
+
+   To: The To header field contains the address-of-record whose
+        registration is to be created or updated.
+
+   From: The From header field contains the address-of-record of the
+        person responsible for the registration. For first-party
+        registration, it is identical to the To header field value.
+
+   Request-URI: The Request-URI names the destination of the
+        registration request, i.e., the domain of the registrar. The
+        user name MUST be empty. Generally, the domains in the Request-
+        URI and the To header field have the same value; however, it is
+        possible to register as a "visitor", while maintaining one's
+        name. For example, a traveler sip:alice at acme.com (To) might
+        register under the Request-URI sip:atlanta.hiayh.org , with the
+        former as the To header field and the latter as the Request-URI.
+        The REGISTER request is no longer forwarded once it has reached
+        the server whose authoritative domain is the one listed in the
+        Request-URI.
+
+   Call-ID: All registrations from a client SHOULD use the same Call-ID
+        header value, at least within the same reboot cycle.
+
+   Cseq: Registrations with the same Call-ID MUST have increasing CSeq
+        header values. However, the server does not reject out-of-order
+        requests.
+
+   Contact: The request MAY contain a Contact header field; future non-
+        REGISTER requests for the URI given in the To header field
+        SHOULD be directed to the address(es) given in the Contact
+        header.
+
+   If the request does not contain a Contact header, the registration
+   remains unchanged.
+
+        This is useful to obtain the current list of registrations
+        in the response.  Registrations using SIP URIs that differ
+        in one or more of host, port, transport-param or maddr-
+        param (see Figure 3) from an existing registration are
+        added to the list of registrations. Other URI types are
+        compared according to the standard URI equivalency rules
+        for the URI schema. If the URIs are equivalent to that of
+        an existing registration, the new registration replaces the
+
+
+
+Handley, et al.             Standards Track                    [Page 32]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        old one if it has a higher q value or, for the same value
+        of q, if the ttl value is higher. All current registrations
+        MUST share the same action value.  Registrations that have
+        a different action than current registrations for the same
+        user MUST be rejected with status of 409 (Conflict).
+
+   A proxy server ignores the q parameter when processing non-REGISTER
+   requests, while a redirect server simply returns that parameter in
+   its Contact response header field.
+
+
+        Having the proxy server interpret the q parameter is not
+        sufficient to guide proxy behavior, as it is not clear, for
+        example, how long it is supposed to wait between trying
+        addresses.
+
+   If the registration is changed while a user agent or proxy server
+   processes an invitation, the new information SHOULD be used.
+
+
+        This allows a service known as "directed pick-up". In the
+        telephone network, directed pickup permits a user at a
+        remote station who hears his own phone ringing to pick up
+        at that station, dial an access code, and be connected to
+        the calling user as if he had answered his own phone.
+
+   A server MAY choose any duration for the registration lifetime.
+   Registrations not refreshed after this amount of time SHOULD be
+   silently discarded. Responses to a registration SHOULD include an
+   Expires header (Section 6.20) or expires Contact parameters (Section
+   6.13), indicating the time at which the server will drop the
+   registration. If none is present, one hour is assumed. Clients MAY
+   request a registration lifetime by indicating the time in an Expires
+   header in the request. A server SHOULD NOT use a higher lifetime than
+   the one requested, but MAY use a lower one. A single address (if
+   host-independent) MAY be registered from several different clients.
+
+   A client cancels an existing registration by sending a REGISTER
+   request with an expiration time (Expires) of zero seconds for a
+   particular Contact or the wildcard Contact designated by a "*" for
+   all registrations. Registrations are matched based on the user, host,
+   port and maddr parameters.
+
+   The server SHOULD return the current list of registrations in the 200
+   response as Contact header fields.
+
+   It is particularly important that REGISTER requests are authenticated
+   since they allow to redirect future requests (see Section 13.2).
+
+
+
+Handley, et al.             Standards Track                    [Page 33]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Beyond its use as a simple location service, this method is
+        needed if there are several SIP servers on a single host.
+        In that case, only one of the servers can use the default
+        port number.
+
+
+   Support of this method is RECOMMENDED.
+
+4.3 Request-URI
+
+   The Request-URI is a SIP URL as described in Section 2 or a general
+   URI. It indicates the user or service to which this request is being
+   addressed. Unlike the To field, the Request-URI MAY be re-written by
+   proxies.
+
+   When used as a Request-URI, a SIP-URL MUST NOT contain the
+   transport-param, maddr-param, ttl-param, or headers elements. A
+   server that receives a SIP-URL with these elements removes them
+   before further processing.
+
+
+        Typically, the UAC sets the Request-URI and To to the same
+        SIP URL, presumed to remain unchanged over long time
+        periods. However, if the UAC has cached a more direct path
+        to the callee, e.g., from the Contact header field of a
+        response to a previous request, the To would still contain
+        the long-term, "public" address, while the Request-URI
+        would be set to the cached address.
+
+   Proxy and redirect servers MAY use the information in the Request-URI
+   and request header fields to handle the request and possibly rewrite
+   the Request-URI. For example, a request addressed to the generic
+   address sip:sales at acme.com is proxied to the particular person, e.g.,
+   sip:bob at ny.acme.com , with the To field remaining as
+   sip:sales at acme.com.  At ny.acme.com , Bob then designates Alice as
+   the temporary substitute.
+
+   The host part of the Request-URI typically agrees with one of the
+   host names of the receiving server. If it does not, the server SHOULD
+   proxy the request to the address indicated or return a 404 (Not
+   Found) response if it is unwilling or unable to do so. For example,
+   the Request-URI and server host name can disagree in the case of a
+   firewall proxy that handles outgoing calls. This mode of operation is
+   similar to that of HTTP proxies.
+
+   If a SIP server receives a request with a URI indicating a scheme
+   other than SIP which that server does not understand, the server MUST
+   return a 400 (Bad Request) response. It MUST do this even if the To
+
+
+
+Handley, et al.             Standards Track                    [Page 34]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   header field contains a scheme it does understand.  This is because
+   proxies are responsible for processing the Request-URI; the To field
+   is of end-to-end significance.
+
+4.3.1 SIP Version
+
+   Both request and response messages include the version of SIP in use,
+   and follow [H3.1] (with HTTP replaced by SIP, and HTTP/1.1 replaced
+   by SIP/2.0) regarding version ordering, compliance requirements, and
+   upgrading of version numbers. To be compliant with this
+   specification, applications sending SIP messages MUST include a SIP-
+   Version of "SIP/2.0".
+
+4.4 Option Tags
+
+   Option tags are unique identifiers used to designate new options in
+   SIP.  These tags are used in Require (Section 6.30) and Unsupported
+   (Section 6.38) fields.
+
+   Syntax:
+
+
+        option-tag  =  token
+
+
+   See Section C for a definition of token. The creator of a new SIP
+   option MUST either prefix the option with their reverse domain name
+   or register the new option with the Internet Assigned Numbers
+   Authority (IANA). For example, "com.foo.mynewfeature" is an apt name
+   for a feature whose inventor can be reached at "foo.com".  Individual
+   organizations are then responsible for ensuring that option names
+   don't collide. Options registered with IANA have the prefix
+   "org.iana.sip.", options described in RFCs have the prefix
+   "org.ietf.rfc.N", where N is the RFC number. Option tags are case-
+   insensitive.
+
+4.4.1 Registering New Option Tags with IANA
+
+   When registering a new SIP option, the following information MUST be
+   provided:
+
+        o  Name and description of option. The name MAY be of any
+          length, but SHOULD be no more than twenty characters long. The
+          name MUST consist of alphanum (See Figure 3) characters only;
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 35]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        o  Indication of who has change control over the option (for
+          example, IETF, ISO, ITU-T, other international standardization
+          bodies, a consortium or a particular company or group of
+          companies);
+
+        o  A reference to a further description, if available, for
+          example (in order of preference) an RFC, a published paper, a
+          patent filing, a technical report, documented source code or a
+          computer manual;
+
+        o  Contact information (postal and email address);
+
+   Registrations should be sent to iana at iana.org
+
+
+        This procedure has been borrowed from RTSP [4] and the RTP
+        AVP [26].
+
+5 Response
+
+   After receiving and interpreting a request message, the recipient
+   responds with a SIP response message. The response message format is
+   shown below:
+
+
+
+        Response  =  Status-Line        ;  Section 5.1
+                     *( general-header
+                     | response-header
+                     | entity-header )
+                     CRLF
+                     [ message-body ]   ;  Section 8
+
+
+   SIP's structure of responses is similar to [H6], but is defined
+   explicitly here.
+
+5.1 Status-Line
+
+   The first line of a Response message is the Status-Line, consisting
+   of the protocol version (Section 4.3.1) followed by a numeric
+   Status-Code and its associated textual phrase, with each element
+   separated by SP characters. No CR or LF is allowed except in the
+   final CRLF sequence.
+
+
+
+        Status-Line  =  SIP-version SP Status-Code SP Reason-Phrase CRLF
+
+
+
+Handley, et al.             Standards Track                    [Page 36]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+5.1.1 Status Codes and Reason Phrases
+
+   The Status-Code is a 3-digit integer result code that indicates the
+   outcome of the attempt to understand and satisfy the request. The
+   Reason-Phrase is intended to give a short textual description of the
+   Status-Code. The Status-Code is intended for use by automata, whereas
+   the Reason-Phrase is intended for the human user. The client is not
+   required to examine or display the Reason-Phrase.
+
+
+
+        Status-Code     =  Informational                     ;Fig. 5
+                       |   Success                           ;Fig. 5
+                       |   Redirection                       ;Fig. 6
+                       |   Client-Error                      ;Fig. 7
+                       |   Server-Error                      ;Fig. 8
+                       |   Global-Failure                    ;Fig. 9
+                       |   extension-code
+        extension-code  =  3DIGIT
+        Reason-Phrase   =  *<TEXT-UTF8,  excluding CR, LF>
+
+
+   We provide an overview of the Status-Code below, and provide full
+   definitions in Section 7. The first digit of the Status-Code defines
+   the class of response. The last two digits do not have any
+   categorization role. SIP/2.0 allows 6 values for the first digit:
+
+   1xx: Informational -- request received, continuing to process the
+        request;
+
+   2xx: Success -- the action was successfully received, understood, and
+        accepted;
+
+   3xx: Redirection -- further action needs to be taken in order to
+        complete the request;
+
+   4xx: Client Error -- the request contains bad syntax or cannot be
+        fulfilled at this server;
+
+   5xx: Server Error -- the server failed to fulfill an apparently valid
+        request;
+
+   6xx: Global Failure -- the request cannot be fulfilled at any server.
+
+   Figures 5 through 9 present the individual values of the numeric
+   response codes, and an example set of corresponding reason phrases
+   for SIP/2.0. These reason phrases are only recommended; they may be
+   replaced by local equivalents without affecting the protocol. Note
+
+
+
+Handley, et al.             Standards Track                    [Page 37]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   that SIP adopts many HTTP/1.1 response codes. SIP/2.0 adds response
+   codes in the range starting at x80 to avoid conflicts with newly
+   defined HTTP response codes, and adds a new class, 6xx, of response
+   codes.
+
+   SIP response codes are extensible. SIP applications are not required
+   to understand the meaning of all registered response codes, though
+   such understanding is obviously desirable. However, applications MUST
+   understand the class of any response code, as indicated by the first
+   digit, and treat any unrecognized response as being equivalent to the
+   x00 response code of that class, with the exception that an
+   unrecognized response MUST NOT be cached. For example, if a client
+   receives an unrecognized response code of 431, it can safely assume
+   that there was something wrong with its request and treat the
+   response as if it had received a 400 (Bad Request) response code. In
+   such cases, user agents SHOULD present to the user the message body
+   returned with the response, since that message body is likely to
+   include human-readable information which will explain the unusual
+   status.
+
+
+
+        Informational  =  "100"  ;  Trying
+                      |   "180"  ;  Ringing
+                      |   "181"  ;  Call Is Being Forwarded
+                      |   "182"  ;  Queued
+        Success        =  "200"  ;  OK
+
+
+   Figure 5: Informational and success status codes
+
+
+
+
+
+        Redirection  =  "300"  ;  Multiple Choices
+                    |   "301"  ;  Moved Permanently
+                    |   "302"  ;  Moved Temporarily
+                    |   "303"  ;  See Other
+                    |   "305"  ;  Use Proxy
+                    |   "380"  ;  Alternative Service
+
+
+   Figure 6: Redirection status codes
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 38]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+        Client-Error  =  "400"  ;  Bad Request
+                     |   "401"  ;  Unauthorized
+                     |   "402"  ;  Payment Required
+                     |   "403"  ;  Forbidden
+                     |   "404"  ;  Not Found
+                     |   "405"  ;  Method Not Allowed
+                     |   "406"  ;  Not Acceptable
+                     |   "407"  ;  Proxy Authentication Required
+                     |   "408"  ;  Request Timeout
+                     |   "409"  ;  Conflict
+                     |   "410"  ;  Gone
+                     |   "411"  ;  Length Required
+                     |   "413"  ;  Request Entity Too Large
+                     |   "414"  ;  Request-URI Too Large
+                     |   "415"  ;  Unsupported Media Type
+                     |   "420"  ;  Bad Extension
+                     |   "480"  ;  Temporarily not available
+                     |   "481"  ;  Call Leg/Transaction Does Not Exist
+                     |   "482"  ;  Loop Detected
+                     |   "483"  ;  Too Many Hops
+                     |   "484"  ;  Address Incomplete
+                     |   "485"  ;  Ambiguous
+                     |   "486"  ;  Busy Here
+
+
+   Figure 7: Client error status codes
+
+
+        Server-Error  =  "500"  ;  Internal Server Error
+                     |   "501"  ;  Not Implemented
+                     |   "502"  ;  Bad Gateway
+                     |   "503"  ;  Service Unavailable
+                     |   "504"  ;  Gateway Time-out
+                     |   "505"  ;  SIP Version not supported
+
+
+   Figure 8: Server error status codes
+
+
+6 Header Field Definitions
+
+   SIP header fields are similar to HTTP header fields in both syntax
+   and semantics. In particular, SIP header fields follow the syntax for
+   message-header as described in [H4.2]. The rules for extending header
+   fields over multiple lines, and use of multiple message-header fields
+   with the same field-name, described in [H4.2] also apply to SIP. The
+
+
+
+Handley, et al.             Standards Track                    [Page 39]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+        Global-Failure |  "600"  ;  Busy Everywhere
+                       |  "603"  ;  Decline
+                       |  "604"  ;  Does not exist anywhere
+                       |  "606"  ;  Not Acceptable
+
+
+   Figure 9: Global failure status codes
+
+
+   rules in [H4.2] regarding ordering of header fields apply to SIP,
+   with the exception of Via fields, see below, whose order matters.
+   Additionally, header fields which are hop-by-hop MUST appear before
+   any header fields which are end-to-end. Proxies SHOULD NOT reorder
+   header fields. Proxies add Via header fields and MAY add other hop-
+   by-hop header fields. They can modify certain header fields, such as
+   Max-Forwards (Section 6.23) and "fix up" the Via header fields with
+   "received" parameters as described in Section 6.40.1. Proxies MUST
+   NOT alter any fields that are authenticated (see Section 13.2).
+
+   The header fields required, optional and not applicable for each
+   method are listed in Table 4 and Table 5. The table uses "o" to
+   indicate optional, "m" mandatory and "-" for not applicable. A "*"
+   indicates that the header fields are needed only if message body is
+   not empty. See sections 6.15, 6.16 and 8 for details.
+
+   The "where" column describes the request and response types with
+   which the header field can be used. "R" refers to header fields that
+   can be used in requests (that is, request and general header fields).
+   "r" designates a response or general-header field as applicable to
+   all responses, while a list of numeric values indicates the status
+   codes with which the header field can be used. "g" and "e" designate
+   general (Section 6.1) and entity header (Section 6.2) fields,
+   respectively. If a header field is marked "c", it is copied from the
+   request to the response.
+
+   The "enc." column describes whether this message header field MAY be
+   encrypted end-to-end. A "n" designates fields that MUST NOT be
+   encrypted, while "c" designates fields that SHOULD be encrypted if
+   encryption is used.
+
+   The "e-e" column has a value of "e" for end-to-end and a value of "h"
+   for hop-by-hop header fields.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 40]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+                          where  enc.  e-e ACK BYE CAN INV OPT REG
+        __________________________________________________________
+        Accept              R           e   -   -   -   o   o   o
+        Accept             415          e   -   -   -   o   o   o
+        Accept-Encoding     R           e   -   -   -   o   o   o
+        Accept-Encoding    415          e   -   -   -   o   o   o
+        Accept-Language     R           e   -   o   o   o   o   o
+        Accept-Language    415          e   -   o   o   o   o   o
+        Allow              200          e   -   -   -   -   m   -
+        Allow              405          e   o   o   o   o   o   o
+        Authorization       R           e   o   o   o   o   o   o
+        Call-ID            gc     n     e   m   m   m   m   m   m
+        Contact             R           e   o   -   -   o   o   o
+        Contact            1xx          e   -   -   -   o   o   -
+        Contact            2xx          e   -   -   -   o   o   o
+        Contact            3xx          e   -   o   -   o   o   o
+        Contact            485          e   -   o   -   o   o   o
+        Content-Encoding    e           e   o   -   -   o   o   o
+        Content-Length      e           e   o   -   -   o   o   o
+        Content-Type        e           e   *   -   -   *   *   *
+        CSeq               gc     n     e   m   m   m   m   m   m
+        Date                g           e   o   o   o   o   o   o
+        Encryption          g     n     e   o   o   o   o   o   o
+        Expires             g           e   -   -   -   o   -   o
+        From               gc     n     e   m   m   m   m   m   m
+        Hide                R     n     h   o   o   o   o   o   o
+        Max-Forwards        R     n     e   o   o   o   o   o   o
+        Organization        g     c     h   -   -   -   o   o   o
+
+
+   Table 4: Summary of header fields, A--O
+
+   Other header fields can be added as required; a server MUST ignore
+   header fields not defined in this specification that it does not
+   understand. A proxy MUST NOT remove or modify header fields not
+   defined in this specification that it does not understand. A compact
+   form of these header fields is also defined in Section 9 for use over
+   UDP when the request has to fit into a single packet and size is an
+   issue.
+
+   Table 6 in Appendix A lists those header fields that different client
+   and server types MUST be able to parse.
+
+6.1 General Header Fields
+
+   General header fields apply to both request and response messages.
+   The "general-header" field names can be extended reliably only in
+   combination with a change in the protocol version. However, new or
+
+
+Handley, et al.             Standards Track                    [Page 41]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+                            where     enc.  e-e ACK BYE CAN INV OPT REG
+    ___________________________________________________________________
+    Proxy-Authenticate       407       n     h   o   o   o   o   o   o
+    Proxy-Authorization       R        n     h   o   o   o   o   o   o
+    Proxy-Require             R        n     h   o   o   o   o   o   o
+    Priority                  R        c     e   -   -   -   o   -   -
+    Require                   R              e   o   o   o   o   o   o
+    Retry-After               R        c     e   -   -   -   -   -   o
+    Retry-After          404,480,486   c     e   o   o   o   o   o   o
+                             503       c     e   o   o   o   o   o   o
+                           600,603     c     e   o   o   o   o   o   o
+    Response-Key              R        c     e   -   o   o   o   o   o
+    Record-Route              R              h   o   o   o   o   o   o
+    Record-Route             2xx             h   o   o   o   o   o   o
+    Route                     R              h   o   o   o   o   o   o
+    Server                    r        c     e   o   o   o   o   o   o
+    Subject                   R        c     e   -   -   -   o   -   -
+    Timestamp                 g              e   o   o   o   o   o   o
+    To                      gc(1)      n     e   m   m   m   m   m   m
+    Unsupported              420             e   o   o   o   o   o   o
+    User-Agent                g        c     e   o   o   o   o   o   o
+    Via                     gc(2)      n     e   m   m   m   m   m   m
+    Warning                   r              e   o   o   o   o   o   o
+    WWW-Authenticate         401       c     e   o   o   o   o   o   o
+
+
+   Table 5: Summary of header fields, P--Z; (1):  copied  with  possible
+   addition of tag; (2): UAS removes first Via header field
+
+   experimental header fields MAY be given the semantics of general
+   header fields if all parties in the communication recognize them to
+   be "general-header" fields. Unrecognized header fields are treated as
+   "entity-header" fields.
+
+6.2 Entity Header Fields
+
+   The "entity-header" fields define meta-information about the
+   message-body or, if no body is present, about the resource identified
+   by the request. The term "entity header" is an HTTP 1.1 term where
+   the response body can contain a transformed version of the message
+   body.  The original message body is referred to as the "entity". We
+   retain the same terminology for header fields but usually refer to
+   the "message body" rather then the entity as the two are the same in
+   SIP.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 42]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.3 Request Header Fields
+
+   The "request-header" fields allow the client to pass additional
+   information about the request, and about the client itself, to the
+   server. These fields act as request modifiers, with semantics
+   equivalent to the parameters of a programming language method
+   invocation.
+
+   The "request-header" field names can be extended reliably only in
+   combination with a change in the protocol version. However, new or
+   experimental header fields MAY be given the semantics of "request-
+   header" fields if all parties in the communication recognize them to
+   be request-header fields. Unrecognized header fields are treated as
+   "entity-header" fields.
+
+6.4 Response Header Fields
+
+   The "response-header" fields allow the server to pass additional
+   information about the response which cannot be placed in the Status-
+   Line. These header fields give information about the server and about
+   further access to the resource identified by the Request-URI.
+
+   Response-header field names can be extended reliably only in
+   combination with a change in the protocol version. However, new or
+   experimental header fields MAY be given the semantics of "response-
+   header" fields if all parties in the communication recognize them to
+   be "response-header" fields. Unrecognized header fields are treated
+   as "entity-header" fields.
+
+6.5 End-to-end and Hop-by-hop Headers
+
+   End-to-end headers MUST be transmitted unmodified across all proxies,
+   while hop-by-hop headers MAY be modified or added by proxies.
+
+6.6 Header Field Format
+
+   Header fields ("general-header", "request-header", "response-header",
+   and "entity-header") follow the same generic header format as that
+   given in Section 3.1 of RFC 822 [24]. Each header field consists of a
+   name followed by a colon (":") and the field value. Field names are
+   case-insensitive. The field value MAY be preceded by any amount of
+   leading white space (LWS), though a single space (SP) is preferred.
+   Header fields can be extended over multiple lines by preceding each
+   extra line with at least one SP or horizontal tab (HT). Applications
+   MUST follow HTTP "common form" when generating these constructs,
+   since there might exist some implementations that fail to accept
+   anything beyond the common forms.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 43]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        message-header  =  field-name ":" [ field-value ] CRLF
+        field-name      =  token
+        field-value     =  *( field-content | LWS )
+        field-content   =  < the OCTETs  making up the field-value
+                            and consisting of either *TEXT-UTF8
+                            or combinations of token,
+                            separators, and quoted-string>
+
+
+   The relative order of header fields with different field names is not
+   significant. Multiple header fields with the same field-name may be
+   present in a message if and only if the entire field-value for that
+   header field is defined as a comma-separated list (i.e., #(values)).
+   It MUST be possible to combine the multiple header fields into one
+   "field-name: field-value" pair, without changing the semantics of the
+   message, by appending each subsequent field-value to the first, each
+   separated by a comma. The order in which header fields with the same
+   field-name are received is therefore significant to the
+   interpretation of the combined field value, and thus a proxy MUST NOT
+   change the order of these field values when a message is forwarded.
+
+   Field names are not case-sensitive, although their values may be.
+
+6.7 Accept
+
+   The Accept header follows the syntax defined in [H14.1]. The
+   semantics are also identical, with the exception that if no Accept
+   header is present, the server SHOULD assume a default value of
+   application/sdp.
+
+   This request-header field is used only with the INVITE, OPTIONS and
+   REGISTER request methods to indicate what media types are acceptable
+   in the response.
+
+   Example:
+
+
+     Accept: application/sdp;level=1, application/x-private, text/html
+
+
+
+6.8 Accept-Encoding
+
+   The Accept-Encoding request-header field is similar to Accept, but
+   restricts the content-codings [H3.4.1] that are acceptable in the
+   response. See [H14.3]. The syntax of this header is defined in
+   [H14.3]. The semantics in SIP are identical to those defined in
+   [H14.3].
+
+
+
+Handley, et al.             Standards Track                    [Page 44]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.9 Accept-Language
+
+   The Accept-Language header follows the syntax defined in [H14.4]. The
+   rules for ordering the languages based on the q parameter apply to
+   SIP as well. When used in SIP, the Accept-Language request-header
+   field can be used to allow the client to indicate to the server in
+   which language it would prefer to receive reason phrases, session
+   descriptions or status responses carried as message bodies. A proxy
+   MAY use this field to help select the destination for the call, for
+   example, a human operator conversant in a language spoken by the
+   caller.
+
+   Example:
+
+
+     Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+
+6.10 Allow
+
+   The Allow entity-header field lists the set of methods supported by
+   the resource identified by the Request-URI. The purpose of this field
+   is strictly to inform the recipient of valid methods associated with
+   the resource. An Allow header field MUST be present in a 405 (Method
+   Not Allowed) response and SHOULD be present in an OPTIONS response.
+
+
+
+        Allow  =  "Allow" ":" 1#Method
+
+
+6.11 Authorization
+
+   A user agent that wishes to authenticate itself with a server --
+   usually, but not necessarily, after receiving a 401 response -- MAY
+   do so by including an Authorization request-header field with the
+   request. The Authorization field value consists of credentials
+   containing the authentication information of the user agent for the
+   realm of the resource being requested.
+
+   Section 13.2 overviews the use of the Authorization header, and
+   section 15 describes the syntax and semantics when used with PGP
+   based authentication.
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 45]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.12 Call-ID
+
+   The Call-ID general-header field uniquely identifies a particular
+   invitation or all registrations of a particular client. Note that a
+   single multimedia conference can give rise to several calls with
+   different Call-IDs, e.g., if a user invites a single individual
+   several times to the same (long-running) conference.
+
+   For an INVITE request, a callee user agent server SHOULD NOT alert
+   the user if the user has responded previously to the Call-ID in the
+   INVITE request. If the user is already a member of the conference and
+   the conference parameters contained in the session description have
+   not changed, a callee user agent server MAY silently accept the call,
+   regardless of the Call-ID. An invitation for an existing Call-ID or
+   session can change the parameters of the conference. A client
+   application MAY decide to simply indicate to the user that the
+   conference parameters have been changed and accept the invitation
+   automatically or it MAY require user confirmation.
+
+   A user may be invited to the same conference or call using several
+   different Call-IDs. If desired, the client MAY use identifiers within
+   the session description to detect this duplication. For example, SDP
+   contains a session id and version number in the origin (o) field.
+
+   The REGISTER and OPTIONS methods use the Call-ID value to
+   unambiguously match requests and responses. All REGISTER requests
+   issued by a single client SHOULD use the same Call-ID, at least
+   within the same boot cycle.
+
+
+        Since the Call-ID is generated by and for SIP, there is no
+        reason to deal with the complexity of URL-encoding and
+        case-ignoring string comparison.
+
+
+
+        Call-ID   =  ( "Call-ID" | "i" ) ":" local-id "@" host
+        local-id  =  1*uric
+
+
+   "host" SHOULD be either a fully qualified domain name or a globally
+   routable IP address. If this is the case, the "local-id" SHOULD be an
+   identifier consisting of URI characters that is unique within "host".
+   Use of cryptographically random identifiers [27] is RECOMMENDED.  If,
+   however, host is not an FQDN or globally routable IP address (such as
+   a net 10 address), the local-id MUST be globally unique, as opposed
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 46]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   to unique within host. These rules guarantee overall global
+   uniqueness of the Call-ID. The value for Call-ID MUST NOT be reused
+   for a different call.  Call-IDs are case-sensitive.
+
+
+        Using cryptographically random identifiers provides some
+        protection against session hijacking. Call-ID, To and From
+        are needed to identify a call leg.  The distinction between
+        call and call leg matters in calls with third-party
+        control.
+
+   For systems which have tight bandwidth constraints, many of the
+   mandatory SIP headers have a compact form, as discussed in Section 9.
+   These are alternate names for the headers which occupy less space in
+   the message. In the case of Call-ID, the compact form is i.
+
+   For example, both of the following are valid:
+
+     Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6 at foo.bar.com
+
+
+   or
+
+     i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 at foo.bar.com
+
+
+
+6.13 Contact
+
+   The Contact general-header field can appear in INVITE, ACK, and
+   REGISTER requests, and in 1xx, 2xx, 3xx, and 485 responses. In
+   general, it provides a URL where the user can be reached for further
+   communications.
+
+   INVITE and ACK requests: INVITE and ACK requests MAY contain Contact
+        headers indicating from which location the request is
+        originating.
+
+
+        This allows the callee to send future requests, such as
+        BYE, directly to the caller instead of through a series of
+        proxies.  The Via header is not sufficient since the
+        desired address may be that of a proxy.
+
+   INVITE 2xx responses: A user agent server sending a definitive,
+        positive response (2xx) MAY insert a Contact response header
+        field indicating the SIP address under which it is reachable
+        most directly for future SIP requests, such as ACK, within the
+
+
+
+Handley, et al.             Standards Track                    [Page 47]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        same Call-ID. The Contact header field contains the address of
+        the server itself or that of a proxy, e.g., if the host is
+        behind a firewall. The value of this Contact header is copied
+        into the Request-URI of subsequent requests for this call if the
+        response did not also contain a Record-Route header. If the
+        response also contains a Record-Route header field, the address
+        in the Contact header field is added as the last item in the
+        Route header field. See Section 6.29 for details.
+
+
+        The Contact value SHOULD NOT be cached across calls, as it
+        may not represent the most desirable location for a
+        particular destination address.
+
+   INVITE 1xx responses: A UAS sending a provisional response (1xx) MAY
+        insert a Contact response header. It has the same semantics in a
+        1xx response as a 2xx INVITE response. Note that CANCEL requests
+        MUST NOT be sent to that address, but rather follow the same
+        path as the original request.
+
+   REGISTER requests: REGISTER requests MAY contain a Contact header
+        field indicating at which locations the user is reachable. The
+        REGISTER request defines a wildcard Contact field, "*", which
+        MUST only be used with Expires: 0 to remove all registrations
+        for a particular user. An optional "expires" parameter indicates
+        the desired expiration time of the registration. If a Contact
+        entry does not have an "expires" parameter, the Expires header
+        field is used as the default value. If neither of these
+        mechanisms is used, SIP URIs are assumed to expire after one
+        hour. Other URI schemes have no expiration times.
+
+   REGISTER 2xx responses: A REGISTER response MAY return all locations
+        at which the user is currently reachable.  An optional "expires"
+        parameter indicates the expiration time of the registration. If
+        a Contact entry does not have an "expires" parameter, the value
+        of the Expires header field indicates the expiration time. If
+        neither mechanism is used, the expiration time specified in the
+        request, explicitly or by default, is used.
+
+   3xx and 485 responses: The Contact response-header field can be used
+        with a 3xx or 485 (Ambiguous) response codes to indicate one or
+        more alternate addresses to try. It can appear in responses to
+        BYE, INVITE and OPTIONS methods. The Contact header field
+        contains URIs giving the new locations or user names to try, or
+        may simply specify additional transport parameters. A 300
+        (Multiple Choices), 301 (Moved Permanently), 302 (Moved
+        Temporarily) or 485 (Ambiguous) response SHOULD contain a
+        Contact field containing URIs of new addresses to be tried. A
+
+
+
+Handley, et al.             Standards Track                    [Page 48]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        301 or 302 response may also give the same location and username
+        that was being tried but specify additional transport parameters
+        such as a different server or multicast address to try or a
+        change of SIP transport from UDP to TCP or vice versa. The
+        client copies the "user", "password", "host", "port" and "user-
+        param" elements of the Contact URI into the Request-URI of the
+        redirected request and directs the request to the address
+        specified by the "maddr" and "port" parameters, using the
+        transport protocol given in the "transport" parameter. If
+        "maddr" is a multicast address, the value of "ttl" is used as
+        the time-to-live value.
+
+   Note that the Contact header field MAY also refer to a different
+   entity than the one originally called. For example, a SIP call
+   connected to GSTN gateway may need to deliver a special information
+   announcement such as "The number you have dialed has been changed."
+
+   A Contact response header field can contain any suitable URI
+   indicating where the called party can be reached, not limited to SIP
+   URLs. For example, it could contain URL's for phones, fax, or irc (if
+   they were defined) or a mailto: (RFC 2368, [28]) URL.
+
+   The following parameters are defined. Additional parameters may be
+   defined in other specifications.
+
+   q: The "qvalue" indicates the relative preference among the locations
+        given. "qvalue" values are decimal numbers from 0 to 1, with
+        higher values indicating higher preference.
+
+   action: The "action" parameter is used only when registering with the
+        REGISTER request. It indicates whether the client wishes that
+        the server proxy or redirect future requests intended for the
+        client. If this parameter is not specified the action taken
+        depends on server configuration. In its response, the registrar
+        SHOULD indicate the mode used. This parameter is ignored for
+        other requests.
+
+   expires: The "expires" parameter indicates how long the URI is valid.
+        The parameter is either a number indicating seconds or a quoted
+        string containing a SIP-date. If this parameter is not provided,
+        the value of the Expires header field determines how long the
+        URI is valid. Implementations MAY treat values larger than
+        2**32-1 (4294967295 seconds or 136 years) as equivalent to
+        2**32-1.
+
+
+
+   Contact = ( "Contact" | "m" ) ":" 
+             ("*" | (1# (( name-addr | addr-spec )
+             [ *( ";" contact-params ) ] [ comment ] )))
+
+   name-addr      = [ display-name ] "<" addr-spec ">"
+   addr-spec      = SIP-URL | URI
+   display-name   = *token | quoted-string
+
+   contact-params = "q"       "=" qvalue
+                  | "action"  "=" "proxy" | "redirect"
+                  | "expires" "=" delta-seconds | <"> SIP-date <">
+                  | extension-attribute
+
+   extension-attribute = extension-name [ "=" extension-value ]
+
+        only allows one address, unquoted. Since URIs can contain
+        commas and semicolons as reserved characters, they can be
+        mistaken for header or parameter delimiters, respectively.
+        The current syntax corresponds to that for the To and From
+        header, which also allows the use of display names.
+
+   Example:
+
+
+     Contact: "Mr. Watson" <sip:watson at worcester.bell-telephone.com>
+        ;q=0.7; expires=3600,
+        "Mr. Watson" <mailto:watson at bell-telephone.com> ;q=0.1
+
+
+
+6.14 Content-Encoding
+
+
+
+        Content-Encoding  =  ( "Content-Encoding" | "e" ) ":"
+                             1#content-coding
+
+
+   The Content-Encoding entity-header field is used as a modifier to the
+   "media-type". When present, its value indicates what additional
+   content codings have been applied to the entity-body, and thus what
+   decoding mechanisms MUST be applied in order to obtain the media-type
+   referenced by the Content-Type header field.  Content-Encoding is
+   primarily used to allow a body to be compressed without losing the
+   identity of its underlying media type.
+
+   If multiple encodings have been applied to an entity, the content
+   codings MUST be listed in the order in which they were applied.
+
+   All content-coding values are case-insensitive. The Internet Assigned
+   Numbers Authority (IANA) acts as a registry for content-coding value
+   tokens. See [3.5] for a definition of the syntax for content-coding.
+
+   Clients MAY apply content encodings to the body in requests. If the
+   server is not capable of decoding the body, or does not recognize any
+   of the content-coding values, it MUST send a 415 "Unsupported Media
+   Type" response, listing acceptable encodings in the Accept-Encoding
+
+
+
+Handley, et al.             Standards Track                    [Page 50]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   header. A server MAY apply content encodings to the bodies in
+   responses. The server MUST only use encodings listed in the Accept-
+   Encoding header in the request.
+
+6.15 Content-Length
+
+   The Content-Length entity-header field indicates the size of the
+   message-body, in decimal number of octets, sent to the recipient.
+
+
+
+        Content-Length  =  ( "Content-Length" | "l" ) ":" 1*DIGIT
+
+
+   An example is
+
+     Content-Length: 3495
+
+
+
+   Applications SHOULD use this field to indicate the size of the
+   message-body to be transferred, regardless of the media type of the
+   entity. Any Content-Length greater than or equal to zero is a valid
+   value. If no body is present in a message, then the Content-Length
+   header field MUST be set to zero. If a server receives a UDP request
+   without Content-Length, it MUST assume that the request encompasses
+   the remainder of the packet.  If a server receives a UDP request with
+   a Content-Length, but the value is larger than the size of the body
+   sent in the request, the client SHOULD generate a 400 class response.
+   If there is additional data in the UDP packet after the last byte of
+   the body has been read, the server MUST treat the remaining data as a
+   separate message. This allows several messages to be placed in a
+   single UDP packet.
+
+   If a response does not contain a Content-Length, the client assumes
+   that it encompasses the remainder of the UDP packet or the data until
+   the TCP connection is closed, as applicable.  Section 8 describes how
+   to determine the length of the message body.
+
+6.16 Content-Type
+
+   The Content-Type entity-header field indicates the media type of the
+   message-body sent to the recipient. The "media-type" element is
+   defined in [H3.7].
+
+
+
+        Content-Type  =  ( "Content-Type" | "c" ) ":" media-type
+
+
+
+Handley, et al.             Standards Track                    [Page 51]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Examples of this header field are
+
+     Content-Type: application/sdp
+     Content-Type: text/html; charset=ISO-8859-4
+
+
+
+6.17 CSeq
+
+   Clients MUST add the CSeq (command sequence) general-header field to
+   every request. A CSeq header field in a request contains the request
+   method and a single decimal sequence number chosen by the requesting
+   client, unique within a single value of Call-ID. The sequence number
+   MUST be expressible as a 32-bit unsigned integer. The initial value
+   of the sequence number is arbitrary, but MUST be less than 2**31.
+   Consecutive requests that differ in request method, headers or body,
+   but have the same Call-ID MUST contain strictly monotonically
+   increasing and contiguous sequence numbers; sequence numbers do not
+   wrap around.  Retransmissions of the same request carry the same
+   sequence number, but an INVITE with a different message body or
+   different header fields (a "re-invitation") acquires a new, higher
+   sequence number. A server MUST echo the CSeq value from the request
+   in its response.  If the Method value is missing in the received CSeq
+   header field, the server fills it in appropriately.
+
+   The ACK and CANCEL requests MUST contain the same CSeq value as the
+   INVITE request that it refers to, while a BYE request cancelling an
+   invitation MUST have a higher sequence number. A BYE request with a
+   CSeq that is not higher should cause a 400 response to be generated.
+
+   A user agent server MUST remember the highest sequence number for any
+   INVITE request with the same Call-ID value. The server MUST respond
+   to, and then discard, any INVITE request with a lower sequence
+   number.
+
+   All requests spawned in a parallel search have the same CSeq value as
+   the request triggering the parallel search.
+
+
+
+        CSeq  =  "CSeq" ":" 1*DIGIT Method
+
+
+
+        Strictly speaking, CSeq header fields are needed for any
+        SIP request that can be cancelled by a BYE or CANCEL
+        request or where a client can issue several requests for
+        the same Call-ID in close succession. Without a sequence
+
+
+
+Handley, et al.             Standards Track                    [Page 52]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        number, the response to an INVITE could be mistaken for the
+        response to the cancellation (BYE or CANCEL). Also, if the
+        network duplicates packets or if an ACK is delayed until
+        the server has sent an additional response, the client
+        could interpret an old response as the response to a re-
+        invitation issued shortly thereafter. Using CSeq also makes
+        it easy for the server to distinguish different versions of
+        an invitation, without comparing the message body.
+
+   The Method value allows the client to distinguish the response to an
+   INVITE request from that of a CANCEL response. CANCEL requests can be
+   generated by proxies; if they were to increase the sequence number,
+   it might conflict with a later request issued by the user agent for
+   the same call.
+
+   With a length of 32 bits, a server could generate, within a single
+   call, one request a second for about 136 years before needing to wrap
+   around.  The initial value of the sequence number is chosen so that
+   subsequent requests within the same call will not wrap around. A
+   non-zero initial value allows to use a time-based initial sequence
+   number, if the client desires. A client could, for example, choose
+   the 31 most significant bits of a 32-bit second clock as an initial
+   sequence number.
+
+   Forked requests MUST have the same CSeq as there would be ambiguity
+   otherwise between these forked requests and later BYE issued by the
+   client user agent.
+
+   Example:
+
+
+     CSeq: 4711 INVITE
+
+
+
+6.18 Date
+
+   Date is a general-header field. Its syntax is:
+
+
+
+        SIP-date  =  rfc1123-date
+
+
+   See [H14.19] for a definition of rfc1123-date. Note that unlike
+   HTTP/1.1, SIP only supports the most recent RFC1123 [29] formatting
+   for dates.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 53]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The Date header field reflects the time when the request or response
+   is first sent. Thus, retransmissions have the same Date header field
+   value as the original.
+
+
+        The Date header field can be used by simple end systems
+        without a battery-backed clock to acquire a notion of
+        current time.
+
+6.19 Encryption
+
+   The Encryption general-header field specifies that the content has
+   been encrypted. Section 13 describes the overall SIP security
+   architecture and algorithms. This header field is intended for end-
+   to-end encryption of requests and responses. Requests are encrypted
+   based on the public key belonging to the entity named in the To
+   header field. Responses are encrypted based on the public key
+   conveyed in the Response-Key header field. Note that the public keys
+   themselves may not be used for the encryption. This depends on the
+   particular algorithms used.
+
+   For any encrypted message, at least the message body and possibly
+   other message header fields are encrypted. An application receiving a
+   request or response containing an Encryption header field decrypts
+   the body and then concatenates the plaintext to the request line and
+   headers of the original message. Message headers in the decrypted
+   part completely replace those with the same field name in the
+   plaintext part.  (Note: If only the body of the message is to be
+   encrypted, the body has to be prefixed with CRLF to allow proper
+   concatenation.) Note that the request method and Request-URI cannot
+   be encrypted.
+
+
+        Encryption only provides privacy; the recipient has no
+        guarantee that the request or response came from the party
+        listed in the From message header, only that the sender
+        used the recipient's public key. However, proxies will not
+        be able to modify the request or response.
+
+
+
+        Encryption         =  "Encryption" ":" encryption-scheme 1*SP
+                              #encryption-params
+        encryption-scheme  =  token
+        encryption-params  =  token "=" ( token | quoted-string )
+
+        The token indicates the form of encryption used; it is
+        described in section 13.
+
+
+
+Handley, et al.             Standards Track                    [Page 54]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The example in Figure 10 shows a message encrypted with ASCII-armored
+   PGP that was generated by applying "pgp -ea" to the payload to be
+   encrypted.
+
+
+   INVITE sip:watson at boston.bell-telephone.com SIP/2.0
+   Via: SIP/2.0/UDP 169.130.12.5
+   From: <sip:a.g.bell at bell-telephone.com>
+   To: T. A. Watson <sip:watson at bell-telephone.com>
+   Call-ID: 187602141351 at worcester.bell-telephone.com
+   Content-Length: 885
+   Encryption: PGP version=2.6.2,encoding=ascii
+
+   hQEMAxkp5GPd+j5xAQf/ZDIfGD/PDOM1wayvwdQAKgGgjmZWe+MTy9NEX8O25Red
+   h0/pyrd/+DV5C2BYs7yzSOSXaj1C/tTK/4do6rtjhP8QA3vbDdVdaFciwEVAcuXs
+   ODxlNAVqyDi1RqFC28BJIvQ5KfEkPuACKTK7WlRSBc7vNPEA3nyqZGBTwhxRSbIR
+   RuFEsHSVojdCam4htcqxGnFwD9sksqs6LIyCFaiTAhWtwcCaN437G7mUYzy2KLcA
+   zPVGq1VQg83b99zPzIxRdlZ+K7+bAnu8Rtu+ohOCMLV3TPXbyp+err1YiThCZHIu
+   X9dOVj3CMjCP66RSHa/ea0wYTRRNYA/G+kdP8DSUcqYAAAE/hZPX6nFIqk7AVnf6
+   IpWHUPTelNUJpzUp5Ou+q/5P7ZAsn+cSAuF2YWtVjCf+SQmBR13p2EYYWHoxlA2/
+   GgKADYe4M3JSwOtqwU8zUJF3FIfk7vsxmSqtUQrRQaiIhqNyG7KxJt4YjWnEjF5E
+   WUIPhvyGFMJaeQXIyGRYZAYvKKklyAJcm29zLACxU5alX4M25lHQd9FR9Zmq6Jed
+   wbWvia6cAIfsvlZ9JGocmQYF7pcuz5pnczqP+/yvRqFJtDGD/v3s++G2R+ViVYJO
+   z/lxGUZaM4IWBCf+4DUjNanZM0oxAE28NjaIZ0rrldDQmO8V9FtPKdHxkqA5iJP+
+   6vGOFti1Ak4kmEz0vM/Nsv7kkubTFhRl05OiJIGr9S1UhenlZv9l6RuXsOY/EwH2
+   z8X9N4MhMyXEVuC9rt8/AUhmVQ==
+   =bOW+
+
+
+
+   Figure 10: PGP Encryption Example
+
+
+
+   Since proxies can base their forwarding decision on any combination
+   of SIP header fields, there is no guarantee that an encrypted request
+   "hiding" header fields will reach the same destination as an
+   otherwise identical un-encrypted request.
+
+6.20 Expires
+
+   The Expires entity-header field gives the date and time after which
+   the message content expires.
+
+   This header field is currently defined only for the REGISTER and
+   INVITE methods. For REGISTER, it is a request and response-header
+   field. In a REGISTER request, the client indicates how long it wishes
+   the registration to be valid. In the response, the server indicates
+
+
+
+Handley, et al.             Standards Track                    [Page 55]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   the earliest expiration time of all registrations. The server MAY
+   choose a shorter time interval than that requested by the client, but
+   SHOULD NOT choose a longer one.
+
+   For INVITE requests, it is a request and response-header field. In a
+   request, the caller can limit the validity of an invitation, for
+   example, if a client wants to limit the time duration of a search or
+   a conference invitation. A user interface MAY take this as a hint to
+   leave the invitation window on the screen even if the user is not
+   currently at the workstation. This also limits the duration of a
+   search. If the request expires before the search completes, the proxy
+   returns a 408 (Request Timeout) status. In a 302 (Moved Temporarily)
+   response, a server can advise the client of the maximal duration of
+   the redirection.
+
+   The value of this field can be either a SIP-date or an integer number
+   of seconds (in decimal), measured from the receipt of the request.
+   The latter approach is preferable for short durations, as it does not
+   depend on clients and servers sharing a synchronized clock.
+   Implementations MAY treat values larger than 2**32-1 (4294967295 or
+   136 years) as equivalent to 2**32-1.
+
+
+
+        Expires  =  "Expires" ":" ( SIP-date | delta-seconds )
+
+
+   Two examples of its use are
+
+     Expires: Thu, 01 Dec 1994 16:00:00 GMT
+     Expires: 5
+
+
+
+6.21 From
+
+   Requests and responses MUST contain a From general-header field,
+   indicating the initiator of the request. The From field MAY contain
+   the "tag" parameter. The server copies the From header field from the
+   request to the response. The optional "display-name" is meant to be
+   rendered by a human-user interface. A system SHOULD use the display
+   name "Anonymous" if the identity of the client is to remain hidden.
+
+   The SIP-URL MUST NOT contain the "transport-param", "maddr-param",
+   "ttl-param", or "headers" elements. A server that receives a SIP-URL
+   with these elements removes them before further processing.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 56]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Even if the "display-name" is empty, the "name-addr" form MUST be
+   used if the "addr-spec" contains a comma, question mark, or
+   semicolon.
+
+
+
+        From         =  ( "From" | "f" ) ":" ( name-addr | addr-spec )
+                        *( ";" addr-params )
+        addr-params  =  tag-param
+        tag-param    =  "tag=" UUID
+        UUID         =  1*( hex | "-" )
+
+
+   Examples:
+
+
+     From: "A. G. Bell" <sip:agb at bell-telephone.com>
+     From: sip:+12125551212 at server.phone2net.com
+     From: Anonymous <sip:c8oqz84zk7z at privacy.org>
+
+
+
+   The "tag" MAY appear in the From field of a request. It MUST be
+   present when it is possible that two instances of a user sharing a
+   SIP address can make call invitations with the same Call-ID.
+
+   The "tag" value MUST be globally unique and cryptographically random
+   with at least 32 bits of randomness. A single user maintains the same
+   tag throughout the call identified by the Call-ID.
+
+
+        Call-ID, To and From are needed to identify a call leg.
+        The distinction between call and call leg matters in calls
+        with multiple responses to a forked request. The format is
+        similar to the equivalent RFC 822 [24] header, but with a
+        URI instead of just an email address.
+
+6.22 Hide
+
+   A client uses the Hide request header field to indicate that it wants
+   the path comprised of the Via header fields (Section 6.40) to be
+   hidden from subsequent proxies and user agents. It can take two
+   forms: Hide: route and Hide:  hop. Hide header fields are typically
+   added by the client user agent, but MAY be added by any proxy along
+   the path.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 57]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   If a request contains the "Hide: route" header field, all following
+   proxies SHOULD hide their previous hop. If a request contains the
+   "Hide: hop" header field, only the next proxy SHOULD hide the
+   previous hop and then remove the Hide option unless it also wants to
+   remain anonymous.
+
+   A server hides the previous hop by encrypting the "host" and "port"
+   parts of the top-most Via header field with an algorithm of its
+   choice. Servers SHOULD add additional "salt" to the "host" and "port"
+   information prior to encryption to prevent malicious downstream
+   proxies from guessing earlier parts of the path based on seeing
+   identical encrypted Via headers. Hidden Via fields are marked with
+   the "hidden" Via option, as described in Section 6.40.
+
+   A server that is capable of hiding Via headers MUST attempt to
+   decrypt all Via headers marked as "hidden" to perform loop detection.
+   Servers that are not capable of hiding can ignore hidden Via fields
+   in their loop detection algorithm.
+
+
+        If hidden headers were not marked, a proxy would have to
+        decrypt all headers to detect loops, just in case one was
+        encrypted, as the Hide: Hop option may have been removed
+        along the way.
+
+   A host MUST NOT add such a "Hide: hop" header field unless it can
+   guarantee it will only send a request for this destination to the
+   same next hop. The reason for this is that it is possible that the
+   request will loop back through this same hop from a downstream proxy.
+   The loop will be detected by the next hop if the choice of next hop
+   is fixed, but could loop an arbitrary number of times otherwise.
+
+   A client requesting "Hide: route" can only rely on keeping the
+   request path private if it sends the request to a trusted proxy.
+   Hiding the route of a SIP request is of limited value if the request
+   results in data packets being exchanged directly between the calling
+   and called user agent.
+
+   The use of Hide header fields is discouraged unless path privacy is
+   truly needed; Hide fields impose extra processing costs and
+   restrictions for proxies and can cause requests to generate 482 (Loop
+   Detected) responses that could otherwise be avoided.
+
+   The encryption of Via header fields is described in more detail in
+   Section 13.
+
+   The Hide header field has the following syntax:
+
+
+
+
+Handley, et al.             Standards Track                    [Page 58]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Hide  =  "Hide" ":" ( "route" | "hop" )
+
+
+6.23 Max-Forwards
+
+   The Max-Forwards request-header field may be used with any SIP method
+   to limit the number of proxies or gateways that can forward the
+   request to the next downstream server. This can also be useful when
+   the client is attempting to trace a request chain which appears to be
+   failing or looping in mid-chain.
+
+
+
+        Max-Forwards  =  "Max-Forwards" ":" 1*DIGIT
+
+
+   The Max-Forwards value is a decimal integer indicating the remaining
+   number of times this request message is allowed to be forwarded.
+
+   Each proxy or gateway recipient of a request containing a Max-
+   Forwards header field MUST check and update its value prior to
+   forwarding the request. If the received value is zero (0), the
+   recipient MUST NOT forward the request. Instead, for the OPTIONS and
+   REGISTER methods, it MUST respond as the final recipient. For all
+   other methods, the server returns 483 (Too many hops).
+
+   If the received Max-Forwards value is greater than zero, then the
+   forwarded message MUST contain an updated Max-Forwards field with a
+   value decremented by one (1).
+
+   Example:
+
+     Max-Forwards: 6
+
+
+
+6.24 Organization
+
+   The Organization general-header field conveys the name of the
+   organization to which the entity issuing the request or response
+   belongs. It MAY also be inserted by proxies at the boundary of an
+   organization.
+
+
+        The field MAY be used by client software to filter calls.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 59]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Organization  =  "Organization" ":" *TEXT-UTF8
+
+
+6.25 Priority
+
+   The Priority request-header field indicates the urgency of the
+   request as perceived by the client.
+
+
+
+        Priority        =  "Priority" ":" priority-value
+        priority-value  =  "emergency" | "urgent" | "normal"
+                        |  "non-urgent"
+
+
+   It is RECOMMENDED that the value of "emergency" only be used when
+   life, limb or property are in imminent danger.
+
+   Examples:
+
+
+     Subject: A tornado is heading our way!
+     Priority: emergency
+
+     Subject: Weekend plans
+     Priority: non-urgent
+
+
+
+
+        These are the values of RFC 2076 [30], with the addition of
+        "emergency".
+
+6.26 Proxy-Authenticate
+
+   The Proxy-Authenticate response-header field MUST be included as part
+   of a 407 (Proxy Authentication Required) response. The field value
+   consists of a challenge that indicates the authentication scheme and
+   parameters applicable to the proxy for this Request-URI.
+
+   Unlike its usage within HTTP, the Proxy-Authenticate header MUST be
+   passed upstream in the response to the UAC. In SIP, only UAC's can
+   authenticate themselves to proxies.
+
+   The syntax for this header is defined in [H14.33]. See 14 for further
+   details on its usage.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 60]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   A client SHOULD cache the credentials used for a particular proxy
+   server and realm for the next request to that server. Credentials
+   are, in general, valid for a specific value of the Request-URI at a
+   particular proxy server. If a client contacts a proxy server that has
+   required authentication in the past, but the client does not have
+   credentials for the particular Request-URI, it MAY attempt to use the
+   most-recently used credential. The server responds with 401
+   (Unauthorized) if the client guessed wrong.
+
+
+        This suggested caching behavior is motivated by proxies
+        restricting phone calls to authenticated users. It seems
+        likely that in most cases, all destinations require the
+        same password. Note that end-to-end authentication is
+        likely to be destination-specific.
+
+6.27 Proxy-Authorization
+
+   The Proxy-Authorization request-header field allows the client to
+   identify itself (or its user) to a proxy which requires
+   authentication. The Proxy-Authorization field value consists of
+   credentials containing the authentication information of the user
+   agent for the proxy and/or realm of the resource being requested.
+
+   Unlike Authorization, the Proxy-Authorization header field applies
+   only to the next outbound proxy that demanded authentication using
+   the Proxy- Authenticate field. When multiple proxies are used in a
+   chain, the Proxy-Authorization header field is consumed by the first
+   outbound proxy that was expecting to receive credentials. A proxy MAY
+   relay the credentials from the client request to the next proxy if
+   that is the mechanism by which the proxies cooperatively authenticate
+   a given request.
+
+   See [H14.34] for a definition of the syntax, and section 14 for a
+   discussion of its usage.
+
+6.28 Proxy-Require
+
+   The Proxy-Require header field is used to indicate proxy-sensitive
+   features that MUST be supported by the proxy. Any Proxy-Require
+   header field features that are not supported by the proxy MUST be
+   negatively acknowledged by the proxy to the client if not supported.
+   Proxy servers treat this field identically to the Require field.
+
+   See Section 6.30 for more details on the mechanics of this message
+   and a usage example.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 61]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.29 Record-Route
+
+   The Record-Route request and response header field is added to a
+   request by any proxy that insists on being in the path of subsequent
+   requests for the same call leg. It contains a globally reachable
+   Request-URI that identifies the proxy server. Each proxy server adds
+   its Request-URI to the beginning of the list.
+
+   The server copies the Record-Route header field unchanged into the
+   response. (Record-Route is only relevant for 2xx responses.)
+
+   The calling user agent client copies the Record-Route header into a
+   Route header field of subsequent requests within the same call leg,
+   reversing the order of requests, so that the first entry is closest
+   to the user agent client. If the response contained a Contact header
+   field, the calling user agent adds its content as the last Route
+   header. Unless this would cause a loop, any client MUST send any
+   subsequent requests for this call leg to the first Request-URI in the
+   Route request header field and remove that entry.
+
+   The calling user agent MUST NOT use the Record-Route header field in
+   requests that contain Route header fields.
+
+
+        Some proxies, such as those controlling firewalls or in an
+        automatic call distribution (ACD) system, need to maintain
+        call state and thus need to receive any BYE and ACK packets
+        for the call.
+
+   The Record-Route header field has the following syntax:
+
+
+        Record-Route  =  "Record-Route" ":" 1# name-addr
+
+
+   Proxy servers SHOULD use the "maddr" URL parameter containing their
+   address to ensure that subsequent requests are guaranteed to reach
+   exactly the same server.
+
+   Example for a request that has traversed the hosts ieee.org and
+   bell-telephone.com , in that order:
+
+     Record-Route: <sip:a.g.bell at bell-telephone.com>,
+       <sip:a.bell at ieee.org>
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 62]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.30 Require
+
+   The Require request-header field is used by clients to tell user
+   agent servers about options that the client expects the server to
+   support in order to properly process the request. If a server does
+   not understand the option, it MUST respond by returning status code
+   420 (Bad Extension) and list those options it does not understand in
+   the Unsupported header.
+
+
+
+        Require  =  "Require" ":" 1#option-tag
+
+
+   Example:
+
+   C->S:   INVITE sip:watson at bell-telephone.com SIP/2.0
+           Require: com.example.billing
+           Payment: sheep_skins, conch_shells
+
+   S->C:   SIP/2.0 420 Bad Extension
+           Unsupported: com.example.billing
+
+
+
+        This is to make sure that the client-server interaction
+        will proceed without delay when all options are understood
+        by both sides, and only slow down if options are not
+        understood (as in the example above).  For a well-matched
+        client-server pair, the interaction proceeds quickly,
+        saving a round-trip often required by negotiation
+        mechanisms. In addition, it also removes ambiguity when the
+        client requires features that the server does not
+        understand. Some features, such as call handling fields,
+        are only of interest to end systems.
+
+   Proxy and redirect servers MUST ignore features that are not
+   understood. If a particular extension requires that intermediate
+   devices support it, the extension MUST be tagged in the Proxy-Require
+   field as well (see Section 6.28).
+
+6.31 Response-Key
+
+   The Response-Key request-header field can be used by a client to
+   request the key that the called user agent SHOULD use to encrypt the
+   response with. The syntax is:
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 63]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Response-Key  =  "Response-Key" ":" key-scheme 1*SP #key-param
+        key-scheme    =  token
+        key-param     =  token "=" ( token | quoted-string )
+
+
+   The "key-scheme" gives the type of encryption to be used for the
+   response. Section 13 describes security schemes.
+
+   If the client insists that the server return an encrypted response,
+   it includes a
+
+                  Require: org.ietf.sip.encrypt-response
+
+   header field in its request. If the server cannot encrypt for
+   whatever reason, it MUST follow normal Require header field
+   procedures and return a 420 (Bad Extension) response. If this Require
+   header field is not present, a server SHOULD still encrypt if it can.
+
+6.32 Retry-After
+
+   The Retry-After general-header field can be used with a 503 (Service
+   Unavailable) response to indicate how long the service is expected to
+   be unavailable to the requesting client and with a 404 (Not Found),
+   600 (Busy), or 603 (Decline) response to indicate when the called
+   party anticipates being available again. The value of this field can
+   be either an SIP-date or an integer number of seconds (in decimal)
+   after the time of the response.
+
+   A REGISTER request MAY include this header field when deleting
+   registrations with "Contact: * ;expires: 0". The Retry-After value
+   then indicates when the user might again be reachable. The registrar
+   MAY then include this information in responses to future calls.
+
+   An optional comment can be used to indicate additional information
+   about the time of callback. An optional "duration" parameter
+   indicates how long the called party will be reachable starting at the
+   initial time of availability. If no duration parameter is given, the
+   service is assumed to be available indefinitely.
+
+
+
+        Retry-After  =  "Retry-After" ":" ( SIP-date | delta-seconds )
+                        [ comment ] [ ";" "duration" "=" delta-seconds ]
+
+
+   Examples of its use are
+
+     Retry-After: Mon, 21 Jul 1997 18:48:34 GMT (I'm in a meeting)
+
+
+
+Handley, et al.             Standards Track                    [Page 64]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+     Retry-After: Mon, 01 Jan 9999 00:00:00 GMT
+       (Dear John: Don't call me back, ever)
+     Retry-After: Fri, 26 Sep 1997 21:00:00 GMT;duration=3600
+     Retry-After: 120
+
+
+
+   In the third example, the callee is reachable for one hour starting
+   at 21:00 GMT. In the last example, the delay is 2 minutes.
+
+6.33 Route
+
+   The Route request-header field determines the route taken by a
+   request. Each host removes the first entry and then proxies the
+   request to the host listed in that entry, also using it as the
+   Request-URI. The operation is further described in Section 6.29.
+
+   The Route header field has the following syntax:
+
+
+        Route  =  "Route" ":" 1# name-addr
+
+
+6.34 Server
+
+   The Server response-header field contains information about the
+   software used by the user agent server to handle the request. The
+   syntax for this field is defined in [H14.39].
+
+6.35 Subject
+
+   This is intended to provide a summary, or to indicate the nature, of
+   the call, allowing call filtering without having to parse the session
+   description. (Also, the session description does not have to use the
+   same subject indication as the invitation.)
+
+
+
+        Subject  =  ( "Subject" | "s" ) ":" *TEXT-UTF8
+
+
+   Example:
+
+
+     Subject: Tune in - they are talking about your work!
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 65]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.36 Timestamp
+
+   The timestamp general-header field describes when the client sent the
+   request to the server. The value of the timestamp is of significance
+   only to the client and it MAY use any timescale. The server MUST echo
+   the exact same value and MAY, if it has accurate information about
+   this, add a floating point number indicating the number of seconds
+   that have elapsed since it has received the request. The timestamp is
+   used by the client to compute the round-trip time to the server so
+   that it can adjust the timeout value for retransmissions.
+
+
+
+        Timestamp  =  "Timestamp" ":" *(DIGIT) [ "." *(DIGIT) ] [ delay ]
+        delay      =  *(DIGIT) [ "." *(DIGIT) ]
+
+
+   Note that there MUST NOT be any LWS between a DIGIT and the decimal
+   point.
+
+6.37 To
+
+   The To general-header field specifies recipient of the request, with
+   the same SIP URL syntax as the From field.
+
+
+
+        To  =  ( "To" | "t" ) ":" ( name-addr | addr-spec )
+               *( ";" addr-params )
+
+
+   Requests and responses MUST contain a To general-header field,
+   indicating the desired recipient of the request. The optional
+   "display-name" is meant to be rendered by a human-user interface.
+   The UAS or redirect server copies the To header field into its
+   response, and MUST add a "tag" parameter if the request contained
+   more than one Via header field.
+
+
+        If there was more than one Via header field, the request
+        was handled by at least one proxy server. Since the
+        receiver cannot know whether any of the proxy servers
+        forked the request, it is safest to assume that they might
+        have.
+
+   The SIP-URL MUST NOT contain the "transport-param", "maddr-param",
+   "ttl-param", or "headers" elements. A server that receives a SIP-URL
+   with these elements removes them before further processing.
+
+
+
+Handley, et al.             Standards Track                    [Page 66]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The "tag" parameter serves as a general mechanism to distinguish
+   multiple instances of a user identified by a single SIP URL. As
+   proxies can fork requests, the same request can reach multiple
+   instances of a user (mobile and home phones, for example). As each
+   can respond, there needs to be a means to distinguish the responses
+   from each at the caller. The situation also arises with multicast
+   requests. The tag in the To header field serves to distinguish
+   responses at the UAC. It MUST be placed in the To field of the
+   response by each instance when there is a possibility that the
+   request was forked at an intermediate proxy. The "tag" MUST be added
+   by UAS, registrars and redirect servers, but MUST NOT be inserted
+   into responses forwarded upstream by proxies. The "tag" is added for
+   all definitive responses for all methods, and MAY be added for
+   informational responses from a UAS or redirect server. All subsequent
+   transactions between two entities MUST include the "tag" parameter,
+   as described in Section 11.
+
+   See Section 6.21 for details of the "tag" parameter.
+
+   The "tag" parameter in To headers is ignored when matching responses
+   to requests that did not contain a "tag" in their To header.
+
+   A SIP server returns a 400 (Bad Request) response if it receives a
+   request with a To header field containing a URI with a scheme it does
+   not recognize.
+
+   Even if the "display-name" is empty, the "name-addr" form MUST be
+   used if the "addr-spec" contains a comma, question mark, or
+   semicolon.
+
+   The following are examples of valid To headers:
+
+     To: The Operator <sip:operator at cs.columbia.edu>;tag=287447
+     To: sip:+12125551212 at server.phone2net.com
+
+
+
+
+        Call-ID, To and From are needed to identify a call leg.
+        The distinction between call and call leg matters in calls
+        with multiple responses from a forked request. The "tag" is
+        added to the To header field in the response to allow
+        forking of future requests for the same call by proxies,
+        while addressing only one of the possibly several
+        responding user agent servers. It also allows several
+        instances of the callee to send requests that can be
+        distinguished.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 67]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+6.38 Unsupported
+
+   The Unsupported response-header field lists the features not
+   supported by the server. See Section 6.30 for a usage example and
+   motivation.
+
+   Syntax:
+
+
+
+        Unsupported  =  "Unsupported" ":" 1#option-tag
+
+
+6.39 User-Agent
+
+   The User-Agent general-header field contains information about the
+   client user agent originating the request. The syntax and semantics
+   are defined in [H14.42].
+
+6.40 Via
+
+   The Via field indicates the path taken by the request so far.  This
+   prevents request looping and ensures replies take the same path as
+   the requests, which assists in firewall traversal and other unusual
+   routing situations.
+
+6.40.1 Requests
+
+   The client originating the request MUST insert into the request a Via
+   field containing its host name or network address and, if not the
+   default port number, the port number at which it wishes to receive
+   responses. (Note that this port number can differ from the UDP source
+   port number of the request.) A fully-qualified domain name is
+   RECOMMENDED. Each subsequent proxy server that sends the request
+   onwards MUST add its own additional Via field before any existing Via
+   fields. A proxy that receives a redirection (3xx) response and then
+   searches recursively, MUST use the same Via headers as on the
+   original proxied request.
+
+   A proxy SHOULD check the top-most Via header field to ensure that it
+   contains the sender's correct network address, as seen from that
+   proxy. If the sender's address is incorrect, the proxy MUST add an
+   additional "received" attribute, as described 6.40.2.
+
+
+        A host behind a network address translator (NAT) or
+        firewall may not be able to insert a network address into
+        the Via header that can be reached by the next hop beyond
+
+
+
+Handley, et al.             Standards Track                    [Page 68]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        the NAT. Use of the received attribute allows SIP requests
+        to traverse NAT's which only modify the source IP address.
+        NAT's which modify port numbers, called Network Address
+        Port Translator's (NAPT) will not properly pass SIP when
+        transported on UDP, in which case an application layer
+        gateway is required. When run over TCP, SIP stands a better
+        chance of traversing NAT's, since its behavior is similar
+        to HTTP in this case (but of course on different ports).
+
+   A proxy sending a request to a multicast address MUST add the "maddr"
+   parameter to its Via header field, and SHOULD add the "ttl"
+   parameter. If a server receives a request which contained an "maddr"
+   parameter in the topmost Via field, it SHOULD send the response to
+   the multicast address listed in the "maddr" parameter.
+
+   If a proxy server receives a request which contains its own address
+   in the Via header value, it MUST respond with a 482 (Loop Detected)
+   status code.
+
+   A proxy server MUST NOT forward a request to a multicast group which
+   already appears in any of the Via headers.
+
+
+        This prevents a malfunctioning proxy server from causing
+        loops. Also, it cannot be guaranteed that a proxy server
+        can always detect that the address returned by a location
+        service refers to a host listed in the Via list, as a
+        single host may have aliases or several network interfaces.
+
+6.40.2 Receiver-tagged Via Header Fields
+
+   Normally, every host that sends or forwards a SIP message adds a Via
+   field indicating the path traversed. However, it is possible that
+   Network Address Translators (NATs) changes the source address and
+   port of the request (e.g., from net-10 to a globally routable
+   address), in which case the Via header field cannot be relied on to
+   route replies. To prevent this, a proxy SHOULD check the top-most Via
+   header field to ensure that it contains the sender's correct network
+   address, as seen from that proxy. If the sender's address is
+   incorrect, the proxy MUST add a "received" parameter to the Via
+   header field inserted by the previous hop. Such a modified Via header
+   field is known as a receiver-tagged Via header field. An example is:
+
+
+     Via: SIP/2.0/UDP erlang.bell-telephone.com:5060
+     Via: SIP/2.0/UDP 10.0.0.1:5060 ;received=199.172.136.3
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 69]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   In this example, the message originated from 10.0.0.1 and traversed a
+   NAT with the external address border.ieee.org (199.172.136.3) to
+   reach erlang.bell-telephone.com.  The latter noticed the mismatch,
+   and added a parameter to the previous hop's Via header field,
+   containing the address that the packet actually came from. (Note that
+   the NAT border.ieee.org is not a SIP server.)
+
+6.40.3 Responses
+
+   Via header fields in responses are processed by a proxy or UAC
+   according to the following rules:
+
+        1.   The first Via header field should indicate the proxy or
+             client processing this response. If it does not, discard
+             the message.  Otherwise, remove this Via field.
+
+        2.   If there is no second Via header field, this response is
+             destined for this client. Otherwise, the processing depends
+             on whether the Via field contains a "maddr" parameter or is
+             a receiver-tagged field:
+
+             - If the second Via header field contains a "maddr"
+               parameter, send the response to the multicast address
+               listed there, using the port indicated in "sent-by", or
+               port 5060 if none is present. The response SHOULD be sent
+               using the TTL indicated in the "ttl" parameter, or with a
+               TTL of 1 if that parameter is not present. For
+               robustness, responses MUST be sent to the address
+               indicated in the "maddr" parameter even if it is not a
+               multicast address.
+
+             - If the second Via header field does not contain a "maddr"
+               parameter and is a receiver-tagged field (Section
+               6.40.2), send the message to the address in the
+               "received" parameter, using the port indicated in the
+               "sent-by" value, or using port 5060 if none is present.
+
+             - If neither of the previous cases apply, send the message
+               to the address indicated by the "sent-by" value in the
+               second Via header field.
+
+6.40.4 User Agent and Redirect Servers
+
+   A UAS or redirect server sends a response based on one of the
+   following rules:
+
+        o  If the first Via header field in the request contains a
+          "maddr" parameter, send the response to the multicast address
+
+
+
+Handley, et al.             Standards Track                    [Page 70]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+          listed there, using the port indicated in "sent-by", or port
+          5060 if none is present. The response SHOULD be sent using the
+          TTL indicated in the "ttl" parameter, or with a TTL of 1 if
+          that parameter is not present. For robustness, responses MUST
+          be sent to the address indicated in the "maddr" parameter even
+          if it is not a multicast address.
+
+        o  If the address in the "sent-by" value of the first Via field
+          differs from the source address of the packet, send the
+          response to the actual packet source address, similar to the
+          treatment for receiver-tagged Via header fields (Section
+          6.40.2).
+
+        o  If neither of these conditions is true, send the response to
+          the address contained in the "sent-by" value. If the request
+          was sent using TCP, use the existing TCP connection if
+          available.
+
+6.40.5 Syntax
+
+   The format for a Via header field is shown in Fig. 11. The defaults
+   for "protocol-name" and "transport" are "SIP" and "UDP",
+   respectively. The "maddr" parameter, designating the multicast
+   address, and the "ttl" parameter, designating the time-to-live (TTL)
+   value, are included only if the request was sent via multicast. The
+   "received" parameter is added only for receiver-added Via fields
+   (Section 6.40.2). For reasons of privacy, a client or proxy may wish
+   to hide its Via information by encrypting it (see Section 6.22). The
+   "hidden" parameter is included if this header field was hidden by the
+   upstream proxy (see 6.22). Note that privacy of the proxy relies on
+   the cooperation of the next hop, as the next-hop proxy will, by
+   necessity, know the IP address and port number of the source host.
+
+
+   The "branch" parameter is included by every forking proxy.  The token
+   MUST be unique for each distinct request generated when a proxy
+   forks. CANCEL requests MUST have the same branch value as the
+   corresponding forked request. When a response arrives at the proxy it
+   can use the branch value to figure out which branch the response
+   corresponds to. A proxy which generates a single request (non-
+   forking) MAY also insert the "branch" parameter. The identifier has
+   to be unique only within a set of isomorphic requests.
+
+
+     Via: SIP/2.0/UDP first.example.com:4000;ttl=16
+       ;maddr=224.2.0.1 ;branch=a7c6a8dlze (Example)
+     Via: SIP/2.0/UDP adk8
+
+
+
+
+Handley, et al.             Standards Track                    [Page 71]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+  Via              = ( "Via" | "v") ":" 1#( sent-protocol sent-by
+                     *( ";" via-params ) [ comment ] )
+  via-params       = via-hidden | via-ttl | via-maddr 
+                   | via-received | via-branch
+  via-hidden       = "hidden"
+  via-ttl          = "ttl" "=" ttl
+  via-maddr        = "maddr" "=" maddr
+  via-received	   = "received" "=" host
+  via-branch       = "branch" "=" token
+  sent-protocol    = protocol-name "/" protocol-version "/" transport
+  protocol-name    = "SIP" | token
+  protocol-version = token
+  transport        = "UDP" | "TCP" | token
+  sent-by          = ( host [ ":" port ] ) | ( concealed-host )
+  concealed-host   = token
+  ttl              = 1*3DIGIT     ; 0 to 255
+
+
+   Figure 11: Syntax of Via header field
+
+
+6.41 Warning
+
+   The Warning response-header field is used to carry additional
+   information about the status of a response. Warning headers are sent
+   with responses and have the following format:
+
+
+
+        Warning        =  "Warning" ":" 1#warning-value
+        warning-value  =  warn-code SP warn-agent SP warn-text
+        warn-code      =  3DIGIT
+        warn-agent     =  ( host [ ":" port ] ) | pseudonym
+                          ;  the name or pseudonym of the server adding
+                          ;  the Warning header, for use in debugging
+        warn-text      =  quoted-string
+
+
+   A response MAY carry more than one Warning header.
+
+   The "warn-text" should be in a natural language that is most likely
+   to be intelligible to the human user receiving the response.  This
+   decision can be based on any available knowledge, such as the
+   location of the cache or user, the Accept-Language field in a
+   request, or the Content-Language field in a response. The default
+   language is i-default [31].
+
+
+
+Handley, et al.             Standards Track                    [Page 72]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Any server MAY add Warning headers to a response. Proxy servers MUST
+   place additional Warning headers before any Authorization headers.
+   Within that constraint, Warning headers MUST be added after any
+   existing Warning headers not covered by a signature. A proxy server
+   MUST NOT delete any Warning header field that it received with a
+   response.
+
+   When multiple Warning headers are attached to a response, the user
+   agent SHOULD display as many of them as possible, in the order that
+   they appear in the response. If it is not possible to display all of
+   the warnings, the user agent first displays warnings that appear
+   early in the response.
+
+   The warn-code consists of three digits. A first digit of "3"
+   indicates warnings specific to SIP.
+
+   This is a list of the currently-defined "warn-code"s, each with a
+   recommended warn-text in English, and a description of its meaning.
+   Note that these warnings describe failures induced by the session
+   description.
+
+   Warnings 300 through 329 are reserved for indicating problems with
+   keywords in the session description, 330 through 339 are warnings
+   related to basic network services requested in the session
+   description, 370 through 379 are warnings related to quantitative QoS
+   parameters requested in the session description, and 390 through 399
+   are miscellaneous warnings that do not fall into one of the above
+   categories.
+
+   300 Incompatible network protocol: One or more network protocols
+        contained in the session description are not available.
+
+   301 Incompatible network address formats: One or more network address
+        formats contained in the session description are not available.
+
+   302 Incompatible transport protocol: One or more transport protocols
+        described in the session description are not available.
+
+   303 Incompatible bandwidth units: One or more bandwidth measurement
+        units contained in the session description were not understood.
+
+   304 Media type not available: One or more media types contained in
+        the session description are not available.
+
+   305 Incompatible media format: One or more media formats contained in
+        the session description are not available.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 73]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   306 Attribute not understood: One or more of the media attributes in
+        the session description are not supported.
+
+   307 Session description parameter not understood: A parameter other
+        than those listed above was not understood.
+
+   330 Multicast not available: The site where the user is located does
+        not support multicast.
+
+   331 Unicast not available: The site where the user is located does
+        not support unicast communication (usually due to the presence
+        of a firewall).
+
+   370 Insufficient bandwidth: The bandwidth specified in the session
+        description or defined by the media exceeds that known to be
+        available.
+
+   399 Miscellaneous warning: The warning text can include arbitrary
+        information to be presented to a human user, or logged. A system
+        receiving this warning MUST NOT take any automated action.
+
+
+        1xx and 2xx have been taken by HTTP/1.1.
+
+   Additional "warn-code"s, as in the example below, can be defined
+   through IANA.
+
+   Examples:
+
+
+     Warning: 307 isi.edu "Session parameter 'foo' not understood"
+     Warning: 301 isi.edu "Incompatible network address type 'E.164'"
+
+
+
+6.42 WWW-Authenticate
+
+   The WWW-Authenticate response-header field MUST be included in 401
+   (Unauthorized) response messages. The field value consists of at
+   least one challenge that indicates the authentication scheme(s) and
+   parameters applicable to the Request-URI. See [H14.46] for a
+   definition of the syntax, and section 14 for an overview of usage.
+
+   The content of the "realm" parameter SHOULD be displayed to the user.
+   A user agent SHOULD cache the authorization credentials for a given
+   value of the destination (To header) and "realm" and attempt to re-
+   use these values on the next request for that destination.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 74]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   In addition to the "basic" and "digest" authentication schemes
+   defined in the specifications cited above, SIP defines a new scheme,
+   PGP (RFC 2015, [32]), Section 15. Other schemes, such as S/MIME, are
+   for further study.
+
+7 Status Code Definitions
+
+   The response codes are consistent with, and extend, HTTP/1.1 response
+   codes. Not all HTTP/1.1 response codes are appropriate, and only
+   those that are appropriate are given here. Other HTTP/1.1 response
+   codes SHOULD NOT be used. Response codes not defined by HTTP/1.1 have
+   codes x80 upwards to avoid clashes with future HTTP response codes.
+   Also, SIP defines a new class, 6xx. The default behavior for unknown
+   response codes is given for each category of codes.
+
+7.1 Informational 1xx
+
+   Informational responses indicate that the server or proxy contacted
+   is performing some further action and does not yet have a definitive
+   response. The client SHOULD wait for a further response from the
+   server, and the server SHOULD send such a response without further
+   prompting. A server SHOULD send a 1xx response if it expects to take
+   more than 200 ms to obtain a final response. A server MAY issue zero
+   or more 1xx responses, with no restriction on their ordering or
+   uniqueness. Note that 1xx responses are not transmitted reliably,
+   that is, they do not cause the client to send an ACK. Servers are
+   free to retransmit informational responses and clients can inquire
+   about the current state of call processing by re-sending the request.
+
+7.1.1 100 Trying
+
+   Some unspecified action is being taken on behalf of this call (e.g.,
+   a database is being consulted), but the user has not yet been
+   located.
+
+7.1.2 180 Ringing
+
+   The called user agent has located a possible location where the user
+   has registered recently and is trying to alert the user.
+
+7.1.3 181 Call Is Being Forwarded
+
+   A proxy server MAY use this status code to indicate that the call is
+   being forwarded to a different set of destinations.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 75]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.1.4 182 Queued
+
+   The called party is temporarily unavailable, but the callee has
+   decided to queue the call rather than reject it. When the callee
+   becomes available, it will return the appropriate final status
+   response. The reason phrase MAY give further details about the status
+   of the call, e.g., "5 calls queued; expected waiting time is 15
+   minutes". The server MAY issue several 182 responses to update the
+   caller about the status of the queued call.
+
+7.2 Successful 2xx
+
+   The request was successful and MUST terminate a search.
+
+7.2.1 200 OK
+
+   The request has succeeded. The information returned with the response
+   depends on the method used in the request, for example:
+
+   BYE: The call has been terminated. The message body is empty.
+
+   CANCEL: The search has been cancelled. The message body is empty.
+
+   INVITE: The callee has agreed to participate; the message body
+        indicates the callee's capabilities.
+
+   OPTIONS: The callee has agreed to share its capabilities, included in
+        the message body.
+
+   REGISTER: The registration has succeeded. The client treats the
+        message body according to its Content-Type.
+
+7.3 Redirection 3xx
+
+   3xx responses give information about the user's new location, or
+   about alternative services that might be able to satisfy the call.
+   They SHOULD terminate an existing search, and MAY cause the initiator
+   to begin a new search if appropriate.
+
+   Any redirection (3xx) response MUST NOT suggest any of the addresses
+   in the Via (Section 6.40) path of the request in the Contact header
+   field. (Addresses match if their host and port number match.)
+
+   To avoid forwarding loops, a user agent client or proxy MUST check
+   whether the address returned by a redirect server equals an address
+   tried earlier.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 76]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.3.1 300 Multiple Choices
+
+   The address in the request resolved to several choices, each with its
+   own specific location, and the user (or user agent) can select a
+   preferred communication end point and redirect its request to that
+   location.
+
+   The response SHOULD include an entity containing a list of resource
+   characteristics and location(s) from which the user or user agent can
+   choose the one most appropriate, if allowed by the Accept request
+   header. The entity format is specified by the media type given in the
+   Content-Type header field. The choices SHOULD also be listed as
+   Contact fields (Section 6.13).  Unlike HTTP, the SIP response MAY
+   contain several Contact fields or a list of addresses in a Contact
+   field. User agents MAY use the Contact header field value for
+   automatic redirection or MAY ask the user to confirm a choice.
+   However, this specification does not define any standard for such
+   automatic selection.
+
+
+        This status response is appropriate if the callee can be
+        reached at several different locations and the server
+        cannot or prefers not to proxy the request.
+
+7.3.2 301 Moved Permanently
+
+   The user can no longer be found at the address in the Request-URI and
+   the requesting client SHOULD retry at the new address given by the
+   Contact header field (Section 6.13). The caller SHOULD update any
+   local directories, address books and user location caches with this
+   new value and redirect future requests to the address(es) listed.
+
+7.3.3 302 Moved Temporarily
+
+   The requesting client SHOULD retry the request at the new address(es)
+   given by the Contact header field (Section 6.13).  The duration of
+   the redirection can be indicated through an Expires (Section 6.20)
+   header. If there is no explicit expiration time, the address is only
+   valid for this call and MUST NOT be cached for future calls.
+
+7.3.4 305 Use Proxy
+
+   The requested resource MUST be accessed through the proxy given by
+   the Contact field. The Contact field gives the URI of the proxy. The
+   recipient is expected to repeat this single request via the proxy.
+   305 responses MUST only be generated by user agent servers.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 77]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.3.5 380 Alternative Service
+
+   The call was not successful, but alternative services are possible.
+   The alternative services are described in the message body of the
+   response.  Formats for such bodies are not defined here, and may be
+   the subject of future standardization.
+
+7.4 Request Failure 4xx
+
+   4xx responses are definite failure responses from a particular
+   server.  The client SHOULD NOT retry the same request without
+   modification (e.g., adding appropriate authorization). However, the
+   same request to a different server might be successful.
+
+7.4.1 400 Bad Request
+
+   The request could not be understood due to malformed syntax.
+
+7.4.2 401 Unauthorized
+
+   The request requires user authentication.
+
+7.4.3 402 Payment Required
+
+   Reserved for future use.
+
+7.4.4 403 Forbidden
+
+   The server understood the request, but is refusing to fulfill it.
+   Authorization will not help, and the request SHOULD NOT be repeated.
+
+7.4.5 404 Not Found
+
+   The server has definitive information that the user does not exist at
+   the domain specified in the Request-URI. This status is also returned
+   if the domain in the Request-URI does not match any of the domains
+   handled by the recipient of the request.
+
+7.4.6 405 Method Not Allowed
+
+   The method specified in the Request-Line is not allowed for the
+   address identified by the Request-URI. The response MUST include an
+   Allow header field containing a list of valid methods for the
+   indicated address.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 78]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.4.7 406 Not Acceptable
+
+   The resource identified by the request is only capable of generating
+   response entities which have content characteristics not acceptable
+   according to the accept headers sent in the request.
+
+7.4.8 407 Proxy Authentication Required
+
+   This code is similar to 401 (Unauthorized), but indicates that the
+   client MUST first authenticate itself with the proxy. The proxy MUST
+   return a Proxy-Authenticate header field (section 6.26) containing a
+   challenge applicable to the proxy for the requested resource. The
+   client MAY repeat the request with a suitable Proxy-Authorization
+   header field (section 6.27). SIP access authentication is explained
+   in section 13.2 and 14.
+
+   This status code is used for applications where access to the
+   communication channel (e.g., a telephony gateway) rather than the
+   callee requires authentication.
+
+7.4.9 408 Request Timeout
+
+   The server could not produce a response, e.g., a user location,
+   within the time indicated in the Expires request-header field. The
+   client MAY repeat the request without modifications at any later
+   time.
+
+7.4.10 409 Conflict
+
+   The request could not be completed due to a conflict with the current
+   state of the resource. This response is returned if the action
+   parameter in a REGISTER request conflicts with existing
+   registrations.
+
+7.4.11 410 Gone
+
+   The requested resource is no longer available at the server and no
+   forwarding address is known. This condition is expected to be
+   considered permanent. If the server does not know, or has no facility
+   to determine, whether or not the condition is permanent, the status
+   code 404 (Not Found) SHOULD be used instead.
+
+7.4.12 411 Length Required
+
+   The server refuses to accept the request without a defined Content-
+   Length. The client MAY repeat the request if it adds a valid
+   Content-Length header field containing the length of the message-body
+   in the request message.
+
+
+
+Handley, et al.             Standards Track                    [Page 79]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.4.13 413 Request Entity Too Large
+
+   The server is refusing to process a request because the request
+   entity is larger than the server is willing or able to process. The
+   server MAY close the connection to prevent the client from continuing
+   the request.
+
+   If the condition is temporary, the server SHOULD include a Retry-
+   After header field to indicate that it is temporary and after what
+   time the client MAY try again.
+
+7.4.14 414 Request-URI Too Long
+
+   The server is refusing to service the request because the Request-URI
+   is longer than the server is willing to interpret.
+
+7.4.15 415 Unsupported Media Type
+
+   The server is refusing to service the request because the message
+   body of the request is in a format not supported by the requested
+   resource for the requested method. The server SHOULD return a list of
+   acceptable formats using the Accept, Accept-Encoding and Accept-
+   Language header fields.
+
+7.4.16 420 Bad Extension
+
+   The server did not understand the protocol extension specified in a
+   Require (Section 6.30) header field.
+
+7.4.17 480 Temporarily Unavailable
+
+   The callee's end system was contacted successfully but the callee is
+   currently unavailable (e.g., not logged in or logged in in such a
+   manner as to preclude communication with the callee). The response
+   MAY indicate a better time to call in the Retry-After header. The
+   user could also be available elsewhere (unbeknownst to this host),
+   thus, this response does not terminate any searches. The reason
+   phrase SHOULD indicate a more precise cause as to why the callee is
+   unavailable. This value SHOULD be setable by the user agent. Status
+   486 (Busy Here) MAY be used to more precisely indicate a particular
+   reason for the call failure.
+
+   This status is also returned by a redirect server that recognizes the
+   user identified by the Request-URI, but does not currently have a
+   valid forwarding location for that user.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 80]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.4.18 481 Call Leg/Transaction Does Not Exist
+
+   This status is returned under two conditions: The server received a
+   BYE request that does not match any existing call leg or the server
+   received a CANCEL request that does not match any existing
+   transaction. (A server simply discards an ACK referring to an unknown
+   transaction.)
+
+7.4.19 482 Loop Detected
+
+   The server received a request with a Via (Section 6.40) path
+   containing itself.
+
+7.4.20 483 Too Many Hops
+
+   The server received a request that contains more Via entries (hops)
+   (Section 6.40) than allowed by the Max-Forwards (Section 6.23) header
+   field.
+
+7.4.21 484 Address Incomplete
+
+   The server received a request with a To (Section 6.37) address or
+   Request-URI that was incomplete. Additional information SHOULD be
+   provided.
+
+
+        This status code allows overlapped dialing. With overlapped
+        dialing, the client does not know the length of the dialing
+        string. It sends strings of increasing lengths, prompting
+        the user for more input, until it no longer receives a 484
+        status response.
+
+7.4.22 485 Ambiguous
+
+   The callee address provided in the request was ambiguous. The
+   response MAY contain a listing of possible unambiguous addresses in
+   Contact headers.
+
+   Revealing alternatives can infringe on privacy concerns of the user
+   or the organization. It MUST be possible to configure a server to
+   respond with status 404 (Not Found) or to suppress the listing of
+   possible choices if the request address was ambiguous.
+
+   Example response to a request with the URL lee at example.com :
+
+   485 Ambiguous SIP/2.0
+   Contact: Carol Lee <sip:carol.lee at example.com>
+
+
+
+
+Handley, et al.             Standards Track                    [Page 81]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Contact: Ping Lee <sip:p.lee at example.com>
+   Contact: Lee M. Foote <sip:lee.foote at example.com>
+
+
+
+        Some email and voice mail systems provide this
+        functionality. A status code separate from 3xx is used
+        since the semantics are different: for 300, it is assumed
+        that the same person or service will be reached by the
+        choices provided. While an automated choice or sequential
+        search makes sense for a 3xx response, user intervention is
+        required for a 485 response.
+
+7.4.23 486 Busy Here
+
+   The callee's end system was contacted successfully but the callee is
+   currently not willing or able to take additional calls. The response
+   MAY indicate a better time to call in the Retry-After header. The
+   user could also be available elsewhere, such as through a voice mail
+   service, thus, this response does not terminate any searches.  Status
+   600 (Busy Everywhere) SHOULD be used if the client knows that no
+   other end system will be able to accept this call.
+
+7.5 Server Failure 5xx
+
+   5xx responses are failure responses given when a server itself has
+   erred. They are not definitive failures, and MUST NOT terminate a
+   search if other possible locations remain untried.
+
+7.5.1 500 Server Internal Error
+
+   The server encountered an unexpected condition that prevented it from
+   fulfilling the request. The client MAY display the specific error
+   condition, and MAY retry the request after several seconds.
+
+7.5.2 501 Not Implemented
+
+   The server does not support the functionality required to fulfill the
+   request. This is the appropriate response when the server does not
+   recognize the request method and is not capable of supporting it for
+   any user.
+
+7.5.3 502 Bad Gateway
+
+   The server, while acting as a gateway or proxy, received an invalid
+   response from the downstream server it accessed in attempting to
+   fulfill the request.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 82]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.5.4 503 Service Unavailable
+
+   The server is currently unable to handle the request due to a
+   temporary overloading or maintenance of the server. The implication
+   is that this is a temporary condition which will be alleviated after
+   some delay. If known, the length of the delay MAY be indicated in a
+   Retry-After header. If no Retry-After is given, the client MUST
+   handle the response as it would for a 500 response.
+
+   Note: The existence of the 503 status code does not imply that a
+   server has to use it when becoming overloaded. Some servers MAY wish
+   to simply refuse the connection.
+
+7.5.5 504 Gateway Time-out
+
+   The server, while acting as a gateway, did not receive a timely
+   response from the server (e.g., a location server) it accessed in
+   attempting to complete the request.
+
+7.5.6 505 Version Not Supported
+
+   The server does not support, or refuses to support, the SIP protocol
+   version that was used in the request message. The server is
+   indicating that it is unable or unwilling to complete the request
+   using the same major version as the client, other than with this
+   error message. The response MAY contain an entity describing why that
+   version is not supported and what other protocols are supported by
+   that server. The format for such an entity is not defined here and
+   may be the subject of future standardization.
+
+7.6 Global Failures 6xx
+
+   6xx responses indicate that a server has definitive information about
+   a particular user, not just the particular instance indicated in the
+   Request-URI. All further searches for this user are doomed to failure
+   and pending searches SHOULD be terminated.
+
+7.6.1 600 Busy Everywhere
+
+   The callee's end system was contacted successfully but the callee is
+   busy and does not wish to take the call at this time. The response
+   MAY indicate a better time to call in the Retry-After header. If the
+   callee does not wish to reveal the reason for declining the call, the
+   callee uses status code 603 (Decline) instead. This status response
+   is returned only if the client knows that no other end point (such as
+   a voice mail system) will answer the request. Otherwise, 486 (Busy
+   Here) should be returned.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 83]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+7.6.2 603 Decline
+
+   The callee's machine was successfully contacted but the user
+   explicitly does not wish to or cannot participate. The response MAY
+   indicate a better time to call in the Retry-After header.
+
+7.6.3 604 Does Not Exist Anywhere
+
+   The server has authoritative information that the user indicated in
+   the To request field does not exist anywhere. Searching for the user
+   elsewhere will not yield any results.
+
+7.6.4 606 Not Acceptable
+
+   The user's agent was contacted successfully but some aspects of the
+   session description such as the requested media, bandwidth, or
+   addressing style were not acceptable.
+
+   A 606 (Not Acceptable) response means that the user wishes to
+   communicate, but cannot adequately support the session described. The
+   606 (Not Acceptable) response MAY contain a list of reasons in a
+   Warning header field describing why the session described cannot be
+   supported. Reasons are listed in Section 6.41.  It is hoped that
+   negotiation will not frequently be needed, and when a new user is
+   being invited to join an already existing conference, negotiation may
+   not be possible. It is up to the invitation initiator to decide
+   whether or not to act on a 606 (Not Acceptable) response.
+
+8 SIP Message Body
+
+8.1 Body Inclusion
+
+   Requests MAY contain message bodies unless otherwise noted. Within
+   this specification, the BYE request MUST NOT contain a message body.
+   For ACK, INVITE and OPTIONS, the message body is always a session
+   description. The use of message bodies for REGISTER requests is for
+   further study.
+
+   For response messages, the request method and the response status
+   code determine the type and interpretation of any message body. All
+   responses MAY include a body. Message bodies for 1xx responses
+   contain advisory information about the progress of the request. 2xx
+   responses to INVITE requests contain session descriptions. In 3xx
+   responses, the message body MAY contain the description of
+   alternative destinations or services, as described in Section 7.3.
+   For responses with status 400 or greater, the message body MAY
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 84]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   contain additional, human-readable information about the reasons for
+   failure. It is RECOMMENDED that information in 1xx and 300 and
+   greater responses be of type text/plain or text/html
+
+8.2 Message Body Type
+
+   The Internet media type of the message body MUST be given by the
+   Content-Type header field. If the body has undergone any encoding
+   (such as compression) then this MUST be indicated by the Content-
+   Encoding header field, otherwise Content-Encoding MUST be omitted. If
+   applicable, the character set of the message body is indicated as
+   part of the Content-Type header-field value.
+
+8.3 Message Body Length
+
+   The body length in bytes SHOULD be given by the Content-Length header
+   field. Section 6.15 describes the behavior in detail.
+
+   The "chunked" transfer encoding of HTTP/1.1 MUST NOT be used for SIP.
+   (Note: The chunked encoding modifies the body of a message in order
+   to transfer it as a series of chunks, each with its own size
+   indicator.)
+
+9 Compact Form
+
+   When SIP is carried over UDP with authentication and a complex
+   session description, it may be possible that the size of a request or
+   response is larger than the MTU. To address this problem, a more
+   compact form of SIP is also defined by using abbreviations for the
+   common header fields listed below:
+
+
+   short field name  long field name   note
+   c                 Content-Type
+   e                 Content-Encoding
+   f                 From
+   i                 Call-ID
+   m                 Contact           from "moved"
+   l                 Content-Length
+   s                 Subject
+   t                 To
+   v                 Via
+
+
+   Thus, the message in section 16.2 could also be written:
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 85]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+     INVITE sip:schooler at vlsi.caltech.edu SIP/2.0
+     v:SIP/2.0/UDP 131.215.131.131;maddr=239.128.16.254;ttl=16
+     v:SIP/2.0/UDP 128.16.64.19
+     f:sip:mjh at isi.edu
+     t:sip:schooler at cs.caltech.edu
+     i:62729-27 at 128.16.64.19
+     c:application/sdp
+     CSeq: 4711 INVITE
+     l:187
+
+     v=0
+     o=user1 53655765 2353687637 IN IP4 128.3.4.5
+     s=Mbone Audio
+     i=Discussion of Mbone Engineering Issues
+     e=mbone at somewhere.com
+     c=IN IP4 224.2.0.1/127
+     t=0 0
+     m=audio 3456 RTP/AVP 0
+
+
+
+   Clients MAY mix short field names and long field names within the
+   same request. Servers MUST accept both short and long field names for
+   requests. Proxies MAY change header fields between their long and
+   short forms, but this MUST NOT be done to fields following an
+   Authorization header.
+
+10 Behavior of SIP Clients and Servers
+
+10.1 General Remarks
+
+   SIP is defined so it can use either UDP (unicast or multicast) or TCP
+   as a transport protocol; it provides its own reliability mechanism.
+
+10.1.1 Requests
+
+   Servers discard isomorphic requests, but first retransmit the
+   appropriate response. (SIP requests are said to be idempotent , i.e.,
+   receiving more than one copy of a request does not change the server
+   state.)
+
+   After receiving a CANCEL request from an upstream client, a stateful
+   proxy server MAY send a CANCEL on all branches where it has not yet
+   received a final response.
+
+   When a user agent receives a request, it checks the Call-ID against
+   those of in-progress calls. If the Call-ID was found, it compares the
+   tag value of To with the user's tag and rejects the request if the
+
+
+
+Handley, et al.             Standards Track                    [Page 86]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   two do not match. If the From header, including any tag value,
+   matches the value for an existing call leg, the server compares the
+   CSeq header field value. If less than or equal to the current
+   sequence number, the request is a retransmission.  Otherwise, it is a
+   new request. If the From header does not match an existing call leg,
+   a new call leg is created.
+
+   If the Call-ID was not found, a new call leg is created, with entries
+   for the To, From and Call-ID headers.  In this case, the To header
+   field should not have contained a tag. The server returns a response
+   containing the same To value, but with a unique tag added. The tag
+   MAY be omitted if the request contained only one Via header field.
+
+10.1.2 Responses
+
+   A server MAY issue one or more provisional responses at any time
+   before sending a final response. If a stateful proxy, user agent
+   server, redirect server or registrar cannot respond to a request with
+   a final response within 200 ms, it SHOULD issue a provisional (1xx)
+   response as soon as possible. Stateless proxies MUST NOT issue
+   provisional responses on their own.
+
+   Responses are mapped to requests by the matching To, From, Call-ID,
+   CSeq headers and the branch parameter of the first Via header.
+   Responses terminate request retransmissions even if they have Via
+   headers that cause them to be delivered to an upstream client.
+
+   A stateful proxy may receive a response that it does not have state
+   for, that is, where it has no a record of an associated request. If
+   the Via header field indicates that the upstream server used TCP, the
+   proxy actively opens a TCP connection to that address. Thus, proxies
+   have to be prepared to receive responses on the incoming side of
+   passive TCP connections, even though most responses will arrive on
+   the incoming side of an active connection. (An active connection is a
+   TCP connection initiated by the proxy, a passive connection is one
+   accepted by the proxy, but initiated by another entity.)
+
+   100 responses SHOULD NOT be forwarded, other 1xx responses MAY be
+   forwarded, possibly after the server eliminates responses with status
+   codes that had already been sent earlier. 2xx responses are forwarded
+   according to the Via header. Once a stateful proxy has received a 2xx
+   response, it MUST NOT forward non-2xx final responses.  Responses
+   with status 300 and higher are retransmitted by each stateful proxy
+   until the next upstream proxy sends an ACK (see below for timing
+   details) or CANCEL.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 87]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   A stateful proxy SHOULD maintain state for at least 32 seconds after
+   the receipt of the first definitive non-200 response, in order to
+   handle retransmissions of the response.
+
+
+        The 32 second window is given by the maximum retransmission
+        duration of 200-class responses using the default timers,
+        in case the ACK is lost somewhere on the way to the called
+        user agent or the next stateful proxy.
+
+10.2 Source Addresses, Destination Addresses and Connections
+
+10.2.1 Unicast UDP
+
+   Responses are returned to the address listed in the Via header field
+   (Section 6.40), not the source address of the request.
+
+
+        Recall that responses are not generated by the next-hop
+        stateless server, but generated by either a proxy server or
+        the user agent server. Thus, the stateless proxy can only
+        use the Via header field to forward the response.
+
+10.2.2 Multicast UDP
+
+   Requests MAY be multicast; multicast requests likely feature a host-
+   independent Request-URI. This request SHOULD be scoped to ensure it
+   is not forwarded beyond the boundaries of the administrative system.
+   This MAY be done with either TTL or administrative scopes[25],
+   depending on what is implemented in the network.
+
+   A client receiving a multicast query does not have to check whether
+   the host part of the Request-URI matches its own host or domain name.
+   If the request was received via multicast, the response is also
+   returned via multicast. Responses to multicast requests are multicast
+   with the same TTL as the request, where the TTL is derived from the
+   ttl parameter in the Via header (Section 6.40).
+
+   To avoid response implosion, servers MUST NOT answer multicast
+   requests with a status code other than 2xx or 6xx. The server delays
+   its response by a random interval uniformly distributed between zero
+   and one second. Servers MAY suppress responses if they hear a lower-
+   numbered or 6xx response from another group member prior to sending.
+   Servers do not respond to CANCEL requests received via multicast to
+   avoid request implosion. A proxy or UAC SHOULD send a CANCEL on
+   receiving the first 2xx or 6xx response to a multicast request.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 88]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Server response suppression is a MAY since it requires a
+        server to violate some basic message processing rules. Lets
+        say A sends a multicast request, and it is received by B,C,
+        and D. B sends a 200 response. The topmost Via field in the
+        response will contain the address of A. C will also receive
+        this response, and could use it to suppress its own
+        response. However, C would normally not examine this
+        response, as the topmost Via is not its own. Normally, a
+        response received with an incorrect topmost Via MUST be
+        dropped, but not in this case. To distinguish this packet
+        from a misrouted or multicast looped packet is fairly
+        complex, and for this reason the procedure is a MAY. The
+        CANCEL, instead, provides a simpler and more standard way
+        to perform response suppression. It is for this reason that
+        the use of CANCEL here is a SHOULD
+
+10.3 TCP
+
+   A single TCP connection can serve one or more SIP transactions. A
+   transaction contains zero or more provisional responses followed by
+   one or more final responses. (Typically, transactions contain exactly
+   one final response, but there are exceptional circumstances, where,
+   for example, multiple 200 responses can be generated.)
+
+   The client SHOULD keep the connection open at least until the first
+   final response arrives. If the client closes or resets the TCP
+   connection prior to receiving the first final response, the server
+   treats this action as equivalent to a CANCEL request.
+
+
+        This behavior makes it less likely that malfunctioning
+        clients cause a proxy server to keep connection state
+        indefinitely.
+
+   The server SHOULD NOT close the TCP connection until it has sent its
+   final response, at which point it MAY close the TCP connection if it
+   wishes to. However, normally it is the client's responsibility to
+   close the connection.
+
+   If the server leaves the connection open, and if the client so
+   desires it MAY re-use the connection for further SIP requests or for
+   requests from the same family of protocols (such as HTTP or stream
+   control commands).
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 89]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   If a server needs to return a response to a client and no longer has
+   a connection open to that client, it MAY open a connection to the
+   address listed in the Via header. Thus, a proxy or user agent MUST be
+   prepared to receive both requests and responses on a "passive"
+   connection.
+
+10.4 Reliability for BYE, CANCEL, OPTIONS, REGISTER Requests
+
+10.4.1 UDP
+
+   A SIP client using UDP SHOULD retransmit a BYE, CANCEL, OPTIONS, or
+   REGISTER request with an exponential backoff, starting at a T1 second
+   interval, doubling the interval for each packet, and capping off at a
+   T2 second interval. This means that after the first packet is sent,
+   the second is sent T1 seconds later, the next 2*T1 seconds after
+   that, the next 4*T1 seconds after that, and so on, until the interval
+   hits T2. Subsequent retransmissions are spaced by T2 seconds. If the
+   client receives a provisional response, it continues to retransmit
+   the request, but with an interval of T2 seconds.  Retransmissions
+   cease when the client has sent a total of eleven packets, or receives
+   a definitive response. Default values for T1 and T2 are 500 ms and 4
+   s, respectively. Clients MAY use larger values, but SHOULD NOT use
+   smaller ones. Servers retransmit the response upon receipt of a
+   request retransmission. After the server sends a final response, it
+   cannot be sure the client has received the response, and thus SHOULD
+   cache the results for at least 10*T2 seconds to avoid having to, for
+   example, contact the user or location server again upon receiving a
+   request retransmission.
+
+
+        Use of the exponential backoff is for congestion control
+        purposes. However, the back-off must cap off, since request
+        retransmissions are used to trigger response
+        retransmissions at the server. Without a cap, the loss of a
+        single response could significantly increase transaction
+        latencies.
+
+   The value of the initial retransmission timer is smaller than that
+   that for TCP since it is expected that network paths suitable for
+   interactive communications have round-trip times smaller than 500 ms.
+   For congestion control purposes, the retransmission count has to be
+   bounded.  Given that most transactions are expected to consist of one
+   request and a few responses, round-trip time estimation is not likely
+   to be very useful. If RTT estimation is desired to more quickly
+   discover a missing final response, each request retransmission needs
+   to be labeled with its own Timestamp (Section 6.36), returned in the
+   response. The server caches the result until it can be sure that the
+   client will not retransmit the same request again.
+
+
+
+Handley, et al.             Standards Track                    [Page 90]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Each server in a proxy chain generates its own final response to a
+   CANCEL request. The server responds immediately upon receipt of the
+   CANCEL request rather than waiting until it has received final
+   responses from the CANCEL requests it generates.
+
+   BYE and OPTIONS final responses are generated by redirect and user
+   agent servers; REGISTER final responses are generated by registrars.
+   Note that in contrast to the reliability mechanism described in
+   Section 10.5, responses to these requests are not retransmitted
+   periodically and not acknowledged via ACK.
+
+10.4.2 TCP
+
+   Clients using TCP do not need to retransmit requests.
+
+10.5 Reliability for INVITE Requests
+
+   Special considerations apply for the INVITE method.
+
+        1.   After receiving an invitation, considerable time can elapse
+             before the server can determine the outcome. For example,
+             if the called party is "rung" or extensive searches are
+             performed, delays between the request and a definitive
+             response can reach several tens of seconds. If either
+             caller or callee are automated servers not directly
+             controlled by a human being, a call attempt could be
+             unbounded in time.
+
+        2.   If a telephony user interface is modeled or if we need to
+             interface to the PSTN, the caller's user interface will
+             provide "ringback", a signal that the callee is being
+             alerted. (The status response 180 (Ringing) MAY be used to
+             initiate ringback.) Once the callee picks up, the caller
+             needs to know so that it can enable the voice path and stop
+             ringback. The callee's response to the invitation could get
+             lost. Unless the response is transmitted reliably, the
+             caller will continue to hear ringback while the callee
+             assumes that the call exists.
+
+        3.   The client has to be able to terminate an on-going request,
+             e.g., because it is no longer willing to wait for the
+             connection or search to succeed. The server will have to
+             wait several retransmission intervals to interpret the lack
+             of request retransmissions as the end of a call. If the
+             call succeeds shortly after the caller has given up, the
+             callee will "pick up the phone" and not be "connected".
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 91]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+10.5.1 UDP
+
+   For UDP, A SIP client SHOULD retransmit a SIP INVITE request with an
+   interval that starts at T1 seconds, and doubles after each packet
+   transmission. The client ceases retransmissions if it receives a
+   provisional or definitive response, or once it has sent a total of 7
+   request packets.
+
+   A server which transmits a provisional response should retransmit it
+   upon reception of a duplicate request. A server which transmits a
+   final response should retransmit it with an interval that starts at
+   T1 seconds, and doubles for each subsequent packet. Response
+   retransmissions cease when any one of the following occurs:
+
+        1.   An ACK request for the same transaction is received;
+
+        2.   a BYE request for the same call leg is received;
+
+        3.   a CANCEL request for the same call leg is received and the
+             final response status was equal or greater to 300;
+
+        4.   the response has been transmitted 7 times.
+
+   Only the user agent client generates an ACK for 2xx final responses,
+   If the response contained a Contact header field, the ACK MAY be sent
+   to the address listed in that Contact header field. If the response
+   did not contain a Contact header, the client uses the same To header
+   field and Request-URI as for the INVITE request and sends the ACK to
+   the same destination as the original INVITE request. ACKs for final
+   responses other than 2xx are sent to the same server that the
+   original request was sent to, using the same Request-URI as the
+   original request. Note, however, that the To header field in the ACK
+   is copied from the response being acknowledged, not the request, and
+   thus MAY additionally contain the tag parameter. Also note than
+   unlike 2xx final responses, a proxy generates an ACK for non-2xx
+   final responses.
+
+   The ACK request MUST NOT be acknowledged to prevent a response-ACK
+   feedback loop. Fig. 12 and 13 show the client and server state
+   diagram for invitations.
+
+
+
+
+        The mechanism in Sec. 10.4 would not work well for INVITE
+        because of the long delays between INVITE and a final
+        response. If the 200 response were to get lost, the callee
+        would believe the call to exist, but the voice path would
+
+
+
+Handley, et al.             Standards Track                    [Page 92]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+              +===========+
+              *           *
+  ...........>*  Initial  *<;;;;;;;;;;
+  : 7 INVITE  *           *          ;
+  :   sent    +===========+          ;
+  :                 |                ;
+  :                 |    -           ;
+  :                 |  INVITE        ;
+  :                 |                ;
+  :                 v                ;
+  :           *************          ;
+  : T1*2^n <--*           *          ;
+  : INVITE -->*  Calling  *--------+ ;
+  :           *           *        | ;
+  :           *************        | ;
+  :             :   |              | ;
+  :.............:   | 1xx      xxx | ;
+                    |  -       ACK | ;
+                    |              | ;
+                    v              | ; 
+              *************        | ;
+              *           *        | ;
+              *  Ringing  *<->1xx  | ; 
+              *           *        | ;
+              *************        | ;
+                    |              | ;
+                    |<-------------+ ; 
+                    |                ;
+                    v                ;
+              *************          ;
+      xxx  <--*           *          ;
+      ACK  -->* Completed *          ;
+              *           *          ;
+              *************          ;
+                    ; 32s (for proxy);
+                    ;;;;;;;;;;;;;;;;;;
+
+ event (xxx=status)
+     message                                          
+
+
+   Figure 12: State transition diagram of client for INVITE method
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 93]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+   7 pkts sent  +===============+                   
++-------------->*               *
+|               *   Initial     *<...............
+|;;;;;;;;;;;;;;>*               *               :
+|;              +===============+               :
+|; CANCEL               !                       :
+|;  200                 !  INVITE               :
+|;                      !   1xx                 :
+|;                      !                       :
+|;                      v                       :
+|;              *****************          BYE  :
+|;    INVITE -->*               *          200  :
+|;      1xx  <--* Call proceed. *..............>:
+|;              *               *               :
+|;;;;;;;;;;;;;;;*****************               :
+|;                    !   !                     :
+|:                    !   !                     :
+|;         failure    !   !  picks up           :
+|;         >= 300     !   !    200              :
+|;            +-------+   +-------+             :
+|;            v                   v             :
+|;       ***********         ***********        :
+|;INVITE<*         *<T1*2^n->*         *>INVITE :
+|;status>* failure *>status<-* success *<status :
+|;       *         *         *         *        :
+|;;;;;;;;***********         ***********        :
+|             ! : |            |  !  :          :
+|             ! : |            |  !  :          :
++-------------!-:-+------------+  !  :          :
+              ! :.................!..:.........>:
+              !                   !         BYE : 
+              +---------+---------+         200 :
+  event                 ! ACK                   :
+message sent            v                       :
+                *****************               :
+            V---*               *               :
+           ACK  *   Confirmed   *               :
+            |-->*               *               :
+                *****************               . 
+                        :......................>:
+
+
+   Figure 13: State transition diagram of server for INVITE method
+
+Handley, et al.             Standards Track                    [Page 94]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        be dead since the caller does not know that the callee has
+        picked up. Thus, the INVITE retransmission interval would
+        have to be on the order of a second or two to limit the
+        duration of this state confusion. Retransmitting the
+        response with an exponential back-off helps ensure that the
+        response is received, without placing an undue burden on
+        the network.
+
+10.5.2 TCP
+
+   A user agent using TCP MUST NOT retransmit requests, but uses the
+   same algorithm as for UDP (Section 10.5.1) to retransmit responses
+   until it receives an ACK.
+
+
+        It is necessary to retransmit 2xx responses as their
+        reliability is assured end-to-end only. If the chain of
+        proxies has a UDP link in the middle, it could lose the
+        response, with no possibility of recovery. For simplicity,
+        we also retransmit non-2xx responses, although that is not
+        strictly necessary.
+
+10.6 Reliability for ACK Requests
+
+   The ACK request does not generate responses. It is only generated
+   when a response to an INVITE request arrives (see Section 10.5). This
+   behavior is independent of the transport protocol. Note that the ACK
+   request MAY take a different path than the original INVITE request,
+   and MAY even cause a new TCP connection to be opened in order to send
+   it.
+
+10.7 ICMP Handling
+
+   Handling of ICMP messages in the case of UDP messages is
+   straightforward. For requests, a host, network, port, or protocol
+   unreachable error SHOULD be treated as if a 400-class response was
+   received. For responses, these errors SHOULD cause the server to
+   cease retransmitting the response.
+
+   Source quench ICMP messages SHOULD be ignored. TTL exceeded errors
+   SHOULD be ignored. Parameter problem errors SHOULD be treated as if a
+   400-class response was received.
+
+11 Behavior of SIP User Agents
+
+   This section describes the rules for user agent client and servers
+   for generating and processing requests and responses.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 95]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+11.1 Caller Issues Initial INVITE Request
+
+   When a user agent client desires to initiate a call, it formulates an
+   INVITE request. The To field in the request contains the address of
+   the callee. The Request-URI contains the same address. The From field
+   contains the address of the caller.  If the From address can appear
+   in requests generated by other user agent clients for the same call,
+   the caller MUST insert the tag parameter in the From field. A UAC MAY
+   optionally add a Contact header containing an address where it would
+   like to be contacted for transactions from the callee back to the
+   caller.
+
+11.2 Callee Issues Response
+
+   When the initial INVITE request is received at the callee, the callee
+   can accept, redirect, or reject the call. In all of these cases, it
+   formulates a response. The response MUST copy the To, From, Call-ID,
+   CSeq and Via fields from the request. Additionally, the responding
+   UAS MUST add the tag parameter to the To field in the response if the
+   request contained more than one Via header field. Since a request
+   from a UAC may fork and arrive at multiple hosts, the tag parameter
+   serves to distinguish, at the UAC, multiple responses from different
+   UAS's. The UAS MAY add a Contact header field in the response. It
+   contains an address where the callee would like to be contacted for
+   subsequent transactions, including the ACK for the current INVITE.
+   The UAS stores the values of the To and From field, including any
+   tags. These become the local and remote addresses of the call leg,
+   respectively.
+
+11.3 Caller Receives Response to Initial Request
+
+   Multiple responses may arrive at the UAC for a single INVITE request,
+   due to a forking proxy. Each response is distinguished by the "tag"
+   parameter in the To header field, and each represents a distinct call
+   leg. The caller MAY choose to acknowledge or terminate the call with
+   each responding UAS. To acknowledge, it sends an ACK request, and to
+   terminate it sends a BYE request.  The To header field in the ACK or
+   BYE MUST be the same as the To field in the 200 response, including
+   any tag. The From header field MUST be the same as the From header
+   field in the 200 (OK) response, including any tag. The Request-URI of
+   the ACK or BYE request MAY be set to whatever address was found in
+   the Contact header field in the 200 (OK) response, if present.
+   Alternately, a UAC may copy the address from the To header field into
+   the Request-URI. The UAC also notes the value of the To and From
+   header fields in each response. For each call leg, the To header
+   field becomes the remote address, and the From header field becomes
+   the local address.
+
+
+
+
+Handley, et al.             Standards Track                    [Page 96]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+11.4 Caller or Callee Generate Subsequent Requests
+
+   Once the call has been established, either the caller or callee MAY
+   generate INVITE or BYE requests to change or terminate the call.
+   Regardless of whether the caller or callee is generating the new
+   request, the header fields in the request are set as follows. For the
+   desired call leg, the To header field is set to the remote address,
+   and the From header field is set to the local address (both including
+   any tags). The Contact header field MAY be different than the Contact
+   header field sent in a previous response or request. The Request-URI
+   MAY be set to the value of the Contact header field received in a
+   previous request or response from the remote party, or to the value
+   of the remote address.
+
+11.5 Receiving Subsequent Requests
+
+   When a request is received subsequently, the following checks are
+   made:
+
+        1.   If the Call-ID is new, the request is for a new call,
+             regardless of the values of the To and From header fields.
+
+        2.   If the Call-ID exists, the request is for an existing call.
+             If the To, From, Call-ID, and CSeq values exactly match
+             (including tags) those of any requests received previously,
+             the request is a retransmission.
+
+        3.   If there was no match to the previous step, the To and From
+             fields are compared against existing call leg local and
+             remote addresses. If there is a match, and the CSeq in the
+             request is higher than the last CSeq received on that leg,
+             the request is a new transaction for an existing call leg.
+
+12 Behavior of SIP Proxy and Redirect Servers
+
+   This section describes behavior of SIP redirect and proxy servers in
+   detail. Proxy servers can "fork" connections, i.e., a single incoming
+   request spawns several outgoing (client) requests.
+
+12.1 Redirect Server
+
+   A redirect server does not issue any SIP requests of its own. After
+   receiving a request other than CANCEL, the server gathers the list of
+   alternative locations and returns a final response of class 3xx or it
+   refuses the request. For well-formed CANCEL requests, it SHOULD
+   return a 2xx response. This response ends the SIP transaction. The
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 97]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   redirect server maintains transaction state for the whole SIP
+   transaction. It is up to the client to detect forwarding loops
+   between redirect servers.
+
+12.2 User Agent Server
+
+   User agent servers behave similarly to redirect servers, except that
+   they also accept requests and can return a response of class 2xx.
+
+12.3 Proxy Server
+
+   This section outlines processing rules for proxy servers. A proxy
+   server can either be stateful or stateless. When stateful, a proxy
+   remembers the incoming request which generated outgoing requests, and
+   the outgoing requests. A stateless proxy forgets all information once
+   an outgoing request is generated. A forking proxy SHOULD be stateful.
+   Proxies that accept TCP connections MUST be stateful.
+
+
+        Otherwise, if the proxy were to lose a request, the TCP
+        client would never retransmit it.
+
+   A stateful proxy SHOULD NOT become stateless until after it sends a
+   definitive response upstream, and at least 32 seconds after it
+   received a definitive response.
+
+   A stateful proxy acts as a virtual UAS/UAC. It implements the server
+   state machine when receiving requests, and the client state machine
+   for generating outgoing requests, with the exception of receiving a
+   2xx response to an INVITE. Instead of generating an ACK, the 2xx
+   response is always forwarded upstream towards the caller.
+   Furthermore, ACK's for 200 responses to INVITE's are always proxied
+   downstream towards the UAS, as they would be for a stateless proxy.
+
+   A stateless proxy does not act as a virtual UAS/UAC (as this would
+   require state). Rather, a stateless proxy forwards every request it
+   receives downstream, and every response it receives upstream.
+
+12.3.1 Proxying Requests
+
+   To prevent loops, a server MUST check if its own address is already
+   contained in the Via header field of the incoming request.
+
+   The To, From, Call-ID, and Contact tags are copied exactly from the
+   original request. The proxy SHOULD change the Request-URI to indicate
+   the server where it intends to send the request.
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 98]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   A proxy server always inserts a Via header field containing its own
+   address into those requests that are caused by an incoming request.
+   Each proxy MUST insert a "branch" parameter (Section 6.40).
+
+12.3.2 Proxying Responses
+
+   A proxy only processes a response if the topmost Via field matches
+   one of its addresses. A response with a non-matching top Via field
+   MUST be dropped.
+
+12.3.3 Stateless Proxy: Proxying Responses
+
+   A stateless proxy removes its own Via field, and checks the address
+   in the next Via field. In the case of UDP, the response is sent to
+   the address listed in the "maddr" tag if present, otherwise to the
+   "received" tag if present, and finally to the address in the "sent-
+   by" field. A proxy MUST remain stateful when handling requests
+   received via TCP.
+
+   A stateless proxy MUST NOT generate its own provisional responses.
+
+12.3.4 Stateful Proxy: Receiving Requests
+
+   When a stateful proxy receives a request, it checks the To, From
+   (including tags), Call-ID and CSeq against existing request records.
+   If the tuple exists, the request is a retransmission. The provisional
+   or final response sent previously is retransmitted, as per the server
+   state machine. If the tuple does not exist, the request corresponds
+   to a new transaction, and the request should be proxied.
+
+   A stateful proxy server MAY generate its own provisional (1xx)
+   responses.
+
+12.3.5 Stateful Proxy: Receiving ACKs
+
+   When an ACK request is received, it is either processed locally or
+   proxied. To make this determination, the To, From, CSeq and Call-ID
+   fields are compared against those in previous requests. If there is
+   no match, the ACK request is proxied as if it were an INVITE request.
+   If there is a match, and if the server had ever sent a 200 response
+   upstream, the ACK is proxied.  If the server had never sent any
+   responses upstream, the ACK is also proxied. If the server had sent a
+   3xx, 4xx, 5xx or 6xx response, but no 2xx response, the ACK is
+   processed locally if the tag in the To field of the ACK matches the
+   tag sent by the proxy in the response.
+
+
+
+
+
+
+Handley, et al.             Standards Track                    [Page 99]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+12.3.6 Stateful Proxy: Receiving Responses
+
+   When a proxy server receives a response that has passed the Via
+   checks, the proxy server checks the To (without the tag), From
+   (including the tag), Call-ID and CSeq against values seen in previous
+   requests. If there is no match, the response is forwarded upstream to
+   the address listed in the Via field. If there is a match, the
+   "branch" tag in the Via field is examined. If it matches a known
+   branch identifier, the response is for the given branch, and
+   processed by the virtual client for the given branch. Otherwise, the
+   response is dropped.
+
+   A stateful proxy should obey the rules in Section 12.4 to determine
+   if the response should be proxied upstream. If it is to be proxied,
+   the same rules for stateless proxies above are followed, with the
+   following addition for TCP. If a request was received via TCP
+   (indicated by the protocol in the top Via header), the proxy checks
+   to see if it has a connection currently open to that address. If so,
+   the response is sent on that connection.  Otherwise, a new TCP
+   connection is opened to the address and port in the Via field, and
+   the response is sent there. Note that this implies that a UAC or
+   proxy MUST be prepared to receive responses on the incoming side of a
+   TCP connection. Definitive non 200-class responses MUST be
+   retransmitted by the proxy, even over a TCP connection.
+
+12.3.7 Stateless, Non-Forking Proxy
+
+   Proxies in this category issue at most a single unicast request for
+   each incoming SIP request, that is, they do not "fork" requests.
+   However, servers MAY choose to always operate in a mode that allows
+   issuing of several requests, as described in Section 12.4.
+
+   The server can forward the request and any responses. It does not
+   have to maintain any state for the SIP transaction. Reliability is
+   assured by the next redirect or stateful proxy server in the server
+   chain.
+
+   A proxy server SHOULD cache the result of any address translations
+   and the response to speed forwarding of retransmissions. After the
+   cache entry has been expired, the server cannot tell whether an
+   incoming request is actually a retransmission of an older request.
+   The server will treat it as a new request and commence another
+   search.
+
+12.4 Forking Proxy
+
+   The server MUST respond to the request immediately with a 100
+   (Trying) response.
+
+
+
+Handley, et al.             Standards Track                   [Page 100]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Successful responses to an INVITE request MAY contain a Contact
+   header field so that the following ACK or BYE bypasses the proxy
+   search mechanism. If the proxy requires future requests to be routed
+   through it, it adds a Record-Route header to the request (Section
+   6.29).
+
+   The following C-code describes the behavior of a proxy server issuing
+   several requests in response to an incoming INVITE request.  The
+   function request(r, a, b) sends a SIP request of type r to address a,
+   with branch id b. await_response() waits until a response is received
+   and returns the response. close(a) closes the TCP connection to
+   client with address a. response(r) sends a response to the client.
+   ismulticast() returns 1 if the location is a multicast address and
+   zero otherwise.  The variable timeleft indicates the amount of time
+   left until the maximum response time has expired. The variable
+   recurse indicates whether the server will recursively try addresses
+   returned through a 3xx response. A server MAY decide to recursively
+   try only certain addresses, e.g., those which are within the same
+   domain as the proxy server. Thus, an initial multicast request can
+   trigger additional unicast requests.
+
+
+     /* request type */
+     typedef enum {INVITE, ACK, BYE, OPTIONS, CANCEL, REGISTER} Method;
+
+     process_request(Method R, int N, address_t address[])
+     {
+       struct {
+         int branch;         /* branch id */
+         int done;           /* has responded */
+       } outgoing[];
+       int done[];           /* address has responded */
+       char *location[];     /* list of locations */
+       int heard = 0;        /* number of sites heard from */
+       int class;            /* class of status code */
+       int timeleft = 120;   /* sample timeout value */
+       int loc = 0;          /* number of locations */
+       struct {              /* response */
+         int status;         /* response: CANCEL=-1 */
+         int locations;      /* number of redirect locations */
+         char *location[];   /* redirect locations */
+         address_t a;        /* address of respondent */
+         int branch;         /* branch identifier */
+       } r, best;            /* response, best response */
+       int i;
+
+       best.status = 1000;
+       for (i = 0; i < N; i++) {
+
+
+
+Handley, et al.             Standards Track                   [Page 101]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+         request(R, address[i], i);
+         outgoing[i].done = 0;
+         outgoing[i].branch = i;
+       }
+
+       while (timeleft > 0 && heard < N) {
+         r = await_response();
+         class = r.status / 100;
+
+         /* If final response, mark branch as done. */
+         if (class >= 2) {
+           heard++;
+           for (i = 0; i < N; i++) {
+             if (r.branch == outgoing[i].branch) {
+               outgoing[i].done = 1;
+               break;
+             }
+           }
+         }
+         /* CANCEL: respond, fork and wait for responses */
+         else if (class < 0) {
+           best.status = 200;
+           response(best);
+           for (i = 0; i < N; i++) {
+             if (!outgoing[i].done)
+               request(CANCEL, address[i], outgoing[i].branch);
+           }
+           best.status = -1;
+         }
+
+         /* Send an ACK */
+
+         if (class != 2) {
+           if (R == INVITE) request(ACK, r.a, r.branch);
+         }
+
+
+         if (class == 2) {
+           if (r.status < best.status) best = r;
+           break;
+         }
+         else if (class == 3) {
+           /* A server MAY optionally recurse.  The server MUST check
+            * whether it has tried this location before and whether
+            * the location is part of the Via path of the incoming
+            * request.  This check is omitted here for brevity.
+            * Multicast locations MUST NOT be returned to the client if
+            * the server is not recursing.
+
+
+
+Handley, et al.             Standards Track                   [Page 102]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+            */
+           if (recurse) {
+             multicast = 0;
+             N += r.locations;
+             for (i = 0; i < r.locations; i++) {
+               request(R, r.location[i]);
+             }
+           } else if (!ismulticast(r.location)) {
+             best = r;
+           }
+         }
+         else if (class == 4) {
+           if (best.status >= 400) best = r;
+         }
+         else if (class == 5) {
+           if (best.status >= 500) best = r;
+         }
+         else if (class == 6) {
+           best = r;
+           break;
+         }
+       }
+
+       /* We haven't heard anything useful from anybody. */
+       if (best.status == 1000) {
+         best.status = 404;
+       }
+       if (best.status/100 != 3) loc = 0;
+       response(best);
+     }
+
+
+   Responses are processed as follows. The process completes (and state
+   can be freed) when all requests have been answered by final status
+   responses (for unicast) or 60 seconds have elapsed (for multicast). A
+   proxy MAY send a CANCEL to all branches and return a 408 (Timeout) to
+   the client after 60 seconds or more.
+
+   1xx: The proxy MAY forward the response upstream towards the client.
+
+   2xx: The proxy MUST forward the response upstream towards the client,
+        without sending an ACK downstream. After receiving a 2xx, the
+        server MAY terminate all other pending requests by sending a
+        CANCEL request and closing the TCP connection, if applicable.
+        (Terminating pending requests is advisable as searches consume
+        resources. Also, INVITE requests could "ring" on a number of
+        workstations if the callee is currently logged in more than
+        once.)
+
+
+
+Handley, et al.             Standards Track                   [Page 103]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   3xx: The proxy MUST send an ACK and MAY recurse on the listed Contact
+        addresses. Otherwise, the lowest-numbered response is returned
+        if there were no 2xx responses.
+
+        Location lists are not merged as that would prevent
+        forwarding of authenticated responses. Also, responses can
+        have message bodies, so that merging is not feasible.
+
+   4xx, 5xx: The proxy MUST send an ACK and remember the response if it
+        has a lower status code than any previous 4xx and 5xx responses.
+        On completion, the lowest-numbered response is returned if there
+        were no 2xx or 3xx responses.
+
+   6xx: The proxy MUST forward the response to the client and send an
+        ACK. Other pending requests MAY be terminated with CANCEL as
+        described for 2xx responses.
+
+   A proxy server forwards any response for Call-IDs for which it does
+   not have a pending transaction according to the response's Via
+   header. User agent servers respond to BYE requests for unknown call
+   legs with status code 481 (Transaction Does Not Exist); they drop ACK
+   requests with unknown call legs silently.
+
+   Special considerations apply for choosing forwarding destinations for
+   ACK and BYE requests. In most cases, these requests will bypass
+   proxies and reach the desired party directly, keeping proxies from
+   having to make forwarding decisions.
+
+   A proxy MAY maintain call state for a period of its choosing. If a
+   proxy still has list of destinations that it forwarded the last
+   INVITE to, it SHOULD direct ACK requests only to those downstream
+   servers.
+
+13 Security Considerations
+
+13.1 Confidentiality and Privacy: Encryption
+
+13.1.1 End-to-End Encryption
+
+   SIP requests and responses can contain sensitive information about
+   the communication patterns and communication content of individuals.
+   The SIP message body MAY also contain encryption keys for the session
+   itself. SIP supports three complementary forms of encryption to
+   protect privacy:
+
+        o  End-to-end encryption of the SIP message body and certain
+          sensitive header fields;
+
+
+
+
+Handley, et al.             Standards Track                   [Page 104]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        o  hop-by-hop encryption to prevent eavesdropping that tracks
+          who is calling whom;
+
+        o  hop-by-hop encryption of Via fields to hide the route a
+          request has taken.
+
+   Not all of the SIP request or response can be encrypted end-to-end
+   because header fields such as To and Via need to be visible to
+   proxies so that the SIP request can be routed correctly.  Hop-by-hop
+   encryption encrypts the entire SIP request or response on the wire so
+   that packet sniffers or other eavesdroppers cannot see who is calling
+   whom. Hop-by-hop encryption can also encrypt requests and responses
+   that have been end-to-end encrypted. Note that proxies can still see
+   who is calling whom, and this information is also deducible by
+   performing a network traffic analysis, so this provides a very
+   limited but still worthwhile degree of protection.
+
+   SIP Via fields are used to route a response back along the path taken
+   by the request and to prevent infinite request loops. However, the
+   information given by them can also provide useful information to an
+   attacker. Section 6.22 describes how a sender can request that Via
+   fields be encrypted by cooperating proxies without compromising the
+   purpose of the Via field.
+
+   End-to-end encryption relies on keys shared by the two user agents
+   involved in the request. Typically, the message is sent encrypted
+   with the public key of the recipient, so that only that recipient can
+   read the message. All implementations SHOULD support PGP-based
+   encryption [33] and MAY implement other schemes.
+
+   A SIP request (or response) is end-to-end encrypted by splitting the
+   message to be sent into a part to be encrypted and a short header
+   that will remain in the clear. Some parts of the SIP message, namely
+   the request line, the response line and certain header fields marked
+   with "n" in the "enc." column in Table 4 and 5 need to be read and
+   returned by proxies and thus MUST NOT be encrypted end-to-end.
+   Possibly sensitive information that needs to be made available as
+   plaintext include destination address (To) and the forwarding path
+   (Via) of the call. The Authorization header field MUST remain in the
+   clear if it contains a digital signature as the signature is
+   generated after encryption, but MAY be encrypted if it contains
+   "basic" or "digest" authentication. The From header field SHOULD
+   normally remain in the clear, but MAY be encrypted if required, in
+   which case some proxies MAY return a 401 (Unauthorized) status if
+   they require a From field.
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 105]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Other header fields MAY be encrypted or MAY travel in the clear as
+   desired by the sender. The Subject, Allow and Content-Type header
+   fields will typically be encrypted. The Accept, Accept-Language,
+   Date, Expires, Priority, Require, Call-ID, Cseq, and Timestamp header
+   fields will remain in the clear.
+
+   All fields that will remain in the clear MUST precede those that will
+   be encrypted. The message is encrypted starting with the first
+   character of the first header field that will be encrypted and
+   continuing through to the end of the message body. If no header
+   fields are to be encrypted, encrypting starts with the second CRLF
+   pair after the last header field, as shown below. Carriage return and
+   line feed characters have been made visible as "$", and the encrypted
+   part of the message is outlined.
+
+
+     INVITE sip:watson at boston.bell-telephone.com SIP/2.0$
+     Via: SIP/2.0/UDP 169.130.12.5$
+     To: T. A. Watson <sip:watson at bell-telephone.com>$
+     From: A. Bell <sip:a.g.bell at bell-telephone.com>$
+     Encryption: PGP version=5.0$
+     Content-Length: 224$
+     Call-ID: 187602141351 at worcester.bell-telephone.com$
+     CSeq: 488$
+     $
+   *******************************************************
+   * Subject: Mr. Watson, come here.$                    *
+   * Content-Type: application/sdp$                      *
+   * $                                                   *
+   * v=0$                                                *
+   * o=bell 53655765 2353687637 IN IP4 128.3.4.5$        *
+   * c=IN IP4 135.180.144.94$                            *
+   * m=audio 3456 RTP/AVP 0 3 4 5$                       *
+   *******************************************************
+
+
+
+   An Encryption header field MUST be added to indicate the encryption
+   mechanism used. A Content-Length field is added that indicates the
+   length of the encrypted body. The encrypted body is preceded by a
+   blank line as a normal SIP message body would be.
+
+   Upon receipt by the called user agent possessing the correct
+   decryption key, the message body as indicated by the Content-Length
+   field is decrypted, and the now-decrypted body is appended to the
+   clear-text header fields. There is no need for an additional
+   Content-Length header field within the encrypted body because the
+   length of the actual message body is unambiguous after decryption.
+
+
+
+Handley, et al.             Standards Track                   [Page 106]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Had no SIP header fields required encryption, the message would have
+   been as below. Note that the encrypted body MUST then include a blank
+   line (start with CRLF) to disambiguate between any possible SIP
+   header fields that might have been present and the SIP message body.
+
+
+     INVITE sip:watson at boston.bell-telephone.com SIP/2.0$
+     Via: SIP/2.0/UDP 169.130.12.5$
+     To: T. A. Watson <sip:watson at bell-telephone.com>$
+     From: A. Bell <a.g.bell at bell-telephone.com>$
+     Encryption: PGP version=5.0$
+     Content-Type: application/sdp$
+     Content-Length: 107$
+     $
+   *************************************************
+   * $                                             *
+   * v=0$                                          *
+   * o=bell 53655765 2353687637 IN IP4 128.3.4.5$  *
+   * c=IN IP4 135.180.144.94$                      *
+   * m=audio 3456 RTP/AVP 0 3 4 5$                 *
+   *************************************************
+
+
+
+13.1.2 Privacy of SIP Responses
+
+   SIP requests can be sent securely using end-to-end encryption and
+   authentication to a called user agent that sends an insecure
+   response.  This is allowed by the SIP security model, but is not a
+   good idea.  However, unless the correct behavior is explicit, it
+   would not always be possible for the called user agent to infer what
+   a reasonable behavior was. Thus when end-to-end encryption is used by
+   the request originator, the encryption key to be used for the
+   response SHOULD be specified in the request. If this were not done,
+   it might be possible for the called user agent to incorrectly infer
+   an appropriate key to use in the response. Thus, to prevent key-
+   guessing becoming an acceptable strategy, we specify that a called
+   user agent receiving a request that does not specify a key to be used
+   for the response SHOULD send that response unencrypted.
+
+   Any SIP header fields that were encrypted in a request SHOULD also be
+   encrypted in an encrypted response. Contact response fields MAY be
+   encrypted if the information they contain is sensitive, or MAY be
+   left in the clear to permit proxies more scope for localized
+   searches.
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 107]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+13.1.3 Encryption by Proxies
+
+   Normally, proxies are not allowed to alter end-to-end header fields
+   and message bodies. Proxies MAY, however, encrypt an unsigned request
+   or response with the key of the call recipient.
+
+
+        Proxies need to encrypt a SIP request if the end system
+        cannot perform encryption or to enforce organizational
+        security policies.
+
+13.1.4 Hop-by-Hop Encryption
+
+   SIP requests and responses MAY also be protected by security
+   mechanisms at the transport or network layer. No particular mechanism
+   is defined or recommended here. Two possibilities are IPSEC [34] or
+   TLS [35]. The use of a particular mechanism will generally need to be
+   specified out of band, through manual configuration, for example.
+
+13.1.5 Via field encryption
+
+   When Via header fields are to be hidden, a proxy that receives a
+   request containing an appropriate "Hide: hop" header field (as
+   specified in section 6.22) SHOULD encrypt the header field. As only
+   the proxy that encrypts the field will decrypt it, the algorithm
+   chosen is entirely up to the proxy implementor. Two methods satisfy
+   these requirements:
+
+        o  The server keeps a cache of Via header fields and the
+          associated To header field, and replaces the Via header field
+          with an index into the cache. On the reverse path, take the
+          Via header field from the cache rather than the message.
+
+        This is insufficient to prevent message looping, and so an
+        additional ID MUST be added so that the proxy can detect loops.
+        This SHOULD NOT normally be the address of the proxy as the goal
+        is to hide the route, so instead a sufficiently large random
+        number SHOULD be used by the proxy and maintained in the cache.
+
+        It is possible for replies to get directed to the wrong
+        originator if the cache entry gets reused, so great care needs
+        to be taken to ensure this does not happen.
+
+        o  The server MAY use a secret key to encrypt the Via field, a
+          timestamp and an appropriate checksum in any such message with
+          the same secret key. The checksum is needed to detect whether
+          successful decoding has occurred, and the timestamp is
+
+
+
+
+Handley, et al.             Standards Track                   [Page 108]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+          required to prevent possible replay attacks and to ensure that
+          no two requests from the same previous hop have the same
+          encrypted Via field.  This is the preferred solution.
+
+13.2 Message Integrity and Access Control: Authentication
+
+   Protective measures need to be taken to prevent an active attacker
+   from modifying and replaying SIP requests and responses. The same
+   cryptographic measures that are used to ensure the authenticity of
+   the SIP message also serve to authenticate the originator of the
+   message.  However, the "basic" and "digest" authentication mechanism
+   offer authentication only, without message integrity.
+
+   Transport-layer or network-layer authentication MAY be used for hop-
+   by-hop authentication. SIP also extends the HTTP WWW-Authenticate
+   (Section 6.42) and Authorization (Section 6.11) header field and
+   their Proxy counterparts to include cryptographically strong
+   signatures. SIP also supports the HTTP "basic" and "digest" schemes
+   (see Section 14) and other HTTP authentication schemes to be defined
+   that offer a rudimentary mechanism of ascertaining the identity of
+   the caller.
+
+
+        Since SIP requests are often sent to parties with which no
+        prior communication relationship has existed, we do not
+        specify authentication based on shared secrets.
+
+   SIP requests MAY be authenticated using the Authorization header
+   field to include a digital signature of certain header fields, the
+   request method and version number and the payload, none of which are
+   modified between client and called user agent. The Authorization
+   header field is used in requests to authenticate the request
+   originator end-to-end to proxies and the called user agent, and in
+   responses to authenticate the called user agent or proxies returning
+   their own failure codes. If required, hop-by-hop authentication can
+   be provided, for example, by the IPSEC Authentication Header.
+
+   SIP does not dictate which digital signature scheme is used for
+   authentication, but does define how to provide authentication using
+   PGP in Section 15. As indicated above, SIP implementations MAY also
+   use "basic" and "digest" authentication and other authentication
+   mechanisms defined for HTTP. Note that "basic" authentication has
+   severe security limitations. The following does not apply to these
+   schemes.
+
+   To cryptographically sign a SIP request, the order of the SIP header
+   fields is important. When an Authorization header field is present,
+   it indicates that all header fields following the Authorization
+
+
+
+Handley, et al.             Standards Track                   [Page 109]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   header field have been included in the signature.  Therefore, hop-
+   by-hop header fields which MUST or SHOULD be modified by proxies MUST
+   precede the Authorization header field as they will generally be
+   modified or added-to by proxy servers.  Hop-by-hop header fields
+   which MAY be modified by a proxy MAY appear before or after the
+   Authorization header. When they appear before, they MAY be modified
+   by a proxy. When they appear after, they MUST NOT be modified by a
+   proxy. To sign a request, a client constructs a message from the
+   request method (in upper case) followed, without LWS, by the SIP
+   version number, followed, again without LWS, by the request headers
+   to be signed and the message body.  The message thus constructed is
+   then signed.
+
+   For example, if the SIP request is to be:
+
+   INVITE sip:watson at boston.bell-telephone.com SIP/2.0
+   Via: SIP/2.0/UDP 169.130.12.5
+   Authorization: PGP version=5.0, signature=...
+   From: A. Bell <sip:a.g.bell at bell-telephone.com>
+   To: T. A. Watson <sip:watson at bell-telephone.com>
+   Call-ID: 187602141351 at worcester.bell-telephone.com
+   Subject: Mr. Watson, come here.
+   Content-Type: application/sdp
+   Content-Length: ...
+
+   v=0
+   o=bell 53655765 2353687637 IN IP4 128.3.4.5
+   c=IN IP4 135.180.144.94
+   m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+   Then the data block that is signed is:
+
+   INVITESIP/2.0From: A. Bell <sip:a.g.bell at bell-telephone.com>
+   To: T. A. Watson <sip:watson at bell-telephone.com>
+   Call-ID: 187602141351 at worcester.bell-telephone.com
+   Subject: Mr. Watson, come here.
+   Content-Type: application/sdp
+   Content-Length: ...
+
+   v=0
+   o=bell 53655765 2353687637 IN IP4 128.3.4.5
+   c=IN IP4 135.180.144.94
+   m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 110]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   Clients wishing to authenticate requests MUST construct the portion
+   of the message below the Authorization header using a canonical form.
+   This allows a proxy to parse the message, take it apart, and
+   reconstruct it, without causing an authentication failure due to
+   extra white space, for example. Canonical form consists of the
+   following rules:
+
+        o  No short form header fields
+
+        o  Header field names are capitalized as shown in this document
+
+        o  No white space between the header name and the colon
+
+        o  A single space after the colon
+
+        o  Line termination with a CRLF
+
+        o  No line folding
+
+        o  No comma separated lists of header values; each must appear
+          as a separate header
+
+        o  Only a single SP between tokens, between tokens and quoted
+          strings, and between quoted strings; no SP after last token or
+          quoted string
+
+        o  No LWS between tokens and separators, except as described
+          above for after the colon in header fields
+
+   Note that if a message is encrypted and authenticated using a digital
+   signature, when the message is generated encryption is performed
+   before the digital signature is generated. On receipt, the digital
+   signature is checked before decryption.
+
+   A client MAY require that a server sign its response by including a
+   Require: org.ietf.sip.signed-response request header field. The
+   client indicates the desired authentication method via the WWW-
+   Authenticate header.
+
+   The correct behavior in handling unauthenticated responses to a
+   request that requires authenticated responses is described in section
+   13.2.1.
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 111]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+13.2.1 Trusting responses
+
+   There is the possibility that an eavesdropper listens to requests and
+   then injects unauthenticated responses that terminate, redirect or
+   otherwise interfere with a call. (Even encrypted requests contain
+   enough information to fake a response.)
+
+   Clients need to be particularly careful with 3xx redirection
+   responses.  Thus a client receiving, for example, a 301 (Moved
+   Permanently) which was not authenticated when the public key of the
+   called user agent is known to the client, and authentication was
+   requested in the request SHOULD be treated as suspicious. The correct
+   behavior in such a case would be for the called-user to form a dated
+   response containing the Contact field to be used, to sign it, and
+   give this signed stub response to the proxy that will provide the
+   redirection. Thus the response can be authenticated correctly. A
+   client SHOULD NOT automatically redirect such a request to the new
+   location without alerting the user to the authentication failure
+   before doing so.
+
+   Another problem might be responses such as 6xx failure responses
+   which would simply terminate a search, or "4xx" and "5xx" response
+   failures.
+
+   If TCP is being used, a proxy SHOULD treat 4xx and 5xx responses as
+   valid, as they will not terminate a search. However, fake 6xx
+   responses from a rogue proxy terminate a search incorrectly. 6xx
+   responses SHOULD be authenticated if requested by the client, and
+   failure to do so SHOULD cause such a client to ignore the 6xx
+   response and continue a search.
+
+   With UDP, the same problem with 6xx responses exists, but also an
+   active eavesdropper can generate 4xx and 5xx responses that might
+   cause a proxy or client to believe a failure occurred when in fact it
+   did not. Typically 4xx and 5xx responses will not be signed by the
+   called user agent, and so there is no simple way to detect these
+   rogue responses. This problem is best prevented by using hop-by-hop
+   encryption of the SIP request, which removes any additional problems
+   that UDP might have over TCP.
+
+   These attacks are prevented by having the client require response
+   authentication and dropping unauthenticated responses. A server user
+   agent that cannot perform response authentication responds using the
+   normal Require response of 420 (Bad Extension).
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 112]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+13.3 Callee Privacy
+
+   User location and SIP-initiated calls can violate a callee's privacy.
+   An implementation SHOULD be able to restrict, on a per-user basis,
+   what kind of location and availability information is given out to
+   certain classes of callers.
+
+13.4 Known Security Problems
+
+   With either TCP or UDP, a denial of service attack exists by a rogue
+   proxy sending 6xx responses. Although a client SHOULD choose to
+   ignore such responses if it requested authentication, a proxy cannot
+   do so. It is obliged to forward the 6xx response back to the client.
+   The client can then ignore the response, but if it repeats the
+   request it will probably reach the same rogue proxy again, and the
+   process will repeat.
+
+14 SIP Authentication using HTTP Basic and Digest Schemes
+
+   SIP implementations MAY use HTTP's basic and digest authentication
+   mechanisms to provide a rudimentary form of security. This section
+   overviews usage of these mechanisms in SIP. The basic operation is
+   almost completely identical to that for HTTP [36]. This section
+   outlines this operation, pointing to [36] for details, and noting the
+   differences when used in SIP.
+
+14.1 Framework
+
+   The framework for SIP authentication parallels that for HTTP [36]. In
+   particular, the BNF for auth-scheme, auth-param, challenge, realm,
+   realm-value, and credentials is identical. The 401 response is used
+   by user agent servers in SIP to challenge the authorization of a user
+   agent client. Additionally, registrars and redirect servers MAY make
+   use of 401 responses for authorization, but proxies MUST NOT, and
+   instead MAY use the 407 response. The requirements for inclusion of
+   the Proxy-Authenticate, Proxy-Authorization, WWW-Authenticate, and
+   Authorization in the various messages is identical to [36].
+
+   Since SIP does not have the concept of a canonical root URL, the
+   notion of protections spaces are interpreted differently for SIP. The
+   realm is a protection domain for all SIP URIs with the same value for
+   the userinfo, host and port part of the SIP Request-URI. For example:
+
+
+      INVITE sip:alice.wonderland at example.com SIP/2.0
+      WWW-Authenticate:  Basic realm="business"
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 113]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   and
+
+
+      INVITE sip:aw at example.com SIP/2.0
+      WWW-Authenticate: Basic realm="business"
+
+
+
+   define different protection realms according to this rule.
+
+   When a UAC resubmits a request with its credentials after receiving a
+   401 or 407 response, it MUST increment the CSeq header field as it
+   would normally do when sending an updated request.
+
+14.2 Basic Authentication
+
+   The rules for basic authentication follow those defined in [36], but
+   with the words "origin server" replaced with "user agent server,
+   redirect server , or registrar".
+
+   Since SIP URIs are not hierarchical, the paragraph in [36] that
+   states that "all paths at or deeper than the depth of the last
+   symbolic element in the path field of the Request-URI also are within
+   the protection space specified by the Basic realm value of the
+   current challenge" does not apply for SIP. SIP clients MAY
+   preemptively send the corresponding Authorization header with
+   requests for SIP URIs within the same protection realm (as defined
+   above) without receipt of another challenge from the server.
+
+14.3 Digest Authentication
+
+   The rules for digest authentication follow those defined in [36],
+   with "HTTP 1.1" replaced by "SIP/2.0" in addition to the following
+   differences:
+
+        1.   The URI included in the challenge has the following BNF:
+
+
+             URI  =  SIP-URL
+
+
+        2.   The BNF for digest-uri-value is:
+
+
+             digest-uri-value  =  Request-URI ; a defined in Section
+             4.3
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 114]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        3.   The example procedure for choosing a nonce based on Etag
+             does not work for SIP.
+
+        4.   The Authentication-Info and Proxy-Authentication-Info
+             fields are not used in SIP.
+
+        5.   The text in [36] regarding cache operation does not apply
+             to SIP.
+
+        6.   [36] requires that a server check that the URI in the
+             request line, and the URI included in the Authorization
+             header, point to the same resource. In a SIP context, these
+             two URI's may actually refer to different users, due to
+             forwarding at some proxy. Therefore, in SIP, a server MAY
+             check that the request-uri in the Authorization header
+             corresponds to a user that the server is willing to accept
+             forwarded or direct calls for.
+
+14.4 Proxy-Authentication
+
+   The use of the Proxy-Authentication and Proxy-Authorization parallel
+   that as described in [36], with one difference. Proxies MUST NOT add
+   the Proxy-Authorization header. 407 responses MUST be forwarded
+   upstream towards the client following the procedures for any other
+   response. It is the client's responsibility to add the Proxy-
+   Authorization header containing credentials for the proxy which has
+   asked for authentication.
+
+
+        If a proxy were to resubmit a request with a Proxy-
+        Authorization header field, it would need to increment the
+        CSeq in the new request. However, this would mean that the
+        UAC which submitted the original request would discard a
+        response from the UAS, as the CSeq value would be
+        different.
+
+   See sections 6.26 and 6.27 for additional information on usage of
+   these fields as they apply to SIP.
+
+15 SIP Security Using PGP
+
+15.1 PGP Authentication Scheme
+
+   The "pgp" authentication scheme is based on the model that the client
+   authenticates itself with a request signed with the client's private
+   key. The server can then ascertain the origin of the request if it
+   has access to the public key, preferably signed by a trusted third
+   party.
+
+
+
+Handley, et al.             Standards Track                   [Page 115]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+15.1.1 The WWW-Authenticate Response Header
+
+
+
+        WWW-Authenticate =  "WWW-Authenticate" ":" "pgp" pgp-challenge
+        pgp-challenge    =  * (";" pgp-params )
+        pgp-params       =  realm | pgp-version | pgp-algorithm | nonce
+        realm            =  "realm" "=" realm-value
+        realm-value      =  quoted-string
+        pgp-version      =  "version" "="
+                             <"> digit *( "." digit ) *letter <">
+        pgp-algorithm    =  "algorithm" "=" ( "md5" | "sha1" | token )
+        nonce            =  "nonce" "=" nonce-value
+        nonce-value      =  quoted-string
+
+
+
+   The meanings of the values of the parameters used above are as
+   follows:
+
+   realm: A string to be displayed to users so they know which identity
+        to use. This string SHOULD contain at least the name of the host
+        performing the authentication and MAY additionally indicate the
+        collection of users who might have access. An example might be "
+        Users with call-out privileges ".
+
+   pgp-algorithm: The value of this parameter indicates the PGP message
+        integrity check (MIC) to be used to produce the signature. If
+        this not present it is assumed to be "md5". The currently
+        defined values are "md5" for the MD5 checksum, and "sha1" for
+        the SHA.1 algorithm.
+
+   pgp-version: The version of PGP that the client MUST use. Common
+        values are "2.6.2" and "5.0". The default is 5.0.
+
+   nonce: A server-specified data string which should be uniquely
+        generated each time a 401 response is made. It is RECOMMENDED
+        that this string be base64 or hexadecimal data.  Specifically,
+        since the string is passed in the header lines as a quoted
+        string, the double-quote character is not allowed. The contents
+        of the nonce are implementation dependent. The quality of the
+        implementation depends on a good choice. Since the nonce is used
+        only to prevent replay attacks and is signed, a time stamp in
+        units convenient to the server is sufficient.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 116]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Replay attacks within the duration of the call setup are of
+        limited interest, so that timestamps with a resolution of a
+        few seconds are often should be sufficient. In that case,
+        the server does not have to keep a record of the nonces.
+
+   Example:
+
+   WWW-Authenticate: pgp ;version="5.0"
+     ;realm="Your Startrek identity, please" ;algorithm=md5
+     ;nonce="913082051"
+
+
+
+15.1.2 The Authorization Request Header
+
+   The client is expected to retry the request, passing an Authorization
+   header line, which is defined as follows.
+
+
+
+        Authorization  =  "Authorization" ":" "pgp" *( ";" pgp-response )
+        pgp-response   =  realm | pgp-version | pgp-signature
+                          | signed-by | nonce
+        pgp-signature  =  "signature" "=" quoted-string
+        signed-by      =  "signed-by" "=" <"> URI <">
+
+
+   The client MUST increment the CSeq header before resubmitting the
+   request. The signature MUST correspond to the From header of the
+   request unless the signed-by parameter is provided.
+
+   pgp-signature: The PGP ASCII-armored signature [33], as it appears
+        between the "BEGIN PGP MESSAGE" and "END PGP MESSAGE"
+        delimiters, without the version indication. The signature is
+        included without any linebreaks.
+
+   The signature is computed across the nonce (if present), request
+   method, request version and header fields following the Authorization
+   header and the message body, in the same order as they appear in the
+   message. The request method and version are prepended to the header
+   fields without any white space. The signature is computed across the
+   headers as sent, and the terminating CRLF. The CRLF following the
+   Authorization header is NOT included in the signature.
+
+   A server MAY be configured not to generate nonces only if replay
+   attacks are not a concern.
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 117]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        Not generating nonces avoids the additional set of request,
+        401 response and possibly ACK messages and reduces delay by
+        one round-trip time.
+
+
+        Using the ASCII-armored version is about 25% less space-
+        efficient than including the binary signature, but it is
+        significantly easier for the receiver to piece together.
+        Versions of the PGP program always include the full
+        (compressed) signed text in their output unless ASCII-
+        armored mode ( -sta ) is specified.  Typical signatures are
+        about 200 bytes long. -- The PGP signature mechanism allows
+        the client to simply pass the request to an external PGP
+        program. This relies on the requirement that proxy servers
+        are not allowed to reorder or change header fields.
+
+   realm: The realm is copied from the corresponding WWW-Authenticate
+        header field parameter.
+
+   signed-by: If and only if the request was not signed by the entity
+        listed in the From header, the signed-by header indicates the
+        name of the signing entity, expressed as a URI.
+
+   Receivers of signed SIP messages SHOULD discard any end-to-end header
+   fields above the Authorization header, as they may have been
+   maliciously added en route by a proxy.
+
+   Example:
+
+   Authorization: pgp version="5.0"
+     ;realm="Your Startrek identity, please"
+     ;nonce="913082051"
+     ;signature="iQB1AwUBNNJiUaYBnHmiiQh1AQFYsgL/Wt3dk6TWK81/b0gcNDf
+     VAUGU4rhEBW972IPxFSOZ94L1qhCLInTPaqhHFw1cb3lB01rA0RhpV4t5yCdUt
+     SRYBSkOK29o5e1KlFeW23EzYPVUm2TlDAhbcjbMdfC+KLFX
+     =aIrx"
+
+
+
+15.2 PGP Encryption Scheme
+
+   The PGP encryption scheme uses the following syntax:
+
+
+
+        Encryption    =  "Encryption" ":" "pgp" pgp-eparams
+        pgp-eparams   =  1# ( pgp-version | pgp-encoding )
+        pgp-encoding  =  "encoding" "=" "ascii" | token
+
+
+
+Handley, et al.             Standards Track                   [Page 118]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   encoding: Describes the encoding or "armor" used by PGP. The value
+        "ascii" refers to the standard PGP ASCII armor, without the
+        lines containing "BEGIN PGP MESSAGE" and "END PGP MESSAGE" and
+        without the version identifier. By default, the encrypted part
+        is included as binary.
+
+   Example:
+
+   Encryption: pgp version="2.6.2", encoding="ascii"
+
+
+
+15.3 Response-Key Header Field for PGP
+
+
+
+        Response-Key  =  "Response-Key" ":" "pgp" pgp-eparams
+        pgp-eparams   =  1# ( pgp-version | pgp-encoding | pgp-key)
+        pgp-key       =  "key" "=" quoted-string
+
+
+   If ASCII encoding has been requested via the encoding parameter, the
+   key parameter contains the user's public key as extracted from the
+   pgp key ring with the "pgp -kxa user ".
+
+   Example:
+
+   Response-Key: pgp version="2.6.2", encoding="ascii",
+     key="mQBtAzNWHNYAAAEDAL7QvAdK2utY05wuUG+ItYK5tCF8HNJM60sU4rLaV+eUnkMk
+     mOmJWtc2wXcZx1XaXb2lkydTQOesrUR75IwNXBuZXPEIMThEa5WLsT7VLme7njnx
+     sE86SgWmAZx5ookIdQAFEbQxSGVubmluZyBTY2h1bHpyaW5uZSA8c2NodWx6cmlu
+     bmVAY3MuY29sdW1iaWEuZWR1Pg==
+     =+y19"
+
+
+
+16 Examples
+
+   In the following examples, we often omit the message body and the
+   corresponding Content-Length and Content-Type headers for brevity.
+
+16.1 Registration
+
+   A user at host saturn.bell-tel.com registers on start-up, via
+   multicast, with the local SIP server named bell-tel.com. In the
+   example, the user agent on saturn expects to receive SIP requests on
+   UDP port 3890.
+
+
+
+
+Handley, et al.             Standards Track                   [Page 119]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   C->S: REGISTER sip:bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP saturn.bell-tel.com
+         From: sip:watson at bell-tel.com
+         To: sip:watson at bell-tel.com
+         Call-ID: 70710 at saturn.bell-tel.com
+         CSeq: 1 REGISTER
+         Contact: <sip:watson at saturn.bell-tel.com:3890;transport=udp>
+         Expires: 7200
+
+
+
+   The registration expires after two hours. Any future invitations for
+   watson at bell-tel.com arriving at sip.bell-tel.com will now be
+   redirected to watson at saturn.bell-tel.com, UDP port 3890.
+
+   If Watson wants to be reached elsewhere, say, an on-line service he
+   uses while traveling, he updates his reservation after first
+   cancelling any existing locations:
+
+
+   C->S: REGISTER sip:bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP saturn.bell-tel.com
+         From: sip:watson at bell-tel.com
+         To: sip:watson at bell-tel.com
+         Call-ID: 70710 at saturn.bell-tel.com
+         CSeq: 2 REGISTER
+         Contact: *
+         Expires: 0
+
+   C->S: REGISTER sip:bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP saturn.bell-tel.com
+         From: sip:watson at bell-tel.com
+         To: sip:watson at bell-tel.com
+         Call-ID: 70710 at saturn.bell-tel.com
+         CSeq: 3 REGISTER
+         Contact: sip:tawatson at example.com
+
+
+
+   Now, the server will forward any request for Watson to the server at
+   example.com, using the Request-URI tawatson at example.com. For the
+   server at example.com to reach Watson, he will need to send a
+   REGISTER there, or inform the server of his current location through
+   some other means.
+
+   It is possible to use third-party registration. Here, the secretary
+   jon.diligent registers his boss, T. Watson:
+
+
+
+
+Handley, et al.             Standards Track                   [Page 120]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   C->S: REGISTER sip:bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP pluto.bell-tel.com
+         From: sip:jon.diligent at bell-tel.com
+         To: sip:watson at bell-tel.com
+         Call-ID: 17320 at pluto.bell-tel.com
+         CSeq: 1 REGISTER
+         Contact: sip:tawatson at example.com
+
+
+
+   The request could be sent to either the registrar at bell-tel.com or
+   the server at example.com. In the latter case, the server at
+   example.com would proxy the request to the address indicated in the
+   Request-URI. Then, Max-Forwards header could be used to restrict the
+   registration to that server.
+
+16.2 Invitation to a Multicast Conference
+
+   The first example invites schooler at vlsi.cs.caltech.edu to a multicast
+   session. All examples use the Session Description Protocol (SDP) (RFC
+   2327 [6]) as the session description format.
+
+16.2.1 Request
+
+
+   C->S: INVITE sip:schooler at cs.caltech.edu SIP/2.0
+         Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+           ;maddr=239.128.16.254;ttl=16
+         Via: SIP/2.0/UDP north.east.isi.edu
+         From: Mark Handley <sip:mjh at isi.edu>
+         To: Eve Schooler <sip:schooler at caltech.edu>
+         Call-ID: 2963313058 at north.east.isi.edu
+         CSeq: 1 INVITE
+         Subject: SIP will be discussed, too
+         Content-Type: application/sdp
+         Content-Length: 187
+
+         v=0
+         o=user1 53655765 2353687637 IN IP4 128.3.4.5
+         s=Mbone Audio
+         i=Discussion of Mbone Engineering Issues
+         e=mbone at somewhere.com
+         c=IN IP4 224.2.0.1/127
+         t=0 0
+         m=audio 3456 RTP/AVP 0
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 121]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The From request header above states that the request was initiated
+   by mjh at isi.edu and addressed to schooler at caltech.edu (From header
+   fields). The Via fields list the hosts along the path from invitation
+   initiator (the last element of the list) towards the callee. In the
+   example above, the message was last multicast to the administratively
+   scoped group 239.128.16.254 with a ttl of 16 from the host
+   csvax.cs.caltech.edu. The second Via header field indicates that it
+   was originally sent from the host north.east.isi.edu. The Request-URI
+   indicates that the request is currently being being addressed to
+   schooler at cs.caltech.edu, the local address that csvax looked up for
+   the callee.
+
+   In this case, the session description is using the Session
+   Description Protocol (SDP), as stated in the Content-Type header.
+
+   The header is terminated by an empty line and is followed by a
+   message body containing the session description.
+
+16.2.2 Response
+
+   The called user agent, directly or indirectly through proxy servers,
+   indicates that it is alerting ("ringing") the called party:
+
+
+   S->C: SIP/2.0 180 Ringing
+         Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+           ;maddr=239.128.16.254;ttl=16
+         Via: SIP/2.0/UDP north.east.isi.edu
+         From: Mark Handley <sip:mjh at isi.edu>
+         To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+         Call-ID: 2963313058 at north.east.isi.edu
+         CSeq: 1 INVITE
+
+
+
+   A sample response to the invitation is given below. The first line of
+   the response states the SIP version number, that it is a 200 (OK)
+   response, which means the request was successful. The Via headers are
+   taken from the request, and entries are removed hop by hop as the
+   response retraces the path of the request. A new authentication field
+   MAY be added by the invited user's agent if required. The Call-ID is
+   taken directly from the original request, along with the remaining
+   fields of the request message. The original sense of From field is
+   preserved (i.e., it is the session initiator).
+
+   In addition, the Contact header gives details of the host where the
+   user was located, or alternatively the relevant proxy contact point
+   which should be reachable from the caller's host.
+
+
+
+Handley, et al.             Standards Track                   [Page 122]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   S->C: SIP/2.0 200 OK
+         Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+           ;maddr=239.128.16.254;ttl=16
+         Via: SIP/2.0/UDP north.east.isi.edu
+         From: Mark Handley <sip:mjh at isi.edu>
+         To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+         Call-ID: 2963313058 at north.east.isi.edu
+         CSeq: 1 INVITE
+         Contact: sip:es at jove.cs.caltech.edu
+
+
+
+   The caller confirms the invitation by sending an ACK request to the
+   location named in the Contact header:
+
+
+   C->S: ACK sip:es at jove.cs.caltech.edu SIP/2.0
+         Via: SIP/2.0/UDP north.east.isi.edu
+         From: Mark Handley <sip:mjh at isi.edu>
+         To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+         Call-ID: 2963313058 at north.east.isi.edu
+         CSeq: 1 ACK
+
+
+
+16.3 Two-party Call
+
+   For two-party Internet phone calls, the response must contain a
+   description of where to send the data. In the example below, Bell
+   calls Watson. Bell indicates that he can receive RTP audio codings 0
+   (PCMU), 3 (GSM), 4 (G.723) and 5 (DVI4).
+
+
+   C->S: INVITE sip:watson at boston.bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com>
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Subject: Mr. Watson, come here.
+         Content-Type: application/sdp
+         Content-Length: ...
+
+         v=0
+         o=bell 53655765 2353687637 IN IP4 128.3.4.5
+         s=Mr. Watson, come here.
+         c=IN IP4 kton.bell-tel.com
+         m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+Handley, et al.             Standards Track                   [Page 123]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   S->C: SIP/2.0 100 Trying
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Content-Length: 0
+
+   S->C: SIP/2.0 180 Ringing
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Content-Length: 0
+
+   S->C: SIP/2.0 182 Queued, 2 callers ahead
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Content-Length: 0
+
+   S->C: SIP/2.0 182 Queued, 1 caller ahead
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Content-Length: 0
+
+   S->C: SIP/2.0 200 OK
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 INVITE
+         Contact: sip:watson at boston.bell-tel.com
+         Content-Type: application/sdp
+         Content-Length: ...
+
+         v=0
+         o=watson 4858949 4858949 IN IP4 192.1.2.3
+         s=I'm on my way
+         c=IN IP4 boston.bell-tel.com
+         m=audio 5004 RTP/AVP 0 3
+
+
+
+
+Handley, et al.             Standards Track                   [Page 124]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   The example illustrates the use of informational status responses.
+   Here, the reception of the call is confirmed immediately (100), then,
+   possibly after some database mapping delay, the call rings (180) and
+   is then queued, with periodic status updates.
+
+   Watson can only receive PCMU and GSM. Note that Watson's list of
+   codecs may or may not be a subset of the one offered by Bell, as each
+   party indicates the data types it is willing to receive. Watson will
+   send audio data to port 3456 at c.bell-tel.com, Bell will send to
+   port 5004 at boston.bell-tel.com.
+
+   By default, the media session is one RTP session. Watson will receive
+   RTCP packets on port 5005, while Bell will receive them on port 3457.
+
+   Since the two sides have agreed on the set of media, Bell confirms
+   the call without enclosing another session description:
+
+
+   C->S: ACK sip:watson at boston.bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 1 ACK
+
+
+
+16.4 Terminating a Call
+
+   To terminate a call, caller or callee can send a BYE request:
+
+
+   C->S: BYE sip:watson at boston.bell-tel.com SIP/2.0
+         Via: SIP/2.0/UDP kton.bell-tel.com
+         From: A. Bell <sip:a.g.bell at bell-tel.com>
+         To: T. A. Watson <sip:watson at bell-tel.com> ;tag=37462311
+         Call-ID: 3298420296 at kton.bell-tel.com
+         CSeq: 2 BYE
+
+
+
+   If the callee wants to abort the call, it simply reverses the To and
+   From fields. Note that it is unlikely that a BYE from the callee will
+   traverse the same proxies as the original INVITE.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 125]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+16.5 Forking Proxy
+
+   In this example, Bell (a.g.bell at bell-tel.com) (C), currently seated
+   at host c.bell-tel.com wants to call Watson (t.watson at ieee.org). At
+   the time of the call, Watson is logged in at two workstations,
+   t.watson at x.bell-tel.com (X) and watson at y.bell-tel.com (Y), and has
+   registered with the IEEE proxy server (P) called sip.ieee.org. The
+   IEEE server also has a registration for the home machine of Watson,
+   at watson at h.bell-tel.com (H), as well as a permanent registration at
+   watson at acm.org (A). For brevity, the examples omit the session
+   description and Via header fields.
+
+   Bell's user agent sends the invitation to the SIP server for the
+   ieee.org domain:
+
+
+   C->P: INVITE sip:t.watson at ieee.org SIP/2.0
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+
+
+   The SIP server at ieee.org tries the four addresses in parallel.  It
+   sends the following message to the home machine:
+
+
+   P->H: INVITE sip:watson at h.bell-tel.com SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=1
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+
+
+   This request immediately yields a 404 (Not Found) response, since
+   Watson is not currently logged in at home:
+
+
+   H->P: SIP/2.0 404 Not Found
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=1
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>;tag=87454273
+
+
+
+Handley, et al.             Standards Track                   [Page 126]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+
+
+   The proxy ACKs the response so that host H can stop retransmitting
+   it:
+
+   P->H: ACK sip:watson at h.bell-tel.com SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=1
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>;tag=87454273
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 ACK
+
+
+
+   Also, P attempts to reach Watson through the ACM server:
+
+   P->A: INVITE sip:watson at acm.org SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=2
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+
+
+   In parallel, the next attempt proceeds, with an INVITE to X and Y:
+
+
+   P->X: INVITE sip:t.watson at x.bell-tel.com SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=3
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+   P->Y: INVITE sip:watson at y.bell-tel.com SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=4
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+
+
+
+
+Handley, et al.             Standards Track                   [Page 127]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   As it happens, both Watson at X and a colleague in the other lab at
+   host Y hear the phones ringing and pick up. Both X and Y return 200s
+   via the proxy to Bell.
+
+
+   X->P: SIP/2.0 200 OK
+         Via:      SIP/2.0/UDP sip.ieee.org ;branch=3
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org> ;tag=192137601
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     1 INVITE
+         Contact:  sip:t.watson at x.bell-tel.com
+
+   Y->P: SIP/2.0 200 OK
+         Via:      SIP/2.0/UDP sip.ieee.org ;branch=4
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         Contact:  sip:t.watson at y.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org> ;tag=35253448
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     1 INVITE
+
+
+
+   Both responses are forwarded to Bell, using the Via information.  At
+   this point, the ACM server is still searching its database. P can now
+   cancel this attempt:
+
+
+   P->A: CANCEL sip:watson at acm.org SIP/2.0
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=2
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 CANCEL
+
+
+
+   The ACM server gladly stops its neural-network database search and
+   responds with a 200. The 200 will not travel any further, since P is
+   the last Via stop.
+
+
+   A->P: SIP/2.0 200 OK
+         Via:     SIP/2.0/UDP sip.ieee.org ;branch=2
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>
+
+
+
+Handley, et al.             Standards Track                   [Page 128]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 CANCEL
+
+
+
+   Bell gets the two 200 responses from X and Y in short order. Bell's
+   reaction now depends on his software. He can either send an ACK to
+   both if human intelligence is needed to determine who he wants to
+   talk to or he can automatically reject one of the two calls. Here, he
+   acknowledges both, separately and directly to the final destination:
+
+
+   C->X: ACK sip:t.watson at x.bell-tel.com SIP/2.0
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org>;tag=192137601
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     1 ACK
+
+   C->Y: ACK sip:watson at y.bell-tel.com SIP/2.0
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org>;tag=35253448
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     1 ACK
+
+
+
+   After a brief discussion between Bell with X and Y, it becomes clear
+   that Watson is at X. (Note that this is not a three-way call; only
+   Bell can talk to X and Y, but X and Y cannot talk to each other.)
+   Thus, Bell sends a BYE to Y, which is replied to:
+
+
+   C->Y: BYE sip:watson at y.bell-tel.com SIP/2.0
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org>;tag=35253448
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     2 BYE
+
+   Y->C: SIP/2.0 200 OK
+         Via:      SIP/2.0/UDP c.bell-tel.com
+         From:     A. Bell <sip:a.g.bell at bell-tel.com>
+         To:       T. Watson <sip:t.watson at ieee.org>;tag=35253448
+         Call-ID:  31415 at c.bell-tel.com
+         CSeq:     2 BYE
+
+
+
+
+Handley, et al.             Standards Track                   [Page 129]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+16.6 Redirects
+
+   Replies with status codes 301 (Moved Permanently) or 302 (Moved
+   Temporarily) specify another location using the Contact field.
+   Continuing our earlier example, the server P at ieee.org decides to
+   redirect rather than proxy the request:
+
+
+   P->C: SIP/2.0 302 Moved temporarily
+         Via:     SIP/2.0/UDP c.bell-tel.com
+         From:    A. Bell <sip:a.g.bell at bell-tel.com>
+         To:      T. Watson <sip:t.watson at ieee.org>;tag=72538263
+         Call-ID: 31415 at c.bell-tel.com
+         CSeq:    1 INVITE
+         Contact: sip:watson at h.bell-tel.com,
+                   sip:watson at acm.org, sip:t.watson at x.bell-tel.com,
+                   sip:watson at y.bell-tel.com
+         CSeq: 1 INVITE
+
+
+
+   As another example, assume Alice (A) wants to delegate her calls to
+   Bob (B) while she is on vacation until July 29th, 1998. Any calls
+   meant for her will reach Bob with Alice's To field, indicating to him
+   what role he is to play. Charlie (C) calls Alice (A), whose server
+   returns:
+
+
+   A->C: SIP/2.0 302 Moved temporarily
+         From: Charlie <sip:charlie at caller.com>
+         To: Alice <sip:alice at anywhere.com> ;tag=2332462
+         Call-ID: 27182 at caller.com
+         Contact: sip:bob at anywhere.com
+         Expires: Wed, 29 Jul 1998 9:00:00 GMT
+         CSeq: 1 INVITE
+
+
+
+   Charlie then sends the following request to the SIP server of the
+   anywhere.com domain. Note that the server at anywhere.com forwards
+   the request to Bob based on the Request-URI.
+
+
+   C->B: INVITE sip:bob at anywhere.com SIP/2.0
+         From: sip:charlie at caller.com
+         To: sip:alice at anywhere.com
+         Call-ID: 27182 at caller.com
+         CSeq: 2 INVITE
+
+
+
+Handley, et al.             Standards Track                   [Page 130]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   In the third redirection example, we assume that all outgoing
+   requests are directed through a local firewall F at caller.com, with
+   Charlie again inviting Alice:
+
+
+   C->F: INVITE sip:alice at anywhere.com SIP/2.0
+         From: sip:charlie at caller.com
+         To: Alice <sip:alice at anywhere.com>
+         Call-ID: 27182 at caller.com
+         CSeq: 1 INVITE
+
+
+
+   The local firewall at caller.com happens to be overloaded and thus
+   redirects the call from Charlie to a secondary server S:
+
+
+   F->C: SIP/2.0 302 Moved temporarily
+         From: sip:charlie at caller.com
+         To: Alice <sip:alice at anywhere.com>
+         Call-ID: 27182 at caller.com
+         CSeq: 1 INVITE
+         Contact: <sip:alice at anywhere.com:5080;maddr=spare.caller.com>
+
+
+
+   Based on this response, Charlie directs the same invitation to the
+   secondary server spare.caller.com at port 5080, but maintains the
+   same Request-URI as before:
+
+
+   C->S: INVITE sip:alice at anywhere.com SIP/2.0
+         From: sip:charlie at caller.com
+         To: Alice <sip:alice at anywhere.com>
+         Call-ID: 27182 at caller.com
+         CSeq: 2 INVITE
+
+
+
+16.7 Negotiation
+
+   An example of a 606 (Not Acceptable) response is:
+
+
+   S->C: SIP/2.0 606 Not Acceptable
+         From: sip:mjh at isi.edu
+         To: <sip:schooler at cs.caltech.edu> ;tag=7434264
+         Call-ID: 14142 at north.east.isi.edu
+
+
+
+Handley, et al.             Standards Track                   [Page 131]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+         CSeq: 1 INVITE
+         Contact: sip:mjh at north.east.isi.edu
+         Warning: 370 "Insufficient bandwidth (only have ISDN)",
+           305 "Incompatible media format",
+           330 "Multicast not available"
+         Content-Type: application/sdp
+         Content-Length: 50
+
+         v=0
+         s=Let's talk
+         b=CT:128
+         c=IN IP4 north.east.isi.edu
+         m=audio 3456 RTP/AVP 5 0 7
+         m=video 2232 RTP/AVP 31
+
+
+
+   In this example, the original request specified a bandwidth that was
+   higher than the access link could support, requested multicast, and
+   requested a set of media encodings. The response states that only 128
+   kb/s is available and that (only) DVI, PCM or LPC audio could be
+   supported in order of preference.
+
+   The response also states that multicast is not available.  In such a
+   case, it might be appropriate to set up a transcoding gateway and
+   re-invite the user.
+
+16.8 OPTIONS Request
+
+   A caller Alice can use an OPTIONS request to find out the
+   capabilities of a potential callee Bob, without "ringing" the
+   designated address. Bob returns a description indicating that he is
+   capable of receiving audio encodings PCM Ulaw (payload type 0), 1016
+   (payload type 1), GSM (payload type 3), and SX7300/8000 (dynamic
+   payload type 99), and video encodings H.261 (payload type 31) and
+   H.263 (payload type 34).
+
+
+   C->S: OPTIONS sip:bob at example.com SIP/2.0
+         From: Alice <sip:alice at anywhere.org>
+         To: Bob <sip:bob at example.com>
+         Call-ID: 6378 at host.anywhere.org
+         CSeq: 1 OPTIONS
+         Accept: application/sdp
+
+   S->C: SIP/2.0 200 OK
+         From: Alice <sip:alice at anywhere.org>
+         To: Bob <sip:bob at example.com> ;tag=376364382
+
+
+
+Handley, et al.             Standards Track                   [Page 132]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+         Call-ID: 6378 at host.anywhere.org
+         Content-Length: 81
+         Content-Type: application/sdp
+
+         v=0
+         m=audio 0 RTP/AVP 0 1 3 99
+         m=video 0 RTP/AVP 31 34
+         a=rtpmap:99 SX7300/8000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 133]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+A Minimal Implementation
+
+A.1 Client
+
+   All clients MUST be able to generate the INVITE and ACK requests.
+   Clients MUST generate and parse the Call-ID, Content-Length,
+   Content-Type, CSeq, From and To headers. Clients MUST also parse the
+   Require header. A minimal implementation MUST understand SDP (RFC
+   2327, [6]). It MUST be able to recognize the status code classes 1
+   through 6 and act accordingly.
+
+   The following capability sets build on top of the minimal
+   implementation described in the previous paragraph. In general, each
+   capability listed below builds on the ones above it:
+
+   Basic: A basic implementation adds support for the BYE method to
+        allow the interruption of a pending call attempt. It includes a
+        User-Agent header in its requests and indicates its preferred
+        language in the Accept-Language header.
+
+   Redirection: To support call forwarding, a client needs to be able to
+        understand the Contact header, but only the SIP-URL part, not
+        the parameters.
+
+   Firewall-friendly: A firewall-friendly client understands the Route
+        and Record-Route header fields and can be configured to use a
+        local proxy for all outgoing requests.
+
+   Negotiation: A client MUST be able to request the OPTIONS method and
+        understand the 380 (Alternative Service) status and the Contact
+        parameters to participate in terminal and media negotiation. It
+        SHOULD be able to parse the Warning response header to provide
+        useful feedback to the caller.
+
+   Authentication: If a client wishes to invite callees that require
+        caller authentication, it MUST be able to recognize the 401
+        (Unauthorized) status code, MUST be able to generate the
+        Authorization request header and MUST understand the WWW-
+        Authenticate response header.
+
+   If a client wishes to use proxies that require caller authentication,
+   it MUST be able to recognize the 407 (Proxy Authentication Required)
+   status code, MUST be able to generate the Proxy-Authorization request
+   header and understand the Proxy-Authenticate response header.
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 134]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+A.2 Server
+
+   A minimally compliant server implementation MUST understand the
+   INVITE, ACK, OPTIONS and BYE requests. A proxy server MUST also
+   understand CANCEL. It MUST parse and generate, as appropriate, the
+   Call-ID, Content-Length, Content-Type, CSeq, Expires, From, Max-
+   Forwards, Require, To and Via headers. It MUST echo the CSeq and
+   Timestamp headers in the response. It SHOULD include the Server
+   header in its responses.
+
+A.3 Header Processing
+
+   Table 6 lists the headers that different implementations support. UAC
+   refers to a user-agent client (calling user agent), UAS to a user-
+   agent server (called user-agent).
+
+   The fields in the table have the following meaning. Type is as in
+   Table 4 and 5. "-" indicates the field is not meaningful to this
+   system (although it might be generated by it). "m" indicates the
+   field MUST be understood. "b" indicates the field SHOULD be
+   understood by a Basic implementation.  "r" indicates the field SHOULD
+   be understood if the system claims to understand redirection. "a"
+   indicates the field SHOULD be understood if the system claims to
+   support authentication. "e" indicates the field SHOULD be understood
+   if the system claims to support encryption. "o" indicates support of
+   the field is purely optional. Headers whose support is optional for
+   all implementations are not shown.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 135]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+
+
+                        type  UAC  proxy  UAS  registrar
+   _____________________________________________________
+   Accept                R     -     o     m      m
+   Accept-Encoding       R     -     -     m      m
+   Accept-Language       R     -     b     b      b
+   Allow                405    o     -     -      -
+   Authorization         R     a     o     a      a
+   Call-ID               g     m     m     m      m
+   Content-Encoding      g     m     -     m      m
+   Content-Length        g     m     m     m      m
+   Content-Type          g     m     -     m      m
+   CSeq                  g     m     m     m      m
+   Encryption            g     e     -     e      e
+   Expires               g     -     o     o      m
+   From                  g     m     o     m      m
+   Hide                  R     -     m     -      -
+   Contact               R     -     -     -      m
+   Contact               r     r     r     -      -
+   Max-Forwards          R     -     b     -      -
+   Proxy-Authenticate   407    a     -     -      -
+   Proxy-Authorization   R     -     a     -      -
+   Proxy-Require         R     -     m     -      -
+   Require               R     m     -     m      m
+   Response-Key          R     -     -     e      e
+   Route                 R     -     m     -      -
+   Timestamp             g     o     o     m      m
+   To                    g     m     m     m      m
+   Unsupported           r     b     b     -      -
+   User-Agent            g     b     -     b      -
+   Via                   g     m     m     m      m
+   WWW-Authenticate     401    a     -     -      -
+
+
+   Table 6: Header Field Processing Requirements
+
+B Usage of the Session Description Protocol (SDP)
+
+   This section describes the use of the Session Description Protocol
+   (SDP) (RFC 2327 [6]).
+
+B.1 Configuring Media Streams
+
+   The caller and callee align their media descriptions so that the nth
+   media stream ("m=" line) in the caller's session description
+   corresponds to the nth media stream in the callee's description.
+
+
+
+
+Handley, et al.             Standards Track                   [Page 136]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   All media descriptions SHOULD contain "a=rtpmap" mappings from RTP
+   payload types to encodings.
+
+        This allows easier migration away from static payload
+        types.
+
+   If the callee wants to neither send nor receive a stream offered by
+   the caller, the callee sets the port number of that stream to zero in
+   its media description.
+
+
+        There currently is no other way than port zero for the
+        callee to refuse a bidirectional stream offered by the
+        caller. Both caller and callee need to be aware what media
+        tools are to be started.
+
+   For example, assume that the caller Alice has included the following
+   description in her INVITE request. It includes an audio stream and
+   two bidirectional video streams, using H.261 (payload type 31) and
+   MPEG (payload type 32).
+
+
+   v=0
+   o=alice 2890844526 2890844526 IN IP4 host.anywhere.com
+   c=IN IP4 host.anywhere.com
+   m=audio 49170 RTP/AVP 0
+   a=rtpmap:0 PCMU/8000
+   m=video 51372 RTP/AVP 31
+   a=rtpmap:31 H261/90000
+   m=video 53000 RTP/AVP 32
+   a=rtpmap:32 MPV/90000
+
+
+
+   The callee, Bob, does not want to receive or send the first video
+   stream, so it returns the media description below:
+
+   v=0
+   o=bob 2890844730 2890844730 IN IP4 host.example.com
+   c=IN IP4 host.example.com
+   m=audio 47920 RTP/AVP 0 1
+   a=rtpmap:0 PCMU/8000
+   a=rtpmap:1 1016/8000
+   m=video 0 RTP/AVP 31
+   m=video 53000 RTP/AVP 32
+   a=rtpmap:32 MPV/90000
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 137]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+B.2 Setting SDP Values for Unicast
+
+   If a session description from a caller contains a media stream which
+   is listed as send (receive) only, it means that the caller is only
+   willing to send (receive) this stream, not receive (send). The same
+   is true for the callee.
+
+   For receive-only and send-or-receive streams, the port number and
+   address in the session description indicate where the media stream
+   should be sent to by the recipient of the session description, either
+   caller or callee. For send-only streams, the address and port number
+   have no significance and SHOULD be set to zero.
+
+   The list of payload types for each media stream conveys two pieces of
+   information, namely the set of codecs that the caller or callee is
+   capable of sending or receiving, and the RTP payload type numbers
+   used to identify those codecs. For receive-only or send-and-receive
+   media streams, a caller SHOULD list all of the codecs it is capable
+   of supporting in the session description in an INVITE or ACK. For
+   send-only streams, the caller SHOULD indicate only those it wishes to
+   send for this session. For receive-only streams, the payload type
+   numbers indicate the value of the payload type field in RTP packets
+   the caller is expecting to receive for that codec type. For send-only
+   streams, the payload type numbers indicate the value of the payload
+   type field in RTP packets the caller is planning to send for that
+   codec type.  For send-and-receive streams, the payload type numbers
+   indicate the value of the payload type field the caller expects to
+   both send and receive.
+
+   If a media stream is listed as receive-only by the caller, the callee
+   lists, in the response, those codecs it intends to use from among the
+   ones listed in the request. If a media stream is listed as send-only
+   by the caller, the callee lists, in the response, those codecs it is
+   willing to receive among the ones listed in the the request. If the
+   media stream is listed as both send and receive, the callee lists
+   those codecs it is capable of sending or receiving among the ones
+   listed by the caller in the INVITE. The actual payload type numbers
+   in the callee's session description corresponding to a particular
+   codec MUST be the same as the caller's session description.
+
+   If caller and callee have no media formats in common for a particular
+   stream, the callee MUST return a session description containing the
+   particular "m=" line, but with the port number set to zero, and no
+   payload types listed.
+
+   If there are no media formats in common for all streams, the callee
+   SHOULD return a 400 response, with a 304 Warning header field.
+
+
+
+
+Handley, et al.             Standards Track                   [Page 138]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+B.3 Multicast Operation
+
+   The interpretation of send-only and receive-only for multicast media
+   sessions differs from that for unicast sessions. For multicast,
+   send-only means that the recipient of the session description (caller
+   or callee) SHOULD only send media streams to the address and port
+   indicated. Receive-only means that the recipient of the session
+   description SHOULD only receive media on the address and port
+   indicated.
+
+   For multicast, receive and send multicast addresses are the same and
+   all parties use the same port numbers to receive media data. If the
+   session description provided by the caller is acceptable to the
+   callee, the callee can choose not to include a session description or
+   MAY echo the description in the response.
+
+   A callee MAY, in the response, return a session description with some
+   of the payload types removed, or port numbers set to zero (but no
+   other value). This indicates to the caller that the callee does not
+   support the given stream or media types which were removed. A callee
+   MUST NOT change whether a given stream is send-only, receive-only, or
+   send-and-receive.
+
+   If a callee does not support multicast at all, it SHOULD return a 400
+   status response and include a 330 Warning.
+
+B.4 Delayed Media Streams
+
+   In some cases, a caller may not know the set of media formats which
+   it can support at the time it would like to issue an invitation. This
+   is the case when the caller is actually a gateway to another protocol
+   which performs media format negotiation after call setup. When this
+   occurs, a caller MAY issue an INVITE with a session description that
+   contains no media lines. The callee SHOULD interpret this to mean
+   that the caller wishes to participate in a multimedia session
+   described by the session description, but that the media streams are
+   not yet known. The callee SHOULD return a session description
+   indicating the streams and media formats it is willing to support,
+   however. The caller MAY update the session description either in the
+   ACK request or in a re-INVITE at a later time, once the streams are
+   known.
+
+B.5 Putting Media Streams on Hold
+
+   If a party in a call wants to put the other party "on hold", i.e.,
+   request that it temporarily stops sending one or more media streams,
+   a party re-invites the other by sending an INVITE request with a
+   modified session description. The session description is the same as
+
+
+
+Handley, et al.             Standards Track                   [Page 139]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   in the original invitation (or response), but the "c" destination
+   addresses for the media streams to be put on hold are set to zero
+   (0.0.0.0).
+
+B.6 Subject and SDP "s=" Line
+
+   The SDP "s=" line and the SIP Subject header field have different
+   meanings when inviting to a multicast session. The session
+   description line describes the subject of the multicast session,
+   while the SIP Subject header field describes the reason for the
+   invitation. The example in Section 16.2 illustrates this point. For
+   invitations to two-party sessions, the SDP "s=" line MAY be left
+   empty.
+
+B.7 The SDP "o=" Line
+
+   The "o=" line is not strictly necessary for two-party sessions, but
+   MUST be present to allow re-use of SDP-based tools.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 140]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+C Summary of Augmented BNF
+
+   All of the mechanisms specified in this document are described in
+   both prose and an augmented Backus-Naur Form (BNF) similar to that
+   used by RFC 822 [9]. Implementors will need to be familiar with the
+   notation in order to understand this specification. The augmented BNF
+   includes the following constructs:
+
+
+
+        name  =  definition
+
+
+   The name of a rule is simply the name itself (without any enclosing
+   "<" and ">") and is separated from its definition by the equal "="
+   character. White space is only significant in that indentation of
+   continuation lines is used to indicate a rule definition that spans
+   more than one line. Certain basic rules are in uppercase, such as SP,
+   LWS, HT, CRLF, DIGIT, ALPHA, etc. Angle brackets are used within
+   definitions whenever their presence will facilitate discerning the
+   use of rule names.
+
+
+   "literal"
+
+
+   Quotation marks surround literal text. Unless stated otherwise, the
+   text is case-insensitive.
+
+
+   rule1 | rule2
+
+
+   Elements separated by a bar ("|") are alternatives, e.g., "yes | no"
+   will accept yes or no.
+
+
+   (rule1 rule2)
+
+
+   Elements enclosed in parentheses are treated as a single element.
+   Thus, "(elem (foo | bar) elem)" allows the token sequences "elem foo
+   elem" and "elem bar elem".
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 141]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   *rule
+
+
+   The character "*" preceding an element indicates repetition. The full
+   form is "<n>*<m>element" indicating at least <n> and at most <m>
+   occurrences of element. Default values are 0 and infinity so that
+   "*(element)" allows any number, including zero; "1*element" requires
+   at least one; and "1*2element" allows one or two.
+
+
+   [rule]
+
+
+   Square brackets enclose optional elements; "[foo bar]" is equivalent
+   to "*1(foo bar)".
+
+
+   N rule
+
+
+   Specific repetition: "<n>(element)" is equivalent to
+   "<n>*<n>(element)"; that is, exactly <n> occurrences of (element).
+   Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three
+   alphabetic characters.
+
+
+   #rule
+
+
+   A construct "#" is defined, similar to "*", for defining lists of
+   elements. The full form is "<n>#<m> element" indicating at least <n>
+   and at most <m> elements, each separated by one or more commas (",")
+   and OPTIONAL linear white space (LWS). This makes the usual form of
+   lists very easy; a rule such as
+
+
+
+           ( *LWS element *( *LWS "," *LWS element ))
+
+
+   can be shown as 1# element. Wherever this construct is used, null
+   elements are allowed, but do not contribute to the count of elements
+   present. That is, "(element), , (element)" is permitted, but counts
+   as only two elements. Therefore, where at least one element is
+   required, at least one non-null element MUST be present. Default
+   values are 0 and infinity so that "#element" allows any number,
+   including zero; "1#element" requires at least one; and "1#2element"
+   allows one or two.
+
+
+
+Handley, et al.             Standards Track                   [Page 142]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   ; comment
+
+
+   A semi-colon, set off some distance to the right of rule text, starts
+   a comment that continues to the end of line. This is a simple way of
+   including useful notes in parallel with the specifications.
+
+
+   implied *LWS
+
+
+   The grammar described by this specification is word-based. Except
+   where noted otherwise, linear white space (LWS) can be included
+   between any two adjacent words (token or quoted-string), and between
+   adjacent tokens and separators, without changing the interpretation
+   of a field. At least one delimiter (LWS and/or separators) MUST exist
+   between any two tokens (for the definition of "token" below), since
+   they would otherwise be interpreted as a single token.
+
+C.1 Basic Rules
+
+   The following rules are used throughout this specification to
+   describe basic parsing constructs. The US-ASCII coded character set
+   is defined by ANSI X3.4-1986.
+
+
+        OCTET     =  <any 8-bit sequence of data>
+        CHAR      =  <any US-ASCII character (octets 0 - 127)>
+        upalpha   =  "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+                     "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+                     "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+        lowalpha  =  "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+                     "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+                     "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+        alpha     =  lowalpha | upalpha
+        digit     =  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+                     "8" | "9"
+        alphanum  =  alpha | digit
+        CTL       =  <any US-ASCII control character
+                     (octets 0 -- 31) and DEL (127)>
+        CR        =  %d13 ; US-ASCII CR, carriage return character
+        LF        =  %d10 ; US-ASCII LF, line feed character
+        SP        =  %d32 ; US-ASCII SP, space character
+        HT        =  %d09 ; US-ASCII HT, horizontal tab character
+        CRLF      =  CR LF ; typically the end of a line
+
+
+   The following are defined in RFC 2396 [12] for the SIP URI:
+
+
+
+Handley, et al.             Standards Track                   [Page 143]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        unreserved  =  alphanum | mark
+        mark        =  "-" | "_" | "." | "!" | "~" | "*" | "'"
+                   |   "(" | ")"
+        escaped     =  "%" hex hex
+
+
+   SIP header field values can be folded onto multiple lines if the
+   continuation line begins with a space or horizontal tab. All linear
+   white space, including folding, has the same semantics as SP. A
+   recipient MAY replace any linear white space with a single SP before
+   interpreting the field value or forwarding the message downstream.
+
+
+
+        LWS  =  [CRLF] 1*( SP | HT ) ; linear whitespace
+
+
+   The TEXT-UTF8 rule is only used for descriptive field contents and
+   values that are not intended to be interpreted by the message parser.
+   Words of *TEXT-UTF8 contain characters from the UTF-8 character set
+   (RFC 2279 [21]). In this regard, SIP differs from HTTP, which uses
+   the ISO 8859-1 character set.
+
+
+
+        TEXT-UTF8  =  <any UTF-8 character encoding, except CTLs,
+                      but including LWS>
+
+
+   A CRLF is allowed in the definition of TEXT-UTF8 only as part of a
+   header field continuation. It is expected that the folding LWS will
+   be replaced with a single SP before interpretation of the TEXT-UTF8
+   value.
+
+   Hexadecimal numeric characters are used in several protocol elements.
+
+
+
+        hex  =  "A" | "B" | "C" | "D" | "E" | "F"
+                | "a" | "b" | "c" | "d" | "e" | "f" | digit
+
+
+   Many SIP header field values consist of words separated by LWS or
+   special characters. These special characters MUST be in a quoted
+   string to be used within a parameter value.
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 144]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+        token       =  1*< any CHAR  except CTL's  or separators>
+        separators  =  "(" | ")" | "<" | ">" | "@" |
+                       "," | ";" | ":" | "\" | <"> |
+                       "/" | "[" | "]" | "?" | "=" |
+                       "{" | "}" | SP | HT
+
+
+   Comments can be included in some SIP header fields by surrounding the
+   comment text with parentheses. Comments are only allowed in fields
+   containing "comment" as part of their field value definition. In all
+   other fields, parentheses are considered part of the field value.
+
+
+
+        comment  =  "(" *(ctext | quoted-pair | comment) ")"
+        ctext    =  < any TEXT-UTF8  excluding "("  and ")">
+
+
+   A string of text is parsed as a single word if it is quoted using
+   double-quote marks.
+
+
+
+        quoted-string  =  ( <"> *(qdtext | quoted-pair ) <"> )
+        qdtext         =  <any TEXT-UTF8 except <">>
+
+
+   The backslash character ("\") MAY be used as a single-character
+   quoting mechanism only within quoted-string and comment constructs.
+
+
+
+        quoted-pair  =  " \ " CHAR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 145]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+D Using SRV DNS Records
+
+   The following procedure is experimental and relies on DNS SRV records
+   (RFC 2052 [14]). The steps listed below are used in place of the two
+   steps in section 1.4.2.
+
+   If a step elicits no addresses, the client continues to the next
+   step.  However if a step elicits one or more addresses, but no SIP
+   server at any of those addresses responds, then the client concludes
+   the server is down and doesn't continue on to the next step.
+
+   When SRV records are to be used, the protocol to use when querying
+   for the SRV record is "sip". SRV records contain port numbers for
+   servers, in addition to IP addresses; the client always uses this
+   port number when contacting the SIP server. Otherwise, the port
+   number in the SIP URI is used, if present. If there is no port number
+   in the URI, the default port, 5060, is used.
+
+        1.   If the host portion of the Request-URI is an IP address,
+             the client contacts the server at the given address. If the
+             host portion of the Request-URI is not an IP address, the
+             client proceeds to the next step.
+
+        2.   The Request-URI is examined. If it contains an explicit
+             port number, the next two steps are skipped.
+
+        3.   The Request-URI is examined. If it does not specify a
+             protocol (TCP or UDP), the client queries the name server
+             for SRV records for both UDP (if supported by the client)
+             and TCP (if supported by the client) SIP servers. The
+             format of these queries is defined in RFC 2052 [14]. The
+             results of the query or queries are merged together and
+             ordered based on priority. Then, the searching technique
+             outlined in RFC 2052 [14] is used to select servers in
+             order.  If DNS doesn't return any records, the user goes to
+             the last step.  Otherwise, the user attempts to contact
+             each server in the order listed.  If no server is
+             contacted, the user gives up.
+
+        4.   If the Request-URI specifies a protocol (TCP or UDP) that
+             is supported by the client, the client queries the name
+             server for SRV records for SIP servers of that protocol
+             type only. If the client does not support the protocol
+             specified in the Request-URI, it gives up. The searching
+             technique outlined in RFC 2052 [14] is used to select
+             servers from the DNS response in order. If DNS doesn't
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 146]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+             return any records, the user goes to the last step.
+             Otherwise, the user attempts to contact each server in the
+             order listed. If no server is contacted, the user gives up.
+
+        5.   The client queries the name server for address records for
+             the host portion of the Request-URI. If there were no
+             address records, the client stops, as it has been unable to
+             locate a server. By address record, we mean A RR's, AAAA
+             RR's, or their most modern equivalent.
+
+   A client MAY cache a successful DNS query result. A successful query
+   is one which contained records in the answer, and a server was
+   contacted at one of the addresses from the answer. When the client
+   wishes to send a request to the same host, it starts the search as if
+   it had just received this answer from the name server. The server
+   uses the procedures specified in RFC1035 [15] regarding cache
+   invalidation when the time-to-live of the DNS result expires. If the
+   client does not find a SIP server among the addresses listed in the
+   cached answer, it starts the search at the beginning of the sequence
+   described above.
+
+   For example, consider a client that wishes to send a SIP request. The
+   Request-URI for the destination is sip:user at company.com.  The client
+   only supports UDP. It would follow these steps:
+
+        1.   The host portion is not an IP address, so the client goes
+             to step 2 above.
+
+        2.   The client does a DNS query of QNAME="sip.udp.company.com",
+             QCLASS=IN, QTYPE=SRV. Since it doesn't support TCP, it
+             omits the TCP query. There were no addresses in the DNS
+             response, so the client goes to the next step.
+
+        3.   The client does a DNS query for A records for
+             "company.com". An address is found, so that client attempts
+             to contact a server at that address at port 5060.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 147]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+E IANA Considerations
+
+   Section 4.4 describes a name space and mechanism for registering SIP
+   options.
+
+   Section 6.41 describes the name space for registering SIP warn-codes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 148]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+F Acknowledgments
+
+   We wish to thank the members of the IETF MMUSIC WG for their comments
+   and suggestions. Detailed comments were provided by Anders
+   Kristensen, Jim Buller, Dave Devanathan, Yaron Goland, Christian
+   Huitema, Gadi Karmi, Jonathan Lennox, Keith Moore, Vern Paxson, Moshe
+   J. Sambol, and Eric Tremblay.
+
+   This work is based, inter alia, on [37,38].
+
+G Authors' Addresses
+
+   Mark Handley
+   AT&T Center for Internet Research at ISCI (ACIRI)
+   1947 Center St., Suite 600
+   Berkeley, CA 94704-119
+   USA
+   Email: mjh at aciri.org
+
+   Henning Schulzrinne
+   Dept. of Computer Science
+   Columbia University
+   1214 Amsterdam Avenue
+   New York, NY 10027
+   USA
+   Email:  schulzrinne at cs.columbia.edu
+
+   Eve Schooler
+   Computer Science Department 256-80
+   California Institute of Technology
+   Pasadena, CA 91125
+   USA
+   Email:  schooler at cs.caltech.edu
+
+   Jonathan Rosenberg
+   Lucent Technologies, Bell Laboratories
+   Rm. 4C-526
+   101 Crawfords Corner Road
+   Holmdel, NJ 07733
+   USA
+   Email:  jdrosen at bell-labs.com
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 149]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+H Bibliography
+
+   [1] Pandya, R., "Emerging mobile and personal communication systems,"
+       IEEE Communications Magazine , vol. 33, pp. 44--52, June 1995.
+
+   [2] Braden, B., Zhang, L., Berson, S., Herzog, S. and S. Jamin,
+       "Resource ReSerVation protocol (RSVP) -- version 1 functional
+       specification", RFC 2205, October 1997.
+
+   [3] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP:
+       a transport protocol for real-time applications", RFC 1889,
+       Internet Engineering Task Force, Jan. 1996.
+
+   [4] Schulzrinne, H., Lanphier, R. and A. Rao, "Real time streaming
+       protocol (RTSP)", RFC 2326, April 1998.
+
+   [5] Handley, M., "SAP: Session announcement protocol," Internet
+       Draft, Internet Engineering Task Force, Nov. 1996.  Work in
+       progress.
+
+   [6] Handley, M. and V. Jacobson, "SDP: session description protocol",
+       RFC 2327, April 1998.
+
+   [7] International Telecommunication Union, "Visual telephone systems
+       and equipment for local area networks which provide a non-
+       guaranteed quality of service," Recommendation H.323,
+       Telecommunication Standardization Sector of ITU, Geneva,
+       Switzerland, May 1996.
+
+   [8] International Telecommunication Union, "Control protocol for
+       multimedia communication," Recommendation H.245,
+       Telecommunication Standardization Sector of ITU, Geneva,
+       Switzerland, Feb. 1998.
+
+   [9] International Telecommunication Union, "Media stream
+       packetization and synchronization on non-guaranteed quality of
+       service LANs," Recommendation H.225.0, Telecommunication
+       Standardization Sector of ITU, Geneva, Switzerland, Nov. 1996.
+
+   [10] Bradner, S., "Key words for use in RFCs to indicate requirement
+        levels", BCP 14,  RFC 2119, Mardch 1997.
+
+   [11] Fielding, R., Gettys, J., Mogul, J., Nielsen, H. and T.
+        Berners-Lee, "Hypertext transfer protocol -- HTTP/1.1", RFC
+        2068, January 1997.
+
+   [12] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform resource
+        identifiers (URI): generic syntax", RFC 2396, August 1998.
+
+
+
+Handley, et al.             Standards Track                   [Page 150]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   [13] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform resource
+        locators (URL)", RFC 1738, December 1994.
+
+   [14] Gulbrandsen, A.  and P. Vixie, "A DNS RR for specifying the
+        location of services (DNS SRV)", RFC 2052, October 1996.
+
+   [15] Mockapetris, P., "Domain names - implementation and
+        specification", STD 13, RFC 1035, Noveberm 1997.
+
+   [16] Hamilton, M. and R. Wright, "Use of DNS aliases for network
+        services", RFC 2219, October 1997.
+
+   [17] Zimmerman, D., "The finger user information protocol", RFC 1288,
+        December 1991.
+
+   [18] Williamson, S., Kosters, M., Blacka, D., Singh, J. and K.
+        Zeilstra, "Referral whois (rwhois) protocol V1.5", RFC 2167,
+        June 1997.
+
+   [19] Yeong, W., Howes, T. and S. Kille, "Lightweight directory access
+        protocol", RFC 1777, March 1995.
+
+   [20] Schooler, E., "A multicast user directory service for
+        synchronous rendezvous," Master's Thesis CS-TR-96-18, Department
+        of Computer Science, California Institute of Technology,
+        Pasadena, California, Aug. 1996.
+
+   [21] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC
+        2279, January 1998.
+
+   [22] Stevens, W., TCP/IP illustrated: the protocols , vol. 1.
+        Reading, Massachusetts: Addison-Wesley, 1994.
+
+   [23] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
+        November 1990.
+
+   [24] Crocker, D., "Standard for the format of ARPA internet text
+        messages", RFC STD 11, RFC 822, August 1982.
+
+   [25] Meyer, D., "Administratively scoped IP multicast", RFC 2365,
+        July 1998.
+
+   [26] Schulzrinne, H., "RTP profile for audio and video conferences
+        with minimal control", RFC 1890, January 1996
+
+   [27] Eastlake, D., Crocker, S. and J. Schiller, "Randomness
+        recommendations for security", RFC 1750, December 1994.
+
+
+
+
+Handley, et al.             Standards Track                   [Page 151]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+   [28] Hoffman, P., Masinter, L. and J. Zawinski, "The mailto URL
+        scheme", RFC 2368, July 1998.
+
+   [29] Braden, B., "Requirements for internet hosts - application and
+        support", STD 3, RFC 1123, October 1989.
+
+   [30] Palme, J., "Common internet message headers", RFC 2076, February
+        1997.
+
+   [31] Alvestrand, H., "IETF policy on character sets and languages",
+        RFC 2277, January 1998.
+
+   [32] Elkins, M., "MIME security with pretty good privacy (PGP)", RFC
+        2015, October 1996.
+
+   [33] Atkins, D., Stallings, W. and P. Zimmermann, "PGP message
+        exchange formats", RFC 1991, August 1996.
+
+   [34] Atkinson, R., "Security architecture for the internet protocol",
+        RFC 2401, November 1998.
+
+   [35] Allen, C. and T. Dierks, "The TLS protocol version 1.0," RFC
+        2246, January 1999.
+
+   [36] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+        Leach, P., Luotonen, A. and L. Stewart, "HTTP authentication:
+        Basic and digest access authentication," Internet Draft,
+        Internet Engineering Task Force, Sept.  1998.  Work in progress.
+
+   [37] Schooler, E., "Case study: multimedia conference control in a
+        packet-switched teleconferencing system," Journal of
+        Internetworking:  Research and Experience , vol. 4, pp. 99--120,
+        June 1993.  ISI reprint series ISI/RS-93-359.
+
+   [38] Schulzrinne, H., "Personal mobility for multimedia services in
+        the Internet," in European Workshop on Interactive Distributed
+        Multimedia Systems and Services (IDMS) , (Berlin, Germany), Mar.
+        1996.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 152]
+
+RFC 2543            SIP: Session Initiation Protocol          March 1999
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al.             Standards Track                   [Page 153]

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# Run the parser tests
+#
+# usage: run-tests [test_program] [test-case...]
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+
+msg_test="${1:-./msg_test}"
+shift
+
+rc=0
+
+for n in "$@";
+do 
+    if "$msg_test" < "$n" > /dev/null ; then 
+	true
+    else
+	echo "$n: ERROR"; rc=1
+    fi
+done
+
+exit $rc
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+#!/bin/sh
+./date_test "Sun, 18 Mar 2001 23:01:00 GMT"

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,608 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "sip" - SIP Parser Module
+ *
+ * @section sip_meta Module Meta Information
+ *
+ * The Sofia @b sip module contains interface to the SIP parser and the
+ * header and message objects.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section sip_overview Overview
+ *
+ * The structure of each header is defined in @b <sip.h>. In addition to the
+ * header structure, there is defined a @em header @em class structure and
+ * some standard functions for each header in the include file @b
+ * <sofia-sip/sip_header.h>. For header @c X, there are types, functions,
+ * macros and header class declared in <sofia-sip/sip_protos.h> and
+ * <sofia-sip/sip_hclass.h>. See @ref sip_header_x for detailed description
+ * of these header-specific boilerplate declarations.
+ *
+ * In addition to this interface, the @ref sip_parser "SIP parser documentation"
+ * contains description of the functionality required when a parser is
+ * extended by a new header. It is possible to add new headers to the SIP
+ * parser or extend the definition of existing ones.
+ *
+ * @section sip_parser_intro Parsing SIP Messages
+ *
+ * Sofia SIP parser follows @em recursive-descent principle.  In other words,
+ * it is a program that descends the SIP syntax tree top-down recursively.
+ * (All syntax trees have root at top and they grow downwards.)
+ *
+ * In the case of SIP such a parser is very efficient. The parser can choose
+ * between different forms based on each token, as SIP syntax is carefully
+ * designed so that it requires only minimal scan-ahead.  It is also easy to
+ * extend a recursive-descent parser via a standard API, unlike, for
+ * instance, a LALR parser generated by @em Bison.
+ *
+ * The abstract message module @b msg contains a high-level parser engine
+ * that drives the parsing process and invokes the SIP parser for each
+ * header. As there are no framing between SIP messages, the parser
+ * considers any received data, be it a UDP datagram or a TCP stream, as a
+ * @em message @em stream, which may consist of one or more SIP messages. 
+ * The parser works by first separating stream into fragments, then building
+ * a complete message based on parsing result. After a message is completed,
+ * it can be given to the message stream customer (typically a protocol
+ * state machine). The parser continues processing the stream and feeding
+ * the messages to protocol engine until the end of the stream is reached.
+ *
+ * For each message, the parser starts by separating the first fragment,
+ * which is either a request or status line. After the first line has been
+ * processed, the parser engine continues by separating the headers
+ * one-by-one from the message. After the parser encounters an empty line
+ * separating the headers and the message body (payload), it invokes a
+ * function parsing the separator and payload fragment(s). When the message
+ * is complete, the parser can hand the message over to the protocol engine. 
+ * Then it is ready to start again with first fragment of the next message.
+ *
+ * @image html sip-parser.gif Separating byte stream to messages
+ * @image latex sip-parser.eps Separating byte stream to messages
+ *
+ * When the parsing process has completed, the request or status line, each
+ * header, separator and the payload are all in their own fragment
+ * structure. The fragments form a dual-linked list known as @e fragment @e
+ * chain as shown in the above figure. The buffers for the message, the
+ * fragment chain, and a whole other stuff is held by the generic message
+ * type, #msg_t, defined in <msg.h>. The internal structure of #msg_t is
+ * known only within @b msg module and it is hidden from other modules.
+ * 
+ * The abstract message module @b msg also drives the reverse process,
+ * invoking the encoding method of each fragment so that the whole outgoing
+ * SIP message is encoded properly.
+ *
+ * @section sip_header_struct SIP Header as a C struct
+ *
+ * Just separating headers from each other and from the message body is not
+ * usually enough. When a header contains structured data, the header
+ * contents should be converted to a form that is convenient to use from C
+ * programs. For that purpose, the message parser needs a special function
+ * for each individual header. The header-specific parsing function divides
+ * the contents of the header into semantically meaningful segments and
+ * stores the result in a header-specific structure.
+ *
+ * The parser passes the fragment contents to a parsing function immediately
+ * after it has separated a fragment from the message. The parsing function
+ * is defined by the @e header @e class. The header class is either
+ * determined by the fragment position (first line, separator line or
+ * payload), or it is found from the hash table using the header name as
+ * key. There is also a special header class for @e unknown headers, headers
+ * with a name that is not regocnized by the parser.
+ *
+ * For instance, the @From header has following syntax:
+ *
+ * @code
+ * from           = ("From" | "f") ":" 
+ *                  ( name-addr | addr-spec ) *( ";" addr-params )
+ * name-addr      = [ display-name ] "<" addr-spec ">"
+ * addr-spec      = SIP-URL | URI
+ * display-name   = *token | quoted-string
+ * addr-params    = *( tag-param |  generic-param )
+ * tag-param      = "tag" "=" ( token | quoted-string )
+ * @endcode
+ *
+ * When a @From header is parsed, the header parser function sip_from_d()
+ * separates the @e display-name, @e addr-spec and each parameter in the @e
+ * addr-params list. The parsing result is assigned to a #sip_from_t
+ * structure, which is defined as follows:
+ *
+ * @code
+ * typedef struct sip_addr_s {
+ *   sip_common_t        a_common[1];
+ *   sip_unknown_t      *a_next;
+ *   char const         *a_display;
+ *   url_t               a_url[1];
+ *   sip_param_t const  *a_params;
+ *   char const         *a_tag;
+ * } sip_from_t;
+ * @endcode
+ *
+ * The string containing the @e display-name is put into the @c a_display
+ * field, the URL contents can be found in the @c a_url field, and the list
+ * of @e addr-params parameters is put in the @c a_params array.  If there
+ * is a @e tag-param present, a pointer to the parameter value is assigned
+ * to @c a_tag field.
+ *
+ * @section sip_msg_struct SIP Message as a C struct
+ *
+ * It is not enough to represent a SIP message as a collection of headers
+ * following each other. The programmer also needs a convenient way to
+ * access certain headers at the SIP message level, for example, accessing
+ * directly the @From header instead of going through all headers and
+ * examining their name. The structured view to the SIP message is provided
+ * via a C struct with type #sip_t. 
+ *
+ * In other words, a single message is represented by two types, first type
+ * (#msg_t) is private to the msg module and inaccessable by an application
+ * programmer, second (#sip_t) is a public structure containing the parsed
+ * headers.
+ *
+ * The #sip_t structure is defined as follows:
+ * @code
+ * typedef struct sip_s {
+ *   msg_common_t        sip_common[1];    // Used with recursive inclusion
+ *   msg_pub_t          *sip_next;         // Ditto
+ *   void               *sip_user;	   // Application data
+ *   unsigned            sip_size;
+ *   int                 sip_flags;
+ *
+ *   sip_error_t        *sip_error;	   // Erroneous headers
+ * 
+ *   sip_request_t      *sip_request;      // Request line
+ *   sip_status_t       *sip_status;       // Status line
+ *
+ *   sip_via_t          *sip_via;          // @Via (v)
+ *   sip_route_t        *sip_route;        // @Route
+ *   sip_record_route_t *sip_record_route; // @RecordRoute
+ *   sip_max_forwards_t *sip_max_forwards; // @MaxForwards
+ *   ...
+ * } sip_t;
+ * @endcode
+ *
+ * As you can see above, the public #sip_t structure contains the common
+ * header members that are also found in the beginning of a header
+ * structure. The @e sip_size indicates the size of the structure - the
+ * application can extend the parser and #sip_t structure beyond the
+ * original size. The @e sip_flags contains various flags used during the
+ * parsing and printing process. They are documented in the <msg.h>. These
+ * boilerplate members are followed by the pointers to various message
+ * elements and headers.
+ *
+ * @note Within the @b msg module, the public structure is known as
+ * #msg_pub_t. The application programmer can cast a #msg_t pointer to
+ * #sip_t with sip_object() function (or macro).
+ *
+ *
+ * @section sip_parsing_example Result of Parsing Process
+ *
+ * Let us now show how a simple message is parsed and presented to the
+ * applications. As an exampe, we choose a BYE message with only the
+ * mandatory fields included:
+ * @code
+ * BYE sip:joe at example.com SIP/2.0
+ * Via: SIP/2.0/UDP sip.example.edu;branch=d7f2e89c.74a72681
+ * Via: SIP/2.0/UDP pc104.example.edu:1030;maddr=110.213.33.19
+ * From: Bobby Brown <sip:bb at example.edu>;tag=77241a86
+ * To: Joe User <sip:joe at example.com>;tag=7c6276c1
+ * Call-ID: 4c4e911b at pc104.example.edu
+ * CSeq: 2
+ * @endcode
+ *
+ * The figure below shows the layout of the BYE message above after parsing:
+ *
+ * @image html sip-parser2.gif BYE message and its representation in C
+ * @image latex sip-parser2.eps BYE message and its representation in C
+ *
+ * The leftmost box represents the message of type #msg_t.  Next box from
+ * the left reprents the #sip_t structure, which contains pointers to a
+ * header objects.  The next column contains the header objects.  There is
+ * one header object for each message fragment. The rightmost box represents
+ * the I/O buffer used when the message was received.  Note that the I/O
+ * buffer may be non-continous and composed of many separate memory areas.
+ *
+ * The message object has link to the public message structure (@a
+ * m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O
+ * buffer (@a m_buffer). The public message header structure contains
+ * pointers to the headers according to their type. If there are multiple
+ * headers of the same type (like there are two @Via headers in the above
+ * message), the headers are put into a single-linked list.
+ * 
+ * Each fragment has pointers to successing and preceding fragment. It also
+ * contains pointer to the corresponding data within the I/O buffer and its
+ * length.
+ * 
+ * The main purpose of the fragment chain is to preserve the original order
+ * of the headers.  If there were an third @Via header after @CSeq in the
+ * message, the fragment representing it would be after the @CSeq header in
+ * the fragment chain but after the second @Via in the header list.
+ *
+ */
+
+/**@defgroup sip_headers SIP Headers
+ *
+ * SIP headers and other SIP message elements.
+ *
+ * For each SIP header recognized by the SIP module, there is a header
+ * structure containing the parsed value.  The header structure name is
+ * generated from the header name by lowercasing the name, replacing the
+ * non-alphanumeric characters (usually just minus "-") with underscore "_"
+ * characters, and then adding prefix @c sip_ and suffix @c _t.  For
+ * instance, the contents of header "MIME-Version" is stored in a structure
+ * called sip_mime_version_t.
+ *
+ */
+
+/**@ingroup sip_headers
+ * @defgroup sip_header_x SIP Header X - Conventions
+ * 
+ * For a SIP header X, there are types, functions, macros and global data
+ * declared in <sofia-sip/sip_protos.h> and <sofia-sip/sip_hclass.h> as
+ * follows:
+ *  - #sip_X_t is the structure used to store parsed header,
+ *  - SIP_X_INIT() initializes a static instance of #sip_X_t,
+ *  - sip_X_init() initializes a dynamic instance of #sip_X_t,
+ *  - sip_is_X() tests if header object is instance of header X,
+ *  - sip_X_make() creates a header X object by decoding given string,
+ *  - sip_X_format() creates a header X object by decoding given 
+ *    printf() list,
+ *  - sip_X_dup() duplicates (deeply copies) the header X, 
+ *  - sip_X_copy() copies the header X,
+ *  - #msg_hclass_t #sip_X_class[] contains the @em header @em class 
+ *    for header X.
+ * 
+ * All header structures contain the common part, a #sip_common_t structure
+ * (@a X_common[]), a link to the next header in list (@a X_next), and
+ * various fields describing the header value (in this case, @a X_value).
+ * The header structure looks like this:
+ * @code
+ * typedef struct sip_X_s
+ * {
+ *   struct msg_common_s {
+ *     msg_header_t       *h_succ;   // Pointer to succeeding fragment
+ *     msg_header_t      **h_prev;   // Pointer to preceeding fragment
+ *     msg_hclass_t       *h_class;  // Header class 
+ *     void const         *h_data;   // Encoded data
+ *     usize_t             h_len;    // Encoding length (including CRLF)
+ *   } X_common[1];
+ *   sip_X_t        *X_next;	     // Link to next X header field
+ *   uint32_t       X_value;         // Value of X
+ *   msg_param_t   *X_param;         // List of parameters
+ * } sip_X_t;
+ * @endcode
+ *
+ * The common structure #msg_common_t (aka #sip_common_t)
+ * can be considered as a base class for all
+ * headers. The structure contains the pointers for dual-linked
+ * fragment chain (@a h_succ, @a h_prev), a pointer to header class (@a
+ * h_class), a pointer to the text encoding of header contents (@a h_data)
+ * and the length of the encoding (@a h_len). (@a X_common is an array of size
+ * 1, as it makes it easy to cast a header pointer to a pointer to
+ * msg_common_t.)
+ *
+ * The @a X_next is a pointer to another header (usually a pointer to
+ * structure of same type). If there are multiple headers with same name,
+ * like the two "Via" headers in the example above, the @a X_next is used to
+ * link the second header to the first. The fragment chain cannot be used
+ * for this purpose as the headers with same name are not necessarily
+ * adjacent in the parsed message.
+ *
+ * The rest of the fields contain the parsed or decoded representation of
+ * the header. In this case, it is a 32-bit integer followed by a list of
+ * parameters. The content of parameters is not parsed, they are just
+ * separated from each other and then stored in an dynamically allocated
+ * array of string pointers. Pointer to the array is stored to @a X_params.
+ * 
+ * For more complex header structures, see #sip_contact_t or #sip_rack_t.
+ *
+ * @{
+ */
+
+/**The structure #sip_X_t contains representation of a SIP
+ * @ref sip_header_x "X" header.
+ *
+ * The #sip_X_t is defined as follows:
+ * @code
+ * typedef struct sip_X_s {
+ *   msg_common_t   X_common[1];        // Common fragment info
+ *   sip_X_t       *X_next;             // Link to next X header field
+ *   uint32_t       X_value;            // Value of X
+ *   msg_param_t   *X_param;            // List of parameters
+ * } sip_X_t;
+ * @endcode
+ */
+typedef struct sip_X_s sip_X_t;
+
+/**@var msg_hclass_t sip_X_class[];
+ * @brief Header class for SIP X.
+ * 
+ * The header class sip_X_class defines how a SIP
+ * X is parsed and printed.  It also
+ * contains methods used by SIP parser and other functions
+ * to manipulate the sip_X_t header structure.
+ * 
+ */
+SIP_DLL extern msg_hclass_t sip_X_class[];
+
+enum { 
+ /** Hash of X. @internal */
+ sip_X_hash = hash 
+};
+
+/** Parse a X. @internal */
+msg_parse_f sip_X_d;
+
+/** Print a X. @internal */
+msg_print_f sip_X_e;
+
+/**Initializer for structure sip_X_t.
+ * 
+ * A static sip_X_t structure must be initialized
+ * with the SIP_X_INIT() macro. For instance,
+ * @code 
+ * 
+ *  sip_X_t sip_X = SIP_X_INIT;
+ * 
+ * @endcode
+ * @HI
+ */
+#define SIP_X_INIT() SIP_HDR_INIT(X)
+
+/**Initialize a structure sip_X_t.
+ * 
+ * An sip_X_t structure can be initialized with the
+ * sip_X_init() function/macro. For instance,
+ * @code
+ * 
+ *  sip_X_t sip_X;
+ * 
+ *  sip_X_init(&sip_X);
+ * 
+ * @endcode
+ * @HI
+ */
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_init(sip_X_t x[1])
+{
+  return SIP_HEADER_INIT(x, sip_X_class, sizeof(sip_X_t));
+}
+#else
+#define sip_X_init(x) \
+  SIP_HEADER_INIT(x, sip_X_class, sizeof(sip_X_t))
+#endif
+
+/**Test if header object is instance of sip_X_t.
+ * 
+ * The function sip_is_X() returns true (nonzero) if
+ * the header class is an instance of X
+ * object and false (zero) otherwise.
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @return
+ * The function sip_is_X() returns true (nonzero) if
+ * the header object is an instance of header X and
+ * false (zero) otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline int sip_is_X(sip_header_t const *header)
+{
+  return header && header->sh_class->hc_id == sip_hdr_X;
+}
+#else
+int sip_is_X(sip_header_t const *header);
+#endif
+
+#define sip_X_p(h) sip_is_X((h))
+
+/**Duplicate (deep copy) @c sip_X_t.
+ * 
+ * The function sip_X_dup() duplicates a header
+ * structure @a hdr.  If the header structure @a hdr
+ * contains a reference (@c hdr->x_next) to a list of
+ * headers, all the headers in the list are duplicated, too.
+ * 
+ * @param home  memory home used to allocate new structure
+ * @param hdr   header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant
+ * strings attached to the header are copied, too.  The
+ * function uses given memory @a home to allocate all the
+ * memory areas used to copy the header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   X = sip_X_dup(home, sip->sip_X);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function sip_X_dup() returns a pointer to the
+ * newly duplicated sip_X_t header structure, or NULL
+ * upon an error.
+ */
+sip_X_t *sip_X_dup(su_home_t *home, sip_X_t const *hdr);
+
+/**Copy a sip_X_t header structure.
+ * 
+ * The function sip_X_copy() copies a header structure @a
+ * hdr.  If the header structure @a hdr contains a reference (@c
+ * hdr->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home
+ * to allocate all the memory areas used to copy the header
+ * structure @a hdr.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param hdr     pointer to the header structure to be duplicated
+ * 
+ * When copying, only the header structure and parameter lists
+ * attached to it are duplicated.  The new header structure
+ * retains all the references to the strings within the old @a
+ * header, including the encoding of the old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   X = sip_X_copy(home, sip->sip_X);
+ * 
+ * @endcode
+ * 
+ * @return
+ * The function sip_X_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+sip_X_t *sip_X_copy(su_home_t *home, sip_X_t const *hdr);
+
+/**Make a header structure sip_X_t.
+ * 
+ * The function sip_X_make() makes a new
+ * sip_X_t header structure.  It allocates a new
+ * header structure, and decodes the string @a s as the
+ * value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @note This function is usually implemented as a macro calling
+ * sip_header_make().
+ * 
+ * @return
+ * The function sip_X_make() returns a pointer to
+ * newly maked sip_X_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_make(su_home_t *home, char const *s)
+{
+  return sip_header_make(home, sip_X_class, s)->sh_X;
+}
+#else
+sip_X_t *sip_X_make(su_home_t *home, char const *s);
+#endif
+
+/**Make a X from formatting result.
+ * 
+ * The function sip_X_format() makes a new
+ * X object using formatting result as its
+ * value.  The function first prints the arguments according to
+ * the format @a fmt specified.  Then it allocates a new header
+ * structure, and uses the formatting result as the header
+ * value.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @note This function is usually implemented as a macro calling
+ * msg_header_format().
+ * 
+ * @return
+ * The function sip_X_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_X_t *sip_X_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((format (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_format(su_home_t *home, char const *fmt, ...)
+{
+  sip_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = sip_header_vformat(home, sip_X_class, fmt, ap);
+  va_end(ap);
+ 
+  return h->sh_X;
+}
+#endif
+
+/**Decode a header X.
+ *
+ * The function sip_X_d() decodes value of the header X in the preallocated
+ * header structure @a h.  The string @a s to be decoded should not contain
+ * the header name or colon. The decoding function also expects that the
+ * leading and trailing whitespace has been removed from the string @a s.
+ *
+ * @param home   memory home used to allocate new header structure.
+ * @param h      sip_X_t header structure 
+ * @param s      string to be decoded
+ * @param bsiz   length of string @a s
+ *
+ * @return
+ * The function sip_X_d() returns non-negative value when successful, or
+ * -1 upon an error.
+ */
+int sip_X_d(su_home_t *home, sip_header_t *h, char *s, int bsiz);
+
+/**Encode a header X.
+ *
+ * The function sip_X_e() encodes a header structure @a h to the given
+ * buffer @a buf.  Even if the given buffer @a buf is NULL or its size @a
+ * bufsiz is too small to fit the encoding result, the function returns the
+ * number of characters required for the encoding.
+ *
+ * @param buf    buffer to store the encoding result
+ * @param bsiz   size of the encoding buffer
+ * @param h      header to be encoded.
+ * @param flags  flags controlling the encoding
+ * 
+ * @note 
+ * The encoding buffer size @b must be @b bigger than, not equal to,
+ * the actual encoding result.
+ *
+ * @return
+ * The function sip_X_e() returns the number of characters required for the
+ * encoding.
+ * 
+ */
+int sip_X_e(char buf[], int bsiz, sip_header_t const *h, int flags);
+
+/** @} */
+
+/**@defgroup sip_status_codes SIP Status Codes and Reason Phrases
+ *
+ * The macros and variables for the standard SIP status codes and reason
+ * phrases are defined in <sip_status.h>.
+ */
+
+/**@defgroup sip_tag SIP Tags
+ *
+ * SIP headers in tag item lists and tagged argument lists. 
+ *
+ * The include file <sip_tag.h> defines tags and tag items for including SIP
+ * headers in tag item lists or tagged argument lists. For each header,
+ * there is a tag for pointer to header object and an another tag for string
+ * containing header value. For example, @From header has tags
+ * SIPTAG_FROM() and SIPTAG_FROM_STR().
+ *
+ * It is also possible to include user-defined headers or non-standard
+ * headers using SIPTAG_HEADER_STR().
+ *
+ * A function taking SIP headers as arguments could be called like this:
+ * @code
+ * sip_payload_t *payload;
+ * ...
+ * sip_add_tl(msg, sip, 
+ *            SIPTAG_CONTENT_TYPE_STR("text/plain"),
+ *            SIPTAG_USER_AGENT(agent->user_agent),
+ *            SIPTAG_PAYLOAD(payload),
+ *            SIPTAG_HEADER_STR("X-Header: contents\nP-Header: bar"),
+ *            TAG_END());
+ * ...
+ * @endcode
+ *
+ * In the above fragment, the function sip_add_tl() will add @ContentType
+ * and @UserAgent headers along with message payload to the SIP message.
+ * The @ContentType header is made with value "text/plain".
+ *
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+ALIASES += \
+ "AcceptContact=@ref sip_accept_contact \"Accept-Contact\"" \
+ "AcceptEncoding=@ref sip_accept_encoding \"Accept-Encoding\"" \
+ "AcceptLanguage=@ref sip_accept_language \"Accept-Language\"" \
+ "Accept=@ref sip_accept \"Accept\"" \
+ "AllowEvents=@ref sip_allow_events \"Allow-Events\"" \
+ "Allow=@ref sip_allow \"Allow\"" \
+ "AuthenticationInfo=@ref sip_authentication_info \"Authentication-Info\"" \
+ "Authorization=@ref sip_authorization \"Authorization\"" \
+ "CSeq=@ref sip_cseq \"CSeq\"" \
+ "CallID=@ref sip_call_id \"Call-ID\"" \
+ "CallInfo=@ref sip_call_info \"Call-Info\"" \
+ "Contact=@ref sip_contact \"Contact\"" \
+ "ContentDisposition=@ref sip_content_disposition \"Content-Disposition\"" \
+ "ContentEncoding=@ref sip_content_encoding \"Content-Encoding\"" \
+ "ContentLanguage=@ref sip_content_language \"Content-Language\"" \
+ "ContentLength=@ref sip_content_length \"Content-Length\"" \
+ "ContentType=@ref sip_content_type \"Content-Type\"" \
+ "Date=@ref sip_date \"Date\"" \
+ "ErrorInfo=@ref sip_error_info \"Error-Info\"" \
+ "Event=@ref sip_event \"Event\"" \
+ "Expires=@ref sip_expires \"Expires\"" \
+ "From=@ref sip_from \"From\"" \
+ "InReplyTo=@ref sip_in_reply_to \"In-Reply-To\"" \
+ "MIMEVersion=@ref sip_mime_version \"MIME-Version\"" \
+ "MaxForwards=@ref sip_max_forwards \"Max-Forwards\"" \
+ "MinExpires=@ref sip_min_expires \"Min-Expires\"" \
+ "MinSE=@ref sip_min_se \"Min-SE\"" \
+ "Organization=@ref sip_organization \"Organization\"" \
+ "Path=@ref sip_path \"Path\"" \
+ "Priority=@ref sip_priority \"Priority\"" \
+ "Privacy=@ref sip_privacy \"Privacy\"" \
+ "ProxyAuthenticate=@ref sip_proxy_authenticate \"Proxy-Authenticate\"" \
+ "ProxyAuthenticationInfo=@ref sip_proxy_authentication_info \"Proxy-Authentication-Info\"" \
+ "ProxyAuthorization=@ref sip_proxy_authorization \"Proxy-Authorization\"" \
+ "ProxyRequire=@ref sip_proxy_require \"Proxy-Require\"" \
+ "RAck=@ref sip_rack \"RAck\"" \
+ "RSeq=@ref sip_rseq \"RSeq\"" \
+ "Reason=@ref sip_reason \"Reason\"" \
+ "RecordRoute=@ref sip_record_route \"Record-Route\"" \
+ "ReferTo=@ref sip_refer_to \"Refer-To\"" \
+ "ReferredBy=@ref sip_referred_by \"Referred-By\"" \
+ "RejectContact=@ref sip_reject_contact \"Reject-Contact\"" \
+ "Replaces=@ref sip_replaces \"Replaces\"" \
+ "RequestDisposition=@ref sip_request_disposition \"Request-Disposition\"" \
+ "Require=@ref sip_require \"Require\"" \
+ "RetryAfter=@ref sip_retry_after \"Retry-After\"" \
+ "Route=@ref sip_route \"Route\"" \
+ "SIPETag=@ref sip_etag \"SIP-ETag\"" \
+ "SIPIfMatch=@ref sip_if_match \"SIP-If-Match\"" \
+ "SecurityClient=@ref sip_security_client \"Security-Client\"" \
+ "SecurityServer=@ref sip_security_server \"Security-Server\"" \
+ "SecurityVerify=@ref sip_security_verify \"Security-Verify\"" \
+ "Server=@ref sip_server \"Server\"" \
+ "ServiceRoute=@ref sip_service_route \"Service-Route\"" \
+ "SessionExpires=@ref sip_session_expires \"Session-Expires\"" \
+ "Subject=@ref sip_subject \"Subject\"" \
+ "SubscriptionState=@ref sip_subscription_state \"Subscription-State\"" \
+ "Supported=@ref sip_supported \"Supported\"" \
+ "Timestamp=@ref sip_timestamp \"Timestamp\"" \
+ "To=@ref sip_to \"To\"" \
+ "Unsupported=@ref sip_unsupported \"Unsupported\"" \
+ "UserAgent=@ref sip_user_agent \"User-Agent\"" \
+ "Via=@ref sip_via \"Via\"" \
+ "WWWAuthenticate=@ref sip_www_authenticate \"WWW-Authenticate\"" \
+ "Warning=@ref sip_warning \"Warning\"" \
+ "ReferSub=@ref sip_refer_sub \"Refer-Sub\"" \
+ "SuppressBodyIfMatch=@ref sip_suppress_body_if_match \"Suppress-Body-If-Match\"" \
+ "SuppressNotifyIfMatch=@ref sip_suppress_notify_if_match \"Suppress-Notify-If-Match\"" \
+  

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+#
+# nta has a bad_mask specifying which headers cause nta to automatically
+# return 400 Bad Message if a critical header or pseudoheader in a request
+# has a parsing error.
+#
+# The parsing error can be later checked with msg_extract_errors(), too.
+#
+# See <sip_parser.h> for definition of mask values.
+#
+# The mask can be set when header is added with
+# msg_mclass_insert_header_flags().  
+#
+# The flags of existing headers can be modified, if a copy of message class
+# is first made with msg_mclass_clone().
+#
+
+#
+# Headers that must be valid for all requests
+#
+request = sip_mask_request | sip_mask_response
+status = sip_mask_request | sip_mask_response
+From = sip_mask_request | sip_mask_response
+To = sip_mask_request | sip_mask_response
+CSeq = sip_mask_request | sip_mask_response
+Call-ID = sip_mask_request | sip_mask_response
+Content-Length = sip_mask_request | sip_mask_response
+Via = sip_mask_request | sip_mask_response
+
+#
+# User-Agent headers
+#
+Content-Type = sip_mask_ua
+Content-Disposition = sip_mask_ua
+Content-Encoding = sip_mask_ua
+
+#
+# Proxy heades
+#
+Route = sip_mask_proxy
+Max-Forwards = sip_mask_proxy
+Proxy-Require = sip_mask_proxy
+Proxy-Authorization = sip_mask_proxy
+
+#
+# Registrar headers
+#
+Min-Expires = sip_mask_registrar
+Authorization = sip_mask_registrar
+Path = sip_mask_registrar
+
+#
+# Headers that must be valid in UA, proxy or registrar
+#
+Supported = sip_mask_ua | sip_mask_proxy | sip_mask_registrar
+Contact = sip_mask_ua | sip_mask_proxy | sip_mask_registrar
+Require = sip_mask_ua | sip_mask_registrar
+Record-Route = sip_mask_ua | sip_mask_proxy
+
+Expires = sip_mask_registrar | sip_mask_events
+
+#
+# 100rel headers
+#
+RAck = sip_mask_100rel
+RSeq = sip_mask_100rel
+
+#
+# Event headers
+#
+Event = sip_mask_events
+Subscription-State = sip_mask_events
+
+#
+# 'timer' headers
+#
+Session-Expires = sip_mask_timer
+Min-SE = sip_mask_timer
+
+#
+# Privacy headers
+#
+Privacy = sip_mask_privacy
+
+#
+# Headers used in caller preferences
+#
+Request-Disposition = sip_mask_pref
+Accept-Contact = sip_mask_pref
+Reject-Contact = sip_mask_pref
+
+#
+# PUBLISH headers (NOTE: No SIP- here!)
+#
+Etag = sip_mask_publish
+If-Match = sip_mask_publish

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2734 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_basic.c
+ * @brief Basic SIP headers.
+ *
+ * Implementation of header classes for basic SIP headers, like request and
+ * status lines, payload, @CallID, @CSeq, @Contact, @ContentLength, @Date,
+ * @Expires, @From, @Route, @RecordRoute, @To, and @Via.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date  Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/string0.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/msg_date.h>
+
+#include <sofia-sip/su_uniqueid.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_request Request Line
+ *
+ * The request line is first line in a SIP request message.  Its syntax defined
+ * in @RFC3261 as follows:
+ * 
+ * @code
+ *    Request-Line   =  Method SP Request-URI SP SIP-Version CRLF
+ *    Request-URI    =  SIP-URI / SIPS-URI / absoluteURI
+ *    absoluteURI    =  scheme ":" ( hier-part / opaque-part )
+ *    hier-part      =  ( net-path / abs-path ) [ "?" query ]
+ *    net-path       =  "//" authority [ abs-path ]
+ *    abs-path       =  "/" path-segments
+ *    opaque-part    =  uric-no-slash *uric
+ *    uric           =  reserved / unreserved / escaped
+ *    uric-no-slash  =  unreserved / escaped / ";" / "?" / ":" / "@"
+ *                      / "&" / "=" / "+" / "$" / ","
+ *    path-segments  =  segment *( "/" segment )
+ *    segment        =  *pchar *( ";" param )
+ *    param          =  *pchar
+ *    pchar          =  unreserved / escaped /
+ *                      ":" / "@" / "&" / "=" / "+" / "$" / ","
+ *    scheme         =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ *    authority      =  srvr / reg-name
+ *    srvr           =  [ [ userinfo "@" ] hostport ]
+ *    reg-name       =  1*( unreserved / escaped / "$" / ","
+ *                      / ";" / ":" / "@" / "&" / "=" / "+" )
+ *    query          =  *uric
+ *    SIP-Version    =  "SIP" "/" 1*DIGIT "." 1*DIGIT
+ * @endcode
+ *
+ * The parsed request-line is stored in #sip_request_t structure.
+ */
+
+/**@ingroup sip_request
+ * @typedef typedef struct sip_request_s sip_request_t;
+ *
+ * The structure #sip_request_t contains representation of SIP request line.
+ *
+ * The #sip_request_t is defined as follows:
+ * @code
+ * typedef struct sip_request_s {
+ *   sip_common_t     rq_common[1];     // Common fragment info
+ *   sip_unknown_t   *rq_next;          // Link to next (dummy)
+ *   sip_method_t     rq_method;        // Method enum
+ *   char const      *rq_method_name;   // Method name
+ *   url_t            rq_url[1];        // RequestURI
+ *   char const      *rq_version;       // Protocol version
+ * } sip_request_t;
+ * @endcode
+ */
+
+#define sip_request_insert msg_request_insert
+
+static msg_xtra_f sip_request_dup_xtra;
+static msg_dup_f sip_request_dup_one;
+#define sip_request_update NULL
+
+msg_hclass_t sip_request_class[] = 
+SIP_HEADER_CLASS(request, NULL, "", rq_common, single_critical, request);
+
+/**Parse @ref sip_request "request line" from a a SIP message. */
+issize_t sip_request_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_request_t *rq = h->sh_request;
+  char *uri, *version;
+
+  if (msg_firstline_d(s, &uri, &version) < 0 || !uri || !version ||
+      (rq->rq_method = sip_method_d(&s, &rq->rq_method_name)) < 0 || *s ||
+      url_d(rq->rq_url, uri) < 0 ||
+      sip_version_d(&version, &rq->rq_version) < 0 || *version)
+    return -1;
+
+  return 0;
+}
+
+/**Encode @ref sip_request "request line" of a a SIP message. */
+issize_t sip_request_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_request_t const *rq = h->sh_request;
+
+  return snprintf(b, bsiz, "%s " URL_FORMAT_STRING " %s" CRLF,
+		  rq->rq_method_name,
+		  URL_PRINT_ARGS(rq->rq_url),
+		  rq->rq_version);
+}
+
+isize_t sip_request_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_request_t const *rq = h->sh_request;
+
+  offset += url_xtra(rq->rq_url);
+  if (!rq->rq_method)
+    offset += MSG_STRING_SIZE(rq->rq_method_name);
+  offset += sip_version_xtra(rq->rq_version);
+
+  return offset;
+}
+
+/** Duplicate one request header. */
+char *sip_request_dup_one(sip_header_t *dst, sip_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  sip_request_t *rq = dst->sh_request;
+  sip_request_t const *o = src->sh_request;
+  char *end = b + xtra;
+
+  URL_DUP(b, end, rq->rq_url, o->rq_url);
+
+  if (!(rq->rq_method = o->rq_method))
+    MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
+  else
+    rq->rq_method_name = o->rq_method_name;
+  sip_version_dup(&b, &rq->rq_version, o->rq_version);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/**@ingroup sip_request
+ *
+ * Create a @ref sip_request "request line" object. 
+ *
+ * Create a request line object with
+ * method enum @a method, method name @a name, request URI @a uri, and
+ * protocol version @a version.  The memory for the header object is
+ * allocated from the memory home @a home.
+ *
+ * @param home     memory home used to allocate #sip_request_t object
+ * @param method   method enum
+ * @param name     method name (required if method is not well-known)
+ * @param uri      request URI
+ * @param version  version string (defaults to "SIP/2.0" if NULL)
+ *
+ * @par Example
+ * The following code fragment creates an OPTIONS request object:
+ * @code
+ *   sip_request_t *rq;
+ *   rq = sip_request_create(home, SIP_METHOD_OPTIONS, requestURI, NULL);
+ * @endcode
+
+ * @note 
+ * If you provide an non-NULL @a version string, it is not copied. The
+ * version string @b MUST remain constant.
+ */
+sip_request_t *sip_request_create(su_home_t *home,
+				  sip_method_t method, char const *name,
+				  url_string_t const *uri,
+				  char const *version)
+{
+  size_t xtra; 
+  sip_request_t *rq;
+
+  if (method)
+    name = sip_method_name(method, name);
+
+  if (!name)
+    return NULL;
+
+  if (!method)
+    method = sip_method_code(name);
+
+  xtra = url_xtra(uri->us_url) + (method ? 0 : strlen(name) + 1);
+
+  rq = sip_header_alloc(home, sip_request_class, xtra)->sh_request;
+
+  if (rq) {
+    char *b = (char *)(rq + 1), *end = b + xtra;
+
+    rq->rq_method      = method;
+    rq->rq_method_name = name;
+    if (!method) 
+      MSG_STRING_DUP(b, rq->rq_method_name, name);
+
+    URL_DUP(b, end, rq->rq_url, uri->us_url);
+
+    rq->rq_version = version ? version : SIP_VERSION_CURRENT;
+    assert(b == end);
+  }
+
+  return rq;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_status Status Line
+ *
+ * The status line is first line in a response message.  It is defined in
+ * @RFC3261 as follows:
+ * 
+ * @code
+ *    Status-Line     =  SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ *    Status-Code     =  Informational
+ *                   /   Redirection
+ *                   /   Success
+ *                   /   Client-Error
+ *                   /   Server-Error
+ *                   /   Global-Failure
+ *                   /   extension-code
+ *    extension-code  =  3DIGIT
+ *    Reason-Phrase   =  *(reserved / unreserved / escaped
+ *                       / UTF8-NONASCII / UTF8-CONT / SP / HTAB)
+ * @endcode
+ *
+ * The parsed status line is stored in #sip_status_t structure.
+ */
+
+/**@ingroup sip_status
+ * @typedef typedef struct sip_status_s sip_status_t;
+ *
+ * The structure #sip_status_t contains representation of SIP 
+ * @ref sip_status "status line".
+ *
+ * The #sip_status_t is defined as follows:
+ * @code
+ * typedef struct sip_status_s {
+ *   sip_common_t   st_common[1];       // Common fragment info
+ *   sip_unknown_t *st_next;            // Link to next (dummy)
+ *   char const    *st_version;         // Protocol version
+ *   int            st_status;          // Status code
+ *   char const    *st_phrase;          // Status phrase
+ * } sip_status_t;
+ * @endcode
+ */
+
+
+static msg_xtra_f sip_status_dup_xtra;
+static msg_dup_f sip_status_dup_one;
+
+#define sip_status_insert msg_status_insert
+#define sip_status_update NULL
+
+msg_hclass_t sip_status_class[] = 
+SIP_HEADER_CLASS(status, NULL, "", st_common, single_critical, status);
+
+/** Parse status line */
+issize_t sip_status_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_status_t *st = h->sh_status;
+  char *status, *phrase;
+  unsigned long code;
+
+  if (msg_firstline_d(s, &status, &phrase) < 0 ||
+      sip_version_d(&s, &st->st_version) < 0 || *s ||
+      (code = strtoul(status, &status, 10)) >= INT_MAX || *status)
+    return -1;
+
+  st->st_status = code;
+  st->st_phrase = phrase;
+
+  return 0;
+}
+
+issize_t sip_status_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  int status;
+
+  assert(sip_is_status(h));
+
+  status = h->sh_status->st_status;
+
+  if (status > 999 || status < 100)
+    status = 0;
+
+  return snprintf(b, bsiz, "%s %03u %s" CRLF,
+		  h->sh_status->st_version,
+		  status,
+		  h->sh_status->st_phrase);
+}
+
+/** Extra size of a #sip_status_t object. */
+isize_t sip_status_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_status_t const *st = h->sh_status;
+  offset += sip_version_xtra(st->st_version);
+  offset += MSG_STRING_SIZE(st->st_phrase);
+  return offset;
+}
+
+/** Duplicate one status header. */
+char *sip_status_dup_one(sip_header_t *dst, sip_header_t const *src,
+			 char *b, isize_t xtra)
+{
+  sip_status_t *st = dst->sh_status;
+  sip_status_t const *o = src->sh_status;
+  char *end = b + xtra;
+
+  sip_version_dup(&b, &st->st_version, o->st_version);
+  st->st_status = o->st_status;
+  MSG_STRING_DUP(b, st->st_phrase, o->st_phrase);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/**@ingroup sip_status
+ *
+ * Create a @ref sip_status "status line" object.
+ *
+ * @param home    memory home used to allocate #sip_status_t object
+ * @param status  status code (in range 100 - 699)
+ * @param phrase  status phrase (may be NULL)
+ * @param version version string (defaults to "SIP/2.0" if NULL)
+ *
+ * @note 
+ * If you provide an non-NULL @a version string, it is not copied. The
+ * string @b MUST remain constant.
+ *
+ * @return
+ * A pointer to newly created @ref sip_status "status line"
+ * structure when successful, or NULL upon an error.
+ */
+sip_status_t *sip_status_create(su_home_t *home,
+				unsigned status,
+				char const *phrase,
+				char const *version)
+{
+  sip_status_t *st;
+
+  if (status < 100 || status > 699)
+    return NULL;
+
+  if (phrase == NULL && (phrase = sip_status_phrase(status)) == NULL)
+    phrase = "";
+
+  if ((st = sip_header_alloc(home, sip_status_class, 0)->sh_status)) {
+    st->st_status = status;
+    st->st_phrase = phrase;
+    st->st_version = version ? version : SIP_VERSION_CURRENT;
+  }
+
+  return st;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_payload Message Body
+ *
+ * The payload structure contains the optional message body. The message
+ * body stored in the #sip_payload_t structure has no internal structure,
+ * but it is accessed as a byte array. Use @ref sdp_parser "SDP parser" to
+ * parse SDP content, for instance.
+ *
+ * The message body is stored in a #sip_payload_t structure.
+ */
+
+/**@ingroup sip_payload
+ * @typedef typedef struct sip_payload_s sip_payload_t;
+ *
+ * The structure #sip_payload_t contains representation of SIP message payload.
+ *
+ * The #sip_payload_t is defined as follows:
+ * @code
+ * typedef struct sip_payload_s {
+ *   msg_common_t    pl_common[1];      // Common fragment info
+ *   msg_header_t   *pl_next;           // Next payload (if multipart message)
+ *   char           *pl_data;           // Data - may contain NUL
+ *   unsigned        pl_len;            // Length of message payload
+ * } sip_payload_t;
+ * @endcode
+ */
+
+#define sip_payload_d 	     msg_payload_d
+#define sip_payload_e 	     msg_payload_e
+#define sip_payload_dup_xtra msg_payload_dup_xtra 
+#define sip_payload_dup_one  msg_payload_dup_one
+#define sip_payload_update   NULL
+
+msg_hclass_t sip_payload_class[] = 
+SIP_HEADER_CLASS(payload, NULL, "", pl_common, single, payload);
+
+/**@ingroup sip_payload
+ *
+ * Create a @ref sip_payload "SIP payload" structure. 
+ *
+ * Create a new SIP payload structure. it
+ * copies the given data to the the payload data, and NUL terminates it (it
+ * allocates one extra byte for NUL).  If a NULL pointer is given as @a data,
+ * sip_payload_create() allocates and zeroes a data buffer of @a len bytes.
+ *
+ * @param home memory home 
+ * @param data payload data 
+ * @param len  payload length
+ *
+ * @return A pointer to newly created
+ * payload structure, if successful, and NULL upon an error.
+ */ 
+sip_payload_t *sip_payload_create(su_home_t *home, void const *data, isize_t len)
+{
+  msg_hclass_t *hc = sip_payload_class;
+  sip_header_t *h = sip_header_alloc(home, hc, len + 1);
+  sip_payload_t *pl = h->sh_payload;
+
+  if (pl) {
+    char *b = sip_header_data(h);
+    if (data) {
+      memcpy(b, data, len);
+      b[len] = 0;
+    }
+    else {
+      memset(b, 0, len + 1);
+    }
+
+    h->sh_data = pl->pl_data = b;
+    h->sh_len = pl->pl_len = len;
+  }
+
+  return pl;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_separator Separator Line
+ *
+ * An empty line separates message headers from the message body (payload).
+ * In order to avoid modifying messages with integrity protection, the
+ * separator line has its own header structure which is included in the
+ * #sip_t structure.
+ *
+ * The parsed separator line is stored in #sip_separator_t structure.
+ */
+
+/**@ingroup sip_separator
+ * @typedef typedef struct sip_separator_s sip_separator_t;
+ *
+ * The structure #sip_separator_t contains representation of separator line
+ * between message headers and body.
+ *
+ * The #sip_separator_t is defined as follows:
+ * @code
+ * typedef struct sip_separator_s {
+ *   msg_common_t    sep_common[1];     // Common fragment info
+ *   msg_header_t   *sep_next;          // Pointer to next header
+ *   char            sep_data[4];       // NUL-terminated separator
+ * } sip_separator_t;
+ * @endcode
+ */
+
+#define sip_separator_d msg_separator_d
+#define sip_separator_e msg_separator_e
+#define sip_separator_insert msg_separator_insert
+
+msg_hclass_t sip_separator_class[] = 
+SIP_HEADER_CLASS(separator, NULL, "", sep_common, single, any);
+
+/**@ingroup sip_separator
+ * 
+ * Create a @ref sip_separator "SIP separator line" structure.
+ */
+sip_separator_t *sip_separator_create(su_home_t *home)
+{
+  sip_separator_t *sep = 
+    sip_header_alloc(home, sip_separator_class, 0)->sh_separator;
+
+  if (sep)
+    strcpy(sep->sep_data, CRLF);
+
+  return sep;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_unknown Unknown Headers
+ *
+ * The unknown headers are handled with #sip_unknown_t structure. The
+ * unknown header name is stored in @a un_name field and the header field
+ * following the colon is stored in @a un_value field.
+ * 
+ * @note It is possible to speed up parsing process by creating a parser
+ * which does understand only a minimum number of headers. If such a parser
+ * is used, some well-known headers are regarded as unknown and put into
+ * list of unknown headers.
+ */
+
+/**@ingroup sip_unknown
+ * @typedef typedef struct sip_unknown_s sip_unknown_t;
+ *
+ * The structure #sip_unknown_t contains representation of unknown headers.
+ *
+ * The #sip_unknown_t is defined as follows:
+ * @code
+ * typedef struct msg_unknown_s {
+ *   msg_common_t    un_common[1];  // Common fragment info 
+ *   msg_unknown_t  *un_next;       // Link to next unknown header 
+ *   char const     *un_name;       // Header name 
+ *   char const     *un_value;      // Header field value 
+ * } sip_unknown_t;
+ * @endcode
+ */
+
+#define sip_unknown_dup_xtra msg_unknown_dup_xtra 
+#define sip_unknown_dup_one  msg_unknown_dup_one
+#define sip_unknown_update NULL
+
+msg_hclass_t sip_unknown_class[] = 
+SIP_HEADER_CLASS(unknown, "", "", un_common, append, unknown);
+
+issize_t sip_unknown_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_unknown_d(home, h, s, slen);
+}
+
+issize_t sip_unknown_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return msg_unknown_e(b, bsiz, h, flags);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_error Erroneous Headers
+ *
+ * The erroneous headers are stored in #sip_error_t structure.
+ * 
+ * @note Other headers (like duplicate @ContentLength headers) may be put
+ * into the list of erroneous headers (@c sip->sip_error). If the list of
+ * erroneous headers is processed, the header type must be validated first
+ * by calling sip_is_error() (or by other relevant tests).
+ */
+
+/**@ingroup sip_error
+ * @typedef typedef msg_error_t sip_error_t;
+ * The structure #sip_error_t contains representation of error headers.
+ *
+ * The #sip_error_t is defined as follows:
+ * @code
+ * typedef struct msg_error_s {
+ *   msg_common_t    er_common[1];  // Common fragment info 
+ *   msg_error_t    *er_next;       // Link to next header 
+ *   char const     *er_name;       // Name of bad header (if any)
+ * } sip_error_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_error_class[] =
+SIP_HEADER_CLASS(error, NULL, "", er_common, append, any);
+
+issize_t sip_error_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+  return 0;
+}
+
+issize_t sip_error_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+  /* There is no way to encode an erroneous header */
+  return 0;
+}
+
+/* ====================================================================== */
+/*
+ * addr           = ("To" | "t" | "From" | "f") ":" 
+ *                  ( name-addr | addr-spec ) *( ";" addr-params )
+ * name-addr      = [ display-name ] "<" addr-spec ">"
+ * addr-spec      = SIP-URL | URI
+ * display-name   = *token | quoted-string
+ */
+
+/**Parse @e name-addr.
+ *
+ * Parses <i>( name-addr | addr-spec )</i> construct on @Contact, @From,
+ * @To, and other compatible headers. It splits the argument string in
+ * four parts:
+ *
+ * @par
+ * @e [display-name] @e addr-spec @e [parameters] @e [comment] @e [ss]
+ *
+ * @param home           pointer to memory home
+ * @param inout_s        pointer to pointer to string to be parsed
+ * @param return_display value-result parameter for @e display-name
+ * @param return_url     value-result parameter for @e addr-spec
+ * @param return_params  value-result paramater for @e parameters 
+ * @param return_comment value-result parameter for @e comment
+ *
+ * @note After succesful call to the function @c sip_name_addr_d(), *ss
+ * contains pointer to the first character not beloging to @e name-addr,
+ * most probably a comma. If that character is a separator, the last parameter
+ * may not be NUL (zero) terminated. So, after examining value of @a **ss,
+ * the calling function @b MUST set it to NUL.
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ *
+ * @sa @From, @To, @Contact
+ */
+issize_t sip_name_addr_d(su_home_t *home,
+			 char **inout_s,
+			 char const **return_display,
+			 url_t *return_url,
+			 msg_param_t const **return_params,
+			 char const **return_comment)
+{
+  char c, *s = *inout_s;
+  char *display = NULL, *addr_spec = NULL;
+  size_t n;
+
+  if (*s == '\0')		/* Empty string */
+    return -1;
+  
+  if (return_display && *s == '"') {
+    /* Quoted string */
+    if (msg_quoted_d(&s, &display) == -1)
+      return -1;
+
+    /* Now, we should have a '<' in s[0] */
+    if (s[0] != '<')
+      return -1;
+    s++[0] = '\0';		/* NUL terminate quoted string... */
+    n = strcspn(s, ">");
+    addr_spec = s; s += n; 
+    if (*s) *s++ = '\0'; else return -1;
+  } 
+  else {
+    if (return_display) 
+      n = span_token_lws(s);
+    else
+      n = 0;
+
+    if (s[n] == '<') {
+      /* OK, we got a display name */
+      display = s; s += n + 1; 
+      /* NUL terminate display name */
+      while (n > 0 && IS_LWS(display[n - 1]))
+	n--;
+      if (n > 0)
+	display[n] = '\0';
+      else 
+	display = "";
+
+      n = strcspn(s, ">");
+      addr_spec = s; s += n; if (*s) *s++ = '\0'; else return -1;
+    }
+    else {
+      /* addr-spec only */
+      addr_spec = s;
+      /**@sa
+       * Discussion about comma, semicolon and question mark in 
+       * @RFC3261 section 20.10.
+       */
+      if (return_params)
+	n = strcspn(s, " \t,;?");	/* DO NOT accept ,;? in URL */
+      else
+	/* P-Asserted-Identity and friends */
+	n = strcspn(s, " ,"); /* DO NOT accept , in URL */
+      s += n;
+      if (IS_LWS(*s))
+	*s++ = '\0';
+    }
+  }
+
+  skip_lws(&s);
+
+  if (return_display)
+    *return_display = display;
+  
+  /* Now, url may still not be NUL terminated, e.g., if 
+   * it is like "Contact: url:foo,sip:bar,sip:zunk"
+   */
+  c = *s; *s = '\0';		/* terminate temporarily */
+  if (url_d(return_url, addr_spec) == -1)
+    return -1;
+  *s = c;			/* return terminator */
+
+  *inout_s = s;
+
+  if (c == ';' && return_params)
+    if (msg_params_d(home, inout_s, return_params) == -1)
+      return -1;
+
+  if (**inout_s == '(' && return_comment)
+    if (msg_comment_d(inout_s, return_comment) == -1)
+      return -1;
+
+  return 0;
+}
+
+/**Encode @e name-addr and parameter list.
+ *
+ * Encodes @e name-addr headers, like @From, @To, @CallInfo, @ErrorInfo,
+ * @Route, and @RecordRoute.
+ *
+ * @param b        buffer to store the encoding result
+ * @param bsiz     size of the buffer @a b
+ * @param flags    encoding flags
+ * @param display  display name encoded before the @a url (may be NULL)
+ * @param brackets if true, use always brackets around @a url
+ * @param url      pointer to URL structure
+ * @param params   pointer to parameter list (may be NULL)
+ * @param comment  comment string encoded after others (may be NULL)
+ *
+ * @return 
+ * Returns number of characters in encoding, excluding the
+ * final NUL.
+ *
+ * @note
+ * The encoding result may be incomplete if the buffer size is not large
+ * enough to store the whole encoding result.
+ */
+issize_t sip_name_addr_e(char b[], isize_t bsiz, 
+			 int flags, 
+			 char const *display, 
+			 int brackets, url_t const url[],
+			 msg_param_t const params[], 
+			 char const *comment)
+{
+  int const compact = MSG_IS_COMPACT(flags);
+  char const *u;
+  char *b0 = b, *end = b + bsiz;
+
+  brackets = brackets || display || 
+    (url && (url->url_params || 
+	     url->url_headers ||
+	     ((u = url->url_user) && u[strcspn(u, ";,?")]) ||
+	     ((u = url->url_password) && u[strcspn(u, ",")])));
+
+  if (display && display[0]) {
+    MSG_STRING_E(b, end, display);
+    if (!compact) MSG_CHAR_E(b, end, ' ');
+  }
+  if (url) {
+    if (brackets) MSG_CHAR_E(b, end, '<');
+    URL_E(b, end, url);
+    if (brackets) MSG_CHAR_E(b, end, '>');
+  }
+
+  MSG_PARAMS_E(b, end, params, flags);
+
+  if (comment) {
+    if (!compact) MSG_CHAR_E(b, end, ' ');
+    MSG_CHAR_E(b, end, '(');
+    MSG_STRING_E(b, end, comment);
+    MSG_CHAR_E(b, end, ')');
+  }
+
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+
+/** Parse @To or @From headers */
+issize_t sip_addr_d(su_home_t *home,
+		    sip_header_t *h,
+		    char *s,
+		    isize_t slen)
+{
+  sip_addr_t *a = (sip_addr_t *)h;
+  char const *comment = NULL;
+  if (sip_name_addr_d(home, 
+		      &s, 
+		      &a->a_display, 
+		      a->a_url, 
+		      &a->a_params,
+		      &comment) == -1 
+      || *s /* XXX - something extra? */)
+    return -1;
+
+  a->a_tag = msg_params_find(a->a_params, "tag=");
+
+  return 0;
+}
+
+static int sip_addr_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_addr_t const *a = (sip_addr_t const *)h;
+
+  return sip_name_addr_e(b, bsiz,
+			 flags,
+			 a->a_display, 
+			 MSG_IS_CANONIC(flags), a->a_url,
+			 a->a_params,
+			 NULL);
+}
+
+/**
+ * Extra dup size of a sip_addr_t object.
+ *
+ * This function calculates extra size required when duplicating a
+ * sip_addr_t object.
+ *
+ * @param a pointer to a sip_addr_t object
+ *
+ * @return
+ *   Size of strings related to sip_addr_t object.
+ */
+static
+isize_t sip_addr_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_addr_t const *a = (sip_addr_t const *)h;
+
+  MSG_PARAMS_SIZE(offset, a->a_params);
+  offset += MSG_STRING_SIZE(a->a_display);
+  offset += url_xtra(a->a_url);
+    
+  return offset;
+}
+
+/**@internal
+ * Duplicate one sip_addr_t object.
+ */
+static char *sip_addr_dup_one(sip_header_t *dst, sip_header_t const *src,
+			      char *b, isize_t xtra)
+{
+  sip_addr_t *a = (sip_addr_t *)dst;
+  sip_addr_t const *o = (sip_addr_t *)src;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&a->a_params, o->a_params, b, xtra);
+  MSG_STRING_DUP(b, a->a_display, o->a_display);
+  URL_DUP(b, end, a->a_url, o->a_url);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/** Update parameters in sip_addr_t object */
+static int sip_addr_update(msg_common_t *h,
+			   char const *name, isize_t namelen,
+			   char const *value)
+{
+  sip_addr_t *a = (sip_addr_t *)h;
+
+  if (name == NULL) {
+    a->a_tag = NULL;
+  }
+  else if (namelen == strlen("tag") && !strncasecmp(name, "tag", namelen)) {
+    a->a_tag = value;
+  }
+
+  return 0;
+}
+
+/** Create an address header object from URL */
+static sip_addr_t *
+sip_addr_make_url(su_home_t *home, msg_hclass_t *hc, url_string_t const *us)
+{
+  size_t n;
+  sip_header_t *h;
+
+  n = url_xtra(us->us_url);
+  h = sip_header_alloc(home, sip_to_class, n);    
+
+  if (h) {
+    sip_addr_t *a = h->sh_to;
+    char *s2 = sip_header_data(h);
+
+    if ((size_t)url_dup(s2, n, a->a_url, us->us_url) == n)
+      return a;
+
+    su_free(home, h);
+  }
+
+  return NULL;
+}
+
+/** Add a tag to address structure. */
+static
+int sip_addr_tag(su_home_t *home, sip_addr_t *a, char const *tag)
+{
+  if (a && tag) {
+    msg_param_t value = strchr(tag, '=');
+
+    if (value)
+      value = strchr(value, '=') + 1;
+    else
+      value = tag;
+
+    if (a->a_tag) {
+      if (strcasecmp(a->a_tag, value) == 0)
+	return 0;
+      else
+	return -1;
+    }
+
+    if (tag == value)
+      tag = su_sprintf(home, "tag=%s", tag);
+    else
+      tag = su_strdup(home, tag);
+
+    if (tag)
+      if (msg_header_replace_param(home, a->a_common, tag) >= 0)
+	return 0;
+  }
+
+  return -1;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_call_id Call-ID Header
+ *
+ * The @b Call-ID header uniquely identifies a particular invitation or all
+ * registrations of a particular client. It is defined in @RFC3261 as
+ * follows:
+ * 
+ * @code
+ *    Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
+ *    callid   =  word [ "@" word ]
+ *    word        =  1*(alphanum / "-" / "." / "!" / "%" / "*" /
+ *                   "_" / "+" / "`" / "'" / "~" / "(" / ")" / "<" / ">" /
+ *                   ":" / "\" / DQUOTE / "/" / "[" / "]" / "?" / "{" / "}" )
+ * @endcode
+ *
+ * The parsed Call-ID Header is stored in #sip_call_id_t structure.
+ */
+
+/**@ingroup sip_call_id
+ * @typedef typedef struct sip_call_id_s sip_call_id_t;
+ *
+ * The structure #sip_call_id_t contains representation of SIP @CallID
+ * header.
+ *
+ * The #sip_call_id_t is defined as follows:
+ * @code
+ * typedef struct sip_call_id_s {
+ *   sip_common_t   i_common[1];        // Common fragment info
+ *   sip_call_id_t *i_next;             // Link to next (dummy)
+ *   char const    *i_id;               // ID value
+ *   uint32_t       i_hash;             // Hash value (always nonzero)
+ * } sip_call_id_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_call_id_dup_xtra;
+static msg_dup_f sip_call_id_dup_one;
+#define sip_call_id_update NULL
+
+msg_hclass_t sip_call_id_class[] = 
+SIP_HEADER_CLASS(call_id, "Call-ID", "i", i_common, single, call_id);
+
+issize_t sip_call_id_d(su_home_t *home,
+		       sip_header_t *h,
+		       char *s, 
+		       isize_t slen)
+{
+  sip_call_id_t *i = h->sh_call_id;
+  
+  i->i_id = s; /* XXX - why not sip_word_at_word_d(&s); */
+  i->i_hash = msg_hash_string(s);
+
+  return 0;
+}
+
+
+issize_t sip_call_id_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  size_t n = strlen(h->sh_call_id->i_id);
+
+  if (bsiz > n)
+    strcpy(b, h->sh_call_id->i_id);
+
+  return (issize_t)n;
+}
+
+/** Extra size of a #sip_call_id_t object. */
+isize_t sip_call_id_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_call_id_t const *i = h->sh_call_id;
+  return offset + MSG_STRING_SIZE(i->i_id);
+}
+
+/**Duplicate a sip_call_id object.
+ *
+ * Duplicate (copy deeply) a single #sip_call_id_t header object.
+ *
+ * @param dst   pointer to newly allocated header object
+ * @param src   pointer to a header object to be duplicated
+ * @param b     memory buffer used to copy external references
+ * @param xtra  number bytes in buffer @a b
+ *
+ * @return Pointer to the new copy of #sip_call_id_t object, or @c NULL
+ * upon an error.
+ */
+char *sip_call_id_dup_one(sip_header_t *dst, sip_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  sip_call_id_t *i = dst->sh_call_id;
+  sip_call_id_t const *o = src->sh_call_id;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, i->i_id, o->i_id);
+  if (!(i->i_hash = o->i_hash))
+    i->i_hash = msg_hash_string(i->i_id);
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/**@ingroup sip_call_id
+ *
+ * Create a @CallID header object. 
+ *
+ * Create a Call-ID header object with a new unique value. It uses
+ * su_guid_generate() function to generate the value. If the local host name
+ * @a domain is specified, it is prepended to the generated value instead of
+ * local MAC address.
+
+ * @param home        memory home
+ * @param domain      local domain name
+ *
+ * @return A pointer to newly created @CallID header object when
+ * successful or NULL upon an error.
+ *
+ * @sa su_guid_generate(), su_guid_sprintf()
+ */
+sip_call_id_t *sip_call_id_create(su_home_t *home, char const *domain)
+{
+  sip_call_id_t *i;
+  size_t xtra = su_guid_strlen + 1 + (domain ? strlen(domain) + 1 : 0);
+
+  i = sip_header_alloc(home, sip_call_id_class, xtra)->sh_call_id;
+  
+  if (i) {
+    char *b;
+    su_guid_t guid[1];
+
+    i->i_id = b = (char *)(i + 1);
+
+    su_guid_generate(guid);
+    /*
+     * Guid looks like "NNNNNNNN-NNNN-NNNN-NNNN-XXXXXXXXXXXX"
+     * where NNNNNNNN-NNNN-NNNN-NNNN is timestamp and XX is MAC address
+     * (but we use usually random ID for MAC because we do not have
+     *  guid generator available for all processes within node)
+     */
+    su_guid_sprintf(b, su_guid_strlen + 1, guid);
+
+    /* If we have a domain name don't include MAC address at the end of guid */
+    if (domain) {
+      b[8 + 5 + 5 + 5] = '@';
+      strcpy(b + 8 + 5 + 5 + 5 + 1, domain);
+    }
+
+    i->i_hash = msg_hash_string(i->i_id);
+  }
+
+  return i;
+
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_cseq CSeq Header 
+ *
+ * The CSeq header (command sequence) uniquely identifies transactions
+ * within a dialog.  It is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    CSeq              =  "CSeq" HCOLON 1*DIGIT LWS Method
+ *    Method            =  INVITEm / ACKm / OPTIONSm / BYEm
+ *                         / CANCELm / REGISTERm
+ *                         / extension-method
+ *    extension-method  =  token
+ * @endcode
+ *
+ * The parsed CSeq header is stored in #sip_cseq_t structure.
+ */
+
+/**@ingroup sip_cseq
+ * @typedef typedef struct sip_cseq_s sip_cseq_t;
+ *
+ * The structure #sip_cseq_t contains representation of SIP @CSeq header.
+ *
+ * The #sip_cseq_t is defined as follows:
+ * @code
+ * typedef struct sip_cseq_s {
+ *   sip_common_t   cs_common[1];       // Common fragment info
+ *   sip_error_t   *cs_next;            // Link to next (dummy)
+ *   uint32_t       cs_seq;             // Sequence number
+ *   sip_method_t   cs_method;          // Method enum
+ *   char const    *cs_method_name;     // Method name
+ * } sip_cseq_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_cseq_dup_xtra;
+static msg_dup_f sip_cseq_dup_one;
+#define sip_cseq_update NULL
+
+msg_hclass_t sip_cseq_class[] = 
+SIP_HEADER_CLASS(cseq, "CSeq", "", cs_common, single, cseq);
+
+issize_t sip_cseq_d(su_home_t *home,
+		    sip_header_t *h,
+		    char *s,
+		    isize_t slen)
+{
+  sip_cseq_t *cs = h->sh_cseq;
+
+  if (msg_uint32_d(&s, &cs->cs_seq) < 0)
+    return -1;
+
+  if (*s) {
+    if ((cs->cs_method = sip_method_d(&s, &cs->cs_method_name)) >= 0)
+      return 0;
+  }
+
+  return -1;
+}
+
+
+issize_t sip_cseq_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_cseq(h));
+
+  return snprintf(b, bsiz, 
+		  "%u %s", 
+		  h->sh_cseq->cs_seq,
+		  h->sh_cseq->cs_method_name);
+}
+
+isize_t sip_cseq_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_cseq_t const *cs = h->sh_cseq;
+  if (!cs->cs_method)
+    return offset + MSG_STRING_SIZE(cs->cs_method_name);
+  else
+    return offset;
+}
+
+char *sip_cseq_dup_one(sip_header_t *dst, sip_header_t const *src,
+		       char *b, isize_t xtra)
+{
+  sip_cseq_t *cs = dst->sh_cseq;
+  sip_cseq_t const *o = src->sh_cseq;
+  char *end = b + xtra;
+
+  if (!(cs->cs_method = o->cs_method))
+    MSG_STRING_DUP(b, cs->cs_method_name, o->cs_method_name);
+  else
+    cs->cs_method_name = o->cs_method_name;
+  cs->cs_seq = o->cs_seq;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/**@ingroup sip_cseq 
+ *
+ * Create a @CSeq header object. 
+ *
+ * Create a @CSeq header object with the
+ * sequence number @a seq, method enum @a method and method name @a
+ * method_name.  The memory for the header object is allocated from the
+ * memory home @a home.
+ *
+ * @param home        memory home
+ * @param seq         sequence number
+ * @param method      method enum
+ * @param method_name method name (required if method is not well-known)
+ *
+ * @par Example
+ * The following code fragment creates a cseq object for OPTIONS request:
+ * @code
+ *   sip_cseq_t *cseq;
+ *   cseq = sip_cseq_create(home, agent->seq++, SIP_METHOD_OPTIONS);
+ * @endcode
+ *
+ * @return
+ * A pointer to newly created @CSeq
+ * header object when successful or NULL upon an error.
+ */
+sip_cseq_t *sip_cseq_create(su_home_t *home,
+			    uint32_t seq,
+			    unsigned method,
+			    char const *method_name)
+{
+  size_t xtra;
+  sip_cseq_t *cs;
+
+  if (method)
+    method_name = sip_method_name(method, method_name);
+
+  if (method_name == NULL)
+    return NULL;
+
+  xtra = (method ? 0 : (strlen(method_name) + 1));
+
+  cs = sip_header_alloc(home, sip_cseq_class, xtra)->sh_cseq;
+  
+  if (cs) {
+    cs->cs_seq = seq;
+    cs->cs_method = method;
+    if (!method)
+      method_name = strcpy((char *)(cs + 1), method_name);
+    cs->cs_method_name = method_name;
+  }
+  return cs;
+}
+
+
+/* ====================================================================== */
+/**@SIP_HEADER sip_contact Contact Header
+ *
+ * The Contact header contain a list of URLs used to redirect future
+ * requests.  Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Contact            =  ("Contact" / "m" ) HCOLON
+ *                          ( STAR / (contact-param *(COMMA contact-param)))
+ *    contact-param      =  (name-addr / addr-spec) *(SEMI contact-params)
+ *    name-addr          =  [ display-name ] LAQUOT addr-spec RAQUOT
+ *    addr-spec          =  SIP-URI / SIPS-URI / absoluteURI
+ *    display-name       =  *(token LWS)/ quoted-string
+ *    contact-params     =  c-p-q / c-p-expires
+ *                          / contact-extension
+ *    c-p-q              =  "q" EQUAL qvalue
+ *    c-p-expires        =  "expires" EQUAL delta-seconds
+ *    contact-extension  =  generic-param
+ *    delta-seconds      =  1*DIGIT
+ * @endcode
+ *
+ * @note
+ * The @RFC2543 syntax allowed <comment>. We accept it, but don't encode it.
+ *
+ * Each parsed Contact header field is stored in #sip_contact_t structure.
+ */
+
+/**@ingroup sip_contact
+ * @typedef typedef struct sip_contact_s sip_contact_t;
+ *
+ * The structure #sip_contact_t contains representation of SIP @Contact
+ * header.
+ *
+ * The #sip_contact_t is defined as follows:
+ * @code
+ * typedef struct sip_contact_s {
+ *   sip_common_t        m_common[1];   // Common fragment info
+ *   sip_contact_t      *m_next;        // Link to next
+ *   char const         *m_display;     // Display name
+ *   url_t               m_url[1];      // SIP URL
+ *   msg_param_t const  *m_params;      // List of contact-params
+ *   char const         *m_comment;     // Comment
+ *
+ *   char const         *m_q;           // Priority
+ *   char const         *m_expires;     // Expiration time 
+ * } sip_contact_t;
+ * @endcode
+ * 
+ * @note The <comment> field @ref sip_contact_s::m_comment "m_comment" is
+ * deprecated: it is parsed but not included in encoding.
+ */
+
+static msg_xtra_f sip_contact_dup_xtra;
+static msg_dup_f sip_contact_dup_one;
+static msg_update_f sip_contact_update;
+
+/** @showinitializer */
+msg_hclass_t sip_contact_class[] =
+  /*
+   * Cut through the fog of macros
+   * SIP_HEADER_CLASS(contact, "Contact", "m", m_params, append, contact);
+   * and show here how the msg_hclass_t is initialized
+   */
+  {{
+    /* hc_hash: */     sip_contact_hash,
+    /* hc_parse: */    sip_contact_d,
+    /* hc_print: */    sip_contact_e,
+    /* hc_dxtra: */    sip_contact_dup_xtra,
+    /* hc_dup_one: */  sip_contact_dup_one,
+    /* hc_update: */   sip_contact_update,
+    /* hc_name: */     "Contact",
+    /* hc_len: */      sizeof("Contact") - 1,
+    /* hc_short: */    "m",
+    /* hc_size: */     MSG_ALIGN(sizeof(sip_contact_t), sizeof(void*)),
+    /* hc_params: */   offsetof(sip_contact_t, m_params),
+    /* hc_kind:	*/     msg_kind_append,
+    /* hc_critical: */ 0
+   }};
+
+issize_t sip_contact_d(su_home_t *home,
+		       sip_header_t *h,
+		       char *s,
+		       isize_t slen)
+{
+  sip_contact_t *m = (sip_contact_t *)h;
+
+  assert(h);
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if (sip_name_addr_d(home, &s, &m->m_display, m->m_url, 
+		      &m->m_params, &m->m_comment) == -1)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+
+issize_t sip_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_contact_t const *m = h->sh_contact;
+  int always_lt_gt = MSG_IS_CANONIC(flags) && m->m_url->url_type != url_any;
+
+  assert(sip_is_contact(h));
+
+  return sip_name_addr_e(b, bsiz, flags,
+			 m->m_display, always_lt_gt, m->m_url, 
+			 m->m_params,
+			 NULL /* m->m_comment */);
+}
+
+
+isize_t sip_contact_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_contact_t const *m = h->sh_contact;
+
+  MSG_PARAMS_SIZE(offset, m->m_params);
+  offset += MSG_STRING_SIZE(m->m_display);
+  offset += url_xtra(m->m_url);
+  offset += MSG_STRING_SIZE(m->m_comment);
+
+  return offset;
+}
+
+char *sip_contact_dup_one(sip_header_t *dst, sip_header_t const *src,
+			  char *b, isize_t xtra)
+{
+  char *end = b + xtra;
+  sip_contact_t *m = dst->sh_contact;
+  sip_contact_t const *o = src->sh_contact;
+
+  b = msg_params_dup(&m->m_params, o->m_params, b, xtra);
+  MSG_STRING_DUP(b, m->m_display, o->m_display);
+  URL_DUP(b, end, m->m_url, o->m_url);
+  MSG_STRING_DUP(b, m->m_comment, o->m_comment);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/** Update parameter in #sip_contact_t */
+static int sip_contact_update(msg_common_t *h, 
+			      char const *name, isize_t namelen,
+			      char const *value)
+{
+  sip_contact_t *m = (sip_contact_t *)h;
+
+  if (name == NULL) {
+    m->m_q = NULL;
+    m->m_expires = NULL;
+  }
+  else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+    /* XXX - check for invalid value? */
+    m->m_q = value;
+  }
+  else if (namelen == strlen("expires") && 
+	   !strncasecmp(name, "expires", namelen)) {
+    m->m_expires = value;
+  }
+
+  return 0;
+}
+
+/**@ingroup sip_contact 
+ *
+ * Add a parameter to a @Contact header object
+ *
+ * Add a parameter to a @Contact
+ * object. It does not copy the contents of the string @c param.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home   memory home
+ * @param m      #sip_contact_t object
+ * @param param  parameter string
+ *
+ * @return 0 when successful, and -1 upon an error.
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_contact_add_param(su_home_t *home,
+			  sip_contact_t *m,
+			  char const *param)
+{
+  return msg_header_replace_param(home, m->m_common, param);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_length Content-Length Header
+ *
+ * The Content-Length header indicates the size of the message-body in
+ * decimal number of octets.  Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ *    Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ * @endcode
+ *
+ * The parsed Content-Length header is stored in #sip_content_length_t
+ * structure.
+ */
+
+/**@ingroup sip_content_length
+ * @typedef typedef struct sip_content_length_s sip_content_length_t;
+ *
+ * The structure #sip_content_length_t contains representation of SIP
+ * @ContentLength header.
+ *
+ * The #sip_content_length_t is defined as follows:
+ * @code
+ * typedef struct sip_content_length_s {
+ *   sip_common_t   l_common[1];        // Common fragment info
+ *   sip_error_t   *l_next;             // Dummy link to next
+ *   uint32_t       l_length;           // Message body length in bytes
+ * } sip_content_length_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_length_class[] = 
+SIP_HEADER_CLASS(content_length, "Content-Length", "l", l_common, 
+		 single_critical, any);
+
+issize_t sip_content_length_d(su_home_t *home,
+			      sip_header_t *h,
+			      char *s,
+			      isize_t slen)
+{
+  return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_content_length_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_content_length(h));
+  return sip_numeric_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_content_length 
+ *
+ * Create a @ContentLength header object. 
+ *
+ * Create a @ContentLength
+ * header object with the value @a n.  The memory for the header is
+ * allocated from the memory home @a home.
+ *
+ * @param home  memory home
+ * @param n     payload size in bytes
+ *
+ * @return
+ * A pointer to newly created @ContentLength header object when successful
+ * or NULL upon an error.
+ */
+sip_content_length_t *sip_content_length_create(su_home_t *home, uint32_t n)
+{
+  sip_content_length_t *l = 
+    sip_header_alloc(home, sip_content_length_class, 0)->sh_content_length;
+  
+  if (l)
+    l->l_length = n;
+
+  return l;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_date Date Header
+ *
+ * The Date header field reflects the time when the request or response was
+ * first sent.  Its syntax is defined in @RFC3261 and @RFC2616 section 14.18 as
+ * follows:
+ * 
+ * @code
+ *    Date          =  "Date" HCOLON SIP-date
+ *    SIP-date      =  rfc1123-date
+ *    rfc1123-date  =  wkday "," SP date1 SP time SP "GMT"
+ *    date1         =  2DIGIT SP month SP 4DIGIT
+ *                     ; day month year (e.g., 02 Jun 1982)
+ *    time          =  2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                     ; 00:00:00 - 23:59:59
+ *    wkday         =  "Mon" / "Tue" / "Wed"
+ *                     / "Thu" / "Fri" / "Sat" / "Sun"
+ *    month         =  "Jan" / "Feb" / "Mar" / "Apr"
+ *                     / "May" / "Jun" / "Jul" / "Aug"
+ *                     / "Sep" / "Oct" / "Nov" / "Dec"
+ * @endcode
+ *
+ * The parsed Date header is stored in #sip_date_t structure.
+ */
+
+/**@ingroup sip_date
+ * @typedef typedef struct sip_date_s sip_date_t;
+ *
+ * The structure #sip_date_t contains representation of SIP @Date header.
+ *
+ * The #sip_date_t is defined as follows:
+ * @code
+ * typedef struct sip_date_s {
+ *   sip_common_t   d_common[1];        // Common fragment info
+ *   sip_date_t    *d_next;             // Link to next (dummy)
+ *   sip_time_t     d_time;             // Seconds since Jan 1, 1900
+ * } sip_date_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_date_class[] = 
+SIP_HEADER_CLASS(date, "Date", "", d_common, single, any);
+
+issize_t sip_date_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_date_t *date = h->sh_date;
+
+  if (msg_date_d((char const **)&s, &date->d_time) < 0 || *s)
+    return -1;
+  else
+    return 0;
+}
+
+issize_t sip_date_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_date_t const *date = h->sh_date;
+
+  return msg_date_e(b, bsiz, date->d_time);
+}
+
+/**@ingroup sip_date
+ * @brief Create an @Date header object. 
+ *
+ * Create a @Date header object with
+ * the date @a date.  If @date is 0, current time (as returned by sip_now())
+ * is used.
+ *
+ * @param home   memory home
+ * @param date   date expressed as seconds since Mon, 01 Jan 1900 00:00:00
+ *
+ * @return
+ * A pointer to newly created @Date header object when successful, or NULL
+ * upon an error.
+ */
+sip_date_t *sip_date_create(su_home_t *home, sip_time_t date)
+{
+  sip_header_t *h = sip_header_alloc(home, sip_date_class, 0);
+  
+  if (h) {
+    if (date == 0)
+      date = sip_now();
+    h->sh_date->d_time = date;
+  }
+
+  return h->sh_date;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_expires Expires Header
+ *
+ * The Expires header field gives the date and time after which the message
+ * content expires.  Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Expires     =  "Expires" HCOLON delta-seconds
+ * @endcode
+ * 
+ * Note that the first SIP revision (@RFC2543) also allowed absolute time in
+ * Expires.
+ *
+ * The parsed Expires header is stored in #sip_expires_t structure.
+ */
+
+/**@ingroup sip_expires
+ * @typedef typedef struct sip_expires_s sip_expires_t;
+ *
+ * The structure #sip_expires_t contains representation of SIP @Expires
+ * header.
+ *
+ * The #sip_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_expires_s {
+ *   sip_common_t        ex_common[1];  // Common fragment info
+ *   sip_error_t        *ex_next;       // Link to next (dummy)
+ *   sip_time_t          ex_date;       // Seconds since Jan 1, 1900
+ *   sip_time_t          ex_delta;      // ...or delta seconds
+ * } sip_expires_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_expires_class[] = 
+SIP_HEADER_CLASS(expires, "Expires", "", ex_common, single, any);
+
+issize_t sip_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_expires_t *expires = h->sh_expires;
+
+  if (msg_date_delta_d((char const **)&s, 
+		       &expires->ex_date, 
+		       &expires->ex_delta) < 0 || *s)
+    return -1;
+  else
+    return 0;
+}
+
+issize_t sip_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_expires_t const *expires = h->sh_expires;
+
+  if (expires->ex_date)
+    return msg_date_e(b, bsiz, expires->ex_date + expires->ex_delta);
+  else
+    return msg_delta_e(b, bsiz, expires->ex_delta);
+}
+
+/**@ingroup sip_expires
+ * @brief Create an @Expires header object. 
+ *
+ * Create an @Expires header object with the expiration time @a delta.
+ *
+ * @param home   memory home used to allocate #sip_expires_t structure
+ * @param delta  relative expiration time in seconds
+ *
+ * @return
+ * A pointer to newly created @Expires header object when successful or NULL
+ * upon an error.
+ */
+sip_expires_t *sip_expires_create(su_home_t *home, sip_time_t delta)
+{
+  sip_header_t *h = sip_header_alloc(home, sip_expires_class, 0);
+
+  if (h)
+    h->sh_expires->ex_delta = delta;
+
+  return h->sh_expires;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_from From Header
+ *
+ * The From header indicates the initiator of the request.  It is defined in
+ * @RFC3261 as follows:
+ * 
+ * @code
+ *    From        =  ( "From" / "f" ) HCOLON from-spec
+ *    from-spec   =  ( name-addr / addr-spec )
+ *                   *( SEMI from-param )
+ *    from-param  =  tag-param / generic-param
+ *    tag-param   =  "tag" EQUAL token
+ * @endcode
+ *
+ *
+ * The parsed From header is stored in #sip_from_t structure.
+ */
+
+/**@ingroup sip_from
+ * @typedef typedef struct sip_addr_s sip_from_t;
+ *
+ * The structure #sip_from_t contains representation of @From header.
+ *
+ * The #sip_from_t is defined as follows:
+ * @code
+ * typedef struct sip_addr_s {
+ *   sip_common_t       a_common[1];    // Common fragment info
+ *   sip_error_t       *a_next;         // Link to next
+ *   char const        *a_display;      // Display name
+ *   url_t              a_url[1];       // URL
+ *   msg_param_t const *a_params;       // List of from-param
+ *   char const        *a_comment;      // Comment
+ *   char const        *a_tag;          // Tag parameter 
+ * } sip_from_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_from_class[] = 
+SIP_HEADER_CLASS(from, "From", "f", a_params, single, addr);
+
+issize_t sip_from_d(su_home_t *home,
+		    sip_header_t *h,
+		    char *s,
+		    isize_t slen)
+{
+  return sip_addr_d(home, h, s, slen);
+}
+
+issize_t sip_from_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_from(h));
+  return sip_addr_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_from
+ *
+ * Create a @From header object with URL.
+ *
+ * @param home      memory home used to allocate #sip_from_t structure
+ * @param s         pointer to the URL or a string
+ *
+ * @return
+ * A pointer to newly created @From header object when successful or NULL
+ * upon an error.
+ */
+sip_from_t *
+sip_from_create(su_home_t *home, url_string_t const *s)
+{
+  return sip_addr_make_url(home, sip_from_class, s);
+}
+
+/**@ingroup sip_from
+ *
+ * Add a parameter to an #sip_from_t object.
+ *
+ * @param home   memory home
+ * @param from   a pointer to #sip_from_t object
+ * @param param  parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_from_add_param(su_home_t *home,
+		       sip_from_t *from,
+		       char const *param)
+{
+  return msg_header_replace_param(home, from->a_common, param);
+}
+
+/**@ingroup sip_from
+ *
+ * Add a tag to a @From header. If @a tag is
+ * identical with the existing one, nothing will be done. An error is
+ * returned, if the header already contains a different tag. The @a tag can
+ * be provided either as a single token ("deadbeer") or as in parameter form
+ * ("tag=deadbeer"). In both cases the tag is duplicated using the memory
+ * home @a home.
+ * 
+ * @param home memory home used to allocate new tag 
+ * @param from @From header to modify
+ * @param tag  tag token or parameter to be added 
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+int sip_from_tag(su_home_t *home, sip_from_t *from, char const *tag)
+{
+  return sip_addr_tag(home, from, tag);
+}
+
+
+int sip_to_tag(su_home_t *home, sip_to_t *to, char const *tag)
+{
+  return sip_addr_tag(home, to, tag);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_max_forwards Max-Forwards Header
+ *
+ * The Max-Forwards header is used to limit the number of proxies or
+ * gateways that can forward the request.  The Max-Forwards syntax is
+ * defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
+ * @endcode
+ *
+ *
+ * The parsed Max-Forwards header is stored in #sip_max_forwards_t structure.
+ */
+
+/**@ingroup sip_max_forwards
+ * @typedef typedef struct sip_max_forwards_s sip_max_forwards_t;
+ *
+ * The structure #sip_max_forwards_t contains representation of SIP
+ * @MaxForwards header.
+ *
+ * The #sip_max_forwards_t is defined as follows:
+ * @code
+ * typedef struct sip_max_forwards_s {
+ *   sip_common_t        mf_common[1];  // Common fragment info
+ *   sip_error_t        *mf_next;       // Link to next (dummy)
+ *   unsigned long       mf_count;      // Digits
+ * } sip_max_forwards_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_max_forwards_class[] = 
+SIP_HEADER_CLASS(max_forwards, "Max-Forwards", "", mf_common, 
+		 single, any);
+
+issize_t sip_max_forwards_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_max_forwards_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_max_forwards(h));
+  return sip_numeric_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_min_expires Min-Expires Header
+ *
+ * The Min-Expires header is used to limit the number of proxies or
+ * gateways that can forward the request.  The Min-Expires syntax is
+ * defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Min-Expires  =  "Min-Expires" HCOLON delta-seconds
+ * @endcode
+ *
+ * The parsed Min-Expires header is stored in #sip_min_expires_t structure.
+ */
+
+/**@ingroup sip_min_expires
+ * @typedef typedef struct sip_min_expires_s sip_min_expires_t;
+ *
+ * The structure #sip_min_expires_t contains representation of SIP
+ * @MinExpires header.
+ *
+ * The #sip_min_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_min_expires_s {
+ *   sip_common_t        me_common[1];  // Common fragment info
+ *   sip_error_t        *me_next;       // Link to next (dummy)
+ *   unsigned long       me_delta;      // Seconds
+ * } sip_min_expires_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_min_expires_class[] = 
+SIP_HEADER_CLASS(min_expires, "Min-Expires", "", me_common, 
+		 single, any);
+
+issize_t sip_min_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_min_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_min_expires(h));
+  return sip_numeric_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_retry_after Retry-After Header
+ * 
+ * The Retry-After response-header field @RFC3261 section 20.33 can be used to
+ * indicate how long the service is expected to be unavailable or when the
+ * called party anticipates being available again. Its syntax is defined in
+ * @RFC3261 as follows:
+ * 
+ * @code
+ *      Retry-After  =  "Retry-After" HCOLON delta-seconds
+ *                      [ comment ] *( SEMI retry-param )
+ *      retry-param  =  ("duration" EQUAL delta-seconds)
+ *                      / generic-param
+ * @endcode
+ *
+ * The parsed Retry-After header is stored in #sip_retry_after_t structure.
+ */
+
+/**@ingroup sip_retry_after
+ * @typedef struct sip_retry_after_s sip_retry_after_t; 
+ *
+ * The structure #sip_retry_after_t contains representation of an 
+ * @RetryAfter header.
+ *
+ * The #sip_retry_after_t is defined as follows:
+ * @code
+ * typedef struct sip_retry_after_s {
+ *   sip_common_t        af_common[1]; // Common fragment info
+ *   sip_error_t        *af_next;      // Link to next (dummy)
+ *   sip_time_t          af_delta;     // Seconds to before retry
+ *   char const         *af_comment;   // Comment string
+ *   msg_param_t const  *af_params;    // List of parameters
+ *   char const         *af_duration;  // Duration parameter
+ * } sip_retry_after_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_retry_after_dup_xtra;
+static msg_dup_f sip_retry_after_dup_one;
+static msg_update_f sip_retry_after_update;
+
+msg_hclass_t sip_retry_after_class[] = 
+SIP_HEADER_CLASS(retry_after, "Retry-After", "", af_params, single,
+		 retry_after);
+
+issize_t sip_retry_after_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_retry_after_t *af = h->sh_retry_after;
+
+  if ((msg_delta_d((char const **)&s, &af->af_delta) < 0) ||
+      (*s == '(' && msg_comment_d(&s, &af->af_comment) == -1) ||
+      (*s == ';' && msg_params_d(home, &s, &af->af_params) == -1) ||
+      (*s != '\0')) {
+    if (af->af_params)
+      su_free(home, (void *)af->af_params), af->af_params = NULL;
+    return -1;
+  }
+
+  if (af->af_params)
+    msg_header_update_params(h->sh_common, 0);
+
+  return 0;
+}
+
+issize_t sip_retry_after_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_retry_after_t const *af = h->sh_retry_after;
+  int const compact = MSG_IS_COMPACT(f);
+  char *b0 = b, *end = b + bsiz;
+
+  b += snprintf(b, bsiz, "%lu", af->af_delta);
+
+  if (af->af_comment) {
+    if (!compact) 
+      MSG_CHAR_E(b, end, ' ');
+    MSG_CHAR_E(b, end, '(');
+    MSG_STRING_E(b, end, af->af_comment);
+    MSG_CHAR_E(b, end, ')');
+    if (!compact && af->af_params && af->af_params[0])
+      MSG_CHAR_E(b, end, ' ');
+  }
+
+  if (af->af_params)
+    MSG_PARAMS_E(b, end, af->af_params, f);
+    
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+
+isize_t sip_retry_after_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_retry_after_t const *af = h->sh_retry_after;
+
+  MSG_PARAMS_SIZE(offset, af->af_params);
+  offset += MSG_STRING_SIZE(af->af_comment);
+
+  return offset;
+}
+
+char *sip_retry_after_dup_one(sip_header_t *dst,
+			      sip_header_t const *src,
+			      char *b,
+			      isize_t xtra)
+{
+  sip_retry_after_t *af = dst->sh_retry_after;
+  sip_retry_after_t const *o = src->sh_retry_after;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&af->af_params, o->af_params, b, xtra);
+  MSG_STRING_DUP(b, af->af_comment, o->af_comment);
+  af->af_delta = o->af_delta;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+static int sip_retry_after_update(msg_common_t *h,
+				  char const *name, isize_t namelen,
+				  char const *value)
+{
+  sip_retry_after_t *af = (sip_retry_after_t *)h;
+
+  if (name == NULL) {
+    af->af_duration = NULL;
+  }
+  else if (namelen == strlen("duration") &&
+	   !strncasecmp(name, "duration", namelen)) {
+    af->af_duration = value;
+  }
+
+  return 0;
+}
+
+
+/* ====================================================================== */
+
+/**Parse a @Route or a @RecordRoute header.
+ *
+ * @retval 0 when successful, 
+ * @retval -1 upon an error.
+ */
+issize_t sip_any_route_d(su_home_t *home,
+			 sip_header_t *h,
+			 char *s,
+			 isize_t slen)
+{
+  sip_route_t *r = (sip_route_t *)h;
+
+  assert(h);
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if (sip_name_addr_d(home, &s, &r->r_display, 
+		      r->r_url, &r->r_params, NULL) < 0)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_any_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_route_t const *r = h->sh_route;
+
+  return sip_name_addr_e(b, bsiz, flags, 
+			 r->r_display, 1, r->r_url, r->r_params, NULL);
+}
+
+isize_t sip_any_route_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_route_t const *r = h->sh_route;
+
+  MSG_PARAMS_SIZE(offset, r->r_params);
+  offset += MSG_STRING_SIZE(r->r_display);
+  offset += url_xtra(r->r_url);
+
+  return offset;
+}
+
+char *sip_any_route_dup_one(sip_header_t *dst, sip_header_t const *src,
+			    char *b,
+			    isize_t xtra)
+{
+  sip_route_t *r = dst->sh_route;
+  sip_route_t const *o = src->sh_route;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&r->r_params, o->r_params, b, xtra);
+  MSG_STRING_DUP(b, r->r_display, o->r_display);
+  URL_DUP(b, end, r->r_url, o->r_url);
+    
+  assert(b <= end);
+
+  return b;
+}
+
+#define sip_any_route_update NULL
+
+
+/** Create a route. 
+ *
+ * Create a route or record-route entry
+ * from two URLs; first one provides the URL, second maddr parameter and
+ * port.
+ *
+ * @param home   memory home
+ * @param rq_url route URL
+ * @param maddr  optional route address and port
+ *  */
+static
+sip_route_t *sip_any_route_create(su_home_t *home,
+				  msg_hclass_t *hc,
+				  url_t const *rq_url,
+				  url_t const *maddr)
+{
+  sip_header_t *h;
+  sip_route_t *rr;
+  url_t url[1]; 
+  size_t xtra, n, n_url, n_params, n_addr; 
+  char *b, *param;
+
+  *url = *rq_url;
+  if (maddr) {
+    url->url_port = maddr->url_port;
+    url->url_params = NULL;
+  }
+  n_url = url_xtra(url);
+
+  n_params = maddr && maddr->url_params ? strlen(maddr->url_params) : 0;
+
+  if (maddr && (!maddr->url_params || 
+		!url_param(maddr->url_params, "maddr", NULL, 0)))
+    n_addr = (n_params != 0) + strlen("maddr=") + strlen(maddr->url_host);
+  else 
+    n_addr = 0;
+
+  xtra = n_url + n_params + n_addr + (n_params || n_addr);
+
+  h = sip_header_alloc(home, hc, xtra);
+  if ((rr = h->sh_record_route)) {
+    b = sip_header_data(h);
+    n = url_dup(b, n_url, rr->r_url, url);
+    assert(n == n_url);
+
+    if (n_params || n_addr) {
+      param = b + n_url;
+      if (n_params) {
+	rr->r_url->url_params = strcpy(param, maddr->url_params);
+	param += n_params;
+      }
+      if (n_addr) {
+	if (n_params)
+	  *param++ = ';';
+	strcpy(param, "maddr="), param += strlen("maddr=");
+	strcpy(param, maddr->url_host), param += strlen(maddr->url_host);
+      }
+      assert(b + xtra == param + 1);
+    }
+  }
+
+  return rr;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_route Route Header
+ *
+ * The Route headers is used to store the route set of a transaction.  
+ * The Route header is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Route        =  "Route" HCOLON route-param *(COMMA route-param)
+ *    route-param  =  name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ * The parsed Route header is stored in #sip_route_t structure.
+ */
+
+/**@ingroup sip_route
+ * @typedef typedef struct sip_route_s sip_route_t;
+ *
+ * The structure #sip_route_t contains representation of SIP @Route header.
+ *
+ * The #sip_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ *   sip_common_t        r_common[1];   // Common fragment info
+ *   sip_route_t        *r_next;        // Link to next @Route
+ *   char const         *r_display;     // Display name
+ *   url_t               r_url[1];      // @Route URL
+ *   msg_param_t const  *r_params;      // List of route parameters
+ * } sip_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_route_class[] = 
+SIP_HEADER_CLASS(route, "Route", "", r_params, append, any_route);
+
+issize_t sip_route_d(su_home_t *home,
+		     sip_header_t *h,
+		     char *s,
+		     isize_t slen)
+{
+  return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_route(h));
+  return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_route 
+ * @brief Create a @Route header object.
+ *
+ * Creates a route entry from two URLs; first one provides the URL, second
+ * maddr parameter and port.
+ *
+ * @param home   memory home
+ * @param url    route URL
+ * @param maddr  optional route address and port
+ *
+ * @return
+ * Returns a pointer to newly created @Route header object when successful,
+ * or NULL upon an error.
+ */
+sip_route_t *sip_route_create(su_home_t *home, 
+			      url_t const *url, 
+			      url_t const *maddr)
+{
+  return sip_any_route_create(home, sip_route_class, url, maddr);  
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_record_route Record-Route Header
+ *
+ * The Record-Route headers are used to establish a route for transactions
+ * belonging to a session.  The Record-Route header is defined in @RFC3261
+ * as follows: 
+ * 
+ * @code
+ *    Record-Route  =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
+ *    rec-route     =  name-addr *( SEMI rr-param )
+ *    rr-param      =  generic-param
+ * @endcode
+ *
+ * The parsed Record-Route header is stored in #sip_record_route_t structure.
+ */
+
+/**@ingroup sip_record_route
+ * @typedef typedef struct sip_record_route_s sip_record_route_t;
+ *
+ * The structure #sip_record_route_t contains representation of SIP
+ * @RecordRoute header.
+ *
+ * The #sip_record_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ *   sip_common_t        r_common[1];   // Common fragment info
+ *   sip_record_route_t *r_next;        // Link to next <rec-route>
+ *   char const         *r_display;     // Display name
+ *   url_t               r_url[1];      // @RecordRoute URL
+ *   msg_param_t const  *r_params;      // List of route parameters
+ * } sip_record_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_record_route_class[] = 
+SIP_HEADER_CLASS(record_route, "Record-Route", "",
+		 r_params, prepend, any_route);
+
+issize_t sip_record_route_d(su_home_t *home,
+			    sip_header_t *h,
+			    char *s,
+			    isize_t slen)
+{
+  return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_record_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_record_route(h));
+  return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/** @ingroup sip_record_route 
+ *
+ * Create a record-route. 
+ *
+ * Create a record-route entry from two URLs; first one provides the URL,
+ * second maddr parameter and port.
+ *
+ * @param home   memory home
+ * @param rq_url route URL
+ * @param maddr  optional route address and port
+ *
+ * @return
+ * A pointer to newly created @RecordRoute header object when successful or
+ * NULL upon an error.
+ */
+sip_record_route_t *sip_record_route_create(su_home_t *home,
+					    url_t const *rq_url,
+					    url_t const *maddr)
+{
+  return sip_any_route_create(home, sip_record_route_class, rq_url, maddr);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_to To Header
+ *
+ * The To header field specifies the "logical" recipient of the
+ * request.  It is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    To        =  ( "To" / "t" ) HCOLON ( name-addr
+ *                 / addr-spec ) *( SEMI to-param )
+ *    to-param  =  tag-param / generic-param
+ * @endcode
+ *
+ * The parsed To header is stored in #sip_to_t structure.
+ */
+
+/**@ingroup sip_to
+ * @typedef typedef struct sip_addr_s sip_to_t;
+ *
+ * The structure #sip_to_t contains representation of @To header.
+ *
+ * The #sip_to_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   sip_common_t       a_common[1];    // Common fragment info
+ *   sip_error_t       *a_next;         // Link to next (dummy)
+ *   char const        *a_display;      // Display name
+ *   url_t              a_url[1];       // URL
+ *   msg_param_t const *a_params;       // List of to-params
+ *   char const        *a_comment;      // Comment
+ *   char const        *a_tag;          // Tag parameter 
+ * } sip_to_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_to_class[] = 
+SIP_HEADER_CLASS(to, "To", "t", a_params, single, addr);
+
+issize_t sip_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_addr_d(home, h, s, slen);
+}
+
+issize_t sip_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_to(h));
+
+  return sip_addr_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_to
+ *
+ * Create a @To header object with URL.
+ *
+ * @param home      memory home
+ * @param url       URL (string or pointer to url_t)
+ *
+ * @return
+ * A pointer to newly created @To header object when successful or NULL upon
+ * an error.
+ */
+sip_to_t *
+sip_to_create(su_home_t *home, url_string_t const *url)
+{
+  return sip_addr_make_url(home, sip_to_class, url);
+}
+
+/**@ingroup sip_to
+ *
+ * Add a parameter to a #sip_to_t object.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home   memory home
+ * @param to     #sip_to_t structure
+ * @param param  parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_to_add_param(su_home_t *home,
+		     sip_to_t *to,
+		     char const *param)
+{
+  return msg_header_replace_param(home, to->a_common, param);
+}
+
+/* ====================================================================== */
+/**@SIP_HEADER sip_via Via Header
+ *
+ * The Via header indicates the path taken by the request so far.  Via
+ * headers can be used to prevent request looping and ensure replies take
+ * the same path as the requests.  The Via syntax is defined in @RFC3261
+ * as follows:
+ * 
+ * @code
+ *    Via               =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ *    via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
+ *    via-params        =  via-ttl / via-maddr
+ *                         / via-received / via-branch
+ *                         / via-extension
+ *    via-ttl           =  "ttl" EQUAL ttl
+ *    via-maddr         =  "maddr" EQUAL host
+ *    via-received      =  "received" EQUAL (IPv4address / IPv6address)
+ *    via-branch        =  "branch" EQUAL token
+ *    via-extension     =  generic-param
+ *    sent-protocol     =  protocol-name SLASH protocol-version
+ *                         SLASH transport
+ *    protocol-name     =  "SIP" / token
+ *    protocol-version  =  token
+ *    transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
+ *                         / other-transport
+ *    sent-by           =  host [ COLON port ]
+ *    ttl               =  1*3DIGIT ; 0 to 255
+ * @endcode
+ *
+ * @note
+ * The @RFC2543 syntax allowed <comment>. We accept it, but don't encode it.
+ *
+ * In addition to the parameters defined in @RFC3261, @RFC3486 defines a
+ * parameter "comp":
+ * @code
+ *     via-compression  =  "comp" EQUAL ("sigcomp" / other-compression)
+ *    via-params      /=  via-compression
+ * @endcode
+ *
+ * @RFC3581 defines a parameter "rport":
+ * @code
+ *    response-port  =  "rport" [EQUAL 1*DIGIT]
+ *    via-params    /=  response-port
+ * @endcode
+ *
+ * The parsed Via header is stored in #sip_via_t structure.
+ */
+
+/**@ingroup sip_via
+ * @typedef typedef struct sip_via_s sip_via_t;
+ *
+ * The structure #sip_via_t contains representation of SIP @Via header.
+ *
+ * The #sip_via_t is defined as follows:
+ * @code
+ * typedef struct sip_via_s {
+ *   sip_common_t        v_common[1];   // Common fragment info
+ *   sip_via_t          *v_next;        // Link to next @Via header
+ *   char const         *v_protocol;    // Application and transport protocol
+ *   char const         *v_host;        // Hostname
+ *   char const         *v_port;        // Port number
+ *   msg_param_t const  *v_params;      // List of via-params
+ *   char const         *v_comment;     // Comment
+ * 
+ *   char const         *v_ttl;         // "ttl" parameter
+ *   char const         *v_maddr;       // "maddr" parameter
+ *   char const         *v_received;    // "received" parameter
+ *   char const         *v_branch;      // "branch" parameter
+ *   char const         *v_comp;        // "comp" parameter
+ *   char const         *v_rport;       // "rport" parameter
+ * } sip_via_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_via_dup_xtra;
+static msg_dup_f sip_via_dup_one;
+static msg_update_f sip_via_update;
+
+msg_hclass_t sip_via_class[] = 
+SIP_HEADER_CLASS(via, "Via", "v", v_params, prepend, via);
+
+issize_t sip_via_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_via_t *v = (sip_via_t *)h;
+
+  assert(h);
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  /* sent-protocol sent-by *( ";" via-params ) [ comment ] */
+
+  /* Parse protocol */
+  if (sip_transport_d(&s, &v->v_protocol) == -1)
+    return -1;
+  /* Host (and port) */
+  if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1)
+    return -1;
+  /* Parameters */
+  if (*s == ';' && msg_params_d(home, &s, &v->v_params) == -1)
+    return -1;
+  /* Comment */
+  if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_via_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  sip_via_t const *v = h->sh_via;
+
+  assert(sip_is_via(h));
+
+  MSG_STRING_E(b, end, v->v_protocol);
+  MSG_CHAR_E(b, end, ' ');
+  MSG_STRING_E(b, end, v->v_host);
+  if (v->v_port) {
+    MSG_CHAR_E(b, end, ':');	
+    MSG_STRING_E(b, end, v->v_port);
+  }
+  MSG_PARAMS_E(b, end, v->v_params, flags);
+#if 0
+  /* Comment is deprecated in @RFC3265 - accept it, but do not send */
+  if (v->v_comment) {
+    if (!MSG_IS_COMPACT(flags)) 
+      MSG_CHAR_E(b, end, ' ');
+    MSG_CHAR_E(b, end, '(');
+    MSG_STRING_E(b, end, v->v_comment);
+    MSG_CHAR_E(b, end, ')');
+  }
+#endif
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+
+isize_t sip_via_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_via_t const *v = h->sh_via;
+
+  MSG_PARAMS_SIZE(offset, v->v_params);
+  offset += sip_transport_xtra(v->v_protocol);
+  offset += MSG_STRING_SIZE(v->v_host);
+  offset += MSG_STRING_SIZE(v->v_port);
+  offset += MSG_STRING_SIZE(v->v_comment);
+
+  return offset;
+}
+
+/** Duplicate one #sip_via_t object */ 
+char *sip_via_dup_one(sip_header_t *dst, sip_header_t const *src,
+		      char *b, isize_t xtra)
+{
+  sip_via_t *v = dst->sh_via;
+  sip_via_t const *o = src->sh_via;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&v->v_params, o->v_params, b, xtra);
+  sip_transport_dup(&b, &v->v_protocol, o->v_protocol);
+  MSG_STRING_DUP(b, v->v_host, o->v_host);
+  MSG_STRING_DUP(b, v->v_port, o->v_port);
+  MSG_STRING_DUP(b, v->v_comment, o->v_comment);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+static int sip_via_update(msg_common_t *h, 
+			  char const *name, isize_t namelen,
+			  char const *value)
+{
+  sip_via_t *v = (sip_via_t *)h;
+
+  if (name == NULL) {
+    v->v_ttl = NULL;
+    v->v_maddr = NULL;
+    v->v_received = NULL;
+    v->v_branch = NULL;
+    v->v_rport = NULL;
+    v->v_comp = NULL;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+   else if (MATCH(ttl)) {
+     v->v_ttl = value;
+   }
+   else if (MATCH(maddr)) {
+     v->v_maddr = value;
+   }
+   else if (MATCH(received)) {
+     v->v_received = value;
+   }
+   else if (MATCH(branch)) {
+     v->v_branch = value;
+   }
+   else if (MATCH(rport)) {
+     v->v_rport = value;
+   }
+   else if (MATCH(comp)) {
+     v->v_comp = value;
+   }
+
+ #undef MATCH
+
+   return 0;
+ }
+
+/**@ingroup sip_via
+ *
+ * Add a parameter to a @Via object.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home   memory home
+ * @param v      #sip_via_t object
+ * @param param  parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_via_add_param(su_home_t *home,
+		      sip_via_t *v,
+		      char const *param)
+{
+  return msg_header_replace_param(home, v->v_common, param);
+}
+
+/**@ingroup sip_via
+ *
+ * Create a @Via object. 
+ *
+ * Create a new @Via header object with
+ * given parameters.  If @a transport is NULL, the default transport
+ * "SIP/2.0/UDP" is used.  A NULL-terminated list of parameters can be
+ * specified after transport.
+ *
+ * @param home 	    memory home
+ * @param host 	    host name
+ * @param port 	    protocol port number
+ * @param transport transport protocol (default is "SIP/2.0/UDP")
+ * @param ...       NULL-terminated list of parameters
+ *
+ * @return
+ * A pointer to newly created
+ * @Via header object when successful or NULL upon an error.
+ */ 
+sip_via_t *sip_via_create(su_home_t *home,
+                          char const *host,
+                          char const *port, 
+                          char const *transport,
+                          /* char const *params */
+                          ...)
+{
+  sip_via_t *v, via[1] = {{{{ NULL }}}};
+  va_list params;
+
+  via->v_common->h_class = sip_via_class;
+
+  if (transport)
+    via->v_protocol = transport;
+  else
+    via->v_protocol = sip_transport_udp;
+
+  via->v_host = host;
+  via->v_port = port;
+
+  v = msg_header_dup_as(home, sip_via_class, (sip_header_t *)via)->sh_via;
+
+  if (v) {
+    char const *param;
+    va_start(params, transport);
+
+    for (param = va_arg(params, char const *); 
+         param; 
+         param = va_arg(params, char const *)) {
+      if ((param = su_strdup(home, param))) {
+	if (msg_header_replace_param(home, v->v_common, param) < 0)
+	  break;
+      }
+    }
+
+    va_end(params);
+  }
+
+  return v;
+}
+
+/**@ingroup sip_via
+ *
+ * Get port number corresponding to a @Via line.
+ * 
+ * If @a using_rport is non-null, try rport.
+ * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
+ * If <protocol> is UDP, set *using_rport to zero.
+ */
+char const *sip_via_port(sip_via_t const *v, int *using_rport)
+{
+  if (v == NULL)
+    return NULL;
+
+  if (using_rport) {
+    char const *port;
+
+    if (v->v_rport && !v->v_maddr /* multicast */) {
+      if (v->v_protocol == sip_transport_udp || 
+	  strcasecmp(v->v_protocol, sip_transport_udp) == 0)
+	port = v->v_rport, *using_rport = 0;
+      else if (*using_rport)
+	port = v->v_rport;
+      else
+	port = NULL;
+
+      if (port && port[0])
+	return port;
+    }
+
+    *using_rport = 0;		/* No, we don't... */
+  }
+
+  if (v->v_port)
+    return v->v_port;
+
+  if (sip_transport_has_tls(v->v_protocol))
+    return SIPS_DEFAULT_SERV;	/* 5061 */
+  else
+    return SIP_DEFAULT_SERV;	/* 5060 */
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,427 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_caller_prefs.c
+ * @brief SIP headers related to Caller Preferences
+ *
+ * Implementation of header classes for Caller-Preferences-related SIP
+ * headers @AcceptContact, @RejectContact, and @RequestDisposition.
+ *
+ * @author Remeres Jacobs <remeres.jacobs at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Th 23.01.2003
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_request_disposition Request-Disposition Header
+ *
+ * The Request-Disposition header syntax is defined in
+ * @RFC3841 section 10 as follows:
+ *
+ * @code
+ *      Request-Disposition  =  ( "Request-Disposition" | "d" ) HCOLON
+ *                              directive *(COMMA directive)
+ *      directive            =  proxy-directive / cancel-directive /
+ *                              fork-directive / recurse-directive /
+ *                              parallel-directive / queue-directive)
+ *      proxy-directive      =  "proxy" / "redirect"
+ *      cancel-directive     =  "cancel" / "no-cancel"
+ *      fork-directive       =  "fork" / "no-fork"
+ *      recurse-directive    =  "recurse" / "no-recurse"
+ *      parallel-directive   =  "parallel" / "sequential"
+ *      queue-directive      =  "queue" / "no-queue"
+ * @endcode
+ *
+ *
+ * The parsed Request-Disposition header 
+ * is stored in #sip_request_disposition_t structure.
+ */
+
+/**@ingroup sip_request_disposition
+ * @typedef typedef struct sip_request_disposition_s sip_request_disposition_t;
+ *
+ * The structure #sip_request_disposition_t contains representation of 
+ * @RequestDisposition header.
+ *
+ * The #sip_request_disposition_t is defined as follows:
+ * @code
+ * typedef struct sip_request_disposition_s
+ * {
+ *   sip_common_t        rd_common[1];   // Common fragment info
+ *   sip_unknown_t      *rd_next;	 // Link to next (dummy)
+ *   msg_param_t        *rd_items;       // List of directives
+ * } sip_request_disposition_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_request_disposition_dup_xtra;
+static msg_dup_f sip_request_disposition_dup_one;
+#define sip_request_disposition_update NULL
+
+msg_hclass_t sip_request_disposition_class[] =
+SIP_HEADER_CLASS(request_disposition, "Request-Disposition", "d", rd_items,
+		 list, request_disposition);
+
+issize_t sip_request_disposition_d(su_home_t *home, sip_header_t *h,
+				   char *s, isize_t slen)
+{
+  sip_request_disposition_t *rd = h->sh_request_disposition;
+
+  return msg_commalist_d(home, &s, &rd->rd_items, msg_token_scan);
+}
+
+
+issize_t sip_request_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_request_disposition_t const *o = h->sh_request_disposition;
+
+  assert(sip_is_request_disposition(h));
+
+  MSG_COMMALIST_E(b, end, o->rd_items, flags);
+
+  return b - b0;
+}
+
+
+isize_t sip_request_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_request_disposition_t const *o = h->sh_request_disposition;
+
+  MSG_PARAMS_SIZE(offset, o->rd_items);
+
+  return offset;
+}
+
+
+/** Duplicate one #sip_request_disposition_t object */
+char *sip_request_disposition_dup_one(sip_header_t *dst,
+				      sip_header_t const *src,
+				      char *b, isize_t xtra)
+{
+  char *end = b + xtra;
+  sip_request_disposition_t *o_dst = dst->sh_request_disposition;
+  sip_request_disposition_t const *o_src = src->sh_request_disposition;
+  msg_param_t const **dst_items = (msg_param_t const **)&o_dst->rd_items;
+
+  b = msg_params_dup(dst_items, o_src->rd_items, b, xtra);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@ingroup sip_caller_prefs
+ *
+ * Add a parameter to a @AcceptContact or @RejectContact header object.
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home   memory home
+ * @param cp     pointer to #sip_accept_contact_t or #sip_reject_contact_t
+ * @param param  parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() instead.
+ */
+int sip_caller_prefs_add_param(su_home_t *home,
+			       sip_caller_prefs_t *cp,
+			       char const *param)
+{
+  return  msg_header_replace_param(home, cp->cp_common, param);
+}
+
+static
+size_t span_attribute_value(char *s)
+{
+  size_t n;
+
+  n = span_token_lws(s);
+  if (n > 0 && s[n] == '=') {
+    n += 1 + span_lws(s + n + 1);
+    if (s[n] == '"')
+      n += span_quoted(s + n);
+    else
+      n += span_token(s + n);
+    n += span_lws(s + n);
+  }
+
+  return n;
+}
+
+static
+issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h,
+			    char *s, isize_t slen)
+{
+  sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
+  url_t url[1];
+  char const *ignore = NULL;
+  int kludge = 0;
+
+  assert(h);
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  /* Kludge: support PoC IS spec with a typo... */
+  if (strncasecmp(s, "*,", 2) == 0)
+    s[1] = ';',  kludge = 0;
+  else if (s[0] != '*' && s[0] != '<') {
+    /* Kludge: missing URL -  */
+    size_t n = span_attribute_value(s);
+    kludge = n > 0 && (s[n] == '\0' || s[n] == ',' || s[n] == ';');
+  }
+
+  if (kludge) {
+    if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params,
+		       msg_attribute_value_scanner, ';') == -1)
+      return -1;
+  }
+  /* Parse params (and ignore display name and url) */
+  else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL)
+	   == -1)
+    return -1;
+  /* Be liberal... */
+  /* if (url->url_type != url_any)
+     return -1; */
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+static
+issize_t sip_caller_prefs_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_caller_prefs_t const *cp = h->sh_caller_prefs;
+  char *b0 = b, *end = b + bsiz;
+
+  MSG_CHAR_E(b, end, '*');
+  MSG_PARAMS_E(b, end, cp->cp_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+
+static
+isize_t sip_caller_prefs_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_caller_prefs_t const *cp = h->sh_caller_prefs;
+
+  MSG_PARAMS_SIZE(offset, cp->cp_params);
+
+  return offset;
+}
+
+static
+char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
+			      char *b, isize_t xtra)
+{
+  char *end = b + xtra;
+  sip_caller_prefs_t *cp = dst->sh_caller_prefs;
+  sip_caller_prefs_t const *o = src->sh_caller_prefs;
+
+  b = msg_params_dup(&cp->cp_params, o->cp_params, b, xtra);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/**@SIP_HEADER sip_accept_contact Accept-Contact Header
+ *
+ * The Accept-Contact syntax is defined in @RFC3841 section 10 as follows:
+ *
+ * @code
+ *    Accept-Contact  =  ("Accept-Contact" / "a") HCOLON ac-value
+ *                       *(COMMA ac-value)
+ *    ac-value        =  "*" *(SEMI ac-params)
+ *    ac-params       =  feature-param / req-param
+ *                        / explicit-param / generic-param
+ *                        ;;feature param from RFC 3840
+ *                        ;;generic-param from RFC 3261
+ *    req-param       =  "require"
+ *    explicit-param  =  "explicit"
+ * @endcode
+ *
+ * Despite the BNF, there MUST NOT be more than one req-param or
+ * explicit-param in an ac-params. Furthermore, there can only be one
+ * instance of any feature tag in feature-param.
+ *
+ * @sa @RFC3840, @RFC3841, sip_contact_accept(), sip_contact_score().
+ *
+ * The parsed Accept-Contact header
+ * is stored in #sip_accept_contact_t structure.
+ */
+
+/**@ingroup sip_accept_contact
+ * @typedef struct sip_caller_prefs_s sip_accept_contact_t;
+ *
+ * The structure #sip_accept_contact_t contains representation of SIP
+ * @AcceptContact header.
+ *
+ * The #sip_accept_contact_t is defined as follows:
+ * @code
+ * typedef struct caller_prefs_s {
+ *   sip_common_t        cp_common[1];   // Common fragment info
+ *   sip_caller_prefs_t *cp_next;        // Link to next ac-value
+ *   msg_param_t const  *cp_params;      // List of parameters
+ *   char const         *cp_q;           // Priority
+ *   unsigned            cp_require :1;  // Shortcut to "require" parameter
+ *   unsigned            cp_explicit :1; // Shortcut to "explicit" parameter
+ * } sip_accept_contact_t;
+ * @endcode
+ */
+
+#define sip_accept_contact_dup_xtra sip_caller_prefs_dup_xtra
+#define sip_accept_contact_dup_one  sip_caller_prefs_dup_one
+
+static int sip_accept_contact_update(msg_common_t *h,
+				     char const *name, isize_t namelen,
+				     char const *value);
+
+msg_hclass_t sip_accept_contact_class[] =
+SIP_HEADER_CLASS(accept_contact, "Accept-Contact", "a", cp_params, append,
+		 accept_contact);
+
+issize_t sip_accept_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_caller_prefs_d(home, h, s, slen);
+}
+
+
+issize_t sip_accept_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return sip_caller_prefs_e(b, bsiz, h, flags);
+}
+
+static int sip_accept_contact_update(msg_common_t *h,
+				     char const *name, isize_t namelen,
+				     char const *value)
+{
+  sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
+
+  if (name == NULL) {
+    cp->cp_q = NULL;
+    cp->cp_require = 0;
+    cp->cp_explicit = 0;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+#if nomore
+  else if (MATCH(q)) {
+    cp->cp_q = value;
+  }
+#endif
+  else if (MATCH(require)) {
+    cp->cp_require = value != NULL;
+  }
+  else if (MATCH(explicit)) {
+    cp->cp_explicit = value != NULL;
+  }
+
+#undef MATCH
+
+  return 0;
+}
+
+
+/**@SIP_HEADER sip_reject_contact Reject-Contact Header
+ *
+ * The Reject-Contact syntax is defined in @RFC3841 section 10 as follows:
+ *
+ * @code
+ *    Reject-Contact  =  ("Reject-Contact" / "j") HCOLON rc-value
+ *                       *(COMMA rc-value)
+ *    rc-value        =  "*" *(SEMI rc-params)
+ *    rc-params       =  feature-param / generic-param
+ *                        ;;feature param from RFC 3840
+ *                        ;;generic-param from RFC 3261
+ * @endcode
+ *
+ * Despite the BNF, there MUST NOT be more than one instance of any feature
+ * tag in feature-param.
+ *
+ * @sa @RFC3840, @RFC3841, sip_contact_reject(), sip_contact_score().
+ *
+ * The parsed Reject-Contact header
+ * is stored in #sip_reject_contact_t structure.
+ */
+
+/**@ingroup sip_reject_contact
+ * @typedef struct sip_caller_prefs_s sip_reject_contact_t;
+ *
+ * The structure #sip_reject_contact_t contains representation of SIP
+ * @RejectContact header.
+ *
+ * The #sip_reject_contact_t is defined as follows:
+ * @code
+ * typedef struct caller_prefs_s {
+ *   sip_common_t        cp_common[1];   // Common fragment info
+ *   sip_caller_prefs_t *cp_next;        // Link to next rc-value
+ *   msg_param_t const  *cp_params;      // List of parameters
+ * } sip_reject_contact_t;
+ * @endcode
+ *
+ * @note Fields @c cp_q, @c cp_require and @c cp_explicit are ignored for
+ * @RejectContact header.
+ */
+
+#define sip_reject_contact_dup_xtra sip_caller_prefs_dup_xtra
+#define sip_reject_contact_dup_one  sip_caller_prefs_dup_one
+#define sip_reject_contact_update   NULL
+
+msg_hclass_t sip_reject_contact_class[] =
+SIP_HEADER_CLASS(reject_contact, "Reject-Contact", "j", cp_params, append,
+		 reject_contact);
+
+issize_t sip_reject_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_caller_prefs_d(home, h, s, slen);
+}
+
+
+issize_t sip_reject_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return sip_caller_prefs_e(b, bsiz, h, flags);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,548 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_event.c
+ * @brief Event SIP headers.
+ *
+ * Implementation of header classes for event-related SIP headers @Event,
+ * @AllowEvents, and @SubscriptionState.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_event Event Header
+ *
+ * The Event header is used to indicate the which event or class of events
+ * the message contains or subscribes. Its syntax is defined in @RFC3265 as
+ * follows:
+ * 
+ * @code
+ *   Event             =  ( "Event" / "o" ) HCOLON event-type
+ *                         *( SEMI event-param )
+ *   event-type        =  event-package *( "." event-template )
+ *   event-package     =  token-nodot
+ *   event-template    =  token-nodot
+ *   token-nodot       =  1*( alphanum / "-"  / "!" / "%" / "*"
+ *                             / "_" / "+" / "`" / "'" / "~" )
+ *   event-param      =  generic-param / ( "id" EQUAL token )
+ * @endcode
+ *
+ * The parsed Event header is stored in #sip_event_t structure.
+ */
+
+/**@ingroup sip_event
+ * @typedef struct sip_event_s sip_event_t; 
+ *
+ * The structure #sip_event_t contains representation of an @Event header.
+ *
+ * The #sip_event_t is defined as follows:
+ * @code
+ * typedef struct sip_event_s
+ * {
+ *   sip_common_t        o_common;	    // Common fragment info
+ *   sip_error_t        *o_next;	    // Link to next (dummy)
+ *   char const *        o_type;	    // Event type
+ *   msg_param_t const  *o_params;	    // List of parameters
+ *   char const         *o_id;	    	    // Event ID
+ * } sip_event_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_event_dup_xtra;
+static msg_dup_f sip_event_dup_one;
+static msg_update_f sip_event_update;
+
+msg_hclass_t sip_event_class[] = 
+SIP_HEADER_CLASS(event, "Event", "o", o_params, single, event);
+
+issize_t sip_event_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_event_t *o = h->sh_event;
+  size_t n;
+
+  n = span_token(s); if (n == 0) return -1;
+  o->o_type = s; s += n;
+  while (IS_LWS(*s)) { *s++ = '\0'; }
+  if (*s == ';') {
+    if (msg_params_d(home, &s, &o->o_params) < 0 || *s)
+      return -1;
+    msg_header_update_params(o->o_common, 0);
+  }
+  return 0;
+}
+
+issize_t sip_event_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_event_t const *o = h->sh_event;
+
+  assert(sip_is_event(h));
+  MSG_STRING_E(b, end, o->o_type);
+  MSG_PARAMS_E(b, end, o->o_params, flags);
+
+  return b - b0;
+}
+
+isize_t sip_event_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_event_t const *o = h->sh_event;
+
+  MSG_PARAMS_SIZE(offset, o->o_params);
+  offset += MSG_STRING_SIZE(o->o_type);
+
+  return offset;
+}
+
+/** Duplicate one #sip_event_t object */ 
+char *sip_event_dup_one(sip_header_t *dst, sip_header_t const *src,
+			char *b, isize_t xtra)
+{
+  sip_event_t *o_dst = dst->sh_event;
+  sip_event_t const *o_src = src->sh_event;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&o_dst->o_params, o_src->o_params, b, xtra);
+  MSG_STRING_DUP(b, o_dst->o_type, o_src->o_type);
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameters in @Event header. */
+static int sip_event_update(msg_common_t *h, 
+			   char const *name, isize_t namelen,
+			   char const *value)
+{
+  sip_event_t *o = (sip_event_t *)h;
+
+  if (name == NULL) {
+    o->o_id = NULL;
+  }
+  else if (namelen == strlen("id") && !strncasecmp(name, "id", namelen)) {
+    o->o_id = value;
+  }
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow_events Allow-Events Header
+ *
+ * The Allow-Events header is used to indicate which events or classes of
+ * events the notifier supports. Its syntax is defined in @RFC3265 as
+ * follows:
+ * 
+ * @code
+ *    Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type 
+ *                                           *(COMMA event-type)
+ * @endcode
+ *
+ * The parsed Allow-Events header is stored in #sip_allow_events_t structure.
+ *
+ * Note that the event name is case-sensitive. The event "Presence" is
+ * different from "presence". However, it is very unwise to use such event
+ * names.
+ *
+ * @sa @Event, @RFC3265, msg_header_find_item(), msg_header_replace_item(),
+ * msg_header_remove_item()
+ */
+
+/**@ingroup sip_allow_events
+ * @typedef struct msg_list_s sip_allow_events_t; 
+ *
+ * The structure #sip_allow_events_t contains representation of an 
+ * @AllowEvents header.
+ *
+ * The #sip_allow_events_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_allow_events_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_allow_events_class[] = 
+SIP_HEADER_CLASS_LIST(allow_events, "Allow-Events", "u", list);
+
+issize_t sip_allow_events_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_allow_events_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_allow_events(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/** Append an event to a @AllowEvents header. 
+ *
+ * @note This function @b does @b duplicate @p event.
+ *
+ * @deprecated Use msg_header_replace_item() directly.
+ */
+int sip_allow_events_add(su_home_t *home, 
+			 sip_allow_events_t *ae, 
+			 char const *event)
+{
+  event = su_strdup(home, event);
+  if (!event)
+    return -1;
+  return msg_header_replace_item(home, ae->k_common, event);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_subscription_state Subscription-State Header
+ *
+ * The Subscription-State header is used to indicate in which state a
+ * subscription is. Its syntax is defined in @RFC3265 section 4.2.4 as
+ * follows:
+ * 
+ * @code
+ *    Subscription-State   = "Subscription-State" HCOLON substate-value
+ *                           *( SEMI subexp-params )
+ *    substate-value       = "active" / "pending" / "terminated"
+ *                           / extension-substate
+ *    extension-substate   = token
+ *    subexp-params        =   ("reason" EQUAL event-reason-value)
+ *                           / ("expires" EQUAL delta-seconds)
+ *                           / ("retry-after" EQUAL delta-seconds)
+ *                           / generic-param
+ *    event-reason-value   =   "deactivated"
+ *                           / "probation"
+ *                           / "rejected"
+ *                           / "timeout"
+ *                           / "giveup"
+ *                           / "noresource"
+ *                           / event-reason-extension
+ *    event-reason-extension = token
+ * @endcode
+ *
+ * The parsed Subscription-State header
+ * is stored in #sip_subscription_state_t structure.
+ */
+
+/**@ingroup sip_subscription_state
+ * @typedef struct sip_subscription_state_s sip_subscription_state_t;
+ *
+ * The structure #sip_subscription_state_t contains representation of an 
+ * @SubscriptionState header.
+ *
+ * The #sip_subscription_state_t is defined as follows:
+ * @code
+ * typedef struct sip_subscription_state_s
+ * {
+ *   sip_common_t       ss_common[1];
+ *   sip_unknown_t     *ss_next;
+ *   // Subscription state: "pending", "active" or "terminated"
+ *   char const        *ss_substate;        
+ *   msg_param_t const *ss_params;      // List of parameters
+ *   char const        *ss_reason;      // Reason of terminating 
+ *   char const        *ss_expires;     // Subscription lifetime in seconds
+ *   char const        *ss_retry_after; // Value of retry-after parameter
+ * } sip_subscription_state_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_subscription_state_dup_xtra;
+static msg_dup_f sip_subscription_state_dup_one;
+static msg_update_f sip_subscription_state_update;
+
+msg_hclass_t sip_subscription_state_class[] = 
+SIP_HEADER_CLASS(subscription_state, "Subscription-State", "", 
+		 ss_params, single, 
+		 subscription_state);
+
+issize_t sip_subscription_state_d(su_home_t *home, sip_header_t *h, 
+				  char *s, isize_t slen)
+{
+   sip_subscription_state_t *ss = h->sh_subscription_state;
+   ss->ss_substate = s;
+   
+   s += span_token(s); /* forwards the pointer to the end of substate-value */
+   if (s == ss->ss_substate)
+     return -1;
+   if (IS_LWS(*s)) { 
+     *s = '\0'; s += span_lws(s + 1) + 1;
+   }
+   
+   /* check if parameters are present and if so parse them */
+   if (*s  == ';') {
+     if ( msg_params_d(home, &s, &ss->ss_params) < 0)
+       return -1;
+     if (msg_header_update_params(ss->ss_common, 0) < 0)
+       return -1;
+   }
+
+   return 0;
+}
+
+issize_t sip_subscription_state_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_subscription_state_t const *ss = h->sh_subscription_state;
+   
+  assert(sip_is_subscription_state(h));
+   
+  MSG_STRING_E(b, end, ss->ss_substate);
+  MSG_PARAMS_E(b, end, ss->ss_params, flags);   
+
+  return b - b0;   
+}
+
+isize_t sip_subscription_state_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+   sip_subscription_state_t const *ss = h->sh_subscription_state;
+   
+   /* Calculates memory size occupied */
+   MSG_PARAMS_SIZE(offset, ss->ss_params);
+   offset += MSG_STRING_SIZE(ss->ss_substate);
+   
+   return offset;   
+}
+
+/** Duplicate one #sip_subscription_state_t object */ 
+char *sip_subscription_state_dup_one(sip_header_t *dst, sip_header_t const *src,
+				     char *b, isize_t xtra)
+{
+  sip_subscription_state_t *ss_dst = dst->sh_subscription_state;
+  sip_subscription_state_t const *ss_src = src->sh_subscription_state;
+  char *end = b + xtra;
+   
+  b = msg_params_dup(&ss_dst->ss_params, ss_src->ss_params, b, xtra);
+  MSG_STRING_DUP(b, ss_dst->ss_substate, ss_src->ss_substate);
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+static int sip_subscription_state_update(msg_common_t *h, 
+					 char const *name, isize_t namelen,
+					 char const *value)
+{
+  sip_subscription_state_t *ss = (sip_subscription_state_t *)h;
+
+  if (name == NULL) {
+    ss->ss_reason = NULL;
+    ss->ss_retry_after = NULL;
+    ss->ss_expires = NULL;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+  else if (MATCH(reason)) {
+    ss->ss_reason = value;
+  }
+  else if (MATCH(retry-after)) {
+    ss->ss_retry_after = value;
+  }
+  else if (MATCH(expires)) {
+    ss->ss_expires = value;
+  }
+
+#undef MATCH
+
+  return 0;
+}
+
+#if 0				/* More dead headers */
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_publication Publication Header
+ *
+ * The Publication header is used to indicate the which publication or class
+ * of publications the message contains. Its syntax is defined
+ * in (draft-niemi-simple-publish-00.txt) as follows:
+ * 
+ * @code
+ *   Publication          =  ( "Publication") HCOLON publish-package
+ *                         *( SEMI publish-param )
+ *   publish-package      =  token-nodot
+ *   token-nodot          =  1*( alphanum / "-"  / "!" / "%" / "*"
+ *                               / "_" / "+" / "`" / "'" / "~" )
+ *   publish-param        = generic-param / pstream / ptype
+ *   pstream              = "stream" EQUAL token
+ *   ptype                = "type" EQUAL token
+ * @endcode
+ *
+ *
+ * The parsed Publication header is stored in #sip_publication_t structure.
+ */
+
+/**@ingroup sip_publication
+ * @brief Structure for Publication header.
+ */
+struct sip_publication_s 
+{
+  sip_common_t        pub_common;	    /**< Common fragment info */
+  sip_error_t        *pub_next;	            /**< Link to next (dummy) */
+  char const *        pub_package;          /**< Publication packaage */
+  msg_param_t const  *pub_params;	    /**< List of parameters */
+  msg_param_t         pub_type; 	    /**< Publication type */
+  msg_param_t         pub_stream;	    /**< Publication stream */
+};
+
+static msg_xtra_f sip_publication_dup_xtra;
+static msg_dup_f sip_publication_dup_one;
+
+msg_hclass_t sip_publication_class[] = 
+SIP_HEADER_CLASS(publication, "Publication", "", pub_params, single, 
+		 publication);
+
+static inline void sip_publication_update(sip_publication_t *pub);
+
+issize_t sip_publication_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_publication_t *pub = h->sh_publication;
+  size_t n;
+
+  n = span_token(s); if (n == 0) return -1;
+  pub->pub_package = s; s += n;
+  while (IS_LWS(*s)) { *s++ = '\0'; }
+  if (*s == ';') {
+    if (msg_params_d(home, &s, &pub->pub_params) < 0 || *s)
+      return -1;
+    sip_publication_update(pub);
+  }
+  return 0;
+}
+
+issize_t sip_publication_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_publication_t const *pub = h->sh_publication;
+
+  assert(sip_is_publication(h));
+  MSG_STRING_E(b, end, pub->pub_package);
+  MSG_PARAMS_E(b, end, pub->pub_params, flags);
+
+  return b - b0;
+}
+
+isize_t sip_publication_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_publication_t const *pub = h->sh_publication;
+
+  MSG_PARAMS_SIZE(offset, pub->pub_params);
+  offset += MSG_STRING_SIZE(pub->pub_package);
+
+  return offset;
+}
+
+/** Duplicate one #sip_publication_t object */ 
+char *sip_publication_dup_one(sip_header_t *dst, sip_header_t const *src,
+			char *b, isize_t xtra)
+{
+  sip_publication_t *pub_dst = dst->sh_publication;
+  sip_publication_t const *pub_src = src->sh_publication;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&pub_dst->pub_params, pub_src->pub_params, b, xtra);
+  MSG_STRING_DUP(b, pub_dst->pub_package, pub_src->pub_package);
+  if (pub_dst->pub_params)
+    sip_publication_update(pub_dst);
+  assert(b <= end);
+
+  return b;
+}
+
+static inline void sip_publication_update(sip_publication_t *pub)
+{
+  size_t i;
+
+  if (pub->pub_params)
+    for (i = 0; pub->pub_params[i]; i++) {
+      if (strncasecmp(pub->pub_params[i], "stream=", strlen("stream=")) == 0)
+	pub->pub_stream = pub->pub_params[i] + strlen("stream=");
+      else if (strncasecmp(pub->pub_params[i], "type=", strlen("type=")) == 0)
+	pub->pub_type = pub->pub_params[i] + strlen("type=");
+    }
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow_publications Allow-Publication Header
+ *
+ * The Allow-Publication header is used to indicate which publications or classes of
+ * publications the server supports.  Its syntax is defined in [niemi]
+ * (draft-niemi-simple-publish-00.txt) as follows:
+ * 
+ * @code
+ *   Allow-Publications   = "Allow-Publications" HCOLON publish-type 
+ *                          * ( COMMA publish-type )
+ * @endcode
+ *
+ *
+ * The parsed Allow-Publication Header
+ * is stored in #sip_allow_publications_t structure.
+ */
+
+msg_hclass_t sip_allow_publications_class[] = 
+SIP_HEADER_CLASS_LIST(allow_publications, "Allow-Publications", "", list);
+
+issize_t sip_allow_publications_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_allow_publications_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_allow_publications(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/** Append an publication to a Allow-Publications header. */
+int sip_allow_publications_add(su_home_t *home, 
+			       sip_allow_publications_t *ae, 
+			       char const *e)
+{
+  e = su_strdup(home, e);
+  if (!e)
+    return -1;
+  return msg_params_replace(home, (msg_param_t **)&ae->k_items, e);
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,890 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_extra.c
+ * @brief Non-critical SIP headers
+ * 
+ * This file contains implementation of @CallInfo, @ErrorInfo,
+ * @Organization, @Priority, @RetryAfter, @Server, @Subject,
+ * @Timestamp, and @UserAgent headers.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ * 
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/sip_extra.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+/* ====================================================================== */
+
+static issize_t sip_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen);
+
+static isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset);
+static char *sip_info_dup_one(sip_header_t *dst,
+			      sip_header_t const *src,
+			      char *b,
+			      isize_t xtra);
+
+#define sip_info_update NULL
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_call_info Call-Info Header
+ * 
+ * The Call-Info header provides additional information about the caller or
+ * callee. Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Call-Info   =  "Call-Info" HCOLON info *(COMMA info)
+ *    info        =  LAQUOT absoluteURI RAQUOT *( SEMI info-param)
+ *    info-param  =  ( "purpose" EQUAL ( "icon" / "info"
+ *                   / "card" / token ) ) / generic-param
+ * @endcode
+ * 
+ *
+ * The parsed Call-Info header is stored in #sip_call_info_t structure.
+ */
+
+/**@ingroup sip_call_info
+ * @typedef struct sip_call_info_s sip_call_info_t;
+ *
+ * The structure #sip_call_info_t contains representation of an 
+ * @CallInfo header.
+ *
+ * The #sip_call_info_t is defined as follows:
+ * @code
+ * struct sip_call_info_s
+ * {
+ *   sip_common_t        ci_common[1]; // Common fragment info
+ *   sip_call_info_t    *ci_next;      // Link to next @CallInfo
+ *   url_t               ci_url[1];    // URI to call info
+ *   msg_param_t const  *ci_params;    // List of parameters
+ *   char const         *ci_purpose;   // Value of @b purpose parameter
+ * };
+ * @endcode
+ */
+
+#define sip_call_info_dup_xtra  sip_info_dup_xtra
+#define sip_call_info_dup_one   sip_info_dup_one
+static msg_update_f sip_call_info_update;
+
+msg_hclass_t sip_call_info_class[] =
+SIP_HEADER_CLASS(call_info, "Call-Info", "",
+		 ci_params, append, call_info);
+
+issize_t sip_call_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  issize_t retval = sip_info_d(home, h, s, slen);
+
+  if (retval == 0)
+    for (;h; h = h->sh_next)
+      msg_header_update_params(h->sh_common, 0);
+
+  return retval;
+}
+
+issize_t sip_call_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_call_info_t *ci = (sip_call_info_t *)h;
+
+  assert(sip_call_info_p(h));
+
+  return sip_name_addr_e(b, bsiz, f, NULL, 1, ci->ci_url, ci->ci_params, NULL);
+}
+
+/** @internal
+ * Update parameter in a @CallInfo object.
+ * 
+ */
+static
+int sip_call_info_update(msg_common_t *h, 
+			  char const *name, isize_t namelen,
+			  char const *value)
+{
+  sip_call_info_t *ci = (sip_call_info_t *)h;
+
+  if (name == NULL) {
+    ci->ci_purpose = NULL;
+  }
+  else if (namelen == strlen("purpose") && 
+	   !strncasecmp(name, "purpose", namelen)) {
+    ci->ci_purpose = value;
+  }
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_error_info Error-Info Header
+ * 
+ * The Error-Info header provides a pointer to additional information about
+ * the error status response. Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Error-Info  =  "Error-Info" HCOLON error-uri *(COMMA error-uri)
+ *    error-uri   =  LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ * @endcode
+ * 
+ *
+ * The parsed Error-Info header is stored in #sip_error_info_t structure.
+ */
+
+/**@ingroup sip_error_info
+ * @typedef struct sip_error_info_s sip_error_info_t;
+ *
+ * The structure #sip_error_info_t contains representation of an 
+ * @ErrorInfo header.
+ *
+ * The #sip_error_info_t is defined as follows:
+ * @code
+ * struct sip_error_info_s
+ * {
+ *   sip_common_t        ei_common[1]; // Common fragment info
+ *   sip_error_info_t   *ei_next;      // Link to next @ErrorInfo
+ *   url_t               ei_url[1];    // URI to error info
+ *   msg_param_t const  *ei_params;    // List of parameters
+ * };
+ * @endcode
+ */
+
+msg_hclass_t sip_error_info_class[] = 
+SIP_HEADER_CLASS(error_info, "Error-Info", "",
+		 ei_params, append, info);
+
+issize_t sip_error_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_info_d(home, h, s, slen);
+}
+
+issize_t sip_error_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_error_info_t const *ei = h->sh_error_info;
+
+  assert(sip_error_info_p(h));
+
+  return sip_name_addr_e(b, bsiz, f,
+			 NULL, 1, ei->ei_url, ei->ei_params, NULL);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_in_reply_to In-Reply-To Header
+ * 
+ * The @b In-Reply-To request header field enumerates the 
+ * @ref sip_call_id "Call-IDs" that this call references or returns.
+ * Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    In-Reply-To  =  "In-Reply-To" HCOLON callid *(COMMA callid)
+ * @endcode
+ *
+ * The parsed In-Reply-To header is stored in #sip_in_reply_to_t structure.
+ */
+
+/**@ingroup sip_in_reply_to
+ * @typedef struct msg_list_s sip_in_reply_to_t;
+ *
+ * The structure #sip_in_reply_to_t contains representation of SIP 
+ * @InReplyTo header. 
+ *
+ * The #sip_in_reply_to_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;       // Link to next header
+ *   msg_param_t       *k_items;      // List of call ids
+ * } sip_allow_events_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_in_reply_to_class[] = 
+SIP_HEADER_CLASS_LIST(in_reply_to, "In-Reply-To", "", list);
+
+issize_t sip_in_reply_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_in_reply_to_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_in_reply_to_p(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_organization Organization Header
+ * 
+ * The Organization header field conveys the name of the organization to
+ * which the entity issuing the request or response belongs. Its syntax is
+ * defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Organization  =  "Organization" HCOLON [TEXT-UTF8-TRIM]
+ * @endcode
+ * 
+ *
+ * The parsed Organization header is stored in #sip_organization_t structure.
+ */
+
+/**@ingroup sip_organization
+ * @typedef struct msg_generic_s sip_organization_t; 
+ *
+ * The structure #sip_organization_t contains representation of a SIP 
+ * @Organization header.
+ *
+ * The #sip_organization_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Organization text
+ * } sip_organization_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_organization_class[] = 
+SIP_HEADER_CLASS_G(organization, "Organization", "", single);
+
+issize_t sip_organization_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_organization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_organization_p(h));
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_priority Priority Header
+ * 
+ * The Priority request-header field indicates the urgency of the request as
+ * perceived by the client. Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Priority        =  "Priority" HCOLON priority-value
+ *    priority-value  =  "emergency" / "urgent" / "normal"
+ *                       / "non-urgent" / other-priority
+ *    other-priority  =  token
+ * @endcode
+ * 
+ *
+ * The parsed Priority header is stored in #sip_priority_t structure.
+ */
+
+/**@ingroup sip_priority
+ * @typedef struct msg_generic_s sip_priority_t; 
+ *
+ * The structure #sip_priority_t contains representation of a SIP 
+ * @Priority header.
+ *
+ * The #sip_priority_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Dummy link to next header
+ *   char const    *g_string;	    // Priority token
+ * } sip_priority_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_priority_class[] = 
+SIP_HEADER_CLASS_G(priority, "Priority", "", single);
+
+issize_t sip_priority_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_priority_t *priority = (sip_priority_t *)h;
+  
+  if (msg_token_d(&s, &priority->g_string) < 0)
+    return -1;
+
+  if (*s && !IS_LWS(*s))	/* Something extra after priority token? */
+    return -1;
+
+  return 0;
+}
+
+issize_t sip_priority_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_priority_p(h));
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_server Server Header
+ * 
+ * The Server response-header field contains information about the software
+ * used by the user agent server to handle the request. Its syntax is
+ * defined in @RFC2616 section 14.38 and @RFC3261 as follows:
+ * 
+ * @code
+ *    Server           =  "Server" HCOLON server-val *(LWS server-val)
+ *    server-val       =  product / comment
+ *    product          =  token [SLASH product-version]
+ *    product-version  =  token
+ * @endcode
+ *
+ * The parsed Server header is stored in #sip_server_t structure.
+ */
+
+/**@ingroup sip_server
+ * @typedef struct msg_generic_s sip_server_t; 
+ *
+ * The structure #sip_server_t contains representation of a SIP 
+ * @Server header.
+ *
+ * The #sip_server_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Server tokens
+ * } sip_server_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_server_class[] = 
+SIP_HEADER_CLASS_G(server, "Server", "", single);
+
+issize_t sip_server_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_server_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_server_p(h));
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_subject Subject Header
+ * 
+ * The Subject header provides a summary or indicates the nature of the
+ * request. Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Subject  =  ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
+ * @endcode
+ * 
+ * The parsed Subject header is stored in #sip_subject_t structure.
+ */
+
+/**@ingroup sip_subject
+ * @typedef struct msg_generic_s sip_subject_t; 
+ *
+ * The structure #sip_subject_t contains representation of a SIP 
+ * @Subject header.
+ *
+ * The #sip_subject_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Subject text
+ * } sip_subject_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_subject_class[] = 
+SIP_HEADER_CLASS_G(subject, "Subject", "s", single);
+
+issize_t sip_subject_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_subject_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_subject_p(h));
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_timestamp Timestamp Header
+ * 
+ * The @b Timestamp header describes when the client sent the request to the
+ * server, and it is used by the client to adjust its retransmission
+ * intervals. Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Timestamp  =  "Timestamp" HCOLON 1*(DIGIT)
+ *                   [ "." *(DIGIT) ] [ LWS delay ]
+ *    delay      =  *(DIGIT) [ "." *(DIGIT) ]
+ * @endcode
+ * 
+ * The parsed Timestamp header is stored in #sip_timestamp_t structure.
+ */
+
+/**@ingroup sip_timestamp
+ * @typedef struct sip_timestamp_s sip_timestamp_t; 
+ *
+ * The structure #sip_timestamp_t contains representation of a SIP 
+ * @Timestamp header.
+ *
+ * The #sip_timestamp_t is defined as follows:
+ * @code
+ * typedef struct sip_timestamp_s
+ * {
+ *   sip_common_t        ts_common[1]; // Common fragment info
+ *   sip_error_t        *ts_next;      // Dummy link
+ *   char const         *ts_stamp;     // Original timestamp
+ *   char const         *ts_delay;     // Delay at UAS
+ * } sip_timestamp_t;
+ * @endcode
+ */
+
+static isize_t sip_timestamp_dup_xtra(sip_header_t const *h, isize_t offset);
+static char *sip_timestamp_dup_one(sip_header_t *dst,
+				   sip_header_t const *src,
+				   char *b,
+				   isize_t xtra);
+#define sip_timestamp_update NULL
+
+msg_hclass_t sip_timestamp_class[] = 
+SIP_HEADER_CLASS(timestamp, "Timestamp", "", ts_common, single,
+		 timestamp);
+
+issize_t sip_timestamp_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_timestamp_t *ts = (sip_timestamp_t*)h;
+
+  ts->ts_stamp = s;
+  s += span_digit(s); 
+  if (s == ts->ts_stamp)
+    return -1;
+  if (*s == '.') { s += span_digit(s + 1) + 1; }
+
+  if (IS_LWS(*s)) {
+    *s = '\0';
+    s += span_lws(s + 1) + 1;
+    ts->ts_delay = s;
+    s += span_digit(s); if (*s == '.') { s += span_digit(s + 1) + 1; }
+  }
+
+  if (!*s || IS_LWS(*s))
+    *s++ = '\0';
+  else
+    return -1;
+  
+  return 0;
+}
+
+issize_t sip_timestamp_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_timestamp_t const *ts = h->sh_timestamp;
+  char *end = b + bsiz, *b0 = b;
+
+  assert(sip_timestamp_p(h));
+
+  MSG_STRING_E(b, end, ts->ts_stamp);
+  if (ts->ts_delay) {
+    MSG_CHAR_E(b, end, ' ');
+    MSG_STRING_E(b, end, ts->ts_delay);
+  }
+
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+
+static
+isize_t sip_timestamp_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_timestamp_t const *ts = h->sh_timestamp;
+
+  offset += MSG_STRING_SIZE(ts->ts_stamp);
+  offset += MSG_STRING_SIZE(ts->ts_delay);
+
+  return offset;
+}
+
+static
+char *sip_timestamp_dup_one(sip_header_t *dst,
+			    sip_header_t const *src,
+			    char *b,
+			    isize_t xtra)
+{
+  sip_timestamp_t *ts = dst->sh_timestamp;
+  sip_timestamp_t const *o = src->sh_timestamp;
+  char *end = b + xtra;
+
+  MSG_STRING_DUP(b, ts->ts_stamp, o->ts_stamp);
+  MSG_STRING_DUP(b, ts->ts_delay, o->ts_delay);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_user_agent User-Agent Header
+ * 
+ * The User-Agent header contains information about the client user agent
+ * originating the request. Its syntax is defined in [H14.43, S10.45] as
+ * follows:
+ * 
+ * @code
+ *    User-Agent       =  "User-Agent" HCOLON server-val *(LWS server-val)
+ *    server-val       =  product / comment
+ *    product          =  token [SLASH product-version]
+ *    product-version  =  token
+ * @endcode
+ * 
+ * The parsed User-Agent header is stored in #sip_user_agent_t structure.
+ */
+
+/**@ingroup sip_user_agent
+ * @typedef struct msg_generic_s sip_user_agent_t; 
+ *
+ * The structure #sip_user_agent_t contains representation of a SIP 
+ * @UserAgent header.
+ *
+ * The #sip_user_agent_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // User-Agent components
+ * } sip_user_agent_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_user_agent_class[] = 
+SIP_HEADER_CLASS_G(user_agent, "User-Agent", "", single);
+
+issize_t sip_user_agent_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_user_agent_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_user_agent_p(h));
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_etag SIP-ETag Header
+ * 
+ * The @b SIP-ETag header field identifies the published event state. Its
+ * syntax is defined in @RFC3903 as follows:
+ * 
+ * @code
+ *      SIP-ETag           = "SIP-ETag" HCOLON entity-tag
+ *      entity-tag         = token
+ * @endcode
+ *
+ * The parsed SIP-ETag header is stored in #sip_etag_t structure.
+ */
+
+/**@ingroup sip_etag
+ * @typedef struct msg_generic_s sip_etag_t; 
+ *
+ * The structure #sip_etag_t contains representation of a SIP 
+ * @SIPETag header.
+ *
+ * The #sip_etag_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // entity-tag
+ * } sip_etag_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_etag_class[] = 
+SIP_HEADER_CLASS_G(etag, "SIP-ETag", "", single);
+
+issize_t sip_etag_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_etag_t *etag = (sip_etag_t *)h;
+
+  return msg_token_d(&s, &etag->g_value);
+}
+
+issize_t sip_etag_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_if_match SIP-If-Match Header
+ * 
+ * The @b SIP-If-Match header field identifies the specific entity of event
+ * state that the request is refreshing, modifying or removing. Its syntax
+ * is defined in @RFC3903 as follows:
+ * 
+ * @code
+ *      SIP-If-Match       = "SIP-If-Match" HCOLON entity-tag
+ *      entity-tag         = token
+ * @endcode
+ *
+ * The parsed SIP-If-Match header is stored in #sip_if_match_t structure.
+ */
+
+/**@ingroup sip_if_match
+ * @typedef struct msg_generic_s sip_if_match_t; 
+ *
+ * The structure #sip_if_match_t contains representation of a SIP 
+ * @SIPIfMatch header.
+ *
+ * The #sip_if_match_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // entity-tag
+ * } sip_if_match_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_if_match_class[] = 
+SIP_HEADER_CLASS_G(if_match, "SIP-If-Match", "", single);
+
+issize_t sip_if_match_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_etag_d(home, h, s, slen);
+}
+
+issize_t sip_if_match_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return sip_etag_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/** Parsing @CallInfo, @ErrorInfo. */
+static
+issize_t sip_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_call_info_t *ci = h->sh_call_info;
+  char *end = s + slen;
+
+  assert(h);
+
+  while (*s == ',')
+    s += span_lws(s + 1) + 1;
+
+  if (sip_name_addr_d(home, &s, NULL, ci->ci_url, &ci->ci_params, NULL) < 0)
+    return -1;
+
+  /* Recurse */
+  return msg_parse_next_field(home, h, s, end - s);
+}
+
+isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_call_info_t const *ci = h->sh_call_info;
+
+  MSG_PARAMS_SIZE(offset, ci->ci_params);
+  offset += url_xtra(ci->ci_url);
+
+  return offset;
+}
+
+char *sip_info_dup_one(sip_header_t *dst,
+		       sip_header_t const *src,
+		       char *b,
+		       isize_t xtra)
+{
+  sip_call_info_t *ci = dst->sh_call_info;
+  sip_call_info_t const *o = src->sh_call_info;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&ci->ci_params, o->ci_params, b, xtra);
+  URL_DUP(b, end, ci->ci_url, o->ci_url);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_suppress_body_if_match Suppress-Body-If-Match Header
+ *
+ * The @b Suppress-Body-If-Match header field identifies a SIP event content
+ * already known by the watcher. Its syntax is defined in
+ * draft-niemi-sip-subnot-etags-01 as follows:
+ *
+ * @code
+ *    Suppress-Body-If-Match = "Suppress-Body-If-Match" HCOLON entity-tag
+ *    entity-tag             = token
+ * @endcode
+ *
+ * The parsed Suppress-Body-If-Match header is stored in
+ * #sip_suppress_body_if_match_t structure.
+ *
+ * @sa @RFC3265, draft-niemi-sip-subnot-etags-01.txt
+ *
+ * @NEW_1_12_5. Note that #sip_t does not contain @a
+ * sip_suppress_body_if_match field, but sip_suppress_body_if_match()
+ * function should be used for accessing the @b Suppress-Body-If-Match
+ * header structure.
+ */
+
+/**@ingroup sip_suppress_body_if_match
+ * @typedef struct sip_suppress_body_if_match_s sip_suppress_body_if_match_t;
+ *
+ * The structure #sip_suppress_body_if_match_t contains representation of a
+ * SIP @SuppressBodyIfMatch header.
+ *
+ * The #sip_suppress_body_if_match_t is defined as follows:
+ * @code
+ * typedef struct sip_suppress_body_if_match_s
+ * {
+ *   sip_common_t   sbim_common[1]; // Common fragment info
+ *   sip_error_t   *sbim_next;      // Dummy link to next header
+ *   char const    *sbim_tag;       // entity-tag
+ * } sip_suppress_body_if_match_t;
+ * @endcode
+ */
+
+#define sip_suppress_body_if_match_dup_xtra  msg_generic_dup_xtra
+#define sip_suppress_body_if_match_dup_one   msg_generic_dup_one
+#define sip_suppress_body_if_match_update NULL
+
+msg_hclass_t sip_suppress_body_if_match_class[] =
+SIP_HEADER_CLASS(suppress_body_if_match,
+		 "Suppress-Body-If-Match", "",
+		 sbim_common, single, suppress_body_if_match);
+
+issize_t sip_suppress_body_if_match_d(su_home_t *home,
+				      sip_header_t *h,
+				      char *s, isize_t slen)
+{
+  sip_suppress_body_if_match_t *sbim = (void *)h;
+  return msg_token_d(&s, &sbim->sbim_tag);
+}
+
+issize_t sip_suppress_body_if_match_e(char b[], isize_t bsiz,
+				      sip_header_t const *h,
+				      int f)
+{
+  return sip_etag_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_suppress_notify_if_match Suppress-Notify-If-Match Header
+ *
+ * The @b Suppress-Notify-If-Match header is used to suppress
+ * superfluous NOTIFY transactions. Its syntax is defined in
+ * draft-niemi-sip-subnot-etags-01 as follows:
+ *
+ * @code
+ *    Suppress-Notify-If-Match = "Suppress-Notify-If-Match" HCOLON entity-tag
+ *    entity-tag               = token
+ * @endcode
+ *
+ * The parsed Suppress-Notify-If-Match header is stored in
+ * #sip_suppress_notify_if_match_t structure.
+ *
+ * @sa @RFC3265, draft-niemi-sip-subnot-etag-01
+ *
+ * @NEW_1_12_5. Note that #sip_t does not contain @a
+ * sip_suppress_notify_if_match field, but sip_suppress_notify_if_match()
+ * function should be used for accessing the @b Suppress-Notify-If-Match
+ * header structure.
+ */
+
+/**@ingroup sip_suppress_notify_if_match
+ * @typedef struct sip_suppress_notify_if_match_s \
+ * sip_suppress_notify_if_match_t;
+ *
+ * The structure #sip_suppress_notify_if_match_t contains representation of a
+ * SIP @SuppressNotifyIfMatch header.
+ *
+ * The #sip_suppress_notify_if_match_t is defined as follows:
+ * @code
+ * typedef struct sip_suppress_notify_if_match_s
+ * {
+ *   sip_common_t   snim_common[1]; // Common fragment info
+ *   sip_error_t   *snim_next;      // Dummy link to next header
+ *   char const    *snim_tag;       // entity-tag
+ * } sip_suppress_notify_if_match_t;
+ * @endcode
+ */
+
+#define sip_suppress_notify_if_match_dup_xtra  msg_generic_dup_xtra
+#define sip_suppress_notify_if_match_dup_one   msg_generic_dup_one
+#define sip_suppress_notify_if_match_update NULL
+
+msg_hclass_t sip_suppress_notify_if_match_class[] =
+SIP_HEADER_CLASS(suppress_notify_if_match,
+		 "Suppress-Notify-If-Match", "",
+		 snim_common, single, suppress_notify_if_match);
+
+issize_t sip_suppress_notify_if_match_d(su_home_t *home,
+					sip_header_t *h,
+					char *s, isize_t slen)
+{
+  sip_suppress_notify_if_match_t *snim = (void *)h;
+  return msg_token_d(&s, &snim->snim_tag);
+}
+
+issize_t sip_suppress_notify_if_match_e(char b[], isize_t bsiz,
+					sip_header_t const *h,
+					int f)
+{
+  return msg_generic_e(b, bsiz, h, f);
+}
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+#
+# This file specifies extra SIP headers not included in sip_t structure
+#
+# The line format is: 
+# C-name @SINCE sip_t-like-comment
+#
+#### EXTRA HEADER LIST STARTS HERE ####
+
+refer_sub @VERSION_1_12_5 /**< Refer-Sub header */
+suppress_body_if_match @VERSION_1_12_5 /**< Suppress-Body-If-Match header */
+suppress_notify_if_match @VERSION_1_12_5 /**< Suppress-Notify-If-Match header*/
+
+#### EXTRA HEADER LIST ENDS HERE ####

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,595 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_feature.c 
+ *
+ * @brief Feature-related SIP header handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow Allow Header
+ *
+ * The Allow header lists the set of methods supported by the user agent
+ * generating the message.  Its syntax is defined in @RFC3261 as
+ * follows:
+ * 
+ * @code
+ *    Allow  =  "Allow" HCOLON [Method *(COMMA Method)]
+ * @endcode
+ *
+ * The parsed Allow header is stored in #sip_allow_t structure.
+ *
+ * Note that SIP methods are case-sensitive: "INVITE" method is different from
+ * "Invite".
+ *
+ * @sa msg_header_find_item(), msg_header_replace_item(),
+ * msg_header_remove_item()
+ */
+
+/**@ingroup sip_allow
+ * @typedef struct msg_list_s sip_allow_t; 
+ *
+ * The structure #sip_allow_t contains representation of an @Allow header.
+ *
+ * The #sip_allow_t is defined as follows:
+ * @code
+ * typedef struct msg_allow_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ *   uint32_t           k_bitmap;     // Bitmap of allowed methods
+ * } sip_allow_t;
+ * @endcode
+ *
+ * @note The field @a k_bitmap was added in @VERSION_1_12_5.
+ */
+
+#define sip_allow_dup_xtra msg_list_dup_xtra
+#define sip_allow_dup_one  msg_list_dup_one
+static msg_update_f sip_allow_update;
+
+msg_hclass_t sip_allow_class[] = 
+SIP_HEADER_CLASS(allow, "Allow", "", k_items, list, allow);
+
+issize_t sip_allow_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_allow_t *k = (sip_allow_t *)h;
+  issize_t retval = msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+  msg_header_update_params(k->k_common, 0);
+  return retval;
+}
+
+issize_t sip_allow_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_allow(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+static int sip_allow_update(msg_common_t *h, 
+			  char const *name, isize_t namelen,
+			  char const *value)
+{
+  sip_allow_t *k = (sip_allow_t *)h;
+
+  if (name == NULL) {
+    k->k_bitmap = 0;
+  }
+  else {
+    sip_method_t method = sip_method_code(name);
+
+    if (method >= 0 && method < 32) 
+      k->k_bitmap |= 1 << method;
+  }
+
+  return 0;
+}
+
+/** Return true if the method is listed in @Allow header. */
+int sip_is_allowed(sip_allow_t const *allow,
+		   sip_method_t method,
+		   char const *name)
+{
+  if (method < sip_method_unknown || !allow)
+    return 0;
+
+  if (sip_method_unknown < method && method < 32)
+    /* Well-known method */
+    return (allow->k_bitmap & (1 << method)) != 0;
+
+  if (method == sip_method_unknown &&
+      (allow->k_bitmap & (1 << sip_method_unknown)) == 0)
+    return 0;
+
+  return msg_header_find_item(allow->k_common, name) != NULL;
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_require Proxy-Require Header
+ *
+ * The Proxy-Require header is used to indicate proxy-sensitive features
+ * that @b MUST be supported by the proxy.  Its syntax is defined in @RFC3261
+ * as follows:
+ * 
+ * @code
+ *    Proxy-Require  =  "Proxy-Require" HCOLON option-tag *(COMMA option-tag)
+ * @endcode
+ *
+ *
+ * The parsed Proxy-Require header is stored in #sip_proxy_require_t structure.
+ */
+
+/**@ingroup sip_proxy_require
+ * @typedef struct msg_list_s sip_proxy_require_t; 
+ *
+ * The structure #sip_proxy_require_t contains representation of an 
+ * @ProxyRequire header.
+ *
+ * The #sip_proxy_require_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Dummy link
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_proxy_require_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_proxy_require_class[] = 
+SIP_HEADER_CLASS_LIST(proxy_require, "Proxy-Require", "", list);
+
+issize_t sip_proxy_require_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_proxy_require_t *k = (sip_proxy_require_t *)h;
+  return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_proxy_require_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_proxy_require(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_require Require Header
+ *
+ * The Require header is used by clients to tell user agent servers about
+ * options that the client expects the server to support in order to
+ * properly process the request.  Its syntax is defined in @RFC3261 
+ * as follows:
+ * 
+ * @code
+ *    Require       =  "Require" HCOLON option-tag *(COMMA option-tag)
+ * @endcode
+ *
+ * The parsed Require header is stored in #sip_require_t structure.
+ */
+
+/**@ingroup sip_require
+ * @typedef struct msg_list_s sip_require_t; 
+ *
+ * The structure #sip_require_t contains representation of an 
+ * @Require header.
+ *
+ * The #sip_require_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_require_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_require_class[] = 
+SIP_HEADER_CLASS_LIST(require, "Require", "", list);
+
+issize_t sip_require_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_require_t *k = (sip_require_t *)h;
+  return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_require_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_require(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_supported Supported Header
+ *
+ * The Supported header enumerates all the capabilities of the client or
+ * server.  Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Supported  =  ( "Supported" / "k" ) HCOLON
+ *                  [option-tag *(COMMA option-tag)]
+ * @endcode
+ *
+ * The parsed option-tags of Supported header
+ * are stored in #sip_supported_t structure.
+ */
+
+/**@ingroup sip_supported
+ * @typedef struct msg_list_s sip_supported_t; 
+ *
+ * The structure #sip_supported_t contains representation of an 
+ * @Supported header.
+ *
+ * The #sip_supported_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_supported_t;
+ * @endcode
+ */
+
+
+msg_hclass_t sip_supported_class[] = 
+SIP_HEADER_CLASS_LIST(supported, "Supported", "k", list);
+
+issize_t sip_supported_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_supported_t *k = (sip_supported_t *)h;
+  return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_supported_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_supported(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_unsupported Unsupported Header
+ *
+ * The Unsupported header lists the features not supported by the server.
+ * Its syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Unsupported  =  "Unsupported" HCOLON [option-tag *(COMMA option-tag)]
+ * @endcode
+ *
+ *
+ * The parsed Unsupported header is stored in #sip_unsupported_t structure.
+ */
+
+/**@ingroup sip_unsupported
+ * @typedef struct msg_list_s sip_unsupported_t; 
+ *
+ * The structure #sip_unsupported_t contains representation of an 
+ * @Unsupported header.
+ *
+ * The #sip_unsupported_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_unsupported_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_unsupported_class[] = 
+SIP_HEADER_CLASS_LIST(unsupported, "Unsupported", "", list);
+
+issize_t sip_unsupported_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_unsupported_t *k = (sip_unsupported_t *)h;
+  return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_unsupported_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_unsupported(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/** Check if required feature is supported.
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ *         #SIP_NONE if @a home is NULL  
+ */
+sip_unsupported_t *sip_has_unsupported(su_home_t *home,
+				       sip_supported_t const *support, 
+				       sip_require_t const *require)
+{
+  return sip_has_unsupported_any(home, support, NULL, NULL, 
+				 require, NULL, NULL);
+}
+
+
+/** Check if required feature is supported.
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ *         #SIP_NONE if @a home is NULL
+ */
+sip_unsupported_t *
+sip_has_unsupported2(su_home_t *home,
+		     sip_supported_t const *support,
+		     sip_require_t const *support_by_require,
+		     sip_require_t const *require)
+{
+  return 
+    sip_has_unsupported_any(home, 
+			    support, support_by_require, NULL, 
+			    require, NULL, NULL);
+}
+
+
+/** Ensure that required features are supported.
+ *
+ * The supported features can be listed in @Supported, @Require or 
+ * @ProxyRequire headers (in @a supported, @a by_require, or @a
+ * by_proxy_require parameters, respectively)
+ *
+ * @param home (optional) home pointer for allocating @Unsupported header
+ * @param supported @Supported features (may be NULL) [IN]
+ * @param by_require  supported features listed by 
+ *                    @Require (may be NULL) [IN] 
+ * @param by_proxy_require supported features listed 
+ *                         by @ProxyRequire (may be NULL) [IN]
+ *
+ * @param require   list of required features (may be NULL) [IN]
+ * @param require2  2nd list of required features (may be NULL) [IN]
+ * @param require3  3rd list of required features (may be NULL) [IN]
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ *         #SIP_NONE if @a home is NULL 
+ */
+sip_unsupported_t *
+sip_has_unsupported_any(su_home_t *home,
+			sip_supported_t const *supported,
+			sip_require_t const *by_require,
+			sip_proxy_require_t const *by_proxy_require,
+			sip_require_t const *require,
+			sip_require_t const *require2,
+			sip_require_t const *require3)
+{
+  size_t i, j;
+  sip_unsupported_t *unsupported = NULL;
+  msg_param_t const empty[1] = { NULL };
+  msg_param_t const *slist = empty;
+  msg_param_t const *rlist = empty;
+  msg_param_t const *prlist = empty;
+
+  if (require2 == NULL)
+    require2 = require3, require3 = NULL;
+  if (require == NULL)
+    require = require2, require2 = NULL;
+
+  if (require && require->k_items) {
+    if (supported && supported->k_items)
+      slist = supported->k_items;
+    if (by_require && by_require->k_items)
+      rlist = by_require->k_items;
+    if (by_proxy_require && by_proxy_require->k_items)
+      prlist = by_proxy_require->k_items;
+
+    for (i = 0; require->k_items && require->k_items[i];) {
+      msg_param_t feature = require->k_items[i++];
+
+      for (j = 0; slist[j]; j++)
+	if (strcasecmp(feature, slist[j]) == 0) {
+	  feature = NULL;
+	  break;
+	}
+
+      if (feature)
+	for (j = 0; rlist[j]; j++)
+	  if (strcasecmp(feature, rlist[j]) == 0) {
+	    feature = NULL;
+	    break;
+	  }
+
+      if (feature)
+	for (j = 0; prlist[j]; j++)
+	  if (strcasecmp(feature, prlist[j]) == 0) {
+	    feature = NULL;
+	    break;
+	  }
+
+      if (feature) {
+	if (home) {
+	  if (unsupported == NULL) 
+	    unsupported = sip_unsupported_make(home, feature);
+	  else
+	    msg_params_add(home, 
+			   (msg_param_t **)&unsupported->k_items, 
+			   feature);
+	}
+	else {
+	  return (sip_unsupported_t *)SIP_NONE;
+	}
+      }
+
+      if (require->k_items[i] == NULL && require2 && require2->k_items) {
+	i = 0, require = require2, require2 = require3, require3 = NULL;
+      }
+    }
+  }
+  
+  return unsupported;
+}
+
+
+int sip_has_feature(msg_list_t const *supported, char const *feature)
+{
+  size_t i;
+  
+  if (!feature || !feature[0])
+    return 1;			/* Empty feature is always supported */
+
+  for (; supported; supported = supported->k_next)
+    if (supported->k_items)
+      for (i = 0; supported->k_items[i]; i++)
+	if (strcasecmp(feature, supported->k_items[i]) == 0)
+	  return 1;
+
+  return 0;
+}
+
+/** Check that a feature is supported. */
+int sip_has_supported(sip_supported_t const *supported, char const *feature)
+{
+  return sip_has_feature(supported, feature);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_path Path Header
+ *
+ * The Path header field is a SIP extension header field (@RFC3327) with
+ * syntax very similar to the @RecordRoute header field. It is used in
+ * conjunction with SIP REGISTER requests and with 200 class messages in
+ * response to REGISTER (REGISTER responses).
+ * 
+ * @code
+ *    Path        =  "Path" HCOLON path-value *(COMMA path-value)
+ *    path-value  =  name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ *
+ * The parsed Path header is stored in #sip_path_t structure.
+ */
+
+/**@ingroup sip_path
+ * @typedef typedef struct sip_route_s sip_path_t;
+ *
+ * The structure #sip_path_t contains representation of SIP @Path header.
+ *
+ * The #sip_path_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ *   sip_common_t        r_common[1];   // Common fragment info
+ *   sip_path_t         *r_next;        // Link to next @Path
+ *   char const         *r_display;     // Display name
+ *   url_t               r_url[1];      // @Path URL
+ *   msg_param_t const  *r_params;      // List of parameters
+ * } sip_path_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_path_class[] =
+SIP_HEADER_CLASS(path, "Path", "", r_params, prepend, any_route);
+
+issize_t sip_path_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_path_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_path(h));
+  return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_service_route Service-Route Header
+ *
+ * The "Service-Route" is a SIP extension header field (@RFC3608), which can
+ * contain a route vector that will direct requests through a specific
+ * sequence of proxies. A registrar may use a Service-Route header field to
+ * inform a UA of a service route that, if used by the UA, will provide
+ * services from a proxy or set of proxies associated with that registrar. 
+ * The Service-Route header field may be included by a registrar in the
+ * response to a REGISTER request. The syntax for the Service-Route header
+ * field is:
+ *
+ * @code
+ *    Service-Route = "Service-Route" HCOLON sr-value *(COMMA sr-value)
+ *    sr-value  =  name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ * The parsed Service-Route header is stored in #sip_service_route_t structure.
+ *
+ * @sa @RFC3608, @Path, @Route, @RecordRoute
+ */
+
+/**@ingroup sip_service_route
+ * @typedef typedef struct sip_route_s sip_service_route_t;
+ *
+ * The structure #sip_service_route_t contains representation of SIP 
+ * @ServiceRoute header.
+ *
+ * The #sip_service_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ *   sip_common_t        r_common[1];   // Common fragment info
+ *   sip_service_route_t*r_next;        // Link to next @ServiceRoute
+ *   char const         *r_display;     // Display name
+ *   url_t               r_url[1];      // Service-Route URL
+ *   msg_param_t const  *r_params;      // List of parameters
+ * } sip_service_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_service_route_class[] =
+SIP_HEADER_CLASS(service_route, "Service-Route", "", 
+		 r_params, append, any_route);
+
+issize_t sip_service_route_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_service_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_service_route(h));
+  return sip_any_route_e(b, bsiz, h, flags);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_header.c
+ *
+ * SIP header handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+/* Get bodies of inlined functions included in library */
+#define SIP_STATIC_INLINE
+
+#include <sofia-sip/su_alloc.h>
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_status.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include <assert.h>
+
+/** Copy a SIP header.
+ *
+ * @deprecated Use msg_header_copy() instead.
+ */
+sip_header_t *sip_header_copy(su_home_t *home, sip_header_t const *h)
+{
+  if (h == NULL || h == SIP_NONE)
+    return NULL;
+  return msg_header_copy_as(home, h->sh_class, h);
+}
+
+/** Duplicate a SIP header.
+ *
+ * @deprecated Use msg_header_dup() instead.
+ */
+sip_header_t *sip_header_dup(su_home_t *home, sip_header_t const *h)
+{
+  if (h == NULL || h == SIP_NONE)
+    return NULL;
+  return msg_header_dup_as(home, h->sh_class, h);
+
+}
+
+/** Decode a SIP header.
+ *
+ * @deprecated Use msg_header_d() instead.
+ */
+sip_header_t *sip_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+  return msg_header_d(home, msg, b);
+}
+
+/** Encode a SIP header. 
+ *
+ * @deprecated Use msg_header_e() instead.
+ */
+issize_t sip_header_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return msg_header_e(b, bsiz, (msg_header_t const *)h, flags);
+}
+
+sip_header_t *sip_header_format(su_home_t *home, 
+				msg_hclass_t *hc,
+				char const *fmt,
+				...)
+{
+  sip_header_t *h;
+  va_list ap;
+
+  va_start(ap, fmt);
+
+  h = msg_header_vformat(home, hc, fmt, ap);
+
+  va_end(ap);
+
+  return h;
+}
+
+/** Add a duplicate of header object to a SIP message. */
+int sip_add_dup(msg_t *msg,
+		sip_t *sip,
+		sip_header_t const *o)
+{
+  return msg_header_add_dup(msg, (msg_pub_t *)sip, o);
+}
+
+int sip_add_dup_as(msg_t *msg,
+		   sip_t *sip,
+		   msg_hclass_t *hc,
+		   sip_header_t const *o)
+{
+  return msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, o);
+}
+
+int sip_add_make(msg_t *msg,
+		 sip_t *sip,
+		 msg_hclass_t *hc,
+		 char const *s)
+{
+  return msg_header_add_make(msg, sip, hc, s);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,717 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_mime.c 
+ *
+ * MIME-related SIP headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/msg_mime_protos.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept Accept Header
+ *
+ * The @b Accept request-header field can be used to specify certain media
+ * types which are acceptable for the response. Its syntax is defined in
+ * [H14.1, S10.6] as follows:
+ * 
+ * @code
+ *    Accept         =  "Accept" HCOLON
+ *                       [ accept-range *(COMMA accept-range) ]
+ *    accept-range   =  media-range *(SEMI accept-param)
+ *    media-range    =  ( "*" "/" "*"
+ *                      / ( m-type SLASH "*" )
+ *                      / ( m-type SLASH m-subtype )
+ *                      ) *( SEMI m-parameter )
+ *    accept-param   =  ("q" EQUAL qvalue) / generic-param
+ *    qvalue         =  ( "0" [ "." 0*3DIGIT ] )
+ *                      / ( "1" [ "." 0*3("0") ] )
+ *    generic-param  =  token [ EQUAL gen-value ]
+ *    gen-value      =  token / host / quoted-string
+ * @endcode
+ *
+ *
+ * The parsed Accept header is stored in #sip_accept_t structure.
+ */
+
+/**@ingroup sip_accept
+ * @typedef typedef struct sip_accept_s sip_accept_t;
+ *
+ * The structure #sip_accept_t contains representation of SIP
+ * @Accept header.
+ *
+ * The #sip_accept_t is defined as follows:
+ * @code
+ * typedef struct sip_accept_s {
+ *   sip_common_t        ac_common[1]; // Common fragment info
+ *   sip_accept_t       *ac_next;      // Pointer to next @Acceptheader
+ *   char const         *ac_type;      // Pointer to type/subtype
+ *   char const         *ac_subtype;   // Points after first slash in type
+ *   msg_param_t const  *ac_params;    // List of parameters
+ *   char const         *ac_q;         // Value of q parameter
+ * } sip_accept_t;
+ * @endcode
+ */
+
+#define sip_accept_dup_xtra msg_accept_dup_xtra
+#define sip_accept_dup_one  msg_accept_dup_one
+#define sip_accept_update   msg_accept_update
+
+msg_hclass_t sip_accept_class[] = 
+SIP_HEADER_CLASS(accept, "Accept", "", ac_params, apndlist, accept);
+
+issize_t sip_accept_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_accept_d(home, h, s, slen);
+}
+
+issize_t sip_accept_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return msg_accept_e(b, bsiz, h, flags);
+}
+
+#if SIP_HAVE_ACCEPT_DISPOSITION
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_disposition Accept-Disposition Header
+ *
+ * The Accept-Disposition header field is used to indicate what content
+ * disposition types are acceptable to a client or server.  Its syntax is
+ * defined in draft-lennox-sip-reg-payload-01.txt section 3.2 as follows:
+ * 
+ * @code
+ *    Accept-Disposition = "Accept-Disposition" ":" 
+ *                         #( (disposition-type | "*") *( ";" generic-param ) )
+ * @endcode
+ *
+ *
+ * The parsed Accept-Disposition header
+ * is stored in #sip_accept_disposition_t structure.
+ */
+
+msg_hclass_t sip_accept_disposition_class[] = 
+SIP_HEADER_CLASS(accept_disposition, "Accept-Disposition", "", 
+		 ad_params, apndlist, accept_disposition);
+
+issize_t sip_accept_disposition_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_accept_disposition_t *ad = (sip_accept_disposition_t *)h;
+
+  assert(h);
+
+  /* Ignore empty entries (comma-whitespace) */
+  while (*s == ',')
+    s += span_lws(s + 1) + 1;
+
+  /* "Accept:" #(type/subtyp ; *(parameters))) */
+  if (/* Parse protocol */
+      sip_version_d(&s, &ad->ad_type) == -1 ||
+      (ad->ad_subtype = strchr(ad->ad_type, '/')) == NULL ||
+      (*s == ';' && msg_params_d(home, &s, &ad->ad_params) == -1))
+    return -1;
+
+  if (ad->ad_subtype) ad->ad_subtype++;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_accept_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  sip_accept_disposition_t const *ad = h->sh_accept_disposition;
+
+  MSG_STRING_E(b, end, ad->ad_type);
+  MSG_PARAMS_E(b, end, ad->ad_params, flags);
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+#endif
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_encoding Accept-Encoding Header
+ *
+ * The Accept-Encoding header is similar to Accept, but restricts the
+ * content-codings that are acceptable in the response.  Its syntax is
+ * defined in [H14.3, S10.7] as follows:
+ * 
+ * @code
+ *    Accept-Encoding  =  "Accept-Encoding" HCOLON
+ *                         [ encoding *(COMMA encoding) ]
+ *    encoding         =  codings *(SEMI accept-param)
+ *    codings          =  content-coding / "*"
+ *    content-coding   =  token
+ * @endcode
+ *
+ *
+ * The parsed Accept-Encoding header
+ * is stored in #sip_accept_encoding_t structure.
+ */
+
+/**@ingroup sip_accept_encoding
+ * @typedef typedef struct msg_accept_any_s sip_accept_encoding_t;
+ *
+ * The structure #sip_accept_encoding_t contains representation of SIP
+ * @AcceptEncoding header.
+ *
+ * The #sip_accept_encoding_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t        aa_common[1]; // Common fragment info
+ *   sip_accept_encoding_t *aa_next;   // Pointer to next @AcceptEncoding header
+ *   char const            *aa_value;  // Encoding token
+ *   msg_param_t const     *aa_params; // List of parameters
+ *   char const            *aa_q;      // Value of q parameter 
+ * } sip_accept_encoding_t;
+ * @endcode
+ */
+
+#define sip_accept_encoding_dup_xtra msg_accept_any_dup_xtra
+#define sip_accept_encoding_dup_one  msg_accept_any_dup_one
+#define sip_accept_encoding_update   msg_accept_any_update
+
+msg_hclass_t sip_accept_encoding_class[] = 
+SIP_HEADER_CLASS(accept_encoding, "Accept-Encoding", "", 
+		 aa_params, apndlist, accept_encoding);
+
+issize_t sip_accept_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  issize_t retval = msg_accept_encoding_d(home, h, s, slen);
+
+  if (retval == -2) {
+    /* Empty Accept-Encoding list is not an error */
+    sip_accept_encoding_t *aa = (sip_accept_encoding_t *)h;
+    aa->aa_value = "";
+    retval = 0;
+  }
+
+  return retval;
+}
+
+issize_t sip_accept_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_accept_encoding_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_language Accept-Language Header
+ *
+ * The Accept-Language header can be used to allow the client to indicate to
+ * the server in which language it would prefer to receive reason phrases,
+ * session descriptions or status responses carried as message bodies.  Its
+ * syntax is defined in [H14.4, S10.8] as follows:
+ * 
+ * @code
+ *    Accept-Language  =  "Accept-Language" HCOLON
+ *                         [ language *(COMMA language) ]
+ *    language         =  language-range *(SEMI accept-param)
+ *    language-range   =  ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
+ * @endcode
+ *
+ *
+ * The parsed Accept-Language header
+ * is stored in #sip_accept_language_t structure.
+ */
+
+/**@ingroup sip_accept_language
+ * @typedef typedef struct msg_accept_any_s sip_accept_language_t;
+ *
+ * The structure #sip_accept_language_t contains representation of SIP
+ * @AcceptLanguage header.
+ *
+ * The #sip_accept_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t        aa_common[1]; // Common fragment info
+ *   sip_accept_language_t *aa_next;   // Pointer to next <language>
+ *   char const            *aa_value;  // Language-range
+ *   msg_param_t const     *aa_params; // List of accept-parameters
+ *   char const            *aa_q;      // Value of q parameter 
+ * } sip_accept_language_t;
+ * @endcode
+ */
+
+#define sip_accept_language_dup_xtra msg_accept_any_dup_xtra
+#define sip_accept_language_dup_one  msg_accept_any_dup_one
+#define sip_accept_language_update   msg_accept_any_update
+
+msg_hclass_t sip_accept_language_class[] = 
+SIP_HEADER_CLASS(accept_language, "Accept-Language", "", 
+		 aa_params, apndlist, accept_language);
+
+issize_t sip_accept_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  int retval = msg_accept_language_d(home, h, s, slen);
+
+  if (retval == -2) {
+    /* Empty Accept-Language list is not an error */
+    ((sip_accept_language_t *)h)->aa_value = "";
+    retval = 0;
+  }
+
+  return retval;
+}
+
+issize_t sip_accept_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_accept_language_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_disposition Content-Disposition Header
+ *
+ * The Content-Disposition header field describes how the message body or,
+ * in the case of multipart messages, a message body part is to be
+ * interpreted by the UAC or UAS.  Its syntax is defined in @RFC3261
+ * as follows:
+ * 
+ * @code
+ *    Content-Disposition   =  "Content-Disposition" HCOLON
+ *                             disp-type *( SEMI disp-param )
+ *    disp-type             =  "render" / "session" / "icon" / "alert"
+ *                             / disp-extension-token
+ *    disp-param            =  handling-param / generic-param
+ *    handling-param        =  "handling" EQUAL
+ *                             ( "optional" / "required"
+ *                             / other-handling )
+ *    other-handling        =  token
+ *    disp-extension-token  =  token
+ * @endcode
+ * 
+ * The Content-Disposition header was extended by
+ * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
+ *
+ * @code
+ *    Content-Disposition      =  "Content-Disposition" ":"
+ *                                disposition-type *( ";" disposition-param )
+ *    disposition-type         =  "script" | "sip-cgi" | token
+ *    disposition-param        =  action-param
+ *                             |  modification-date-param
+ *                             |  generic-param
+ *    action-param             =  "action" "=" action-value
+ *    action-value             =  "store" | "remove" | token
+ *    modification-date-param  =  "modification-date" "=" quoted-date-time
+ *    quoted-date-time         =  <"> SIP-date <">
+ * @endcode
+ *
+ * The parsed Content-Disposition header
+ * is stored in #sip_content_disposition_t structure.
+ */
+
+/**@ingroup sip_content_disposition
+ * @typedef struct msg_content_disposition_s sip_content_disposition_t; 
+ *
+ * The structure #sip_content_disposition_t contains representation of an
+ * @ContentDisposition header.
+ *
+ * The #sip_content_disposition_t is defined as follows:
+ * @code
+ * typedef struct msg_content_disposition_s
+ * {
+ *   msg_common_t       cd_common[1];  // Common fragment info
+ *   msg_error_t       *cd_next;       // Link to next (dummy)
+ *   char const        *cd_type;       // Disposition type
+ *   msg_param_t const *cd_params;     // List of parameters
+ *   char const        *cd_handling;   // Value of @b handling parameter
+ *   unsigned           cd_required:1; // True if handling=required
+ *   unsigned           cd_optional:1; // True if handling=optional
+ * } sip_content_disposition_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_content_disposition_dup_xtra;
+static msg_dup_f sip_content_disposition_dup_one;
+#define sip_content_disposition_update msg_content_disposition_update
+
+msg_hclass_t sip_content_disposition_class[] = 
+SIP_HEADER_CLASS(content_disposition, "Content-Disposition", "", cd_params,
+		 single, content_disposition);
+
+issize_t sip_content_disposition_d(su_home_t *home, sip_header_t *h, 
+				   char *s, isize_t slen)
+{
+  return msg_content_disposition_d(home, h, s, slen);
+}
+
+issize_t sip_content_disposition_e(char b[], isize_t bsiz,
+				   sip_header_t const *h, int f)
+{
+  return msg_content_disposition_e(b, bsiz, h, f);
+}
+
+static
+isize_t sip_content_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  return msg_content_disposition_dup_xtra(h, offset);
+}
+
+/** Duplicate one #sip_content_disposition_t object */ 
+static
+char *sip_content_disposition_dup_one(sip_header_t *dst, 
+				      sip_header_t const *src,
+				      char *b, isize_t xtra)
+{
+  return msg_content_disposition_dup_one(dst, src, b, xtra);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_encoding Content-Encoding Header
+ *
+ * The Content-Encoding header indicates what additional content codings
+ * have been applied to the entity-body.  Its syntax is defined in @RFC3261
+ * as follows:
+ * 
+ * @code
+ * Content-Encoding  =  ( "Content-Encoding" / "e" ) HCOLON
+ *                      content-coding *(COMMA content-coding)
+ * content-coding    =  token
+ * @endcode
+ *
+ * The parsed Content-Encoding header
+ * is stored in #sip_content_encoding_t structure.
+ */
+
+/**@ingroup sip_content_encoding
+ * @typedef struct msg_list_s sip_content_encoding_t; 
+ *
+ * The structure #sip_content_encoding_t contains representation of an
+ * @ContentEncoding header.
+ *
+ * The #sip_content_encoding_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ *   msg_common_t       k_common[1];  // Common fragment info
+ *   msg_list_t        *k_next;	      // Link to next header
+ *   msg_param_t       *k_items;      // List of items
+ * } sip_content_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_encoding_class[] = 
+SIP_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
+
+issize_t sip_content_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_content_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_language Content-Language Header
+ *
+ * The Content-Language header @RFC2616 section 14.12 describes the natural language(s) of
+ * the intended audience for the enclosed entity. Note that this might not
+ * be equivalent to all the languages used within the entity-body. Its
+ * syntax is defined in @RFC3261 as follows:
+ * 
+ * @code
+ *    Content-Language  =  "Content-Language" HCOLON
+ *                         language-tag *(COMMA language-tag)
+ *    language-tag      =  primary-tag *( "-" subtag )
+ *    primary-tag       =  1*8ALPHA
+ *    subtag            =  1*8ALPHA
+ * @endcode
+ *
+ * The parsed Content-Language header
+ * is stored in #sip_content_language_t structure.
+ */
+
+/**@ingroup sip_content_language
+ * @typedef typedef struct msg_content_language_s sip_content_language_t;
+ *
+ * The structure #sip_content_language_t contains representation of
+ * @ContentLanguage header.
+ *
+ * The #sip_content_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ *   msg_common_t            k_common[1]; // Common fragment info
+ *   msg_content_language_t *k_next;      // (Content-Encoding header)
+ *   msg_param_t            *k_items;     // List of languages
+ * } sip_content_language_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_language_class[] = 
+SIP_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);
+
+issize_t sip_content_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_content_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_type Content-Type Header
+ *
+ * The Content-Type header indicates the media type of the message-body sent
+ * to the recipient.  Its syntax is defined in [H3.7, S] as
+ * follows:
+ * 
+ * @code
+ * Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
+ * media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
+ * m-type           =  discrete-type / composite-type
+ * discrete-type    =  "text" / "image" / "audio" / "video"
+ *                     / "application" / extension-token
+ * composite-type   =  "message" / "multipart" / extension-token
+ * extension-token  =  ietf-token / x-token
+ * ietf-token       =  token
+ * x-token          =  "x-" token
+ * m-subtype        =  extension-token / iana-token
+ * iana-token       =  token
+ * m-parameter      =  m-attribute EQUAL m-value
+ * m-attribute      =  token
+ * m-value          =  token / quoted-string
+ * @endcode
+ *
+ * The parsed Content-Type header is stored in #sip_content_type_t structure.
+ */
+
+/**@ingroup sip_content_type
+ * @typedef typedef struct sip_content_type_s sip_content_type_t;
+ *
+ * The structure #sip_content_type_t contains representation of SIP
+ * @ContentType header.
+ *
+ * The #sip_content_type_t is defined as follows:
+ * @code
+ * typedef struct sip_content_type_s {
+ *   sip_common_t        c_common[1];  // Common fragment info
+ *   sip_unknown_t      *c_next;       // Dummy link to next
+ *   char const         *c_type;       // Pointer to type/subtype
+ *   char const         *c_subtype;    // Points after first slash in type
+ *   msg_param_t const  *c_params;     // List of parameters
+ * } sip_content_type_t;
+ * @endcode
+ *
+ * The whitespace in the @a c_type is always removed when parsing.
+ */
+
+static msg_xtra_f sip_content_type_dup_xtra;
+static msg_dup_f sip_content_type_dup_one;
+#define sip_content_type_update NULL
+
+msg_hclass_t sip_content_type_class[] = 
+SIP_HEADER_CLASS(content_type, "Content-Type", "c", c_params, 
+		 single, content_type);
+
+issize_t sip_content_type_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_content_type_t *c;
+
+  assert(h);
+
+  c = h->sh_content_type;
+
+  /* "Content-type:" type/subtyp *(; parameter))) */
+  if (/* Parse protocol */
+      sip_version_d(&s, &c->c_type) == -1 || /* compacts token / token */
+      (c->c_subtype = strchr(c->c_type, '/')) == NULL ||
+      (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
+      (*s != '\0'))
+    return -1;
+
+  c->c_subtype++;
+
+  return 0;
+}
+
+issize_t sip_content_type_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  sip_content_type_t const *c = h->sh_content_type;
+
+  MSG_STRING_E(b, end, c->c_type);
+  MSG_PARAMS_E(b, end, c->c_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+static
+isize_t sip_content_type_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_content_type_t const *c = h->sh_content_type;
+
+  MSG_PARAMS_SIZE(offset, c->c_params);
+  offset += MSG_STRING_SIZE(c->c_type);
+
+  return offset;
+}
+
+/** Duplicate one #sip_content_type_t object */ 
+static
+char *sip_content_type_dup_one(sip_header_t *dst, sip_header_t const *src,
+			       char *b, isize_t xtra)
+{
+  sip_content_type_t *c = dst->sh_content_type;
+  sip_content_type_t const *o = src->sh_content_type;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+  MSG_STRING_DUP(b, c->c_type, o->c_type);
+  c->c_subtype = strchr(c->c_type, '/');
+  c->c_subtype++;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_mime_version MIME-Version Header
+ *
+ * MIME-Version header indicates what version of the MIME protocol was used
+ * to construct the message.  Its syntax is defined in [H19.4.1, S10.28]
+ * as follows:
+ * 
+ * @code
+ *    MIME-Version  =  "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
+ * @endcode
+ *
+ * The parsed MIME-Version header is stored in #sip_mime_version_t structure.
+ */
+
+/**@ingroup sip_mime_version
+ * @typedef struct msg_generic_s sip_mime_version_t; 
+ *
+ * The structure #sip_mime_version_t contains representation of an
+ * @MIMEVersion header.
+ *
+ * The #sip_mime_version_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ *   msg_common_t   g_common[1];    // Common fragment info
+ *   msg_generic_t *g_next;	    // Link to next header
+ *   char const    *g_string;	    // Header value
+ * } sip_mime_version_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_mime_version_class[] = 
+SIP_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);
+
+issize_t sip_mime_version_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_mime_version_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_warning Warning Header
+ * 
+ * The Warning response-header field is used to carry additional information
+ * about the status of a response. Its syntax is defined in @RFC3261 as
+ * follows:
+ * 
+ * @code
+ *    Warning        =  "Warning" HCOLON warning-value *(COMMA warning-value)
+ *    warning-value  =  warn-code SP warn-agent SP warn-text
+ *    warn-code      =  3DIGIT
+ *    warn-agent     =  hostport / pseudonym
+ *                      ;  the name or pseudonym of the server adding
+ *                      ;  the Warning header, for use in debugging
+ *    warn-text      =  quoted-string
+ *    pseudonym      =  token
+ * @endcode
+ *
+ * The parsed Warning header is stored in #sip_warning_t structure.
+ */
+
+/**@ingroup sip_warning
+ * @typedef struct msg_warning_s sip_warning_t; 
+ *
+ * The structure #sip_warning_t contains representation of an
+ * @Warning header.
+ *
+ * The #sip_warning_t is defined as follows:
+ * @code
+ * typedef struct msg_warning_s
+ * {
+ *   msg_common_t        w_common[1];  // Common fragment info
+ *   msg_warning_t      *w_next;       // Link to next @Warning header
+ *   unsigned            w_code;       // Warning code
+ *   char const         *w_host;       // Hostname or pseudonym
+ *   char const         *w_port;       // Port number
+ *   char const         *w_text;       // Warning text
+ * } sip_warning_t;
+ * @endcode
+ */
+
+#define sip_warning_dup_xtra msg_warning_dup_xtra
+#define sip_warning_dup_one msg_warning_dup_one
+#define sip_warning_update NULL
+
+msg_hclass_t sip_warning_class[] = 
+SIP_HEADER_CLASS(warning, "Warning", "", w_common, append, warning);
+
+issize_t sip_warning_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_warning_d(home, h, s, slen);
+}
+issize_t sip_warning_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return msg_warning_e(b, bsiz, h, f);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,568 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_parser
+ * @CFILE sip_parser.c
+ *
+ * SIP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Oct  5 14:01:24 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include <sofia-sip/su_tagarg.h>
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/msg_mclass.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+/** Version of the SIP module */
+char const sip_parser_version[] = VERSION;
+
+/** SIP version 2.0. */
+char const sip_version_2_0[] = "SIP/2.0";
+
+/** Default message class */
+extern msg_mclass_t sip_mclass[];
+
+msg_mclass_t *sip_default_mclass(void)
+{
+  return sip_mclass;
+}
+
+/** Extract the SIP message body, including separator line. 
+ *
+ * @param msg  message object [IN]
+ * @param sip  public SIP message structure [IN/OUT]
+ * @param b    buffer containing unparsed data [IN]
+ * @param bsiz buffer size [IN]
+ * @param eos  true if buffer contains whole message [IN]
+ *
+ * @retval -1 error
+ * @retval 0  cannot proceed
+ * @retval m 
+ */
+issize_t sip_extract_body(msg_t *msg, sip_t *sip, char b[], isize_t bsiz, int eos)
+{
+  ssize_t m = 0;
+  size_t body_len;
+  
+  if (!(sip->sip_flags & MSG_FLG_BODY)) {
+    /* We are looking at a potential empty line */
+    m = msg_extract_separator(msg, (msg_pub_t *)sip, b, bsiz, eos);
+    if (m <= 0)
+      return m;
+    sip->sip_flags |= MSG_FLG_BODY;
+    b += m;
+    bsiz -= m;
+  }
+
+  if (sip->sip_content_length)
+    body_len = sip->sip_content_length->l_length;
+  else if (MSG_IS_MAILBOX(sip->sip_flags)) /* message fragments */
+    body_len = 0;
+  else if (eos)
+    body_len = bsiz;
+  else if (bsiz == 0)
+    return m;
+  else
+    return -1;
+
+  if (body_len == 0) {
+    sip->sip_flags |= MSG_FLG_COMPLETE;
+    return m;
+  }
+
+  if (m)
+    return m;
+
+  if (eos && body_len > bsiz) {
+    sip->sip_flags |= MSG_FLG_TRUNC | MSG_FLG_ERROR;
+    return bsiz;
+  }
+
+  if ((m = msg_extract_payload(msg, (msg_pub_t *)sip, 
+			       NULL, body_len, b, bsiz, eos)) == -1)
+    return -1;
+  
+  sip->sip_flags |= MSG_FLG_FRAGS;
+  if (bsiz >= body_len)
+    sip->sip_flags |= MSG_FLG_COMPLETE;
+
+  return m;
+}
+
+/** Parse SIP version.
+ *
+ * Parse a SIP version string. Update the 
+ * pointer at @a ss to first non-LWS character after the version string.
+ *
+ * @param ss   string to be parsed [IN/OUT]
+ * @param ver  value result for version [OUT]
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int sip_version_d(char **ss, char const **ver)
+{
+  char *s = *ss;
+  char const *result;
+  size_t const version_size = sizeof(sip_version_2_0) - 1;
+
+  if (strncasecmp(s, sip_version_2_0, version_size) == 0 && 
+      !IS_TOKEN(s[version_size])) {
+    result = sip_version_2_0;
+    s += version_size;
+  }
+  else {
+    /* Version consists of two tokens, separated by / */
+    size_t l1 = 0, l2 = 0, n;
+
+    result = s;
+
+    l1 = span_token(s);
+    for (n = l1; IS_LWS(s[n]); n++);
+    if (s[n] == '/') {
+      for (n++; IS_LWS(s[n]); n++);
+      l2 = span_token(s + n);
+      n += l2;
+    }
+
+    if (l1 == 0 || l2 == 0)
+      return -1;
+
+    /* If there is extra ws between tokens, compact version */
+    if (n > l1 + 1 + l2) {
+      s[l1] = '/';
+      memmove(s + l1 + 1, s + n - l2, l2);
+      s[l1 + 1 + l2] = 0;
+
+      /* Compare again with compacted version */ 
+      if (strcasecmp(s, sip_version_2_0) == 0)
+	result = sip_version_2_0;
+    }
+
+    s += n;
+  }
+
+  while (IS_WS(*s)) *s++ = '\0';
+  
+  *ss = s;
+
+  if (ver) 
+    *ver = result;
+
+  return 0;
+}
+
+/** Calculate extra space required by version string */
+isize_t sip_version_xtra(char const *version)
+{
+  if (version == SIP_VERSION_CURRENT)
+    return 0;
+  return MSG_STRING_SIZE(version);
+}
+
+/** Duplicate a transport string */
+void sip_version_dup(char **pp, char const **dd, char const *s)
+{
+  if (s == SIP_VERSION_CURRENT)
+    *dd = s;
+  else
+    MSG_STRING_DUP(*pp, *dd, s);
+}
+
+char const sip_method_name_invite[] =  	 "INVITE";
+char const sip_method_name_ack[] =     	 "ACK";
+char const sip_method_name_cancel[] =  	 "CANCEL";
+char const sip_method_name_bye[] =     	 "BYE";
+char const sip_method_name_options[] = 	 "OPTIONS";
+char const sip_method_name_register[] =  "REGISTER";
+char const sip_method_name_info[] =      "INFO";
+char const sip_method_name_prack[] =     "PRACK";
+char const sip_method_name_update[] =    "UPDATE";
+char const sip_method_name_message[] =   "MESSAGE";
+char const sip_method_name_subscribe[] = "SUBSCRIBE";
+char const sip_method_name_notify[] =    "NOTIFY";
+char const sip_method_name_refer[] =     "REFER";
+char const sip_method_name_publish[] =   "PUBLISH";
+
+/** Well-known SIP method names. */
+char const * const sip_method_names[] = {
+  "<UNKNOWN>",
+  sip_method_name_invite,
+  sip_method_name_ack,
+  sip_method_name_cancel,
+  sip_method_name_bye,
+  sip_method_name_options,
+  sip_method_name_register,
+  sip_method_name_info,
+  sip_method_name_prack,
+  sip_method_name_update,
+  sip_method_name_message,
+  sip_method_name_subscribe,
+  sip_method_name_notify,
+  sip_method_name_refer,
+  sip_method_name_publish,
+  /* If you add something here, add also them to sip_method_d! */
+  NULL
+};
+
+/** Get canonic method name. */
+char const *sip_method_name(sip_method_t method, char const *name)
+{
+  const size_t N = sizeof(sip_method_names)/sizeof(sip_method_names[0]);
+  if (method > 0 && (size_t)method <= N)
+    return sip_method_names[method];
+  else if (method == 0)
+    return name;
+  else
+    return NULL;
+}
+
+/**Parse a SIP method name.
+ *
+ * Parse a SIP method name and return a code corresponding to the method. 
+ * The address of the first non-LWS character after method name is stored in
+ * @a *ss.
+ *
+ * @param ss    pointer to pointer to string to be parsed
+ * @param return_name  value-result parameter for method name
+ *
+ * @note
+ * If there is no whitespace after method name, the value in @a *return_name
+ * may not be NUL-terminated.  The calling function @b must NUL terminate
+ * the value by setting the @a **ss to NUL after first examining its value.
+ *
+ * @return The method code if method
+ * was identified, 0 (sip_method_unknown()) if method is not known, or @c -1
+ * (sip_method_invalid()) if an error occurred.
+ *
+ * If the value-result argument @a return_name is not @c NULL,
+ * a pointer to the method name is stored to it.
+ */
+sip_method_t sip_method_d(char **ss, char const **return_name)
+{
+  char *s = *ss, c = *s;
+  char const *name;
+  int code = sip_method_unknown;
+  size_t n = 0;
+
+#define MATCH(s, m) (strncmp(s, m, n = sizeof(m) - 1) == 0)
+
+  switch (c) {
+  case 'A': if (MATCH(s, "ACK")) code = sip_method_ack; break;
+  case 'B': if (MATCH(s, "BYE")) code = sip_method_bye; break;
+  case 'C': 
+    if (MATCH(s, "CANCEL")) 
+      code = sip_method_cancel; 
+    break;
+  case 'I': 
+    if (MATCH(s, "INVITE"))
+      code = sip_method_invite;
+    else if (MATCH(s, "INFO"))
+      code = sip_method_info;
+    break;
+  case 'M': if (MATCH(s, "MESSAGE")) code = sip_method_message; break;
+  case 'N': if (MATCH(s, "NOTIFY")) code = sip_method_notify; break;
+  case 'O': if (MATCH(s, "OPTIONS")) code = sip_method_options; break;
+  case 'P': 
+    if (MATCH(s, "PRACK")) code = sip_method_prack; 
+    else if (MATCH(s, "PUBLISH")) code = sip_method_publish; 
+    break;
+  case 'R': 
+    if (MATCH(s, "REGISTER")) 
+      code = sip_method_register; 
+    else if (MATCH(s, "REFER"))
+      code = sip_method_refer; 
+    break;
+  case 'S': 
+    if (MATCH(s, "SUBSCRIBE")) 
+      code = sip_method_subscribe; 
+    break;
+  case 'U':
+    if (MATCH(s, "UPDATE"))
+      code = sip_method_update;
+    break;
+  }
+
+#undef MATCH
+
+  if (IS_NON_WS(s[n])) 
+    /* Unknown method */
+    code = sip_method_unknown;
+
+  if (code == sip_method_unknown) {
+    name = s;
+    for (n = 0; IS_UNRESERVED(s[n]); n++)
+      ;
+    if (s[n]) {
+      if (!IS_LWS(s[n]))
+	return sip_method_invalid;
+      if (return_name)
+	s[n++] = '\0';
+    }
+  }
+  else {
+    name = sip_method_names[code];
+  }
+
+  while (IS_LWS(s[n]))
+    n++;
+
+  *ss = (s + n);
+  if (return_name) *return_name = name;
+
+  return code;
+}
+
+/** Get method enum corresponding to method name */
+sip_method_t sip_method_code(char const *name)
+{
+  /* Note that sip_method_d() does not change string if return_name is NULL */
+  return sip_method_d((char **)&name, NULL);
+}
+
+char const sip_transport_udp[] = "SIP/2.0/UDP";
+char const sip_transport_tcp[] = "SIP/2.0/TCP";
+char const sip_transport_sctp[] = "SIP/2.0/SCTP";
+char const sip_transport_tls[] = "SIP/2.0/TLS";
+
+/** Decode transport */
+issize_t sip_transport_d(char **ss, char const **ttransport)
+{
+  char const *transport;
+  char *pn, *pv, *pt;
+  size_t pn_len, pv_len, pt_len;
+  char *s = *ss;
+
+#define TRANSPORT_MATCH(t)					     \
+  (strncasecmp(s+7, t+7, sizeof(t)-8) == 0 && (IS_LWS(s[sizeof(t)])) \
+   && (transport = t, s += sizeof(t) - 1))
+
+  if (strncasecmp(s, "SIP/2.0", 7) != 0 ||
+      (!TRANSPORT_MATCH(sip_transport_udp) &&
+       !TRANSPORT_MATCH(sip_transport_tcp) &&
+       !TRANSPORT_MATCH(sip_transport_sctp) &&
+       !TRANSPORT_MATCH(sip_transport_tls))) {
+    /* Protocol name */ 
+    transport = pn = s;
+    skip_token(&s);
+    pn_len = s - pn;
+    skip_lws(&s);
+    if (pn_len == 0 || *s++ != '/') return -1;
+    skip_lws(&s);
+    
+    /* Protocol version */
+    pv = s;
+    skip_token(&s);
+    pv_len = s - pv;
+    skip_lws(&s);
+    if (pv_len == 0 || *s++ != '/') return -1;
+    skip_lws(&s);
+    
+    /* Transport protocol */
+    pt = s;
+    skip_token(&s);
+    pt_len = s - pt;
+    if (pt_len == 0) return -1;
+    
+    /* Remove whitespace between protocol name and version */
+    if (pn + pn_len + 1 != pv) {
+      pn[pn_len] = '/';
+      pv = memmove(pn + pn_len + 1, pv, pv_len);
+    }
+
+    /* Remove whitespace between protocol version and transport */
+    if (pv + pv_len + 1 != pt) {
+      pv[pv_len] = '/';
+      pt = memmove(pv + pv_len + 1, pt, pt_len);
+      pt[pt_len] = '\0';
+      
+      /* extra whitespace? */
+      if (!strcasecmp(transport, sip_transport_udp))
+	transport = sip_transport_udp;
+      else if (!strcasecmp(transport, sip_transport_tcp))
+	transport = sip_transport_tcp;
+      else if (!strcasecmp(transport, sip_transport_sctp))
+	transport = sip_transport_sctp;
+      else if (!strcasecmp(transport, sip_transport_tls))
+	transport = sip_transport_tls;
+    }
+  }
+
+  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+  *ss = s;
+  *ttransport = transport;
+  return 0;
+}
+
+/** Calculate extra space required by sip_transport_dup() */
+isize_t sip_transport_xtra(char const *transport)
+{
+  if (transport == sip_transport_udp ||
+      transport == sip_transport_tcp ||
+      transport == sip_transport_sctp ||
+      transport == sip_transport_tls ||
+      strcasecmp(transport, sip_transport_udp) == 0 ||
+      strcasecmp(transport, sip_transport_tcp) == 0 ||
+      strcasecmp(transport, sip_transport_sctp) == 0 ||
+      strcasecmp(transport, sip_transport_tls) == 0)
+    return 0;
+
+  return MSG_STRING_SIZE(transport);
+}
+
+/** Duplicate a transport string */
+void sip_transport_dup(char **pp, char const **dd, char const *s)
+{
+  if (s == sip_transport_udp)
+    *dd = s;
+  else if (s == sip_transport_tcp)
+    *dd = s;
+  else if (s == sip_transport_sctp)
+    *dd = s;
+  else if (s == sip_transport_tls)
+    *dd = s;
+  else if (strcasecmp(s, sip_transport_udp) == 0)
+    *dd = sip_transport_udp;
+  else if (strcasecmp(s, sip_transport_tcp) == 0)
+    *dd = sip_transport_tcp;
+  else if (strcasecmp(s, sip_transport_sctp) == 0)
+    *dd = sip_transport_sctp;
+  else if (strcasecmp(s, sip_transport_tls) == 0)
+    *dd = sip_transport_tls;
+  else
+    MSG_STRING_DUP(*pp, *dd, s);
+}
+
+/** Parse SIP <word "@" word> construct used in @CallID. */
+char *sip_word_at_word_d(char **ss)
+{
+  char *rv = *ss, *s0 = *ss;
+
+  skip_word(ss);
+  if (s0 == *ss)
+    return NULL;
+  if (**ss == '@') {
+    (*ss)++;
+    s0 = *ss;
+    skip_word(ss);
+    if (s0 == *ss)
+      return NULL;
+  }
+  if (IS_LWS(**ss))
+    (*ss)++;
+  skip_lws(ss);
+
+  return rv;
+}
+
+/**Add message separator, then test if message is complete. 
+ *
+ * Add sip_content_length and sip_separator if they are missing. 
+ * The test that all necessary message components ( @From, @To,
+ * @CSeq, @CallID, @ContentLength and message separator are present.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error: headers are missing and they could not be added
+ */
+int sip_complete_message(msg_t *msg)
+{
+  sip_t *sip = sip_object(msg);
+  su_home_t *home = msg_home(msg);
+  size_t len = 0;
+  ssize_t mplen;
+
+  if (sip == NULL)
+    return -1;
+
+  if (!sip->sip_separator)
+    sip->sip_separator = sip_separator_create(msg_home(msg));
+
+  if (sip->sip_multipart) {
+    sip_content_type_t *c = sip->sip_content_type;
+    msg_multipart_t *mp = sip->sip_multipart;
+    sip_common_t *head;
+
+    if (!c || msg_multipart_complete(msg_home(msg), c, mp) < 0)
+      return -1;
+
+    if (sip->sip_payload)
+      head = sip->sip_payload->pl_common;
+    else
+      head = sip->sip_separator->sep_common;
+
+    if (!head || !msg_multipart_serialize(&head->h_succ, mp))
+      return -1;
+
+    mplen = msg_multipart_prepare(msg, mp, sip->sip_flags);
+    if (mplen == -1)
+      return -1;
+    len = (size_t)mplen;
+  } 
+
+  if (sip->sip_payload)
+    len += sip->sip_payload->pl_len;
+
+  if (len > UINT32_MAX)
+    return -1;
+
+  if (!sip->sip_content_length) {
+    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t*)
+		      sip_content_length_create(home, (uint32_t)len));
+  }
+  else {
+    if (sip->sip_content_length->l_length != len) {
+      sip->sip_content_length->l_length = (uint32_t)len;
+      sip_fragment_clear(sip->sip_content_length->l_common);
+    }
+  }
+  
+  if (!sip->sip_cseq || 
+      !sip->sip_call_id ||
+      !sip->sip_to ||
+      !sip->sip_from ||
+      !sip->sip_separator ||
+      !sip->sip_content_length)
+    return -1;
+  
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,91 @@
+/* -*- c -*- */
+
+/**@page sip_parser SIP Parser
+ *
+ * This part of the Sofia documentation describes the internal working of
+ * SIP parser. It documents the internal functions and macros used when a
+ * new parser is added.
+ *
+ * The @b sip module contains interface to the SIP headers and message
+ * objects. The interface is abstracted using objects known as 
+ * @ref msg_hclass_s "header classes" and @ref msg_mclass_s "message classes".
+ *
+ * The @ref msg_mclass_s "message class" defines how a message is handled:
+ * parsed and encoded. It contains a parser table with references to header
+ * classes. It also contains function pointers used by the parser to handle
+ * message body and other details that vary between protocols.
+ *
+ * A @ref msg_hclass_s "header class" defines how a single header is parsed. 
+ * Each header has its own header class. There are also header classes for
+ * message elements that are not really headers, like @ref sip_request
+ * "request" and @ref sip_status "status line", 
+ * @ref sip_separator "separator between headers" and 
+ * @ref sip_payload "message body"
+ * (which is also known as payload). There is also a header classes
+ * for @ref sip_unknown "unknown headers" and 
+ * @ref sip_error "headers that contained parsing errors".
+ *
+ *
+ * @section sip_add_headers Adding Headers to Parser
+ *
+ * Sofia SIP Parser can be extended easily, either by application or by
+ * internally extending the sofia-sip library itself.
+ *
+ * Create a header template for your header just like sip_rfc2543.h.in,
+ * e.g, sip_example.h.in:
+ * 
+ *@code
+/**@file sip_example.h.in
+ *
+ * Template for <sofia-sip/sip_example.h>.
+ */
+
+#ifndef SIP_EXAMPLE_H 
+/** Defined when <sofia-sip/sip_example.h> has been included. */
+#define SIP_EXAMPLE_H 
+
+/**@file sofia-sip/sip_example.h 
+*
+ * @brief Example header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi
+ */
+
+#ifndef SIP_H
+#include <sip.h>
+#endif
+
+/**@ingroup sip_also
+ * @brief Structure for @b Also header.
+ */
+struct sip_also_s
+{
+  sip_common_t   also_common[1];    /**< Common fragment info */
+  sip_also_t    *also_next;	    /**< Link to next Also header */
+  char const    *also_display;	    /**< Display name */
+  url_t          also_url[1];	    /**< URL */
+};
+
+typedef struct sip_also_s           sip_also_t;
+typedef sip_generic_t	     	    sip_hide_t;
+typedef sip_auth_t	     	    sip_encryption_t;
+typedef sip_auth_t	     	    sip_response_key_t;
+
+struct sip_example_dummy_structure {
+  /* === Headers start here */
+  sip_also_t *sip_also;                                  /**< Also */
+  sip_hide_t *sip_hide;                                  /**< Hide */
+  sip_encryption_t *sip_encryption;                /**< Encryption */
+  sip_response_key_t *sip_response_key;          /**< Response-Key */
+  /* === Headers end here */
+};
+
+
+#endif /** !defined(SIP_EXAMPLE_H) */
+--->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---
+ * @endcode
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/**@IFILE sip_parser_table.c.in
+ *
+ * Template for <sip_parser_table.c>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_parser_table.c 
+ * @brief SIP parser table
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Oct  1 20:28:59 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include <sofia-sip/sip_parser.h>
+#include <sofia-sip/sip_extra.h>
+#include <sofia-sip/msg_mclass.h>
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_prack.c
+ * @brief SIP headers for Prack.
+ *
+ * The file @b sip_prack.c contains implementation of header classes for
+ * PRACK-related SIP headers @RAck and @RSeq.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_rack RAck Header
+ *
+ * The RAck header indicates the sequence number of the provisional response
+ * which is being acknowledged.  Its syntax is defined in
+ * @RFC3262 section 10 as follows:
+ * 
+ * @code
+ *    RAck          =  "RAck" HCOLON response-num LWS CSeq-num LWS Method
+ *    response-num  =  1*DIGIT
+ *    CSeq-num      =  1*DIGIT
+ * @endcode
+ *
+ * @sa @RFC3262, nta_outgoing_prack(), nta_reliable_treply(),
+ *   nta_reliable_mreply().
+ *
+ * The parsed RAck header is stored in #sip_rack_t structure.
+ */
+
+/**@ingroup sip_rack
+ * @typedef struct sip_rack_s sip_rack_t;
+ *
+ * The structure #sip_rack_t contains representation of an @RAck header.
+ *
+ * The #sip_rack_t is defined as follows:
+ * @code
+ * typedef struct sip_rack_s
+ * {
+ *   sip_common_t        ra_common;        // Common fragment info
+ *   sip_error_t        *ra_next;          // Dummy link to next
+ *   uint32_t            ra_response;      // Sequence number of response
+ *   uint32_t            ra_cseq;          // Sequence number of request
+ *   sip_method_t        ra_method;        // Original request method
+ *   char const         *ra_method_name;   // Original request method name
+ * } sip_rack_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_rack_dup_xtra;
+static msg_dup_f sip_rack_dup_one;
+#define sip_rack_update NULL
+
+msg_hclass_t sip_rack_class[] = 
+SIP_HEADER_CLASS(rack, "RAck", "", ra_common, single, rack);
+
+issize_t sip_rack_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_rack_t *ra = h->sh_rack;
+
+  ra->ra_response = strtoul(s, &s, 10);
+
+  if (IS_LWS(*s)) {
+    skip_lws(&s);
+    ra->ra_cseq = strtoul(s, &s, 10);
+
+    if (IS_LWS(*s)) {
+      skip_lws(&s);
+      if ((ra->ra_method = sip_method_d(&s, &ra->ra_method_name)) >= 0) {
+	return 0;
+      }
+    }
+  }
+
+  return -1;
+}
+
+issize_t sip_rack_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_rack_t const *ra = h->sh_rack;
+
+  assert(sip_is_rack(h));
+
+  return snprintf(b, bsiz, "%u %u %s", 
+		  ra->ra_response, ra->ra_cseq, ra->ra_method_name);
+}
+
+isize_t sip_rack_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_rack_t const *ra = h->sh_rack;
+
+  if (ra->ra_method == sip_method_unknown)
+    return offset + MSG_STRING_SIZE(ra->ra_method_name);
+  else
+    return offset;
+}
+
+/** Duplicate one #sip_rack_t object */ 
+char *sip_rack_dup_one(sip_header_t *dst, sip_header_t const *src,
+			char *b, isize_t xtra)
+{
+  sip_rack_t *ra_dst = dst->sh_rack;
+  sip_rack_t const *ra_src = src->sh_rack;
+
+  char *end = b + xtra;
+
+  ra_dst->ra_response = ra_src->ra_response;
+  ra_dst->ra_cseq     = ra_src->ra_cseq;
+  ra_dst->ra_method   = ra_src->ra_method;
+
+  if (ra_src->ra_method == sip_method_unknown)
+    MSG_STRING_DUP(b, ra_dst->ra_method_name, ra_src->ra_method_name);
+  else
+    ra_dst->ra_method_name = ra_src->ra_method_name;
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_rseq RSeq Header
+ *
+ * The RSeq header identifies provisional responses within a transaction. 
+ * Its syntax is defined in @RFC3262 section 10 as follows:
+ * 
+ * @code
+ *    RSeq          =  "RSeq" HCOLON response-num
+ *    response-num  =  1*DIGIT
+ * @endcode
+ *
+ * The parsed RSeq header is stored in #sip_rseq_t structure.
+ */
+
+/**@ingroup sip_rseq
+ * @typedef struct sip_rseq_s sip_rseq_t;
+ *
+ * The structure #sip_rseq_t contains representation of an @RSeq header.
+ *
+ * The #sip_rseq_t is defined as follows:
+ * @code
+ * typedef struct sip_rseq_s
+ * {
+ *   sip_common_t        rs_common;        // Common fragment info
+ *   sip_error_t        *rs_next;          // Dummy link to next
+ *   uint32_t            rs_response;      // Sequence number of response
+ * } sip_rseq_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_rseq_class[] = 
+SIP_HEADER_CLASS(rseq, "RSeq", "", rs_common, single, any);
+
+issize_t sip_rseq_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_rseq_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_rseq(h));
+  return msg_numeric_e(b, bsiz, h, f);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,559 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_pref_util.c
+ * 
+ * SIP callercaps and callerprefs utility functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Nov  2 16:39:33 EET 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+/** Parse a single preference */
+int sip_prefs_parse(union sip_pref *sp, 
+		    char const **in_out_s, 
+		    int *return_negation)
+{
+  char const *s;
+  size_t n;
+  enum sp_type old_type;
+
+  assert(sp && in_out_s && *in_out_s && return_negation);
+
+  old_type = sp->sp_type;
+  sp->sp_type = sp_error;
+
+  s = *in_out_s;
+  if (!s)
+    return 0;
+
+  if (old_type == sp_init) {
+    if (s[0] == '\0' || 
+	strcasecmp(s, "TRUE") == 0 ||
+	strcasecmp(s, "\"TRUE\"") == 0) {
+      /* Boolean */
+      sp->sp_type = sp_literal;
+      sp->sp_literal.spl_value = "TRUE";
+      sp->sp_literal.spl_length = 4;
+      *return_negation = 0;
+      *in_out_s = s + strlen(s);
+      return 1;
+    } else if (strcasecmp(s, "FALSE") == 0 || 
+	       strcasecmp(s, "\"FALSE\"") == 0) {
+      /* Boolean */
+      sp->sp_type = sp_literal;
+      sp->sp_literal.spl_value = "FALSE";
+      sp->sp_literal.spl_length = 5;
+      *return_negation = 0;
+      *in_out_s = s + strlen(s);
+      return 1;
+    } else if (s[0] == '"' && s[1] != '\0') {
+      for (s++; IS_LWS(s[0]); s++);
+    } else
+      old_type = sp_error;      
+  } else if (!s[0]) {
+    sp->sp_type = sp_init;
+    return 0;
+  }
+
+  if (old_type == sp_error)
+    return 0;
+
+  if ((*return_negation = s[0] == '!'))
+      for (s++; IS_LWS(s[0]); s++);
+
+  if (*s == '#') {
+    /* Numeric */
+    double n1, n2;
+    char s0, *e;
+
+    for (s++; IS_LWS(s[0]); s++);
+    
+    s0 = s[0];
+
+    if (s0 == '=')
+      sp->sp_type = sp_range, n1 = n2 = strtod(s = s + 1, &e);
+    else if (s0 == '<' && s[1] == '=')
+      sp->sp_type = sp_range, n1 = DBL_MIN, n2 = strtod(s = s + 2, &e);
+    else if (s0 == '>' && s[1] == '=')
+      sp->sp_type = sp_range, n1 = strtod(s = s + 2, &e), n2 = DBL_MAX;
+    else if (((n1 = strtod(s, &e)) != 0.0 || s != e) && e[0] == ':')
+      sp->sp_type = sp_range, n2 = strtod(s = e + 1, &e);
+    else
+      /* Error in conversion */
+      sp->sp_type = sp_error, n1 = DBL_MAX, n2 = DBL_MIN;
+
+    if (s == e && (n1 == 0.0 || n2 == 0.0))
+      sp->sp_type = sp_error;      /* Error in conversion */
+
+    sp->sp_range.spr_lower = n1;
+    sp->sp_range.spr_upper = n2;
+
+    s = e;
+  } else if (*s == '<') {
+    /* Quoted string */
+    n = strcspn(++s, ">");
+    sp->sp_type = sp_string;
+    sp->sp_string.sps_value = s;
+    sp->sp_string.sps_length = n;
+    s += n + 1;
+  } else if ((n = span_token(s))) {
+    /* Literal */
+    sp->sp_type = sp_literal;
+    sp->sp_literal.spl_value = s;
+    sp->sp_literal.spl_length = n;
+    s += n;
+  }
+
+  for (; IS_LWS(s[0]); s++);
+
+  if (s[0] == ',' || (s[0] == '"' && s[1] == '\0'))
+    for (s++; IS_LWS(s[0]); s++);
+  else
+    old_type = sp_error;
+
+  if (old_type != sp_init && old_type != sp->sp_type) 
+    sp->sp_type = sp_error;
+    
+  *in_out_s = s;
+
+  return sp->sp_type != sp_error;
+}
+
+/** Return true if preferences match */
+int sip_prefs_match(union sip_pref const *a, 
+		    union sip_pref const *b)
+{
+  if (!a || !b)
+    return 0;
+  if (a->sp_type != b->sp_type)
+    return 0;
+  switch (a->sp_type) {
+  default:
+  case sp_error: 
+    return 0;
+  case sp_literal:
+    return 
+      a->sp_literal.spl_length == b->sp_literal.spl_length &&
+      strncasecmp(a->sp_literal.spl_value, b->sp_literal.spl_value,
+		  a->sp_literal.spl_length) == 0;
+  case sp_string:
+    return 
+      a->sp_string.sps_length == b->sp_string.sps_length &&
+      strncmp(a->sp_string.sps_value, b->sp_string.sps_value,
+	      a->sp_string.sps_length) == 0;
+  case sp_range:
+    return 
+      a->sp_range.spr_lower <= b->sp_range.spr_upper &&
+      a->sp_range.spr_upper >= b->sp_range.spr_lower;
+  }
+}
+
+/**Find a matching parameter-value pair from a parameter list.
+ *
+ * Check if the given feature values match with each other.
+ *
+ * @param pvalue first feature parameter
+ * @param nvalue second feature parameter
+ * @param return_parse_error return-value parameter for error (may be NULL)
+ *
+ * @retval 1 if given feature parameters match
+ * @retval 0 if there is no match or a parse or type error occurred.
+ *
+ * If there is a parsing or type error, 0 is returned and @a
+ * *return_parse_error is set to -1.
+ *
+ * @sa sip_prefs_parse(), sip_prefs_match(), union #sip_pref.
+ */
+int sip_prefs_matching(char const *pvalue,
+		       char const *nvalue,
+		       int *return_parse_error)
+{
+  int error;
+  char const *p;
+  union sip_pref np[1], pp[1];
+  int n_negated, p_negated;
+
+  if (!return_parse_error)
+    return_parse_error = &error;
+
+  if (!pvalue || !nvalue)
+    return 0;
+
+  memset(np, 0, sizeof np);
+
+  /* Usually nvalue is from Accept/Reject-Contact, 
+     pvalue is from Contact */
+  while (sip_prefs_parse(np, &nvalue, &n_negated)) {
+    memset(pp, 0, sizeof pp);
+    p = pvalue;
+
+    while (sip_prefs_parse(pp, &p, &p_negated)) {
+      if (pp->sp_type != np->sp_type) /* Types do not match */
+	return 0;
+
+      if (sip_prefs_match(np, pp) /* We found matching value */
+	  ? !p_negated	/* without negative */
+	  : p_negated)	/* Negative did not match */
+	break;
+    }
+
+    if (pp->sp_type == sp_error)
+      return *return_parse_error = -1, 0;
+
+    if (pp->sp_type != sp_init /* We found matching value */
+	? !n_negated		/* and we expected one */
+	: n_negated)		/* We found none and expected none */
+      return 1;
+  }
+
+  if (np->sp_type == sp_error)
+    *return_parse_error = -1;
+
+  return 0;
+}
+
+/** Check if the parameter is a valid feature tag. 
+ *
+ * A feature tag is a parameter starting with a single plus, or a well-known
+ * feature tag listed in @RFC3841: "audio", "automata", "application",
+ * "class", "control", "duplex", "data", "description", "events", "isfocus",
+ * "language", "mobility", "methods", "priority", "schemes", "type", or
+ * "video". However, well-known feature tag can not start with plus. So,
+ * "+alarm" or "audio" is a feature tag, "alarm", "++alarm", or "+audio" are
+ * not.
+ *
+ * @retval 1 if string is a feature tag parameter
+ * @retval 0 otherwise
+ */
+int sip_is_callerpref(char const *param)
+{
+#define MATCH(s) \
+  (strncasecmp(param + 1, s + 1, strlen(s) - 1) == 0 && \
+   (param[strlen(s)] == '=' || param[strlen(s)] == '\0'))
+
+  int xor = 0, base = 0;
+
+  if (!param || !param[0])
+    return 0;
+
+  if (param[0] == '+')
+    param++, xor = 1;
+
+  switch (param[0]) {
+  case 'a': case 'A':
+    base = MATCH("audio") || MATCH("automata") || MATCH("application") ||
+      MATCH("actor");
+    break;
+  case 'c': case 'C':
+    base = MATCH("class") || MATCH("control");
+    break;
+  case 'd': case 'D':
+    base = MATCH("duplex") || MATCH("data") || MATCH("description");
+    break;
+  case 'e': case 'E':
+    base = MATCH("events");
+    break;
+  case 'i': case 'I':
+    base = MATCH("isfocus");
+    break;
+  case 'l': case 'L':
+    base = MATCH("language");
+    break;
+  case 'm': case 'M':
+    base = MATCH("mobility") || MATCH("methods");
+    break;
+  case 'p': case 'P':
+    base = MATCH("priority");
+    break;
+  case 's': case 'S':
+    base = MATCH("schemes");
+    break;
+  case 't': case 'T':
+    base = MATCH("type");
+    break;
+  case 'v': case 'V':
+    base = MATCH("video");
+    break;
+  default:
+    base = 0;
+    break;
+  }
+#undef MATCH
+
+  return base ^ xor;
+}
+
+/** Check if @Contact is immune to callerprefs. */
+int sip_contact_is_immune(sip_contact_t const *m)
+{
+  unsigned i;
+
+  if (m->m_params)
+    for (i = 0; m->m_params[i]; i++) {
+      if (sip_is_callerpref(m->m_params[i]))
+	return 0;
+    }
+
+  return 1;
+}
+
+/**Check if @Contact matches by @AcceptContact.
+ * 
+ * Matching @AcceptContact and @Contact headers is done as explained in
+ * @RFC3841 section 7.2.4. The caller score can be calculated from the
+ * returned S and N values.
+ *
+ * @par Matching
+ * The @AcceptContact header contains number of feature tag parameters. The
+ * count of feature tags is returned in @a return_N. For each feature tag in
+ * @AcceptContact, the feature tag with same name is searched from the
+ * @Contact header. If both headers contain the feature tag with same name,
+ * their values are compared. If the value in @AcceptContact does not match
+ * with the value in @Contact, there is mismatch and 0 is returned. If they
+ * match, S is increased by 1.
+ *
+ * @param m   pointer to @Contact header structure
+ * @param cp   pointer to @AcceptContact header structure
+ * @param return_N   return-value parameter for number of 
+ *                   feature tags in @AcceptContact
+ * @param return_S   return-value parameter for number of 
+ *                   matching feature tags
+ * @param return_error   return-value parameter for parsing error
+ *
+ * For example,
+ * @code
+ * if (sip_contact_accept(contact, accept_contact, &S, &N, &error)) {
+ *   if (N == 0)
+ *     score == 1.0;
+ *   else
+ *     score = (double)S / (double)N;
+ *   if (accept_contact->cp_explicit) {
+ *     if (accept_contact->cp_require)
+ *       goto drop;
+ *     else
+ *       score = 0.0;
+ *   }
+ * }
+ * else if (!error) {
+ *   score = 0.0;
+ * }
+ * @endcode
+ *
+ * @retval 1 if @Contact matches
+ * @return @a return_S contains number of matching feature tags
+ * @return @a return_N contains number of feature tags in @AcceptContact
+ * @retval 0 if @Contact does not match
+ * @return @a return_error contains -1 if feature tag value was malformed
+ *
+ * @sa @RFC3841 section 7.2.4, sip_contact_score(), sip_contact_reject(),
+ * sip_contact_is_immune(), sip_contact_immunize(), sip_is_callerpref(),
+ * sip_prefs_matching().
+ */
+int sip_contact_accept(sip_contact_t const *m, 
+		       sip_accept_contact_t const *cp,
+		       unsigned *return_S,
+		       unsigned *return_N,
+		       int *return_error)
+{
+  char const *cap, *acc;
+  unsigned i, S, N;
+  size_t eq;
+
+  if (!return_N) return_N = &N;
+  if (!return_S) return_S = &S;
+
+  *return_S = 0, *return_N = 0;
+
+  if (!m || !cp || !m->m_params || !cp->cp_params)
+    return 1;
+
+  for (i = 0, S = 0, N = 0; cp->cp_params[i]; i++) {
+    acc = cp->cp_params[i];
+    if (!sip_is_callerpref(acc))
+      continue;
+
+    N++;
+
+    cap = msg_params_find(m->m_params, acc);
+
+    if (cap) {
+      eq = strcspn(acc, "=");
+      acc += eq + (acc[eq] == '=');
+
+      if (!sip_prefs_matching(cap, acc, return_error)) 
+	return 0;
+      
+      S++;
+    }
+  }
+
+  *return_S = S; /* Matched feature tags */
+  *return_N = N; /* Number of feature tags in @AcceptContact */
+
+  return 1; 
+}
+
+
+/** Check if @Contact is rejected by @RejectContact.
+ *
+ * @param m pointer to @Contact header
+ * @param reject pointer to @RejectContact header
+ *
+ * @retval 1 when rejecting
+ * @retval 0 when @Contact does not match with @RejectContact
+ *
+ * @sa sip_contact_score(), sip_contact_accept(), sip_contact_immunize(),
+ * sip_contact_is_immune(), @RFC3841, @RejectContact, @Contact
+ */
+int sip_contact_reject(sip_contact_t const *m, 
+		       sip_reject_contact_t const *reject)
+{
+  unsigned S, N;
+  int error;
+
+  if (!m || !m->m_params || !reject || !reject->cp_params)
+    return 0;
+
+  return sip_contact_accept(m, reject, &S, &N, &error) && S == N && N > 0;
+}
+
+/**Immunize @Contact to callerprefs.
+ *
+ * Make a copy of @Contact header @a m and remove all parameters which
+ * affect caller preferences.
+ *
+ * @param home   home object used when allocating copy
+ * @param m   pointer to @Contact header structure to immunize
+ *
+ * @retval pointer to immunized copy if successful
+ * @retval NULL upon an error
+ * 
+ * @sa @RFC3841, sip_is_callerpref(), sip_contact_score(),
+ * sip_contact_accept(), sip_contact_reject(), @Contact
+ */
+sip_contact_t *sip_contact_immunize(su_home_t *home, sip_contact_t const *m)
+{
+  unsigned i, j;
+  sip_contact_t m0[1], *m1;
+  msg_param_t *params;
+
+  if (!m)
+    return NULL;
+
+  *m0 = *m, m0->m_next = NULL;
+
+  m1 = sip_contact_copy(home, m0);
+
+  if (m1 == NULL || !m1->m_params)
+    return m1;
+
+  params = (msg_param_t *)m1->m_params;
+
+  for (i = 0, j = 0; params[i]; i++) {
+    if (!sip_is_callerpref(params[i]))
+      params[j++] = params[i];
+  }
+
+  params[j] = NULL;
+
+  return m1;
+}
+
+/** Calculate score for contact.
+ *
+ * The caller preference score is an integer in range of 0 to 1000.
+ * 
+ * @retval -1 if the contact is rejected
+ * @retval 1000 if contact is immune to caller preferences
+ * @retval 0..1000 reflecting @RFC3481 score in 0.000 - 1.000.
+ *
+ * @sa sip_q_value(),
+ * sip_contact_accept(), sip_contact_reject(), sip_contact_is_immune(),
+ * sip_contact_immunize(), sip_is_callerpref(), sip_prefs_matching(),
+ * @RFC3481, @AcceptContact, @RejectContact, @Contact
+ */
+int sip_contact_score(sip_contact_t const *m,
+		      sip_accept_contact_t const *ac,
+		      sip_reject_contact_t const *rc)
+{
+  unsigned long S_total = 0;
+  unsigned M = 0, scale = 1000;
+  int error = 0;
+
+  if (sip_contact_is_immune(m))
+    return 1000;		/* Immune */
+
+  for (; rc; rc = rc->cp_next)
+    if (sip_contact_reject(m, rc)) 
+      break;
+  if (rc)
+    return -1;			/* Rejected */
+
+  for (; ac; ac = ac->cp_next) {
+    unsigned S, N;
+	
+    if (!sip_contact_accept(m, ac, &S, &N, &error)) {
+      if (ac->cp_require)
+	return 0;		/* Discarded */
+      continue;
+    }
+
+    M++;
+
+    /* Apply score */
+    if (S < N && ac->cp_explicit) {
+      S = 0;
+      if (ac->cp_require)
+	return 0;		/* Dropped */
+    }
+
+    if (S > 0 && N > 0) 
+      S_total += sip_q_value(ac->cp_q) * (scale * S / N + (2 * S >= N));
+  }
+
+  if (!M) 
+    return 0;
+
+  S_total /= M;
+
+  if (S_total < scale * 1000)
+    return S_total / scale;
+  else
+    return 1000;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_reason.c
+ * @brief @Reason header.
+ *
+ * The file @b sip_reason.c contains implementation of header class for
+ * SIP header @Reason.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/**@SIP_HEADER sip_reason Reason Header
+ *
+ * The Reason header is used to indicate why a SIP request was issued or why
+ * a provisional response was sent. It can be used with HRPF scenarios. It
+ * is defined in @RFC3326 as follows:
+ * 
+ * @code
+ *   Reason            =  "Reason" HCOLON reason-value *(COMMA reason-value)
+ *   reason-value      =  protocol *(SEMI reason-params)
+ *   protocol          =  "SIP" / "Q.850" / token
+ *   reason-params     =  protocol-cause / reason-text
+ *                        / reason-extension
+ *   protocol-cause    =  "cause" EQUAL cause
+ *   cause             =  1*DIGIT
+ *   reason-text       =  "text" EQUAL quoted-string
+ *   reason-extension  =  generic-param
+ * @endcode
+ * 
+ * The parsed Reason header is stored in #sip_reason_t structure.
+ */
+
+/**@ingroup sip_reason
+ * @typedef typedef struct sip_reason_s sip_reason_t;
+ *
+ * The structure #sip_reason_t contains representation of SIP @Reason header.
+ *
+ * The #sip_reason_t is defined as follows:
+ * @code
+ * typedef struct sip_reason_s
+ * {
+ *   sip_common_t        re_common[1]; // Common fragment info 
+ *   sip_reason_t       *re_next;      // Link to next <reason-value> 
+ *   char const         *re_protocol;  // Protocol 
+ *   msg_param_t const  *re_params;    // List of reason parameters 
+ *   char const         *re_cause;     // Value of cause parameter 
+ *   char const         *re_text;      // Value of text parameter 
+ * } sip_reason_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_reason_dup_xtra;
+static msg_dup_f sip_reason_dup_one;
+static msg_update_f sip_reason_update;
+
+msg_hclass_t sip_reason_class[] = 
+SIP_HEADER_CLASS(reason, "Reason", "", re_params, append, reason);
+
+issize_t sip_reason_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_reason_t *re = (sip_reason_t *)h;
+  size_t n;
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  re->re_protocol = s;
+  if ((n = span_token(s)) == 0) 
+    return -1;
+  s += n; while (IS_LWS(*s)) *s++ = '\0'; 
+  if (*s == ';' && msg_params_d(home, &s, &re->re_params) < 0)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_reason_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_reason_t const *re = h->sh_reason;
+
+  assert(sip_is_reason(h));
+  MSG_STRING_E(b, end, re->re_protocol);
+  MSG_PARAMS_E(b, end, re->re_params, flags);
+
+  return b - b0;
+}
+
+isize_t sip_reason_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_reason_t const *re = h->sh_reason;
+
+  MSG_PARAMS_SIZE(offset, re->re_params);
+  offset += MSG_STRING_SIZE(re->re_protocol);
+
+  return offset;
+}
+
+/** Duplicate one #sip_reason_t object */ 
+char *sip_reason_dup_one(sip_header_t *dst, sip_header_t const *src,
+			char *b, isize_t xtra)
+{
+  sip_reason_t *re_dst = dst->sh_reason;
+  sip_reason_t const *re_src = src->sh_reason;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&re_dst->re_params, re_src->re_params, b, xtra);
+  MSG_STRING_DUP(b, re_dst->re_protocol, re_src->re_protocol);
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameter values for @Reason header */
+static int sip_reason_update(msg_common_t *h, 
+			     char const *name, isize_t namelen,
+			     char const *value)
+{
+  sip_reason_t *re = (sip_reason_t *)h;
+
+  if (name == NULL) {
+    re->re_cause = NULL;
+    re->re_text = NULL;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+  else if (MATCH(cause)) {
+    re->re_cause = value;
+  }
+  else if (MATCH(text)) {
+    re->re_text = value;
+  }
+
+#undef MATCH
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,555 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_refer.c
+ * @brief SIP REFER-related headers.
+ *
+ * The file @b sip_refer.c contains implementation of header classes for
+ * REFER-related SIP headers @ReferTo and @ReferredBy.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jan 23 13:23:45 EET 2002 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/sip_extra.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_refer_to Refer-To Header
+ *
+ * The Refer-To header provides a URI to reference. Its syntax is defined in
+ * @RFC3515 section 2.1 as follows:
+ *
+ * @code
+ *  Refer-To = ("Refer-To" / "r") HCOLON ( name-addr / addr-spec )
+ *            *(SEMI generic-param)
+ * @endcode
+ *
+ *
+ * The parsed Refer-To header is stored in #sip_refer_to_t structure.
+ */
+
+/**@ingroup sip_refer_to
+ *
+ * @typedef typedef struct sip_refer_to_s sip_refer_to_t;
+ *
+ * The structure #sip_refer_to_t contains representation of @ReferTo
+ * header.
+ *
+ * The #sip_refer_to_t is defined as follows:
+ * @code
+ * typedef struct sip_refer_to_s
+ * {
+ *   sip_common_t        r_common[1];   // Common fragment info
+ *   sip_error_t        *r_next;	// Link to next (dummy)
+ *   char const          r_display;     // Display name
+ *   url_t               r_url[1];	// URI to reference
+ *   msg_param_t const  *r_params;      // List of generic parameters
+ * } sip_refer_to_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_refer_to_dup_xtra;
+static msg_dup_f sip_refer_to_dup_one;
+#define sip_refer_to_update NULL
+
+msg_hclass_t sip_refer_to_class[] =
+SIP_HEADER_CLASS(refer_to, "Refer-To", "r", r_params, single, refer_to);
+
+issize_t sip_refer_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  issize_t retval;
+  sip_refer_to_t *r = (sip_refer_to_t *)h;
+
+  retval = sip_name_addr_d(home, &s,
+			   &r->r_display,
+			   r->r_url,
+			   &r->r_params,
+			   NULL);
+  if (retval < 0)
+    return retval;
+
+  if (*s == '?' && !r->r_display && !r->r_url->url_headers) {
+    /* Missing <> around URL */
+    *s++ = '\0';
+    r->r_url->url_headers = s;
+    s += strcspn(s, " \t;,");
+    if (IS_LWS(*s))
+      *s++ = '\0', skip_lws(&s);
+    if (*s)
+      return -1;
+    r->r_display = s;	/* Put empty string in display so that we encode using <> */
+  }
+  else if (*s)
+    return -1;
+
+  return retval;
+}
+
+issize_t sip_refer_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  sip_refer_to_t const *r = h->sh_refer_to;
+
+  assert(sip_is_refer_to(h));
+
+  return sip_name_addr_e(b, bsiz, flags,
+			 r->r_display, MSG_IS_CANONIC(flags),
+			 r->r_url,
+			 r->r_params,
+			 NULL);
+}
+
+isize_t sip_refer_to_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_refer_to_t const *r = h->sh_refer_to;
+
+  MSG_PARAMS_SIZE(offset, r->r_params);
+  offset += MSG_STRING_SIZE(r->r_display);
+  offset += url_xtra(r->r_url);
+
+  return offset;
+}
+
+/** Duplicate one #sip_refer_to_t object */
+char *sip_refer_to_dup_one(sip_header_t *dst, sip_header_t const *src,
+			   char *b, isize_t xtra)
+{
+  sip_refer_to_t *r_dst = dst->sh_refer_to;
+  sip_refer_to_t const *r_src = src->sh_refer_to;
+
+  char *end = b + xtra;
+
+  b = msg_params_dup(&r_dst->r_params, r_src->r_params, b, xtra);
+  MSG_STRING_DUP(b, r_dst->r_display, r_src->r_display);
+  URL_DUP(b, end, r_dst->r_url, r_src->r_url);
+
+  assert(b <= end);
+
+  return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_referred_by Referred-By Header
+ *
+ * The Referred-By header conveys the identity of the original referrer to
+ * the referred-to party. Its syntax is defined in
+ * @RFC3892 section 3 as follows:
+ *
+ * @code
+ *    Referred-By  =  ("Referred-By" / "b") HCOLON referrer-uri
+ *                   *( SEMI (referredby-id-param / generic-param) )
+ *
+ *    referrer-uri = ( name-addr / addr-spec )
+ *
+ *    referredby-id-param = "cid" EQUAL sip-clean-msg-id
+ *
+ *    sip-clean-msg-id = LDQUOT dot-atom "@" (dot-atom / host) RDQUOT
+ *
+ *    dot-atom = atom *( "." atom )
+ *
+ *    atom     = 1*( alphanum / "-" / "!" / "%" / "*" /
+ *                        "_" / "+" / "'" / "`" / "~"   )
+ * @endcode
+ *
+ *
+ * The parsed Referred-By header is stored in #sip_referred_by_t structure.
+ */
+
+/**@ingroup sip_referred_by
+ *
+ * @typedef typedef struct sip_referred_by_s sip_referred_by_t;
+ *
+ * The structure #sip_referred_by_t contains representation of @ReferredBy
+ * header.
+ *
+ * The #sip_referred_by_t is defined as follows:
+ * @code
+ * typedef struct sip_referred_by_s
+ * {
+ *   sip_common_t        b_common[1];   // Common fragment info
+ *   sip_error_t        *b_next;	// Link to next (dummy)
+ *   char const          b_display,
+ *   url_t               b_url[1];	// Referrer-URI
+ *   msg_param_t const  *b_params;      // List of parameters
+ *   char const         *b_cid;
+ * } sip_referred_by_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_referred_by_dup_xtra;
+static msg_dup_f sip_referred_by_dup_one;
+static msg_update_f sip_referred_by_update;
+
+msg_hclass_t sip_referred_by_class[] =
+SIP_HEADER_CLASS(referred_by, "Referred-By", "b", b_params, single,
+		 referred_by);
+
+issize_t sip_referred_by_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_referred_by_t *b = h->sh_referred_by;
+
+  if (sip_name_addr_d(home, &s,
+		      &b->b_display,
+		      b->b_url,
+		      &b->b_params,
+		      NULL) < 0 || *s /* Extra stuff? */)
+    return -1;
+
+  if (b->b_params)
+    msg_header_update_params(b->b_common, 0);
+
+  return 0;
+}
+
+issize_t sip_referred_by_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  assert(sip_is_referred_by(h));
+
+  return sip_name_addr_e(b, bsiz, flags,
+			 h->sh_referred_by->b_display,
+			 MSG_IS_CANONIC(flags), h->sh_referred_by->b_url,
+			 h->sh_referred_by->b_params,
+			 NULL);
+}
+
+isize_t sip_referred_by_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_referred_by_t const *b = h->sh_referred_by;
+
+  MSG_PARAMS_SIZE(offset, b->b_params);
+  offset += MSG_STRING_SIZE(b->b_display);
+  offset += url_xtra(b->b_url);
+
+  return offset;
+}
+
+char *sip_referred_by_dup_one(sip_header_t *dst, sip_header_t const *src,
+			      char *b,
+			      isize_t xtra)
+{
+  sip_referred_by_t *nb = dst->sh_referred_by;
+  sip_referred_by_t const *o = src->sh_referred_by;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&nb->b_params, o->b_params, b, xtra);
+  MSG_STRING_DUP(b, nb->b_display, o->b_display);
+  URL_DUP(b, end, nb->b_url, o->b_url);
+
+  nb->b_cid = msg_params_find(nb->b_params, "cid=");
+
+  assert(b <= end);
+
+  return b;
+}
+
+static int sip_referred_by_update(msg_common_t *h, 
+			   char const *name, isize_t namelen,
+			   char const *value)
+{
+  sip_referred_by_t *b = (sip_referred_by_t *)h;
+
+  if (name == NULL) {
+    b->b_cid = NULL;
+  }
+  else if (namelen == strlen("cid") && !strncasecmp(name, "cid", namelen)) {
+    b->b_cid = value;
+  }
+
+  return 0;
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_replaces Replaces Header
+ *
+ * The Replaces header indicates that a single dialog identified by the
+ * header field is to be shut down and logically replaced by the incoming
+ * INVITE in which it is contained. Its syntax is defined in
+ * @RFC3891 section 6.1 as follows:
+ *
+ * @code
+ *    Replaces        = "Replaces" HCOLON callid *(SEMI replaces-param)
+ *    replaces-param  = to-tag / from-tag / early-flag / generic-param
+ *    to-tag          = "to-tag" EQUAL token
+ *    from-tag        = "from-tag" EQUAL token
+ *    early-flag      = "early-only"
+ * @endcode
+ *
+ * A Replaces header field MUST contain exactly one <to-tag> and exactly
+ * one <from-tag>, as they are required for unique dialog matching.  For
+ * compatibility with dialogs initiated by @RFC2543 compliant UAs, a
+ * tag of zero ("0") matches both tags of zero and null.  A Replaces header
+ * field MAY contain the <early-only> flag.
+ *
+ * The parsed Replaces header is stored in #sip_replaces_t structure.
+ *
+ * @sa @RFC3891, nta_leg_by_replaces(), nta_leg_make_replaces()
+ */
+
+/**@ingroup sip_replaces
+ *
+ * @typedef typedef struct sip_replaces_s sip_replaces_t;
+ *
+ * The structure #sip_replaces_t contains representation of @Replaces
+ * header.
+ *
+ * The #sip_replaces_t is defined as follows:
+ * @code
+ * typedef struct sip_replaces_s
+ * {
+ *   sip_common_t        rp_common[1];   // Common fragment info
+ *   sip_error_t        *rp_next;	 // Dummy link to next
+ *   char const         *rp_call_id;     // @CallID of dialog to replace 
+ *   msg_param_t const  *rp_params;      // List of parameters 
+ *   char const         *rp_to_tag;      // Value of "to-tag" parameter 
+ *   char const         *rp_from_tag;    // Value of "from-tag" parameter 
+ *   unsigned            rp_early_only;  // early-only parameter
+ * } sip_replaces_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_replaces_dup_xtra;
+static msg_dup_f sip_replaces_dup_one;
+static msg_update_f sip_replaces_update;
+
+msg_hclass_t sip_replaces_class[] =
+SIP_HEADER_CLASS(replaces, "Replaces", "", rp_params, single, replaces);
+
+/** Decode (parse) @Replaces header */
+issize_t sip_replaces_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_replaces_t *rp = h->sh_replaces;
+
+  rp->rp_call_id = sip_word_at_word_d(&s);
+  if (!rp->rp_call_id)
+    return -1;
+  if (*s) {
+    if (msg_params_d(home, &s, &rp->rp_params) == -1)
+      return -1;
+    msg_header_update_params(rp->rp_common, 0);
+  }
+
+  return s - rp->rp_call_id;
+}
+
+/** Encode (print) @Replaces header */
+issize_t sip_replaces_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  sip_replaces_t const *rp = h->sh_replaces;
+
+  assert(sip_is_replaces(h));
+  MSG_STRING_E(b, end, rp->rp_call_id);
+  MSG_PARAMS_E(b, end, rp->rp_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra storage used by @Replaces header field */
+isize_t sip_replaces_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_replaces_t const *rp = h->sh_replaces;
+
+  MSG_PARAMS_SIZE(offset, rp->rp_params);
+  offset += MSG_STRING_SIZE(rp->rp_call_id);
+
+  return offset;
+}
+
+/** Duplicate a @Replaces header field */
+char *sip_replaces_dup_one(sip_header_t *dst, sip_header_t const *src,
+			   char *b, isize_t xtra)
+{
+  sip_replaces_t *rp_dst = dst->sh_replaces;
+  sip_replaces_t const *rp_src = src->sh_replaces;
+
+  char *end = b + xtra;
+
+  b = msg_params_dup(&rp_dst->rp_params, rp_src->rp_params, b, xtra);
+  MSG_STRING_DUP(b, rp_dst->rp_call_id, rp_src->rp_call_id);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameters in @Replaces header. */
+static int sip_replaces_update(msg_common_t *h, 
+			       char const *name, isize_t namelen,
+			       char const *value)
+{
+  sip_replaces_t *rp = (sip_replaces_t *)h;
+
+  if (name == NULL) {
+    rp->rp_to_tag = NULL;
+    rp->rp_from_tag = NULL;
+    rp->rp_early_only = 0;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+  else if (MATCH(to-tag)) {
+    rp->rp_to_tag = value;
+  }
+  else if (MATCH(from-tag)) {
+    rp->rp_from_tag = value;
+  }
+  else if (MATCH(early-only)) {
+    rp->rp_early_only = value != NULL;
+  }
+
+#undef MATCH
+
+  return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_refer_sub Refer-Sub Header
+ *
+ * SIP header field @b Refer-Sub is meaningful and MAY be used with a REFER
+ * request and the corresponding 2XX response only. This header field set to
+ * "false" specifies that a REFER-Issuer requests that the REFER-Recipient
+ * doesn't establish an implicit subscription and the resultant dialog.
+ *
+ *  Refer-Sub       = "Refer-Sub" HCOLON refer-sub-value *(SEMI exten)
+ *  refer-sub-value = "true" / "false"
+ *  exten           = generic-param
+ *
+ * The parsed Refer-Sub header is stored in #sip_refer_sub_t structure.
+ * 
+ * @NEW_1_12_5. Note that #sip_t does not contain @a sip_refer_sub field,
+ * but sip_refer_sub() accessor function should be used for accessing @b
+ * Refer-Sub header structure.
+ *
+ * @sa @RFC4488, nua_refer(), #nua_i_refer
+ */
+
+/**@ingroup sip_refer_sub
+ *
+ * @typedef typedef struct sip_refer_sub_s sip_refer_sub_t;
+ *
+ * The structure #sip_refer_sub_t contains representation of @ReferSub
+ * header.
+ *
+ * The #sip_refer_sub_t is defined as follows:
+ * @code
+ * typedef struct sip_refer_sub_s
+ * {
+ *   sip_common_t        rs_common[1];   // Common fragment info
+ *   sip_error_t        *rs_next;	 // Dummy link to next
+ *   char const         *rs_value;       // "true" or "false"
+ *   msg_param_t const  *rs_params;      // List of extension parameters 
+ * } sip_refer_sub_t;
+ * @endcode
+ * 
+ * @NEW_1_12_5.
+ */
+
+static msg_xtra_f sip_refer_sub_dup_xtra;
+static msg_dup_f sip_refer_sub_dup_one;
+#define sip_refer_sub_update NULL
+
+msg_hclass_t sip_refer_sub_class[] =
+SIP_HEADER_CLASS(refer_sub, "Refer-Sub", "", rs_params, single, refer_sub);
+
+/** Decode (parse) @ReferSub header */
+issize_t sip_refer_sub_d(su_home_t *home,
+			 sip_header_t *h,
+			 char *s, isize_t slen)
+{
+  sip_refer_sub_t *rs = (sip_refer_sub_t *)h;
+
+  if (msg_token_d(&s, &rs->rs_value) < 0)
+    return -1;
+
+  if (strcasecmp(rs->rs_value, "false") && 
+      strcasecmp(rs->rs_value, "true"))
+    return -1;
+
+  if (*s)
+    if (msg_params_d(home, &s, &rs->rs_params) == -1)
+      return -1;
+
+  return s - rs->rs_value;
+}
+
+/** Encode (print) @ReferSub header */
+issize_t sip_refer_sub_e(char b[], isize_t bsiz,
+			 sip_header_t const *h,
+			 int flags)
+{
+  char *b0 = b, *end = b + bsiz;
+  sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
+
+  assert(sip_is_refer_sub(h));
+  MSG_STRING_E(b, end, rs->rs_value);
+  MSG_PARAMS_E(b, end, rs->rs_params, flags);
+  MSG_TERM_E(b, end);
+
+  return b - b0;
+}
+
+/** Calculate extra storage used by @ReferSub header field */
+isize_t sip_refer_sub_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
+
+  MSG_PARAMS_SIZE(offset, rs->rs_params);
+  offset += MSG_STRING_SIZE(rs->rs_value);
+
+  return offset;
+}
+
+/** Duplicate a @ReferSub header field */
+char *sip_refer_sub_dup_one(sip_header_t *dst, sip_header_t const *src,
+			   char *b, isize_t xtra)
+{
+  sip_refer_sub_t *rs_dst = (sip_refer_sub_t *)dst;
+  sip_refer_sub_t const *rs_src = (sip_refer_sub_t *)src;
+
+  char *end = b + xtra;
+
+  b = msg_params_dup(&rs_dst->rs_params, rs_src->rs_params, b, xtra);
+  MSG_STRING_DUP(b, rs_dst->rs_value, rs_src->rs_value);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,841 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_security.c
+ *
+ * Security-related SIP header handling.
+ *
+ * This file contains implementation of headers related to HTTP authentication
+ * (@RFC2617):
+ * @ref sip_authorization "Authorization", 
+ * @ref sip_authentication_info "Authentication-Info",
+ * @ref sip_proxy_authenticate "Proxy-Authenticate",
+ * @ref sip_proxy_authentication_info "Proxy-Authentication-Info",
+ * @ref sip_proxy_authorization "Proxy-Authorization", and
+ * @ref sip_www_authenticate "WWW-Authenticate".
+ *
+ * There is also implementation of headers related to security agreement
+ * (@RFC3329):
+ * @ref sip_security_client "Security-Client",
+ * @ref sip_security_server "Security-Server", and
+ * @ref sip_security_verify "Security-Verify" headers.
+ *
+ * The implementation of @ref sip_privacy "Privacy" header (@RFC3323) is
+ * also here. 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_authorization Authorization Header
+ *
+ * The Authorization header consists of credentials containing the
+ * authentication information of the user agent for the realm of the
+ * resource being requested. Its syntax is defined in @RFC2617 and @RFC3261
+ * as follows:
+ *
+ * @code
+ *    Authorization     =  "Authorization" HCOLON credentials
+ *    credentials       =  ("Digest" LWS digest-response)
+ *                         / other-response
+ *    digest-response   =  dig-resp *(COMMA dig-resp)
+ *    dig-resp          =  username / realm / nonce / digest-uri
+ *                          / dresponse / algorithm / cnonce
+ *                          / opaque / message-qop
+ *                          / nonce-count / auth-param
+ *    username          =  "username" EQUAL username-value
+ *    username-value    =  quoted-string
+ *    digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
+ *    digest-uri-value  =  rquest-uri ; Equal to request-uri as specified
+ *                         by HTTP/1.1
+ *    message-qop       =  "qop" EQUAL qop-value
+ *    cnonce            =  "cnonce" EQUAL cnonce-value
+ *    cnonce-value      =  nonce-value
+ *    nonce-count       =  "nc" EQUAL nc-value
+ *    nc-value          =  8LHEX
+ *    dresponse         =  "response" EQUAL request-digest
+ *    request-digest    =  LDQUOT 32LHEX RDQUOT
+ *    auth-param        =  auth-param-name EQUAL
+ *                         ( token / quoted-string )
+ *    auth-param-name   =  token
+ *    other-response    =  auth-scheme LWS auth-param
+ *                         *(COMMA auth-param)
+ *    auth-scheme       =  token
+ * @endcode
+ *
+ * The parsed Authorization header
+ * is stored in #sip_authorization_t structure.
+ *
+ * @sa @RFC2617, auth_mod_verify(), auth_mod_check(), auth_get_params(),
+ * auth_digest_response_get().
+ */
+
+/**@ingroup sip_authorization
+ * @typedef typedef struct sip_authorization_s sip_authorization_t;
+ *
+ * The structure #sip_authorization_t contains representation of SIP
+ * @Authorization header.
+ *
+ * The #sip_authorization_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_s {
+ *   msg_common_t       au_common[1];  // Common fragment info 
+ *   msg_auth_t        *au_next;       // Link to next header 
+ *   char const        *au_scheme;     // Auth-scheme like "Basic" or "Digest" 
+ *   msg_param_t const *au_params;     // Comma-separated parameters
+ * } sip_authorization_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_authorization_class[] =
+SIP_HEADER_CLASS_AUTH(authorization, "Authorization", single);
+
+issize_t sip_authorization_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_authorization(h));
+  return msg_auth_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authenticate Proxy-Authenticate Header
+ *
+ * The Proxy-Authenticate header consists of a challenge that indicates the
+ * authentication scheme and parameters applicable to the proxy.  Its syntax
+ * is defined in [H14.33, S10.31] as follows:
+ *
+ * @code
+ *    Proxy-Authenticate  =  "Proxy-Authenticate" HCOLON challenge
+ *    challenge           =  ("Digest" LWS digest-cln *(COMMA digest-cln))
+ *                           / other-challenge
+ *    other-challenge     =  auth-scheme LWS auth-param
+ *                           *(COMMA auth-param)
+ *    digest-cln          =  realm / domain / nonce
+ *                            / opaque / stale / algorithm
+ *                            / qop-options / auth-param
+ *    realm               =  "realm" EQUAL realm-value
+ *    realm-value         =  quoted-string
+ *    domain              =  "domain" EQUAL LDQUOT URI
+ *                           *( 1*SP URI ) RDQUOT
+ *    URI                 =  absoluteURI / abs-path
+ *    nonce               =  "nonce" EQUAL nonce-value
+ *    nonce-value         =  quoted-string
+ *    opaque              =  "opaque" EQUAL quoted-string
+ *    stale               =  "stale" EQUAL ( "true" / "false" )
+ *    algorithm           =  "algorithm" EQUAL ( "MD5" / "MD5-sess"
+ *                           / token )
+ *    qop-options         =  "qop" EQUAL LDQUOT qop-value
+ *                           *("," qop-value) RDQUOT
+ *    qop-value           =  "auth" / "auth-int" / token
+ * @endcode
+ *
+ *
+ * The parsed Proxy-Authenticate header
+ * is stored in #sip_proxy_authenticate_t structure.
+ */
+
+/**@ingroup sip_proxy_authenticate
+ * @typedef typedef struct sip_proxy_authenticate_s sip_proxy_authenticate_t;
+ *
+ * The structure #sip_proxy_authenticate_t contains representation of SIP
+ * @ProxyAuthenticate header.
+ *
+ * The #sip_proxy_authenticate_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_s {
+ *   msg_common_t       au_common[1];  // Common fragment info 
+ *   msg_auth_t        *au_next;       // Link to next header 
+ *   char const        *au_scheme;     // Auth-scheme like "Basic" or "Digest" 
+ *   msg_param_t const *au_params;     // Comma-separated parameters
+ * } sip_proxy_authenticate_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_proxy_authenticate_class[] =
+SIP_HEADER_CLASS_AUTH(proxy_authenticate, "Proxy-Authenticate", append);
+
+issize_t sip_proxy_authenticate_d(su_home_t *home, sip_header_t *h,
+				  char *s, isize_t slen)
+{
+  return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_proxy_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_proxy_authenticate(h));
+  return msg_auth_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authorization Proxy-Authorization Header
+ *
+ * The Proxy-Authorization header consists of credentials containing the
+ * authentication information of the user agent for the proxy and/or realm
+ * of the resource being requested.  Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ *    Proxy-Authorization  = "Proxy-Authorization" ":" credentials
+ *    credentials          =  ("Digest" LWS digest-response)
+ *                            / other-response
+ * @endcode
+ *
+ * @sa auth_mod_verify(), auth_mod_check(), auth_get_params(),
+ * auth_digest_response_get().
+ *
+ * The parsed Proxy-Authorization header
+ * is stored in #sip_proxy_authorization_t structure.
+ */
+
+/**@ingroup sip_proxy_authorization
+ * @typedef typedef struct sip_proxy_authorization_s sip_proxy_authorization_t;
+ *
+ * The structure #sip_proxy_authorization_t contains representation of SIP
+ * @ProxyAuthorization header.
+ *
+ * The #sip_proxy_authorization_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_s {
+ *   msg_common_t       au_common[1];  // Common fragment info 
+ *   msg_auth_t        *au_next;       // Link to next header 
+ *   char const        *au_scheme;     // Auth-scheme like "Basic" or "Digest" 
+ *   msg_param_t const *au_params;     // Comma-separated parameters
+ * } sip_proxy_authorization_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_proxy_authorization_class[] =
+SIP_HEADER_CLASS_AUTH(proxy_authorization, "Proxy-Authorization", append);
+
+issize_t sip_proxy_authorization_d(su_home_t *home, sip_header_t *h,
+				   char *s, isize_t slen)
+{
+  return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_proxy_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_proxy_authorization(h));
+  return msg_auth_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_www_authenticate WWW-Authenticate Header
+ *
+ * The WWW-Authenticate header consists of at least one challenge that
+ * indicates the authentication scheme(s) and parameters applicable to the
+ * Request-URI.  Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ *    WWW-Authenticate  = "WWW-Authenticate" HCOLON challenge
+ *    challenge         =  ("Digest" LWS digest-cln *(COMMA digest-cln))
+ *                      / other-challenge
+ *    other-challenge   =  auth-scheme LWS auth-param *(COMMA auth-param)
+ * @endcode
+ *
+ * See @ProxyAuthenticate for the definition of \<digest-cln\>.
+ *
+ * The parsed WWW-Authenticate header
+ * is stored in #sip_www_authenticate_t structure.
+ */
+
+/**@ingroup sip_www_authenticate
+ * @typedef typedef struct sip_www_authenticate_s sip_www_authenticate_t;
+ *
+ * The structure #sip_www_authenticate_t contains representation of SIP
+ * @WWWAuthenticate header.
+ *
+ * The #sip_www_authenticate_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_s {
+ *   msg_common_t       au_common[1];  // Common fragment info 
+ *   msg_auth_t        *au_next;       // Link to next header 
+ *   char const        *au_scheme;     // Auth-scheme like "Basic" or "Digest" 
+ *   msg_param_t const *au_params;     // Comma-separated parameters
+ * } sip_www_authenticate_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_www_authenticate_class[] =
+SIP_HEADER_CLASS_AUTH(www_authenticate, "WWW-Authenticate", single);
+
+issize_t sip_www_authenticate_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_www_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_www_authenticate(h));
+  return msg_auth_e(b, bsiz, h, f);
+}
+
+/**@SIP_HEADER sip_authentication_info Authentication-Info Header
+ *
+ * The @b Authentication-Info header contains either a next-nonce used by
+ * next request and/or authentication from server used in mutual
+ * authentication. The syntax of @b Authentication-Info header is defined in
+ * @RFC2617 and @RFC3261 as follows:
+ *
+ * @code
+ *   Authentication-Info  = "Authentication-Info" HCOLON ainfo
+ *                           *(COMMA ainfo)
+ *   ainfo                =  nextnonce / message-qop
+ *                            / response-auth / cnonce
+ *                            / nonce-count
+ *   nextnonce            =  "nextnonce" EQUAL nonce-value
+ *   response-auth        =  "rspauth" EQUAL response-digest
+ *   response-digest      =  LDQUOT *LHEX RDQUOT
+ * @endcode
+ *
+ * The parsed Authentication-Info header
+ * is stored in #sip_authentication_info_t structure.
+ */
+
+/**@ingroup sip_authentication_info
+ * @typedef typedef struct sip_authentication_info_s sip_authentication_info_t;
+ *
+ * The structure #sip_authentication_info_t contains representation of SIP
+ * @AuthenticationInfo header.
+ *
+ * The #sip_authentication_info_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_info_s
+ * {
+ *   msg_common_t       ai_common[1];  // Common fragment info
+ *   msg_error_t       *ai_next;       // Dummy link to next header
+ *   msg_param_t       *ai_items;      // List of ainfo
+ * } sip_authentication_info_t;
+ * @endcode
+ */
+
+#define sip_authentication_info_dup_xtra msg_list_dup_xtra
+#define sip_authentication_info_dup_one msg_list_dup_one
+#define sip_authentication_info_update NULL
+
+msg_hclass_t sip_authentication_info_class[] =
+  SIP_HEADER_CLASS(authentication_info, "Authentication-Info", "",
+		   ai_params, append, authentication_info);
+
+issize_t sip_authentication_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return msg_list_d(home, (msg_header_t *)h, s, slen);
+}
+
+
+issize_t sip_authentication_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  assert(sip_is_authentication_info(h));
+  return msg_list_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authentication_info Proxy-Authentication-Info Header
+ *
+ * The @b Proxy-Authentication-Info header contains either a next-nonce used
+ * by next request and/or authentication from proxy used in mutual
+ * authentication. The syntax of @b Proxy-Authentication-Info header is defined
+ * in @RFC2617 as follows:
+ *
+ * @code
+ *   Proxy-Authentication-Info  = "Proxy-Authentication-Info" HCOLON ainfo
+ *                           *(COMMA ainfo)
+ *   ainfo                =  nextnonce / message-qop
+ *                            / response-auth / cnonce
+ *                            / nonce-count
+ *   nextnonce            =  "nextnonce" EQUAL nonce-value
+ *   response-auth        =  "rspauth" EQUAL response-digest
+ *   response-digest      =  LDQUOT *LHEX RDQUOT
+ * @endcode
+ *
+ * @note @b Proxy-Authentication-Info is not specified @RFC3261 and it is
+ * mentioned by @RFC2617 but in passage.
+ *
+ * The parsed Proxy-Authentication-Info header
+ * is stored in #sip_proxy_authentication_info_t structure.
+ */
+
+/**@ingroup sip_proxy_authentication_info
+ * @typedef typedef struct msg_authentication_info_s sip_proxy_authentication_info_t;
+ *
+ * The structure #sip_proxy_authentication_info_t contains representation of SIP
+ * @ProxyAuthenticationInfo header.
+ *
+ * The #sip_proxy_authentication_info_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_info_s
+ * {
+ *   msg_common_t       ai_common[1];  // Common fragment info
+ *   msg_error_t       *ai_next;       // Dummy link to next header
+ *   msg_param_t       *ai_items;      // List of ainfo
+ * } sip_proxy_authentication_info_t;
+ * @endcode
+ *
+ */
+
+#define sip_proxy_authentication_info_dup_xtra msg_list_dup_xtra
+#define sip_proxy_authentication_info_dup_one msg_list_dup_one
+#define sip_proxy_authentication_info_update NULL
+
+msg_hclass_t sip_proxy_authentication_info_class[] =
+  SIP_HEADER_CLASS(proxy_authentication_info, "Proxy-Authentication-Info", "",
+		   ai_params, append, proxy_authentication_info);
+
+issize_t sip_proxy_authentication_info_d(su_home_t *home, sip_header_t *h,
+					 char *s, isize_t slen)
+{
+  return msg_list_d(home, (msg_header_t *)h, s, slen);
+}
+
+issize_t sip_proxy_authentication_info_e(char b[], isize_t bsiz, 
+					 sip_header_t const *h, int f)
+{
+  assert(sip_is_proxy_authentication_info(h)); /* This is soo popular */
+  return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/* Functions parsing @RFC3329 SIP Security Agreement headers */
+
+typedef struct sip_security_agree_s sip_security_agree_t;
+#define sh_security_agree sh_security_client
+
+static 
+issize_t sip_security_agree_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_security_agree_t *sa = (sip_security_agree_t *)h;
+
+  isize_t n;
+
+  while (*s == ',')   /* Ignore empty entries (comma-whitespace) */
+    *s = '\0', s += span_lws(s + 1) + 1;
+
+  if ((n = span_token(s)) == 0) 
+    return -1;
+  sa->sa_mec = s; s += n; while (IS_LWS(*s)) *s++ = '\0'; 
+  if (*s == ';' && msg_params_d(home, &s, &sa->sa_params) < 0)
+    return -1;
+
+  return msg_parse_next_field(home, h, s, slen);
+}
+
+static 
+issize_t sip_security_agree_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  char *end = b + bsiz, *b0 = b;
+  sip_security_agree_t const *sa = (sip_security_agree_t const *)h;
+
+  MSG_STRING_E(b, end, sa->sa_mec);
+  MSG_PARAMS_E(b, end, sa->sa_params, flags);
+
+  return b - b0;
+}
+
+static 
+isize_t sip_security_agree_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_security_agree_t const *sa = h->sh_security_agree;
+
+  MSG_PARAMS_SIZE(offset, sa->sa_params);
+  offset += MSG_STRING_SIZE(sa->sa_mec);
+
+  return offset;
+}
+
+/** Duplicate one sip_security_agree_t object */ 
+static 
+char *sip_security_agree_dup_one(sip_header_t *dst, sip_header_t const *src,
+				 char *b, isize_t xtra)
+{
+  sip_security_agree_t *sa_dst = dst->sh_security_agree;
+  sip_security_agree_t const *sa_src = src->sh_security_agree;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&sa_dst->sa_params, sa_src->sa_params, b, xtra);
+  MSG_STRING_DUP(b, sa_dst->sa_mec, sa_src->sa_mec);
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+static int sip_security_agree_update(msg_common_t *h, 
+				     char const *name, isize_t namelen,
+				     char const *value)
+{
+  sip_security_agree_t *sa = (sip_security_agree_t *)h;
+
+  if (name == NULL) {
+    sa->sa_q = NULL;
+    sa->sa_d_alg = NULL;
+    sa->sa_d_qop = NULL;
+    sa->sa_d_ver = NULL;
+  }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+  else if (MATCH(q)) {
+    sa->sa_q = value;
+  }
+  else if (MATCH(d-alg)) {
+    sa->sa_d_alg = value;
+  }
+  else if (MATCH(d-qop)) {
+    sa->sa_d_qop = value;
+  }
+  else if (MATCH(d-ver)) {
+    sa->sa_d_ver = value;
+  }
+
+#undef MATCH
+
+  return 0;
+}
+
+
+/**@SIP_HEADER sip_security_client Security-Client Header
+ *
+ * The Security-Client header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @code
+ *    security-client  = "Security-Client" HCOLON
+ *                       sec-mechanism *(COMMA sec-mechanism)
+ *    security-server  = "Security-Server" HCOLON
+ *                       sec-mechanism *(COMMA sec-mechanism)
+ *    security-verify  = "Security-Verify" HCOLON
+ *                       sec-mechanism *(COMMA sec-mechanism)
+ *    sec-mechanism    = mechanism-name *(SEMI mech-parameters)
+ *    mechanism-name   = ( "digest" / "tls" / "ipsec-ike" /
+ *                        "ipsec-man" / token )
+ *    mech-parameters  = ( preference / digest-algorithm /
+ *                         digest-qop / digest-verify / extension )
+ *    preference       = "q" EQUAL qvalue
+ *    qvalue           = ( "0" [ "." 0*3DIGIT ] )
+ *                        / ( "1" [ "." 0*3("0") ] )
+ *    digest-algorithm = "d-alg" EQUAL token
+ *    digest-qop       = "d-qop" EQUAL token
+ *    digest-verify    = "d-ver" EQUAL LDQUOT 32LHEX RDQUOT
+ *    extension        = generic-param
+ * @endcode
+ *
+ * @sa @SecurityServer, @SecurityVerify, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329
+ *
+ * The parsed Security-Client header
+ * is stored in #sip_security_client_t structure.
+ */
+
+/**@ingroup sip_security_client
+ * @typedef typedef struct sip_security_client_s sip_security_client_t;
+ *
+ * The structure #sip_security_client_t contains representation of SIP
+ * @SecurityClient header.
+ *
+ * The #sip_security_client_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ *   sip_common_t        sa_common[1]; // Common fragment info 
+ *   sip_security_client_t *sa_next;   // Link to next mechanism 
+ *   char const         *sa_mec;       // Security mechanism
+ *   msg_param_t const  *sa_params;    // List of mechanism parameters
+ *   char const         *sa_q;         // Value of q (preference) parameter
+ *   char const         *sa_d_alg;     // Value of d-alg parameter
+ *   char const         *sa_d_qop;     // Value of d-qop parameter
+ *   char const         *sa_d_ver;     // Value of d-ver parameter
+ * } sip_security_client_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_security_client_class[] = 
+SIP_HEADER_CLASS(security_client, "Security-Client", "", 
+		 sa_params, append, security_agree);
+
+issize_t sip_security_client_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_client_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return sip_security_agree_e(b, bsiz, h, f);
+}
+
+
+/**@SIP_HEADER sip_security_server Security-Server Header
+ *
+ * The Security-Server header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @sa @SecurityClient, @SecurityVerify, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329.
+ *
+ * The parsed Security-Server header
+ * is stored in #sip_security_server_t structure.
+ */
+
+/**@ingroup sip_security_server
+ * @typedef typedef struct sip_security_server_s sip_security_server_t;
+ *
+ * The structure #sip_security_server_t contains representation of SIP
+ * @SecurityServer header.
+ *
+ * The #sip_security_server_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ *   sip_common_t        sa_common[1]; // Common fragment info 
+ *   sip_security_server_t *sa_next;   // Link to next mechanism 
+ *   char const         *sa_mec;       // Security mechanism
+ *   msg_param_t const  *sa_params;    // List of mechanism parameters
+ *   char const         *sa_q;         // Value of q (preference) parameter
+ *   char const         *sa_d_alg;     // Value of d-alg parameter
+ *   char const         *sa_d_qop;     // Value of d-qop parameter
+ *   char const         *sa_d_ver;     // Value of d-ver parameter
+ * } sip_security_server_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_security_server_class[] = 
+SIP_HEADER_CLASS(security_server, "Security-Server", "", 
+		 sa_params, append, security_agree);
+
+issize_t sip_security_server_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_server_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return sip_security_agree_e(b, bsiz, h, f);
+}
+
+
+/**@SIP_HEADER sip_security_verify Security-Verify Header
+ *
+ * The Security-Verify header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @sa @SecurityClient, @SecurityServer, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329.
+ *
+ * The parsed Security-Verify header
+ * is stored in #sip_security_verify_t structure.
+ */
+
+/**@ingroup sip_security_verify
+ * @typedef typedef struct sip_security_verify_s sip_security_verify_t;
+ *
+ * The structure #sip_security_verify_t contains representation of SIP
+ * @SecurityVerify header.
+ *
+ * The #sip_security_verify_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ *   sip_common_t        sa_common[1]; // Common fragment info 
+ *   sip_security_verify_t *sa_next;   // Link to next mechanism 
+ *   char const         *sa_mec;       // Security mechanism
+ *   msg_param_t const  *sa_params;    // List of mechanism parameters
+ *   char const         *sa_q;         // Value of q (preference) parameter
+ *   char const         *sa_d_alg;     // Value of d-alg parameter
+ *   char const         *sa_d_qop;     // Value of d-qop parameter
+ *   char const         *sa_d_ver;     // Value of d-ver parameter
+ * } sip_security_verify_t;
+ * @endcode
+ */
+
+
+msg_hclass_t sip_security_verify_class[] = 
+SIP_HEADER_CLASS(security_verify, "Security-Verify", "", 
+		 sa_params, append, security_agree);
+
+issize_t sip_security_verify_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_verify_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  return sip_security_agree_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+/* RFC 3323 */
+
+/**@SIP_HEADER sip_privacy Privacy Header
+ * 
+ * The Privacy header is used by User-Agent to request privacy services from
+ * the network. Its syntax is defined in @RFC3323 as follows:
+ * 
+ * @code
+ *    Privacy-hdr  =  "Privacy" HCOLON priv-value *(";" priv-value)
+ *    priv-value   =   "header" / "session" / "user" / "none" / "critical"
+ *                     / token
+ * @endcode
+ *
+ * The parsed Privacy header is stored in #sip_privacy_t structure.
+ */
+
+/**@ingroup sip_privacy
+ * @typedef typedef struct sip_privacy_s sip_privacy_t;
+ *
+ * The structure #sip_privacy_t contains representation of a SIP @Privacy
+ * header.
+ *
+ * The #sip_privacy_t is defined as follows:
+ * @code
+ * typedef struct sip_privacy_s {
+ *   sip_common_t       priv_common[1];	// Common fragment info 
+ *   sip_error_t       *priv_next;     	// Dummy link 
+ *   msg_param_t const *priv_values;   	// List of privacy values 
+ * } sip_privacy_t;
+ * @endcode
+ */
+
+msg_xtra_f sip_privacy_dup_xtra;
+msg_dup_f sip_privacy_dup_one;
+
+#define sip_privacy_update NULL
+
+msg_hclass_t sip_privacy_class[] = 
+SIP_HEADER_CLASS(privacy, "Privacy", "", priv_values, single, privacy);
+
+static 
+issize_t sip_privacy_token_scan(char *start)
+{
+  char *s = start;
+  skip_token(&s);
+
+  if (s == start)
+    return -1;
+
+  if (IS_LWS(*s))
+    *s++ = '\0';
+  skip_lws(&s);
+
+  return s - start;
+}
+
+issize_t sip_privacy_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_privacy_t *priv = (sip_privacy_t *)h;
+
+  while (*s == ';' || *s == ',') {
+    s++;
+    skip_lws(&s);
+  }
+
+  for (;;) {
+    if (msg_any_list_d(home, &s, (msg_param_t **)&priv->priv_values,
+		       sip_privacy_token_scan, ';') < 0)
+      return -1;
+
+    if (*s == '\0')
+      return 0;			/* Success! */
+
+    if (*s == ',')
+      *s++ = '\0';		/* We accept comma-separated list, too */
+    else if (IS_TOKEN(*s))
+      ;				/* LWS separated list...  */
+    else
+      return -1;
+  }
+}
+
+issize_t sip_privacy_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+  sip_privacy_t const *priv = h->sh_privacy;
+  char *b0 = b, *end = b + bsiz;
+  size_t i;
+
+  if (priv->priv_values) {
+    for (i = 0; priv->priv_values[i]; i++) {
+      if (i > 0) MSG_CHAR_E(b, end, ';');
+      MSG_STRING_E(b, end, priv->priv_values[i]);
+    }
+  }
+
+  MSG_TERM_E(b, end);
+    
+  return b - b0;
+}
+
+isize_t sip_privacy_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_privacy_t const *priv = h->sh_privacy;
+
+  MSG_PARAMS_SIZE(offset, priv->priv_values);
+
+  return offset;
+}
+
+char *sip_privacy_dup_one(sip_header_t *dst,
+			  sip_header_t const *src,
+			  char *b,
+			  isize_t xtra)
+{
+  sip_privacy_t *priv = dst->sh_privacy;
+  sip_privacy_t const *o = src->sh_privacy;
+  char *end = b + xtra;
+
+  b = msg_params_dup(&priv->priv_values, o->priv_values, b, xtra);
+
+  assert(b <= end); (void)end;
+
+  return b;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_session.c
+ * @brief Session Timer SIP headers.
+ *
+ * The file @b sip_session.c contains implementation of header classes for
+ * session-timer-related SIP headers @SessionExpires and @MinSE.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/msg_date.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_session_expires Session-Expires Header
+ *
+ * The Session-Expires header is used to convey the lifetime of the session. 
+ * Its syntax is defined in @RFC4028 as follows:
+ * 
+ * @code
+ *      Session-Expires  =  ("Session-Expires" | "x") HCOLON delta-seconds
+ *                           *(SEMI se-params)
+ *      se-params        = refresher-param / generic-param
+ *      refresher-param  = "refresher" EQUAL  ("uas" / "uac")
+ * @endcode
+ *
+ * The parsed Session-Expires header is stored in #sip_session_expires_t structure.
+ */
+
+/**@ingroup sip_session_expires
+ * @typedef typedef struct sip_session_expires_s sip_session_expires_t;
+ *
+ * The structure #sip_session_expires_t contains representation of the SIP
+ * @SessionExpires header.
+ *
+ * The #sip_session_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_session_expires_s
+ * {
+ *  sip_common_t    x_common[1];
+ *  sip_unknown_t  *x_next;
+ *  unsigned long   x_delta; //Delta Seconds
+ *  msg_param_t    *x_params; 
+ *  char const     *x_refresher; //Who will send the refresh UAS or UAC
+ * } sip_session_expires_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_session_expires_dup_xtra;
+static msg_dup_f sip_session_expires_dup_one;
+static msg_update_f sip_session_expires_update;
+
+msg_hclass_t sip_session_expires_class[] =
+SIP_HEADER_CLASS(session_expires, "Session-Expires", "x", x_params, single, 
+		 session_expires);
+
+issize_t sip_session_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_session_expires_t *x = h->sh_session_expires;
+
+  if (msg_delta_d((char const **) &s, &x->x_delta) < 0)
+    return -1;
+  if (*s == ';') {
+    if (msg_params_d(home, &s, &x->x_params) < 0 || *s)
+      return -1;
+     x->x_refresher = msg_params_find(x->x_params, "refresher");
+  }
+  return 0;
+}
+
+issize_t sip_session_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *end = b + bsiz, *b0 = b;
+  int n = 0;
+  sip_session_expires_t const *o = h->sh_session_expires;
+
+  n = snprintf(b, bsiz, "%lu", o->x_delta);
+  b += n; 
+  MSG_PARAMS_E(b, end, o->x_params, flags);
+
+  return b - b0;
+}
+
+isize_t sip_session_expires_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_session_expires_t const *o = h->sh_session_expires;
+
+  MSG_PARAMS_SIZE(offset, o->x_params);
+   
+  return offset;
+}
+
+/** Duplicate one #sip_session_expires_t object */ 
+char *sip_session_expires_dup_one(sip_header_t *dst, sip_header_t const *src,
+				  char *b, isize_t xtra)
+{
+  sip_session_expires_t *o_dst = dst->sh_session_expires;
+  sip_session_expires_t const *o_src = src->sh_session_expires;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&o_dst->x_params, o_src->x_params, b, xtra);
+  o_dst->x_delta = o_src->x_delta;
+  assert(b <= end); (void)end;
+
+  return b;
+}
+
+/** Update parameters in @SessionExpires header. */
+static int sip_session_expires_update(msg_common_t *h, 
+				      char const *name, isize_t namelen,
+				      char const *value)
+{
+  sip_session_expires_t *x = (sip_session_expires_t *)h;
+
+  if (name == NULL) {
+    x->x_refresher = NULL;
+  }
+  else if (namelen == strlen("refresher") && 
+	   !strncasecmp(name, "refresher", namelen)) {
+    x->x_refresher = value;
+  }
+
+  return 0;
+}
+
+
+
+/**@SIP_HEADER sip_min_se Min-SE Header
+ *
+ * The Min-SE header is used to indicate the minimum value for the session
+ * interval. Its syntax is defined in @RFC4028 as follows:
+ * 
+ * @code
+ *      MMin-SE  =  "Min-SE" HCOLON delta-seconds *(SEMI generic-param)
+ * @endcode
+ *
+ * The parsed Min-SE header is stored in #sip_min_se_t structure.
+ */
+
+/**@ingroup sip_min_se
+ * @typedef typedef struct sip_min_se_s sip_min_se_t;
+ *
+ * The structure #sip_min_se_t contains representation of the SIP
+ * @MinSE header.
+ *
+ * The #sip_min_se_t is defined as follows:
+ * @code
+ * typedef struct sip_min_se_s
+ * {
+ *   sip_common_t    min_common[1];
+ *   sip_unknown_t  *min_next;
+ *   unsigned long   min_delta;   // Delta seconds
+ *   sip_params_t   *min_params;  // List of extension parameters
+ * } sip_min_se_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_min_se_dup_xtra;
+static msg_dup_f sip_min_se_dup_one;
+#define sip_min_se_update NULL
+
+msg_hclass_t sip_min_se_class[] =
+SIP_HEADER_CLASS(min_se, "Min-SE", "", min_params, single, min_se);
+
+issize_t sip_min_se_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  sip_min_se_t *min = h->sh_min_se;
+
+  if (msg_delta_d((char const **) &s, &min->min_delta) < 0)
+    return -1;
+  if (*s == ';') {
+    if (msg_params_d(home, &s, &min->min_params) < 0 || *s)
+      return -1;
+  }
+
+  return 0;
+}
+
+issize_t sip_min_se_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+  char *end = b + bsiz, *b0 = b;
+  int n = 0;
+  sip_min_se_t const *o = (sip_min_se_t *)h;
+
+  n = snprintf(b, bsiz, "%lu", o->min_delta);
+  b += n; 
+  MSG_PARAMS_E(b, end, o->min_params, flags);
+
+  return b - b0;
+}
+
+isize_t sip_min_se_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+  sip_min_se_t const *o = (sip_min_se_t *)h;
+
+  MSG_PARAMS_SIZE(offset, o->min_params);
+   
+  return offset;
+}
+
+/** Duplicate one #sip_min_se_t object */ 
+char *sip_min_se_dup_one(sip_header_t *dst, sip_header_t const *src,
+			char *b, isize_t xtra)
+{
+  sip_min_se_t *o_dst = (sip_min_se_t *)dst;
+  sip_min_se_t const *o_src = (sip_min_se_t *)src;
+
+  char *end = b + xtra;
+  b = msg_params_dup(&o_dst->min_params, o_src->min_params, b, xtra);
+  o_dst->min_delta = o_src->min_delta;
+  assert(b <= end); (void)end;
+
+  return b;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_status_codes
+ * @CFILE sip_status.c
+ * 
+ * SIP status codes and standard phrases.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date  Created: Fri Aug 11 18:03:33 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <sofia-sip/sip_status.h>
+
+char const 
+  sip_100_Trying[] =                   "Trying",
+  sip_180_Ringing[] =                  "Ringing",
+  sip_181_Call_is_being_forwarded[] =  "Call Is Being Forwarded",
+  sip_182_Queued[] =                   "Queued",
+  sip_183_Session_progress[] =         "Session Progress",
+  
+  sip_200_OK[] =                       "OK",
+  sip_202_Accepted[] =                 "Accepted",
+  
+  sip_300_Multiple_choices[] =         "Multiple Choices",
+  sip_301_Moved_permanently[] =        "Moved Permanently",
+  sip_302_Moved_temporarily[] =        "Moved Temporarily",
+  sip_305_Use_proxy[] =                "Use Proxy",
+  sip_380_Alternative_service[] =      "Alternative Service",
+  
+  sip_400_Bad_request[] =              "Bad Request",
+  sip_401_Unauthorized[] =             "Unauthorized",
+  sip_402_Payment_required[] =         "Payment Required",
+  sip_403_Forbidden[] =                "Forbidden",
+  sip_404_Not_found[] =                "Not Found",
+  sip_405_Method_not_allowed[] =       "Method Not Allowed",
+  sip_406_Not_acceptable[] =           "Not Acceptable",
+  sip_407_Proxy_auth_required[] =      "Proxy Authentication Required",
+  sip_408_Request_timeout[] =          "Request Timeout",
+  sip_409_Conflict[] =                 "Conflict",
+  sip_410_Gone[] =                     "Gone",
+  sip_411_Length_required[] =          "Length Required",
+  sip_412_Precondition_failed[] =      "Precondition Failed",
+  sip_413_Request_too_large[] =        "Request Entity Too Large",
+  sip_414_Request_uri_too_long[] =     "Request-URI Too Long",
+  sip_415_Unsupported_media[] =        "Unsupported Media Type",
+  sip_416_Unsupported_uri[] =          "Unsupported URI Scheme",
+  sip_417_Resource_priority[]=         "Unknown Resource-Priority",
+  sip_420_Bad_extension[] =            "Bad Extension",
+  sip_421_Extension_required[] =       "Extension Required",
+  sip_422_Session_timer[] =            "Session Interval Too Small",
+  sip_423_Interval_too_brief[] =       "Interval Too Brief",
+  
+  sip_480_Temporarily_unavailable[] =  "Temporarily Unavailable",
+  sip_481_No_transaction[] =           "Call/Transaction Does Not Exist",
+  sip_482_Loop_detected[] =            "Loop Detected",
+  sip_483_Too_many_hops[] =            "Too Many Hops",
+  sip_484_Address_incomplete[] =       "Address Incomplete",
+  sip_485_Ambiguous[] =                "Ambiguous",
+  sip_486_Busy_here[] =                "Busy Here",
+  sip_487_Request_terminated[] =       "Request Terminated",
+  sip_488_Not_acceptable[] =           "Not Acceptable Here",
+  sip_489_Bad_event[] =                "Bad Event",
+  sip_490_Request_updated[] =          "Request Updated",
+  sip_491_Request_pending[] =          "Request Pending",
+  sip_493_Undecipherable[] =           "Undecipherable",
+  sip_494_Secagree_required [] =       "Security Agreement Required",
+
+  sip_500_Internal_server_error[] =    "Internal Server Error",
+  sip_501_Not_implemented[] =          "Not Implemented",
+  sip_502_Bad_gateway[] =              "Bad Gateway",
+  sip_503_Service_unavailable[] =      "Service Unavailable",
+  sip_504_Gateway_time_out[] =         "Gateway Time-out",
+  sip_505_Version_not_supported[] =    "Version Not Supported",
+  sip_513_Message_too_large[] =        "Message Too Large",
+  sip_580_Precondition[] =             "Precondition Failure",
+
+  sip_600_Busy_everywhere[] =          "Busy Everywhere",
+  sip_603_Decline[] =                  "Decline",
+  sip_604_Does_not_exist_anywhere[] =  "Does Not Exist Anywhere",
+  sip_606_Not_acceptable[] =           "Not Acceptable",
+  sip_687_Dialog_terminated[] =        "Dialog Terminated"
+  ;
+
+/** Convert a SIP status code to a status phrase.
+ *
+ * Convert a SIP status code to a status phrase. If the status code is not
+ * in the range 100..699, NULL is returned. If the status code is not known,
+ * empty string "" is returned.
+ *
+ * @param status well-known status code in range 100..699
+ * 
+ * @return
+ * A response message corresponding to status code, or NULL upon an error.
+ */
+char const *sip_status_phrase(int status)
+{
+  if (status < 100 || status > 699) 
+    return NULL;
+
+  switch (status) {
+  case 100: return sip_100_Trying;
+  case 180: return sip_180_Ringing;
+  case 181: return sip_181_Call_is_being_forwarded;
+  case 182: return sip_182_Queued;
+  case 183: return sip_183_Session_progress;
+
+  case 200: return sip_200_OK;
+  case 202: return sip_202_Accepted;
+
+  case 300: return sip_300_Multiple_choices;
+  case 301: return sip_301_Moved_permanently;
+  case 302: return sip_302_Moved_temporarily;
+  case 305: return sip_305_Use_proxy;
+  case 380: return sip_380_Alternative_service;
+
+  case 400: return sip_400_Bad_request;
+  case 401: return sip_401_Unauthorized;
+  case 402: return sip_402_Payment_required;
+  case 403: return sip_403_Forbidden;
+  case 404: return sip_404_Not_found;
+  case 405: return sip_405_Method_not_allowed;
+  case 406: return sip_406_Not_acceptable;
+  case 407: return sip_407_Proxy_auth_required;
+  case 408: return sip_408_Request_timeout;
+  case 409: return sip_409_Conflict;
+  case 410: return sip_410_Gone;
+  case 411: return sip_411_Length_required;
+  case 412: return sip_412_Precondition_failed;
+  case 413: return sip_413_Request_too_large;
+  case 414: return sip_414_Request_uri_too_long;
+  case 415: return sip_415_Unsupported_media;
+  case 416: return sip_416_Unsupported_uri;
+  case 417: return sip_417_Resource_priority;
+
+  case 420: return sip_420_Bad_extension;
+  case 421: return sip_421_Extension_required;
+  case 422: return sip_422_Session_timer;
+  case 423: return sip_423_Interval_too_brief;
+
+  case 480: return sip_480_Temporarily_unavailable;
+  case 481: return sip_481_No_transaction;
+  case 482: return sip_482_Loop_detected;
+  case 483: return sip_483_Too_many_hops;
+  case 484: return sip_484_Address_incomplete;
+  case 485: return sip_485_Ambiguous;
+  case 486: return sip_486_Busy_here;
+  case 487: return sip_487_Request_terminated;
+  case 488: return sip_488_Not_acceptable;
+  case 489: return sip_489_Bad_event;
+  case 490: return sip_490_Request_updated;
+  case 491: return sip_491_Request_pending;
+  case 493: return sip_493_Undecipherable;
+  case 494: return sip_494_Secagree_required;
+
+  case 500: return sip_500_Internal_server_error;
+  case 501: return sip_501_Not_implemented;
+  case 502: return sip_502_Bad_gateway;
+  case 503: return sip_503_Service_unavailable;
+  case 504: return sip_504_Gateway_time_out;
+  case 505: return sip_505_Version_not_supported;
+  case 513: return sip_513_Message_too_large;
+  case 580: return sip_580_Precondition;
+
+  case 600: return sip_600_Busy_everywhere;
+  case 603: return sip_603_Decline;
+  case 604: return sip_604_Does_not_exist_anywhere;
+  case 606: return sip_606_Not_acceptable;
+  case 687: return sip_687_Dialog_terminated;
+  }
+
+  return "";
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,94 @@
+/**@IFILE sip_tag.c.in
+ *
+ * Template for <sip_tag.c>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_tag.c  SIP Tags.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+#define TAG_NAMESPACE "sip"
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_tag.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/sip_tag_class.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+tag_typedef_t siptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t siptag_sip = SIPMSGTAG_TYPEDEF(sip);
+
+tag_typedef_t siptag_header = {{ "sip", "header", siphdrtag_class, 0 }};
+
+tag_typedef_t siptag_header_str = STRTAG_TYPEDEF(header_str);
+
+tag_typedef_t siptag_end = TAG_TYPEDEF(tag_end, end);
+
+
+extern msg_hclass_t sip_#xxxxxx#_class[];
+
+/**@ingroup sip_#xxxxxx#
+ * Tag for @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" object.
+ */
+tag_typedef_t siptag_#xxxxxx# = SIPHDRTAG_TYPEDEF(#xxxxxx#);
+/**@ingroup sip_#xxxxxx#
+ * Tag for string with @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value.
+ */
+tag_typedef_t siptag_#xxxxxx#_str = SIPSTRTAG_TYPEDEF(#xxxxxx#);
+
+/** List of all tags for SIP headers */
+tag_type_t sip_tag_list[] =
+{
+  siptag_#xxxxxx#,
+  NULL
+};
+
+/** List of all string tags for SIP headers  */
+tag_type_t sip_tag_str_list[] = 
+{
+  siptag_#xxxxxx#_str,
+  NULL
+};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,476 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SIP_TAG
+ * 
+ * @CFILE sip_tag_class.c  SIP Tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/sip_parser.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+
+#include <ctype.h>
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+/** Tag class for SIP header tags. @HIDE */
+tag_class_t siphdrtag_class[1] = 
+  {{
+    sizeof(siphdrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msghdrtag_xtra,
+    /* tc_dup */      msghdrtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msghdrtag_snprintf,
+    /* tc_filter */   siptag_filter,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     msghdrtag_scan,
+  }};
+
+/** Tag class for SIP header string tags. @HIDE */
+tag_class_t sipstrtag_class[1] = 
+  {{
+    sizeof(sipstrtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     t_str_xtra,
+    /* tc_dup */      t_str_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_str_snprintf,
+    /* tc_filter */   NULL /* msgtag_str_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     t_str_scan
+  }};
+
+/** Tag class for SIP message tags. @HIDE */
+tag_class_t sipmsgtag_class[1] = 
+  {{
+    sizeof(sipmsgtag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     msgobjtag_xtra,
+    /* tc_dup */      msgobjtag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ msgobjtag_snprintf,
+    /* tc_filter */   NULL /* siptag_sip_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+  }};
+
+
+/** Filter a for SIP header tag.
+ *
+ * @param[in] dst tag list for filtering result. May be NULL.
+ * @param[in] f   filter tag 
+ * @param[in] src tag item from source list. 
+ * @param[in,out] bb pointer to pointer of mempory area used to dup 
+ *                   the filtering result
+ *
+ * This function is also used to calculate size for filtering result.
+ */
+tagi_t *siptag_filter(tagi_t *dst,
+		      tagi_t const f[],
+		      tagi_t const *src, 
+		      void **bb)
+{
+  tagi_t stub[2] = {{ NULL }};
+  tag_type_t srctt, tt = f->t_tag;
+  msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
+
+  assert(src);
+
+  srctt = src->t_tag;
+
+  /* Match filtered header with a header from a SIP message */
+  if (srctt && srctt->tt_class == sipmsgtag_class) {
+    sip_t const *sip = (sip_t const *)src->t_value;
+    sip_header_t const **hh, *h;
+
+    if (sip == NULL)
+      return dst;
+
+    hh = (sip_header_t const **)
+      msg_hclass_offset((msg_mclass_t *)sip->sip_common->h_class, 
+			(msg_pub_t *)sip, hc);
+
+    /* Is header present in the SIP message? */
+    if ((char *)hh >= ((char *)sip + sip->sip_size) ||
+	(char *)hh < (char *)&sip->sip_request)
+      return dst;
+
+    h = *hh;
+
+    if (h == NULL)
+      return dst;
+
+    stub[0].t_tag = tt;
+    stub[0].t_value = (tag_value_t)h;
+    src = stub; srctt = tt;
+  }
+
+  if (tt != srctt)
+    return dst;
+
+  if (!src->t_value)
+    return dst;
+  else if (dst) {
+    return t_dup(dst, src, bb);
+  }
+  else {
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst + 1;
+  }
+}
+
+/** Duplicate headers from taglist and add them to the SIP message. */
+int sip_add_tl(msg_t *msg, sip_t *sip,
+	       tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t const *t;
+  ta_list ta;
+  int retval;
+
+  ta_start(ta, tag, value);
+
+  t = ta_args(ta);
+
+  retval = sip_add_tagis(msg, sip, &t);
+
+  ta_end(ta);
+  return retval;
+}
+
+/** Add duplicates of headers from taglist to the SIP message. */
+int sip_add_tagis(msg_t *msg, sip_t *sip, tagi_t const **inout_list)
+{
+  tagi_t const *t;
+  tag_type_t tag;
+  tag_value_t value;
+
+  if (!msg || !inout_list)
+    return -1;
+
+  if (sip == NULL)
+    sip = sip_object(msg);
+
+  for (t = *inout_list; t; t = t_next(t)) {
+    tag = t->t_tag, value = t->t_value;
+
+    if (tag == NULL || tag == siptag_end) {
+      t = t_next(t);
+      break;
+    }
+
+    if (!value)
+      continue;
+
+    if (SIPTAG_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      msg_header_t *h = (msg_header_t *)value, **hh;
+
+      if (h == SIP_NONE) {	/* Remove header */
+	hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)sip, hc);
+	while (*hh)
+	  msg_header_remove(msg, (msg_pub_t *)sip, *hh);
+	continue;
+      } 
+
+      if (tag == siptag_header)
+	hc = h->sh_class;
+
+      if (msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, h) < 0)
+	break;
+    }
+    else if (SIPTAG_STR_P(tag)) {
+      msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+      char const *s = (char const *)value;
+      if (s && msg_header_add_make(msg, (msg_pub_t *)sip, hc, s) < 0)
+	return -1;
+    }
+    else if (tag == siptag_header_str) {
+      if (msg_header_add_str(msg, (msg_pub_t *)sip, (char const *)value) < 0)
+	return -1;
+    }
+  }
+
+  *inout_list = t;
+
+  return 0;
+}
+
+static char const *append_escaped(su_strlst_t *l,
+				  msg_hclass_t *hc,
+				  char const *s);
+
+/** Convert tagged SIP headers to a URL-encoded headers list.
+ *
+ * The SIP URI can contain a query part separated with the "?", which
+ * specifies SIP headers that are included in the request constructed
+ * from the URI. For example, using URI @code <sip:example.com?subject=test>
+ * would include @Subject header with value "test" in the request.
+ *
+ * @param home memory home used to allocate query string (if NULL, use malloc)
+ * @param tag, value, ... list of tagged arguments
+ *
+ * @bug This function returns NULL if SIPTAG_REQUEST(), SIPTAG_STATUS(),
+ * SIPTAG_HEADER(), SIPTAG_UNKNOWN(), SIPTAG_ERROR(), SIPTAG_SEPARATOR(), or
+ * any corresponding string tag is included in the tag list. It ignores
+ * SIPTAG_SIP().
+ *
+ * @par Example
+ * @code
+ * url->url_headers = 
+ *   sip_headers_as_url_query(home, SIPTAG_REPLACES(replaces), TAG_END());
+ * @endcode
+ * 
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa 
+ * url_query_as_header_string(), sip_url_query_as_taglist(),
+ * nta_msg_request_complete(),
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
+ */
+char *sip_headers_as_url_query(su_home_t *home,
+			       tag_type_t tag, tag_value_t value,
+			       ...)
+{
+  ta_list ta;
+  tagi_t const *t;
+  su_strlst_t *l = su_strlst_create(home);
+  su_home_t *lhome = su_strlst_home(l);
+  char const *retval = "";
+
+  if (!l)
+    return NULL;
+
+  ta_start(ta, tag, value);
+
+  for (t = ta_args(ta); t && retval; t = t_next(t)) {
+    msg_hclass_t *hc;
+
+    if (t->t_value == 0 || t->t_value == -1)
+      continue;
+
+    hc = (msg_hclass_t *)t->t_tag->tt_magic;
+
+    if (SIPTAG_P(t->t_tag)) {
+      sip_header_t const *h = (sip_header_t const *)t->t_value;
+      char *s = sip_header_as_string(lhome, h);
+
+      retval = append_escaped(l, hc, s);
+
+      if (retval != s)
+	su_free(lhome, s);
+    }
+    else if (SIPTAG_STR_P(t->t_tag)) {
+      retval = append_escaped(l, hc, (char const *)t->t_value);
+    }
+  }
+
+  ta_end(ta);
+
+  if (retval)
+    retval = su_strlst_join(l, home, "");
+
+  su_strlst_destroy(l);
+
+  return (char *)retval;
+}
+
+/* "[" / "]" / "/" / "?" / ":" / "+" / "$" */
+#define HNV_UNRESERVED "[]/?;+$"
+#define HNV_RESERVED ":=,"
+
+/* Append a string to list and url-escape it if needed */
+static
+char const *append_escaped(su_strlst_t *l,
+			   msg_hclass_t *hc,
+			   char const *s)
+{
+  char const *name;
+
+  if (hc == NULL)
+    return NULL;
+
+  if (hc->hc_hash == sip_payload_hash)
+    name = "body";
+  else				/* XXX - could we use short form? */
+    name = hc->hc_name;
+
+  if (name == NULL)
+    return NULL;
+
+  if (s) {
+    su_home_t *lhome = su_strlst_home(l);
+    size_t slen;
+    isize_t elen;
+    char *n, *escaped;
+    char *sep = su_strlst_len(l) > 0 ? "&" : "";
+
+    n = su_sprintf(lhome, "%s%s=", sep, name);
+    if (!su_strlst_append(l, n))
+      return NULL;
+
+    for (;*n; n++)
+      if (isupper(*n))
+	*n = tolower(*n);
+    
+    slen = strlen(s); elen = url_esclen(s, HNV_RESERVED);
+
+    if ((size_t)elen == slen)
+      return su_strlst_append(l, s);
+    
+    escaped = su_alloc(lhome, elen + 1);
+    if (escaped)
+      return su_strlst_append(l, url_escape(escaped, s, HNV_RESERVED));
+  }
+
+  return NULL;
+}
+
+/** Convert URL query to a tag list.
+ *
+ * SIP headers encoded as URL @a query is parsed returned as a tag list.
+ * Unknown headers are encoded as SIPTAG_HEADER_STR().
+ *
+ * @param home memory home used to alloate string (if NULL, malloc() it)
+ * @param query query part from SIP URL 
+ * @param parser optional SIP parser used
+ * 
+ * @sa sip_add_tl(), sip_add_tagis(), SIPTAG_HEADER_STR(),
+ * sip_headers_as_url_query(), url_query_as_header_string(),
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
+ *
+ * @NEW_1_12_4.
+ *
+ * @bug Extension headers are ignored. The @a parser parameter is not used
+ * at the moment.
+ */
+tagi_t *sip_url_query_as_taglist(su_home_t *home, char const *query,
+				 msg_mclass_t const *parser)
+{
+  tagi_t *retval = NULL;
+  char *s;
+  su_strlst_t *l;
+  isize_t N;
+  size_t i, j, n;
+
+  if (query == NULL || query[0] == '\0' || query[0] == '&')
+    return NULL;
+
+  s = su_strdup(home, query); if (!s) return NULL;
+  l = su_strlst_split(home, s, "&");
+  N = su_strlst_len(l);
+
+  if (N == 0)
+    goto error;
+
+  retval = su_zalloc(home, (N + 1) * sizeof (*retval));
+  if (retval == NULL)
+    goto error;
+
+  for (i = 0; i < N; i++) {
+    char const *hnv;
+    char *value;
+    tag_type_t t;
+    tag_value_t v;
+    msg_hclass_t *hc = NULL;
+
+    hnv = su_strlst_item(l, i);
+    n = strcspn(hnv, "=");
+    if (n == 0)
+      break;
+
+    if (n == 4 && strncasecmp(hnv, "body", 4) == 0)
+      t = siptag_payload, hc = sip_payload_class;
+    else for (j = 0; (t = sip_tag_list[j]); j++) {
+      hc = (msg_hclass_t *)sip_tag_list[j]->tt_magic;
+      if (n == 1 && strncasecmp(hnv, hc->hc_short, 1) == 0)
+	break;
+      else if (n == (size_t)hc->hc_len && strncasecmp(hnv, hc->hc_name, n) == 0)
+	break;
+    }
+
+    value = (char *)hnv + n;
+    *value++ = ':';
+    n = url_unescape_to(value, value, SIZE_MAX);
+    value[n] = '\0';
+
+    if (t) {
+      msg_header_t *h = msg_header_make(home, hc, value);
+      if (!h)
+	break;
+      v = (tag_value_t)h;
+    }
+    else {
+      char *s;
+      s = su_alloc(home, n + 1);
+      if (!s)
+	break;
+      memcpy(s, value, n + 1);
+      t = siptag_header_str;
+      v = (tag_value_t)s;
+    }
+    retval[i].t_tag = t, retval[i].t_value = v;
+  }
+
+  retval[i].t_tag = NULL, retval[i].t_value = (tag_value_t)0;
+
+  if (i < N) {
+    for (j = 0; j < i; j++) {
+      if (retval[i].t_tag == siptag_header_str)
+	su_free(home, (void *)retval[i].t_value);
+      else
+	msg_header_free_all(home, (msg_header_t *)retval[i].t_value);
+    }
+    su_free(home, retval);
+    retval = NULL;
+  }
+
+ error:
+  su_free(home, s);
+  su_strlst_destroy(l);
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_time.c 
+ * @brief SIP time handling
+ *
+ * Functions for handling time and dates in SIP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 18:57:06 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/msg_date.h>
+#include <sofia-sip/su_time.h>
+
+/** Return current time as seconds since Epoch. */
+sip_time_t sip_now(void)
+{
+  return su_now().tv_sec;
+}
+
+/**@ingroup sip_expires
+ *
+ * Calculate the expiration time for a SIP @Contact. 
+ *
+ * @param m     @Contact header
+ * @param ex    @Expires header
+ * @param date  @Date header
+ * @param def   default expiration time
+ * @param now   current time.
+ *
+ * @note If @a m is NULL, the function calculates the expiration time
+ *       based on the @Expires and @Date headers.
+ *
+ * @note If @a now is 0, the function gets the current time using sip_now().
+ *
+ * @return 
+ *   The expiration time in seconds. 
+ */
+sip_time_t sip_contact_expires(sip_contact_t const *m,
+			       sip_expires_t const *ex,
+			       sip_date_t const *date,
+			       sip_time_t def,
+			       sip_time_t now)
+{
+  sip_time_t time = 0, delta = def;
+
+  /* "Contact: *" */
+  if (m && m->m_url->url_type == url_any)
+    return 0;
+
+  if (m && m->m_expires) {
+    msg_param_t expires = m->m_expires;
+    if (msg_date_delta_d(&expires, &time, &delta) < 0)
+      return def;
+  }
+  else if (ex) {
+    time = ex->ex_date;
+    delta = ex->ex_delta;
+  }
+
+  if (time) {
+    if (date) 
+      now = date->d_time;
+    else if (now == 0)
+      now = sip_now();
+
+    if (time > now)
+      delta = time - now;
+    else
+      delta = 0;
+  }
+
+  return delta;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1422 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_util.c
+ * 
+ * SIP utility functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/string0.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/bnf.h>
+#include <sofia-sip/hostdomain.h>
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+
+/** 
+ * Compare two SIP addresses ( @From or @To headers).
+ *
+ * @retval nonzero if matching.
+ * @retval zero if not matching.
+ */
+int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b)
+{
+  return
+    (a->a_tag == NULL || b->a_tag == NULL || 
+     strcmp(a->a_tag, b->a_tag) == 0)
+    &&
+    str0casecmp(a->a_host, b->a_host) == 0 
+    &&
+    str0cmp(a->a_user, b->a_user) == 0 
+    &&
+    str0cmp(a->a_url->url_scheme, b->a_url->url_scheme);
+}
+
+
+/**@ingroup sip_contact
+ *
+ * Create a contact header.
+ *
+ * Create a @Contact header object with the given URL and list of parameters.
+ *
+ * @param home      memory home
+ * @param url       URL (string or pointer to url_t)
+ * @param p,...     NULL-terminated list of @Contact parameters
+ *
+ * @return
+ * A pointer to newly created @Contact header object when successful or NULL
+ * upon an error.
+ *
+ */
+sip_contact_t * sip_contact_create(su_home_t *home,
+				   url_string_t const *url,
+				   char const *p, ...)
+{
+  su_strlst_t *l;
+  su_home_t *lhome;
+  sip_contact_t *m;
+
+  if (url == NULL)
+    return NULL;
+
+  l = su_strlst_create_with(NULL, "<", NULL), lhome = su_strlst_home(l);
+  if (l == NULL)
+    return NULL;
+
+  if (url_is_string(url))
+    su_strlst_append(l, (char const *)url);
+  else
+    su_strlst_append(l, url_as_string(lhome, url->us_url));
+
+  su_strlst_append(l, ">");
+
+  if (p) {
+    va_list ap;
+    va_start(ap, p);
+
+    for (; p; p = va_arg(ap, char const *)) {
+      su_strlst_append(l, ";");
+      su_strlst_append(l, p);
+    }
+
+    va_end(ap);
+  }
+
+  m = sip_contact_make(home, su_strlst_join(l, lhome, ""));
+
+  su_strlst_destroy(l);
+
+  return m;
+}
+
+/** Convert a @Via header to @Contact header.
+ *
+ * The @Contact URI will contain the port number if needed. If transport
+ * protocol name starts with "TLS", "SIPS:" URI schema is used. Transport
+ * parameter is included in the URI unless the transport protocol is UDP.
+ *
+ * @param home      memory home
+ * @param v         @Via header field structure 
+ *                  (with <sent-protocol> and <sent-by> parameters)
+ * @param user      username for @Contact URI (may be NULL)
+ *
+ * @retval contact header structure
+ * @retval NULL upon an error
+ *
+ * @sa sip_contact_create_from_via_with_transport(), 
+ *     sip_contact_string_from_via()
+ */
+sip_contact_t *
+sip_contact_create_from_via(su_home_t *home,
+			    sip_via_t const *v,
+			    char const *user)
+{
+  const char *tp;
+
+  if (!v) return NULL;
+
+  tp = v->v_protocol;
+
+  if (tp == sip_transport_udp ||
+      strcasecmp(tp, sip_transport_udp) == 0)  /* Default is UDP */
+    tp = NULL;
+
+  return sip_contact_create_from_via_with_transport(home, v, user, tp);
+}
+
+/** Convert a @Via header to @Contact header.
+ *
+ * The @Contact URI will contain the port number and transport parameters if
+ * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
+ * is used.
+ *
+ * @param home      memory home
+ * @param v         @Via header field structure
+ *                  (with <sent-by> parameter containing host and port)
+ * @param user      username for @Contact URI (may be NULL)
+ * @param transport transport name for @Contact URI (may be NULL)
+ *
+ * @retval contact header structure
+ * @retval NULL upon an error
+ *
+ * @sa sip_contact_create_from_via(), sip_contact_string_from_via()
+ */
+sip_contact_t *
+sip_contact_create_from_via_with_transport(su_home_t *home,
+					   sip_via_t const *v,
+					   char const *user,
+					   char const *transport)
+{
+  char *s = sip_contact_string_from_via(NULL, v, user, transport);
+  sip_contact_t *m = sip_contact_make(home, s);
+  su_free(NULL, s);
+  return m;
+}
+
+/** Convert a @Via header to @Contact URL string.
+ *
+ * The @Contact URI will contain the port number and transport parameters if
+ * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
+ * is used.
+ *
+ * The contact URI string returned will always have angle brackets ("<" and
+ * ">") around it.
+ *
+ * @param home      memory home
+ * @param v         @Via header field structure
+ *                  (with <sent-by> parameter containing host and port)
+ * @param user      username for @Contact URI (may be NULL)
+ * @param transport transport name for @Contact URI (may be NULL)
+ *
+ * @retval string containing Contact URI with angle brackets
+ * @retval NULL upon an error
+ */
+char *
+sip_contact_string_from_via(su_home_t *home,
+			    sip_via_t const *v,
+			    char const *user,
+			    char const *transport)
+{
+  const char *host, *port, *maddr, *comp;
+  char const *scheme = "sip:";
+  int one = 1;
+  char _transport[16];
+
+  if (!v) return NULL;
+
+  host = v->v_host;
+  if (v->v_received)
+    host = v->v_received;
+  port = sip_via_port(v, &one);
+  maddr = v->v_maddr;
+  comp = v->v_comp;
+
+  if (host == NULL)
+    return NULL;
+
+  if (sip_transport_has_tls(v->v_protocol) ||
+      sip_transport_has_tls(transport)) {
+    scheme = "sips:";
+    if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0)
+      port = NULL;
+    if (port || host_is_ip_address(host))
+      transport = NULL;
+  }
+  else if (port && host_is_ip_address(host) &&
+	   strcmp(port, SIP_DEFAULT_SERV) == 0) {
+    port = NULL;
+  }
+
+  if (transport && strncasecmp(transport, "SIP/2.0/", 8) == 0)
+    transport += 8;
+
+  /* Make transport parameter lowercase */
+  if (transport && strlen(transport) < (sizeof _transport)) {
+    char *s = strcpy(_transport, transport);
+
+    for (s = _transport; *s && *s != ';'; s++)
+      if (isupper(*s))
+	*s = tolower(*s);
+
+    transport = _transport;
+  }
+
+  return su_strcat_all(home,
+		       "<",
+		       scheme,
+		       user ? user : "", user ? "@" : "",
+		       host,
+		       SIP_STRLOG(":", port),
+		       SIP_STRLOG(";transport=", transport),
+		       SIP_STRLOG(";maddr=", maddr),
+		       SIP_STRLOG(";comp=", comp),
+		       ">",
+		       NULL);
+}
+
+/** Check if tranport name refers to TLS */
+int sip_transport_has_tls(char const *transport_name)
+{
+  if (!transport_name)
+    return 0;
+
+  if (transport_name == sip_transport_tls)
+    return 1;
+
+  /* transport name starts with TLS or SIP/2.0/TLS */
+  return
+    strncasecmp(transport_name, "TLS", 3) == 0 ||
+    strncasecmp(transport_name, sip_transport_tls, 11) == 0;
+}
+
+/**Perform sanity check on a SIP message
+ * 
+ * Check that the SIP message has all the mandatory fields. 
+ *
+ * @param sip SIP message to be checked
+ *
+ * @return 
+ * When the SIP message fulfills the minimum requirements, return zero,
+ * otherwise a negative status code.
+ */
+int
+sip_sanity_check(sip_t const *sip)
+{
+  if (!sip ||
+      !((sip->sip_request != NULL) ^ (sip->sip_status != NULL)) ||
+      !sip->sip_to ||
+      !sip->sip_from ||
+      !sip->sip_call_id ||
+      !sip->sip_cseq ||
+      !sip->sip_via ||
+      (sip->sip_flags & MSG_FLG_TRUNC))
+    return -1;  /* Bad request */
+
+  if (sip->sip_request) {
+    url_t const *ruri = sip->sip_request->rq_url;
+
+    switch (ruri->url_type) {
+    case url_invalid:
+      return -1;
+
+    case url_sip: case url_sips: case url_im: case url_pres:
+      if (!ruri->url_host || strlen(ruri->url_host) == 0)
+	return -1;
+      break;
+
+    case url_tel: 
+      if (!ruri->url_user || strlen(ruri->url_user) == 0)
+	return -1;
+      break;
+    }
+
+    if (sip->sip_request->rq_method != sip->sip_cseq->cs_method)
+      return -1;
+    if (sip->sip_request->rq_method == sip_method_unknown &&
+	str0casecmp(sip->sip_request->rq_method_name,
+		    sip->sip_cseq->cs_method_name))
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Decode a string containg header field.
+ *
+ * The header object is initialized with the contents of the string. The
+ * string is modified when parsing. The home is used to allocate extra
+ * memory required when parsing, e.g., for parameter list or when there
+ * string contains multiple header fields.
+ * 
+ * @deprecated
+ * Use msg_header_make() or header-specific make functions, e.g.,
+ * sip_via_make().
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+issize_t sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+  assert(SIP_HDR_TEST(h));
+
+  if (h && s && s[slen] == '\0') {
+    size_t n = span_lws(s);
+    s += n; slen -= n;
+    
+    for (n = slen; n >= 1 && IS_LWS(s[n - 1]); n--)
+      ;
+    
+    s[n] = '\0';
+    
+    return h->sh_class->hc_parse(home, h, s, slen);
+  }
+  else
+    return -1;
+}
+
+/** Encode a SIP header contents.
+ *
+ * @deprecated Use msg_header_field_e() instead.
+ */
+issize_t sip_header_field_e(char *b, isize_t bsiz, sip_header_t const *h, int flags)
+{
+  return msg_header_field_e(b, bsiz, h, flags);
+}
+
+/** Convert the header @a h to a string allocated from @a home. */
+char *sip_header_as_string(su_home_t *home, sip_header_t const *h)
+{
+  ssize_t len;
+  char *rv, s[128];
+
+  if (h == NULL)
+    return NULL;
+
+  len = sip_header_field_e(s, sizeof(s), h, 0);
+
+  if (len >= 0 && (size_t)len < sizeof(s))
+    return su_strdup(home, s);
+
+  if (len == -1)
+    len = 2 * sizeof(s);
+  else
+    len += 1;
+
+  for (rv = su_alloc(home, len);
+       rv;
+       rv = su_realloc(home, rv, len)) {
+    ssize_t n = sip_header_field_e(s, sizeof(s), h, 0);
+    if (n > -1 && n + 1 <= len)
+      break;
+    if (n > -1)			/* glibc >2.1 */
+      len = n + 1;		
+    else			/* glibc 2.0 */
+      len *= 2;			
+  }
+
+  return rv;
+}
+
+/** Calculate size of a SIP header. */
+isize_t sip_header_size(sip_header_t const *h)
+{
+  assert(h == NULL || h == SIP_NONE || h->sh_class);
+  if (h == NULL || h == SIP_NONE)
+    return 0;
+  else
+    return h->sh_class->hc_dxtra(h, h->sh_class->hc_size);
+}
+
+/** Duplicate a url or make a url out of string. 
+ * @deprecated Use url_hdup() instead.
+ */
+url_t *sip_url_dup(su_home_t *home, url_t const *o)
+{
+  return url_hdup(home, o);
+}
+
+/**Calculate Q value.
+ * 
+ * Convert q-value string @a q to numeric value
+ * in range (0..1000).  Q values are used, for instance, to describe
+ * relative priorities of registered contacts.
+ *
+ * @param q q-value string <code>("1" | "." 1,3DIGIT)</code>
+ * 
+ * @return An integer in range 0 .. 1000.
+ */
+unsigned sip_q_value(char const *q)
+{
+  unsigned value = 0;
+
+  if (!q)
+    return 1000;
+  if (q[0] != '0' && q[0] != '.' && q[0] != '1')
+    return 500; /* Garbage... */
+  while (q[0] == '0')
+    q++;
+  if (q[0] >= '1' && q[0] <= '9')
+    return 1000;
+  if (q[0] == '\0')
+    return 0;
+  if (q[0] != '.')      
+    return 500;    /* Garbage... */
+
+  if (q[1] >= '0' && q[1] <= '9') {
+    value = (q[1] - '0') * 100;
+    if (q[2] >= '0' && q[2] <= '9') {
+      value += (q[2] - '0') * 10;
+      if (q[3] >= '0' && q[3] <= '9') {
+	value += (q[3] - '0');
+	if (q[4] > '5' && q[4] <= '9')
+	  /* Round upwards */
+	  value += 1;
+	else if (q[4] == '5') 
+	  value += value & 1; /* Round to even */
+      }
+    }
+  }
+
+  return value;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Get first route header and remove it from its fragment chain. 
+ *
+ */
+sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip)
+{
+  sip_route_t *r;
+
+  if ((r = sip->sip_route))
+    msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
+
+  return r;
+}
+
+/**@ingroup sip_route
+ *
+ * Get last route header and remove it from its fragment chain. 
+ *
+ */
+sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip)
+{
+  sip_route_t *r;
+
+  for (r = sip->sip_route; r; r = r->r_next) 
+    if (r->r_next == NULL) {
+      msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
+      return r;
+    }
+
+  return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Get first route header and rewrite the RequestURI. 
+ */
+sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip)
+{
+  if (sip->sip_route) {
+    /* XXX - in case of outbound proxy, route may contain our address */ 
+      
+    sip_route_t *r = sip_route_remove(msg, sip);
+    sip_request_t *rq = sip->sip_request;
+
+    rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name,
+			    (url_string_t const *)r->r_url, rq->rq_version);
+    url_strip_transport(rq->rq_url);
+
+    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq);
+
+    return r;
+  }
+  return NULL;
+}
+
+/**@ingroup sip_route
+ * 
+ * Check if route header has lr param.
+ *
+ * "lr" param can be either URL or header parameter.
+ */
+int 
+sip_route_is_loose(sip_route_t const *r)
+{
+  if (!r)
+    return 0;
+  if (r->r_url->url_params)
+    return url_has_param(r->r_url, "lr");
+  else
+    return r->r_params && msg_params_find(r->r_params, "lr") != NULL;
+}
+
+/**@ingroup sip_route
+ *
+ * Reverse a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
+ */
+sip_route_t *sip_route_reverse_as(su_home_t *home, 
+				  msg_hclass_t *hc,
+				  sip_route_t const *route)
+{
+  sip_route_t *reverse = NULL;
+  sip_route_t r[1], *tmp;
+  sip_route_init(r);
+
+  r->r_common->h_class = hc;
+
+  for (reverse = NULL; route; route = route->r_next) {
+    *r->r_url = *route->r_url;
+    /* Fix broken (Record-)Routes without <> */
+    if (r->r_url->url_params == NULL
+	&& r->r_params 
+	&& r->r_params[0] 
+	&& (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+	&& (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+	&& (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
+      r->r_url->url_params = route->r_params[0],
+	r->r_params = route->r_params + 1;
+    else
+      r->r_params = route->r_params;
+    tmp = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
+    if (!tmp) 
+      goto error;
+    tmp->r_next = reverse;
+    reverse = tmp;
+  }
+
+  return reverse;
+
+ error:
+  msg_header_free_all(home, (msg_header_t *)reverse);
+  return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Reverse a @Route header. 
+ *
+ * Reverse A route header like @RecordRoute or @Path.
+ */
+sip_route_t *sip_route_reverse(su_home_t *home, sip_route_t const *route)
+{
+  return sip_route_reverse_as(home, sip_route_class, route);
+}
+
+
+/**@ingroup sip_route
+ *
+ * Fix and duplicate a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
+ *
+ */
+sip_route_t *sip_route_fixdup_as(su_home_t *home,
+				 msg_hclass_t *hc,
+				 sip_route_t const *route)
+{
+  sip_route_t *copy = NULL;
+  sip_route_t r[1], **rr;
+  sip_route_init(r);
+
+  /* Copy the record route as route */
+  for (rr = &copy; route; route = route->r_next) {
+    *r->r_url = *route->r_url;
+    /* Fix broken (Record-)Routes without <> */
+    if (r->r_url->url_params == NULL
+	&& r->r_params 
+	&& r->r_params[0] 
+	&& (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+	&& (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+	&& (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
+      r->r_url->url_params = route->r_params[0],
+	r->r_params = route->r_params + 1;
+    else
+      r->r_params = route->r_params;
+    *rr = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
+    if (!*rr) goto error;
+    rr = &(*rr)->r_next;
+  }
+
+  return copy;
+
+ error:
+  msg_header_free_all(home, (msg_header_t *)copy);
+  return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Fix and duplicate a @Route header. 
+ *
+ * Copy a route header like @RecordRoute or @Path as @Route.
+ *
+ */
+sip_route_t *sip_route_fixdup(su_home_t *home, sip_route_t const *route)
+{
+  return sip_route_fixdup_as(home, sip_route_class, route);
+}
+
+static void sip_fragment_clear_chain(sip_header_t *h)
+{
+  void const *next;
+
+  for (h = h; h; h = h->sh_succ) {
+    next = (char *)h->sh_data + h->sh_len;
+
+    sip_fragment_clear(h->sh_common);
+
+    if (!next ||
+	!h->sh_succ ||
+	h->sh_next != h->sh_succ ||
+	h->sh_succ->sh_data != next ||
+	h->sh_succ->sh_len)
+      return;
+  }
+}
+
+/**@ingroup sip_route
+ *
+ * Fix @Route header.
+ */
+sip_route_t *sip_route_fix(sip_route_t *route)
+{
+  sip_route_t *r;
+  sip_header_t *h = NULL;
+  size_t i;
+
+  for (r = route; r; r = r->r_next) {
+    /* Keep track of first header structure on this header line */
+    if (!h 
+	|| (char *)h->sh_data + h->sh_len != r->r_common->h_data
+	|| r->r_common->h_len)
+      h = (sip_header_t *)r;
+
+    if (r->r_url->url_params == NULL
+	&& r->r_params 
+	&& r->r_params[0] 
+	&& (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+	&& (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+	&& (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) {
+      r->r_url->url_params = r->r_params[0];
+
+      for (i = 0; r->r_params[i]; i++)
+	((char const **)r->r_params)[i] = r->r_params[i + 1];
+
+      sip_fragment_clear_chain(h);
+    }
+  }
+
+  return route;
+}
+
+/**@ingroup sip_via
+ *
+ * Get first via header and remove it from its fragment chain. 
+ */
+sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip)
+{
+  sip_via_t *v;
+
+  if (sip == NULL)
+    return NULL;
+  
+  for (v = sip->sip_via; v; v = v->v_next) {
+    sip_fragment_clear(v->v_common);
+
+    if (v->v_next != (void *)v->v_common->h_succ)
+      break;
+  }
+
+  if ((v = sip->sip_via))
+    msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+
+  return v;
+}
+
+/** Serialize payload.
+ *
+ * The sip_payload_serialize() adds missing headers to MIME multiparty payload,
+ * encodes them and orders them in header chain.  It also calculates the total
+ * length of the payload.
+ */
+unsigned long sip_payload_serialize(msg_t *msg, sip_payload_t *pl)
+{
+  unsigned long total;
+
+  for (total = 0; pl; pl = (sip_payload_t *)pl->pl_next) {
+    total += (unsigned)pl->pl_common->h_len;
+  }
+
+  return total;
+}
+
+/** 
+ * Remove extra parameters from an AOR URL.
+ *
+ * The extra parameters listed in the @RFC3261 table 1 include port number,
+ * method, maddr, ttl, transport, lr and headers.
+ * 
+ * @note The funtion modifies the @a url and the strings attached to it.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int sip_aor_strip(url_t *url)
+{
+  if (url == NULL)
+    return -1;
+
+  url->url_port = NULL;
+  url->url_headers = NULL;
+
+  if (url->url_params)
+    url_strip_transport(url);
+    
+  if (url->url_params)
+    url->url_params = 
+      url_strip_param_string((char *)url->url_params, "lr");
+
+  return 0;
+}
+
+/** Compare @SecurityVerify header with @SecurityServer header. */
+int sip_security_verify_compare(sip_security_server_t const *s,
+				sip_security_verify_t const *v,
+				msg_param_t *return_d_ver)
+{
+  size_t i, j;
+  int retval, digest;
+  msg_param_t const *s_params, *v_params, empty[] = { NULL };
+
+  if (return_d_ver)
+    *return_d_ver = NULL;
+
+  if (s == NULL)
+    return 0;
+
+  for (;;s = s->sa_next, v = v->sa_next) {
+    if (s == NULL || v == NULL)
+      return (s == NULL) - (v == NULL);
+    
+    if ((retval = str0cmp(s->sa_mec, v->sa_mec)))
+      return retval;
+
+    digest = strcasecmp(s->sa_mec, "Digest") == 0;
+
+    s_params = s->sa_params, v_params = v->sa_params;
+
+    if (digest && s_params == NULL && v_params != NULL)
+      s_params = empty;
+
+    if (s_params == NULL || v_params == NULL) {
+      if ((retval = (s_params == NULL) - (v_params == NULL)))
+	return retval;
+      continue;
+    }
+
+    for (i = 0, j = 0;; i++, j++) {
+      if (digest && v_params[j] && 
+	  strncasecmp(v_params[j], "d-ver=", 6) == 0) {
+	if (return_d_ver)
+	  *return_d_ver = v_params[j] + strlen("d-ver=");
+	j++;
+      }
+
+      retval = str0cmp(s_params[i], v_params[j]);
+      
+      if (retval || s_params[i] == NULL || v_params[j] == NULL) 
+	break;
+    }
+
+    if (retval)
+      return retval;
+  }
+}
+
+/** Select best mechanism from @SecurityClient header. 
+ *
+ * @note We assume that @SecurityServer header in @a s is sorted by
+ * preference.
+ */
+sip_security_client_t const *
+sip_security_client_select(sip_security_client_t const *client,
+			   sip_security_server_t const *server)
+{
+  sip_security_server_t const *c, *s;
+
+  if (server == NULL || client == NULL)
+    return NULL;
+
+  for (s = server; s; s = s->sa_next) {
+    for (c = client; c; c = c->sa_next) {
+      if (str0cmp(s->sa_mec, c->sa_mec) == 0)
+	return c;
+    }
+  }
+
+  return NULL;
+}
+
+/**Checks if the response with given response code terminates dialog or
+ * dialog usage.
+ * 
+ * @return -1 if the response with given code terminates whole dialog.
+ * @return 1 if the response terminates the dialog usage.
+ * @return 0 if the response does not terminate dialog or dialog usage.
+ * 
+ * @return
+ * The @a *return_graceful_terminate_usage is set to 1, if application
+ * should gracefully terminate its dialog usage. It is set to 0, if no
+ * graceful terminate is required. If it is up to application policy to
+ * decide whether to gracefully terminate or not, the
+ * @a *return_graceful_terminate_usage is left unmodified.
+ *
+ * @sa 
+ * http://www.ietf.org/internet-drafts/draft-ietf-sipping-dialogusage-02.txt
+ */
+int sip_response_terminates_dialog(int response_code,
+				   sip_method_t method,
+				   int *return_graceful_terminate_usage)
+{
+  enum { no_effect, terminate_usage = 1, terminate_dialog = -1 };
+  int dummy;
+
+  if (!return_graceful_terminate_usage) 
+    return_graceful_terminate_usage = &dummy;
+
+  if (response_code < 300)
+    return *return_graceful_terminate_usage = 0;
+
+  /*  
+      3xx responses: Redirection mid-dialog is not well understood in SIP,
+      but whatever effect it has impacts the entire dialog and all of
+      its usages equally.  In our example scenario, both the
+      subscription and the invite usage would be redirected by this
+      single response.
+  */
+  if (response_code < 400) 
+    return *return_graceful_terminate_usage = 0;
+
+  if (response_code < 500) switch (response_code) {
+  default:
+  case 400: /** @par 400 and unrecognized 4xx responses 
+
+      These responses affect only the NOTIFY transaction, not the
+      subscription, the dialog it resides in (beyond affecting the local
+      CSeq), or any other usage of that dialog. In general, the response
+      is a complaint about this transaction, not the usage or dialog the
+      transaction occurs in.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 401: 
+  case 407: /** @par 401 Unauthorized and 407 Proxy Authentication Required
+
+      This request, not the subscription or dialog, is being challenged. The
+      usages and dialog are not terminated.
+    */ 
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 402: /** @par 402 Payment Required 
+
+      This is a reserved response code. If encountered, it should be
+      treated as an unrecognized 4xx.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 403: /** @par 403 Forbidden 
+
+      This response terminates the subscription, but has no effect on
+      any other usages of the dialog. In our example scenario, the
+      invite usage continues to exist. Similarly, if the 403 came in
+      response to a re-INVITE, the invite usage would be terminated, but
+      not the subscription.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+    
+  case 404: /** @par 404 Not Found 
+
+      This response destroys the dialog and all usages sharing it. The
+      Request-URI that is being 404ed is the remote target set by the
+      @Contact provided by the peer. Getting this response means
+      something has gone fundamentally wrong with the dialog state.
+    */
+    return terminate_dialog;
+
+  case 405: /** @par 405 Method Not Allowed 
+
+      In our example scenario, this response destroys the subscription,
+      but not the invite usage or the dialog. It's an aberrant case for
+      NOTIFYs to receive a 405 since they only come as a result to
+      something that creates subscription. In general, a 405 within a
+      given usage affects only that usage, but does not affect other
+      usages of the dialog.
+    */
+    switch (method) {
+    case sip_method_notify:
+    case sip_method_subscribe:
+    case sip_method_invite:
+      return terminate_usage;
+    default:
+      *return_graceful_terminate_usage = 0;
+      return 0;
+    }
+
+  case 406: /** @par 406 Not Acceptable 
+
+      These responses concern details of the message in the transaction. 
+      Subsequent requests in this same usage may succeed. Neither the
+      usage nor dialog is terminated, other usages sharing this dialog
+      are unaffected.
+      */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 408: /** @par 408 Request Timeout 
+
+      Receiving a 408 will have the same effect on
+      usages and dialogs as a real transaction timeout as described in
+      Section 3.2.
+    */
+    return terminate_usage;
+
+  case 410: /** @par 410 Gone 
+
+      This response destroys the dialog and all usages sharing
+      it.  The Request-URI that is being rejected is the remote target
+      set by the @Contact provided by the peer.  Similar to 404, getting
+      this response means something has gone fundamentally wrong with
+      the dialog state, its slightly less aberrant in that the other
+      endpoint recognizes that this was once a valid URI that it isn't
+      willing to respond to anymore.
+    */
+    return terminate_dialog;
+
+  case 412: /* Conditional Request Failed: */ 
+  case 413: /* Request Entity Too Large: */
+  case 414: /* Request-URI Too Long: */
+  case 415: /* Unsupported Media Type: */
+    /** @par 412, 413, 414 and 415 
+
+      These responses concern details of the message in the transaction. 
+      Subsequent requests in this same usage may succeed. Neither the usage
+      nor dialog is terminated, other usages sharing this dialog are
+      unaffected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 416: /** @par 416 Unsupported URI Scheme 
+
+      Similar to 404 and 410, this response
+      came to a request whose Request-URI was provided by the peer in a
+      @Contact header field.  Something has gone fundamentally wrong, and
+      the dialog and all of its usages are destroyed.
+    */
+    return terminate_dialog;
+
+  case 417:
+    /** @par 417 Uknown Resource-Priority
+      The effect of this response on usages
+      and dialogs is analgous to that for 420 and 488.  The usage is not
+      affected.  The dialog is only affected by a change in its local
+      @CSeq.  No other usages of the dialog are affected.
+    */
+
+  case 420: /* Bad Extension */ 
+  case 421: /* Extension Required */
+
+    /** @par 420 Bad Extension and 421 Extension Required
+
+      These responses are objecting to the request, not the usage. The
+      usage is not affected. The dialog is only affected by a change in
+      its local @CSeq. No other usages of the dialog are affected.
+    */
+
+  case 422: /** @par 422 Session Interval Too Small
+
+      This response will not be returned to
+      a NOTIFY in our example scenario.  This response is non-sensical
+      for any mid-usage request.  If it is received, an element in the
+      path of the request is violating protocol, and the recipient
+      should treat this as it would an unknown 4xx response.  If the
+      response came to a request that was attempting to establish a new
+      usage in an existing dialog, no new usage is created and existing
+      usages are unaffected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 423: /** @par 423 Interval Too Brief 
+
+      This response won't happen in our example
+      scenario, but if it came in response to a re-SUBSCRIBE, the
+      subscribe usage is not destroyed (or otherwise affected).  No
+      other usages of the dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return sip_method_subscribe == method ? terminate_usage : no_effect;
+
+  case 428: /** @par 428 Use Identity Header
+
+      This response objects to the request, not
+      the usage.  The usage is not affected.  The dialog is only
+      affected by a change in its local @CSeq.  No other usages of the
+      dialog are affected. */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 429: /** @par 429 Provide Referrer Identity 
+
+      This response won't be returned to a NOTIFY as in our example
+      scenario, but when it is returned to a REFER, it is objecting to
+      the REFER request itself, not any usage the REFER occurs within. 
+      The usage is unaffected. Any other usages sharing this dialog are
+      unaffected. The dialog is only affected by a change in its local
+      @CSeq.
+    */
+
+  case 436: case 437: case 438:
+    /** @par 436 Bad Identity-Info, 437 Unsupported Certificate, 438 Invalid \
+     *  Identity Header 
+     *
+     * These responses object to the request, not the usage.
+     * The usage is not affected.  The dialog is only affected by a
+     * change in its local @CSeq.  No other usages of the dialog are
+     * affected.
+     */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+
+  case 480: /** @par 480 Temporarily Unavailable
+
+      @RFC3261 is unclear on what this response means for mid-usage
+      requests. Clarifications will be made to show that this response
+      affects only the usage in which the request occurs. No other usages
+      are affected. If the response included a @RetryAfter header field,
+      further requests in that usage should not be sent until the indicated
+      time has past. Requests in other usages may still be sent at any time.
+    */
+    return terminate_usage;
+
+
+  case 481: /** @par 481 Call/Transaction Does Not Exist 
+
+      This response indicates that the peer has lost its copy of the dialog
+      state. The dialog and any usages sharing it are destroyed.
+
+      The dialog
+      itself should not be destroyed unless this was the last usage.
+      The effects of a 481 on a dialog and its usages are the most
+      ambiguous of any final response.  There are implementations that
+      have chosen the meaning recommended here, and others that destroy
+      the entire dialog without regard to the number of outstanding
+      usages.  Going forward with this clarification will allow those
+      deployed implementations that assumed only the usage was destroyed
+      to work with a wider number of implementations.  Those that made
+      the other choice will continue to function as they do now,
+      suffering at most the same extra messages needed for a peer to
+      discover that that other usages have gone away that they currently
+      do.  However, the necessary clarification to @RFC3261 needs to
+      make it very clear that the ability to terminate usages
+      independently from the overall dialog using a 481 is not
+      justification for designing new applications that count on
+      multiple usages in a dialog.
+    */
+    return terminate_usage;
+
+
+  case 482: /** @par 482 Loop Detected 
+
+      This response is aberrant mid-dialog.  It will
+      only occur if the @RecordRoute header field was improperly
+      constructed by the proxies involved in setting up the dialog's
+      initial usage, or if a mid-dialog request forks and merges (which
+      should never happen).  Future requests using this dialog state
+      will also fail.  The dialog and any usages sharing it are
+      destroyed.  
+    */
+    return terminate_dialog;
+
+
+  case 483: /** @par 483 Too Many Hops 
+
+      Similar to 482, receiving this mid-dialog is
+      aberrant.  Unlike 482, recovery may be possible by increasing
+      @MaxForwards (assuming that the requester did something strange
+      like using a smaller value for @MaxForwards in mid-dialog requests
+      than it used for an initial request).  If the request isn't tried
+      with an increased @MaxForwards, then the agent should attempt to
+      gracefully terminate this usage and all other usages that share
+      its dialog.  
+    */
+    *return_graceful_terminate_usage = 1;
+    return 0;
+
+  case 484: /* Address Incomplete */
+  case 485: /* Ambiguous */
+    /** @par 484 Address Incomplete and 485 Ambiguous
+
+      Similar to 404 and 410, these
+      responses came to a request whose Request-URI was provided by the
+      peer in a @Contact header field.  Something has gone fundamentally
+      wrong, and the dialog and all of its usages are destroyed.
+    */
+    return terminate_dialog;
+
+  case 486: /** @par 486 Busy Here 
+
+      This response is non-sensical in our example scenario,
+      or in any scenario where this response comes inside an established
+      usage.  If it occurs in that context, it should be treated as an
+      unknown 4xx response.  The usage, and any other usages sharing its
+      dialog are unaffected.  The dialog is only affected by the change
+      in its local @CSeq.  If this response is to a request that is
+      attempting to establish a new usage within an existing dialog
+      (such as an INVITE sent within a dialog established by a
+      subscription), the request fails, no new usage is created, and no
+      other usages are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 487: /** @par 487 Request Terminated 
+
+      This response speaks to the disposition of a
+      particular request (transaction).  The usage in which that request
+      occurs is not affected by this response (it may be affected by
+      another associated request within that usage).  No other usages
+      sharing this dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 488: /** @par 488 Not Acceptable Here 
+
+      This response is objecting to the request,
+      not the usage.  The usage is not affected.  The dialog is only
+      affected by a change in its local @CSeq.  No other usages of the
+      dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 489: /** @par 489 Bad Event 
+
+      In our example scenario, @RFC3265 declares that the
+      subscription usage in which the NOTIFY is sent is terminated.  The
+      invite usage is unaffected and the dialog continues to exist.
+      This response is only valid in the context of SUBSCRIBE and
+      NOTIFY.  UAC behavior for receiving this response to other methods
+      is not specified, but treating it as an unknown 4xx is a
+      reasonable practice.
+    */
+    *return_graceful_terminate_usage = 0;
+    return method == sip_method_notify ? terminate_usage : no_effect;
+
+  case 491: /** @par 491 Request Pending 
+
+      This response addresses in-dialog request glare.
+      Its affect is scoped to the request.  The usage in which the
+      request occurs is not affected.  The dialog is only affected by
+      the change in its local @CSeq.  No other usages sharing this dialog
+      are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 493: /** @par 493 Undecipherable 
+
+      This response objects to the request, not the
+      usage.  The usage is not affected.  The dialog is only affected by
+      a change in its local @CSeq.  No other usages of the dialog are
+      affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 494: /** @par 494 Security Agreement Required 
+
+      This response is objecting to the
+      request, not the usage.  The usage is not affected.  The dialog is
+      only affected by a change in its local @CSeq.  No other usages of
+      the dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+  }
+
+  if (response_code < 600) switch (response_code) {
+  case 500: /* 500 and 5xx unrecognized responses */
+  default:
+    /** @par 500 and 5xx unrecognized responses
+
+      These responses are complaints against the request (transaction),
+      not the usage. If the response contains a @RetryAfter header field
+      value, the server thinks the condition is temporary and the
+      request can be retried after the indicated interval. This usage,
+      and any other usages sharing the dialog are unaffected. If the
+      response does not contain a @RetryAfter header field value, the UA
+      may decide to retry after an interval of its choosing or attempt
+      to gracefully terminate the usage. Whether or not to terminate
+      other usages depends on the application. If the UA receives a 500
+      (or unrecognized 5xx) in response to an attempt to gracefully
+      terminate this usage, it can treat this usage as terminated. If
+      this is the last usage sharing the dialog, the dialog is also
+      terminated.
+    */
+    /* Do not change *return_graceful_terminate_usage */
+    return 0;
+
+  case 501: /** @par 501 Not Implemented 
+
+      This would be a degenerate response in our
+      example scenario since the NOTIFY is being sent as part of an
+      established subscribe usage.  In this case, the UA knows the
+      condition is unrecoverable and should stop attempting to send
+      NOTIFYs on this usage.  (It may or may not destroy the usage.  If
+      it remembers the bad behavior, it can reject any refresh
+      subscription).  In general, this response may or may not affect
+      the usage (a 501 to an unknown method or an INFO will not end an
+      invite usage).  It will never affect other usages sharing this
+      usage's dialog.
+    */
+    /* Do not change *return_graceful_terminate_usage */
+    return 0;
+
+  case 502: /** @par 502 Bad Gateway 
+
+      This response is aberrant mid-dialog. It will only occur if the
+      @RecordRoute header field was improperly constructed by the
+      proxies involved in setting up the dialog's initial usage. Future
+      requests using this dialog state will also fail. The dialog and
+      any usages sharing it are destroyed.
+    */
+    return terminate_dialog;
+
+  case 503: /** @par 503 Service Unavailable 
+
+      As per @RFC3263, the logic handling locating SIP servers for
+      transactions may handle 503 requests (effectively sequentially
+      forking at the endpoint based on DNS results). If this process
+      does not yield a better response, a 503 may be returned to the
+      transaction user. Like a 500 response, the error is a complaint
+      about this transaction, not the usage. Because this response
+      occurred in the context of an established usage (hence an existing
+      dialog), the route-set has already been formed and any opportunity
+      to try alternate servers (as recommended in @RFC3261) has been exhausted
+      by the @RFC3263 logic. The response should be handled as described
+      for 500 earlier in this memo.
+    */
+    /* Do not change *return_graceful_terminate_usage */
+    return 0;
+
+  case 504: /** @par 504 Server Time-out 
+
+      It is not obvious under what circumstances this
+      response would be returned to a request in an existing dialog.  If
+      it occurs it should have the same affect on the dialog and its
+      usages as described for unknown 5xx responses.
+    */
+    /* Do not change *return_graceful_terminate_usage */
+    return 0;
+
+  case 505: /* Version Not Supported */
+  case 513: /* Message Too Large */
+    /** @par 505 Version Not Supported and 513 Message Too Large
+
+      These responses are objecting to the request, not the usage. The
+      usage is not affected. The dialog is only affected by a change in
+      its local @CSeq. No other usages of the dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 580: /** @par 580 Precondition Failure 
+
+      This response is objecting to the request,
+      not the usage.  The usage is not affected.  The dialog is only
+      affected by a change in its local @CSeq.  No other usages of the
+      dialog are affected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+  }
+
+  if (response_code < 700) switch (response_code) {
+  case 600: /* 600 and 6xx unrecognized responses */
+  default:
+    /** @par 600 and 6xx unrecognized responses
+
+      Unlike 400 Bad Request, a 600 response code says something about
+      the recipient user, not the request that was made. This end user
+      is stating an unwillingness to communicate. 
+
+      If the response contains a @RetryAfter header field value, the
+      user is indicating willingness to communicate later and the
+      request can be retried after the indicated interval. This usage,
+      and any other usages sharing the dialog are unaffected. If the
+      response does not contain a @RetryAfter header field value, the UA
+      may decide to retry after an interval of its choosing or attempt
+      to gracefully terminate the usage. Whether or not to terminate
+      other usages depends on the application. If the UA receives a 600
+      (or unrecognized 6xx) in response to an attempt to gracefully
+      terminate this usage, it can treat this usage as terminated. If
+      this is the last usage sharing the dialog, the dialog is also
+      terminated.
+    */
+    /* Do not change graceful_terminate */
+    return 0;
+
+  case 603: /** @par 603 Decline 
+
+      This response declines the action indicated by the
+      associated request.  It can be used, for example, to decline a
+      hold or transfer attempt.  Receiving this response does NOT
+      terminate the usage it occurs in.  Other usages sharing the dialog
+      are unaffected.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+
+  case 604: /** @par 604 Does Not Exist Anywhere 
+
+      Like 404, this response destroys the
+      dialog and all usages sharing it.  The Request-URI that is being
+      604ed is the remote target set by the @Contact provided by the
+      peer.  Getting this response means something has gone
+      fundamentally wrong with the dialog state.
+    */
+    return terminate_dialog;
+
+  case 606: /** @par 606 Not Acceptable 
+
+      This response is objecting to aspects of the
+      associated request, not the usage the request appears in.  The
+      usage is unaffected.  Any other usages sharing the dialog are
+      unaffected.  The only affect on the dialog is the change in the
+      local @CSeq.
+    */
+    *return_graceful_terminate_usage = 0;
+    return 0;
+  }
+
+  /* Do not change graceful_terminate */
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,919 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_H
+/** Defined when <sofia-sip/sip.h> has been included. */
+#define SIP_H
+
+/**@file sofia-sip/sip.h 
+ * 
+ * SIP objects.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created      : Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** IDs for well-known SIP methods. */
+typedef enum {
+  sip_method_invalid = -1,	/**< Invalid method name */
+  sip_method_unknown = 0,	/**< Unknown method, use @c method_name */
+  sip_method_invite,		/**< INVITE */
+  sip_method_ack,		/**< ACK */
+  sip_method_cancel,		/**< CANCEL */
+  sip_method_bye,		/**< BYE */
+  sip_method_options,		/**< OPTIONS */
+  sip_method_register,		/**< REGISTER */
+  sip_method_info,		/**< INFO */
+  sip_method_prack,		/**< PRACK */
+  sip_method_update,		/**< UPDATE */
+  sip_method_message,		/**< MESSAGE */
+  sip_method_subscribe,		/**< SUBSCRIBE */
+  sip_method_notify,		/**< NOTIFY */
+  sip_method_refer,		/**< REFER */
+  sip_method_publish,		/**< PUBLISH */
+} sip_method_t;
+
+#define SIP_METHOD(s)         sip_method_unknown, #s
+#define SIP_METHOD_ACK        sip_method_ack, "ACK"
+#define SIP_METHOD_CANCEL     sip_method_cancel, "CANCEL"
+#define SIP_METHOD_BYE        sip_method_bye, "BYE"
+#define SIP_METHOD_INVITE     sip_method_invite, "INVITE"
+#define SIP_METHOD_OPTIONS    sip_method_options, "OPTIONS"
+#define SIP_METHOD_REGISTER   sip_method_register, "REGISTER"
+#define SIP_METHOD_INFO       sip_method_info, "INFO"
+#define SIP_METHOD_PRACK      sip_method_prack, "PRACK"
+#define SIP_METHOD_UPDATE     sip_method_update, "UPDATE"
+#define SIP_METHOD_MESSAGE    sip_method_message, "MESSAGE"
+#define SIP_METHOD_SUBSCRIBE  sip_method_subscribe, "SUBSCRIBE"
+#define SIP_METHOD_NOTIFY     sip_method_notify, "NOTIFY"
+#define SIP_METHOD_REFER      sip_method_refer, "REFER"
+#define SIP_METHOD_PUBLISH    sip_method_publish, "PUBLISH"
+
+/** Magic pointer value - never valid for SIP headers. @HI */
+#define SIP_NONE ((void const *)-1L)
+
+/** SIP protocol identifier @HIDE */
+#define SIP_PROTOCOL_TAG   ((void *)0x53495020)	/* 'SIP'20 */
+
+enum {
+  /** Default port for SIP as integer */
+ SIP_DEFAULT_PORT = 5060,
+#define SIP_DEFAULT_PORT SIP_DEFAULT_PORT
+
+/** Default port for SIP as string */
+#define SIP_DEFAULT_SERV "5060"
+
+ /** Default port for SIPS as integer */
+ SIPS_DEFAULT_PORT = 5061,
+#define SIPS_DEFAULT_PORT SIPS_DEFAULT_PORT
+ /** Default port for SIPS as string */
+#define SIPS_DEFAULT_SERV "5061"
+};
+
+/** Time in seconds since Jan 01 1900.  */
+typedef msg_time_t sip_time_t;
+
+/** Latest time that can be expressed with #sip_time_t. @HIDE */
+#define SIP_TIME_MAX ((sip_time_t)MSG_TIME_MAX)
+
+/** SIP message object. */
+typedef struct sip_s                sip_t;
+
+/** Any SIP header - union of all possible SIP headers. */
+typedef union sip_header_u          sip_header_t;
+
+/** Type of a generic SIP header. */
+typedef struct msg_generic_s        sip_generic_t;
+#define g_value g_string
+
+/** Common part of all the header structures. */
+typedef msg_common_t                sip_common_t;
+
+/** SIP parameter string. */
+typedef msg_param_t                 sip_param_t;
+
+/** @To or @From header. */
+typedef struct sip_addr_s           sip_addr_t;
+
+/** @Authorization, @ProxyAuthenticate, @WWWAuthenticate */
+typedef msg_auth_t                  sip_auth_t;
+
+typedef struct sip_request_s 	    sip_request_t;
+typedef struct sip_status_s  	    sip_status_t;
+typedef msg_error_t                 sip_error_t;
+typedef msg_unknown_t               sip_unknown_t;
+typedef msg_separator_t             sip_separator_t;
+typedef msg_payload_t               sip_payload_t;
+
+typedef struct sip_accept_s  	    sip_accept_t;
+typedef msg_accept_any_t      	    sip_accept_encoding_t;
+typedef msg_accept_any_t      	    sip_accept_language_t;
+typedef struct sip_allow_s	    sip_allow_t;
+typedef struct msg_auth_info_s      sip_authentication_info_t;
+typedef struct msg_auth_s 	    sip_authorization_t;
+typedef struct sip_call_id_s 	    sip_call_id_t;
+typedef struct sip_call_info_s      sip_call_info_t;
+typedef struct sip_contact_s 	    sip_contact_t;
+typedef struct sip_cseq_s    	    sip_cseq_t;
+typedef struct msg_generic_s        sip_etag_t;
+typedef struct msg_generic_s        sip_if_match_t;
+typedef msg_content_disposition_t   sip_content_disposition_t;
+typedef msg_list_t	      	    sip_content_encoding_t;
+typedef msg_list_t	      	    sip_content_language_t;
+typedef struct sip_content_length_s sip_content_length_t;
+typedef struct msg_content_type_s   sip_content_type_t;
+typedef struct msg_generic_s        sip_mime_version_t;
+typedef struct sip_date_s	    sip_date_t;
+typedef struct sip_error_info_s     sip_error_info_t;
+typedef struct sip_expires_s        sip_expires_t;
+typedef struct sip_addr_s  	    sip_from_t;
+typedef msg_list_t                  sip_in_reply_to_t;
+typedef struct sip_max_forwards_s   sip_max_forwards_t;
+typedef struct sip_min_expires_s    sip_min_expires_t;
+typedef struct sip_min_se_s         sip_min_se_t;
+typedef struct msg_generic_s        sip_organization_t;
+typedef struct msg_generic_s        sip_priority_t;
+typedef struct msg_auth_s 	    sip_proxy_authenticate_t;
+typedef struct msg_auth_info_s      sip_proxy_authentication_info_t;
+typedef struct msg_auth_s     	    sip_proxy_authorization_t;
+typedef msg_list_t	     	    sip_proxy_require_t;
+typedef struct sip_rack_s           sip_rack_t;
+typedef struct sip_reason_s         sip_reason_t;
+typedef struct sip_route_s     	    sip_record_route_t;
+
+typedef struct sip_refer_to_s       sip_refer_to_t;
+typedef struct sip_referred_by_s    sip_referred_by_t;
+typedef struct sip_replaces_s       sip_replaces_t;
+
+typedef struct sip_request_disposition_s sip_request_disposition_t;
+
+typedef struct sip_caller_prefs_s   sip_caller_prefs_t;
+typedef struct sip_caller_prefs_s   sip_accept_contact_t;
+typedef struct sip_caller_prefs_s   sip_reject_contact_t;
+
+typedef msg_list_t	     	    sip_require_t;
+typedef struct sip_retry_after_s    sip_retry_after_t;
+typedef struct sip_route_s     	    sip_route_t;
+typedef struct sip_rseq_s           sip_rseq_t;     
+typedef struct msg_generic_s        sip_server_t;
+typedef struct sip_session_expires_s
+                                    sip_session_expires_t;
+typedef struct msg_generic_s        sip_subject_t;
+typedef struct sip_subscription_state_s
+                                    sip_subscription_state_t;
+typedef msg_list_t	     	    sip_supported_t;
+typedef struct sip_timestamp_s 	    sip_timestamp_t;
+typedef struct sip_addr_s           sip_to_t;
+typedef msg_list_t	     	    sip_unsupported_t;
+typedef struct msg_generic_s        sip_user_agent_t;
+typedef struct sip_via_s 	    sip_via_t;
+typedef msg_warning_t	            sip_warning_t;
+typedef struct msg_auth_s 	    sip_www_authenticate_t;
+
+typedef struct sip_event_s          sip_event_t;
+typedef msg_list_t                  sip_allow_events_t;
+
+/* RFC 3323 - @Privacy */
+typedef struct sip_privacy_s sip_privacy_t;
+
+/* RFC 3327 - @Path */
+typedef struct sip_route_s     	    sip_path_t;
+
+/* RFC 3329 - Security Mechanism Agreement */
+typedef struct sip_security_agree_s sip_security_client_t;
+typedef struct sip_security_agree_s sip_security_server_t;
+typedef struct sip_security_agree_s sip_security_verify_t;
+
+/* RFC 3608 - Service Route */
+typedef struct sip_route_s     	    sip_service_route_t;
+
+
+/**SIP message object.
+ *
+ * This structure contains a parsed SIP message. The struct is usually
+ * referred with typedef #sip_t. It is used to access the headers and
+ * payload within the SIP message. The generic transport aspects of the
+ * message, like network address, is accessed using the #msg_t object
+ * directly.
+ */
+struct sip_s {
+  msg_common_t               sip_common[1];     /**< For recursive inclusion */
+  msg_pub_t                 *sip_next;          /**< Dummy link to msgfrag */
+  void                      *sip_user;	        /**< Application data */
+  unsigned                   sip_size;          /**< Size of structure */
+  int                        sip_flags;	        /**< Parser flags */
+
+  sip_error_t               *sip_error;	        /**< Erroneous headers */
+
+  /* Pseudoheaders */
+  sip_request_t             *sip_request;       /**< Request line  */
+  sip_status_t              *sip_status;        /**< Status line */
+
+  /* === Headers start here */
+  sip_via_t        	    *sip_via;		/**< Via (v) */
+  sip_route_t               *sip_route;		/**< Route */
+  sip_record_route_t        *sip_record_route;	/**< Record-Route */
+  sip_max_forwards_t        *sip_max_forwards;	/**< Max-Forwards */
+  sip_proxy_require_t       *sip_proxy_require;	/**< Proxy-Require */
+
+  sip_from_t       	    *sip_from;		/**< From (f) */
+  sip_to_t         	    *sip_to;		/**< To (t) */
+  sip_call_id_t             *sip_call_id;	/**< Call-ID (i) */
+  sip_cseq_t       	    *sip_cseq;		/**< CSeq */
+  sip_contact_t             *sip_contact;	/**< Contact (m) */
+  sip_rseq_t                *sip_rseq;          /**< RSeq */
+  sip_rack_t                *sip_rack;          /**< RAck */
+
+  /* Caller Preferences */
+  sip_request_disposition_t *sip_request_disposition; 
+                                                /**< Request-Disposition (d) */
+  sip_accept_contact_t      *sip_accept_contact;/**< Accept-Contact (a) */
+  sip_reject_contact_t      *sip_reject_contact;/**< Reject-Contact (j) */
+
+  sip_expires_t             *sip_expires;	/**< Expires */
+  sip_date_t                *sip_date;		/**< Date */
+  sip_retry_after_t         *sip_retry_after;	/**< Retry-After */
+  sip_timestamp_t           *sip_timestamp;	/**< Timestamp */
+  sip_min_expires_t         *sip_min_expires;   /**< Min-Expires */
+
+  sip_subject_t    	    *sip_subject;	/**< Subject (s) */
+  sip_priority_t            *sip_priority;	/**< Priority */
+
+  sip_call_info_t           *sip_call_info;	/**< Call-Info */
+  sip_organization_t        *sip_organization;	/**< Organization */
+  sip_server_t              *sip_server;	/**< Server */
+  sip_user_agent_t          *sip_user_agent;	/**< User-Agent */
+  sip_in_reply_to_t         *sip_in_reply_to;   /**< In-Reply-To */
+
+  sip_accept_t              *sip_accept;	/**< Accept */
+  sip_accept_encoding_t     *sip_accept_encoding; /**< Accept-Encoding */
+  sip_accept_language_t     *sip_accept_language; /**< Accept-Language */
+
+  sip_allow_t               *sip_allow;		/**< Allow */
+  sip_require_t             *sip_require;	/**< Require */
+  sip_supported_t           *sip_supported;	/**< Supported (k) */
+  sip_unsupported_t         *sip_unsupported;	/**< Unsupported */
+
+  /* RFC 3265 */
+  sip_event_t               *sip_event;	        /**< Event (o) */
+  sip_allow_events_t        *sip_allow_events;  /**< Allow-Events (u) */
+  sip_subscription_state_t  *sip_subscription_state; 
+				/**< Subscription-State */
+
+  sip_proxy_authenticate_t  *sip_proxy_authenticate;
+				/**< Proxy-Authenticate */
+  sip_proxy_authentication_info_t *sip_proxy_authentication_info;
+				/**< Proxy-Authentication-Info */
+  sip_proxy_authorization_t *sip_proxy_authorization;
+				/**< Proxy-Authorization */
+  sip_authorization_t       *sip_authorization;       
+				/**< Authorization */
+  sip_www_authenticate_t    *sip_www_authenticate;
+				/**< WWW-Authenticate */
+  sip_authentication_info_t *sip_authentication_info;
+                                /**< Authentication-Info */
+  sip_error_info_t          *sip_error_info;    /**< Error-Info */
+  sip_warning_t             *sip_warning;	/**< Warning */
+
+  /* RFC 3515 */
+  sip_refer_to_t            *sip_refer_to;      /**< Refer-To (r) */
+  sip_referred_by_t         *sip_referred_by;   /**< Referred-By (b) */
+  sip_replaces_t            *sip_replaces;      /**< Replaces */
+
+  /* draft-ietf-sip-session-timer */
+  sip_session_expires_t     *sip_session_expires;
+				/**< Session-Expires (x) */
+  sip_min_se_t              *sip_min_se;        /**< Min-SE */
+
+  sip_path_t                *sip_path;        /**< Path */
+  sip_service_route_t       *sip_service_route; /**< Service-Route */
+
+  sip_reason_t              *sip_reason;        /**< Reason */
+
+  sip_security_client_t     *sip_security_client; /**< Security-Client */
+  sip_security_server_t     *sip_security_server; /**< Security-Server */
+  sip_security_verify_t     *sip_security_verify; /**< Security-Verify */
+
+  sip_privacy_t             *sip_privacy; /**< Privacy */
+
+  sip_etag_t                *sip_etag;          /**< SIP-ETag */
+  sip_if_match_t            *sip_if_match;      /**< SIP-If-Match */
+
+  /* Entity headers */
+  sip_mime_version_t        *sip_mime_version;	/**< MIME-Version */
+  sip_content_type_t        *sip_content_type;	/**< Content-Type (c) */
+  sip_content_encoding_t    *sip_content_encoding; 
+				/**< Content-Encoding (e) */
+  sip_content_language_t    *sip_content_language; /**< Content-Language */
+  sip_content_disposition_t *sip_content_disposition; 
+				/**< Content-Disposition */
+  sip_content_length_t      *sip_content_length;/**< Content-Length (l) */
+
+  /* === Headers end here */
+
+  sip_unknown_t             *sip_unknown;       /**< Unknown headers */
+  sip_separator_t           *sip_separator;     
+				/**< Separator between headers and payload */
+  sip_payload_t             *sip_payload;	/**< Message payload */
+  msg_multipart_t           *sip_multipart;     /**< Multipart MIME payload */
+};
+
+
+/** @ingroup sip_request
+ * @brief Structure for @ref sip_request "SIP request line".
+ */
+struct sip_request_s
+{
+  sip_common_t     rq_common[1];   /**< Common fragment info */
+  sip_error_t     *rq_next;	   /**< Link to next (dummy) */
+  sip_method_t     rq_method;	   /**< Method enum */
+  char const      *rq_method_name; /**< Method name */
+  url_t            rq_url[1];	   /**< RequestURI */
+  char const      *rq_version;     /**< Protocol version */
+};
+
+/**@ingroup sip_status
+ * @brief Structure for @ref sip_status "SIP status line".
+ */
+struct sip_status_s
+{
+  sip_common_t   st_common[1];	/**< Common fragment info */
+  sip_error_t   *st_next;	/**< Link to next (dummy) */
+  char const    *st_version;	/**< Protocol version */
+  int            st_status;	/**< Status code */
+  char const    *st_phrase;	/**< Status phrase */
+};
+
+/**@ingroup sip_from
+ * @brief Structure for @From and @To headers.
+ */
+struct sip_addr_s
+{
+  sip_common_t       a_common[1];   /**< Common fragment info */
+  sip_error_t       *a_next;
+  char const        *a_display;	    /**< Display name */
+  url_t              a_url[1];	    /**< URL */
+  msg_param_t const *a_params;	    /**< Parameter table  */
+  char const        *a_comment;	    /**< Comment */
+ 
+  char const        *a_tag;	    /**< Tag parameter */
+};
+
+#define a_user a_url->url_user
+#define a_host a_url->url_host
+
+/**@ingroup sip_accept
+ * @brief Structure for @Accept header field.
+ */
+struct sip_accept_s
+{
+  sip_common_t        ac_common[1]; /**< Common fragment info */
+  sip_accept_t       *ac_next;	    /**< Pointer to next @Accept value */
+  char const         *ac_type;	    /**< Pointer to type/subtype */
+  char const         *ac_subtype;   /**< Points after first slash in type */
+  msg_param_t const  *ac_params;    /**< List of parameters */
+  char const         *ac_q;	    /**< Value of q parameter */
+};
+
+/**@ingroup sip_allow
+ * @brief Structure for @Allow header field.
+ *
+ * @NEW_1_12_5 (before used struct msg_list_s with @Allow).
+ */
+struct sip_allow_s
+{
+  msg_common_t       k_common[1];   /**< Common fragment info */
+  msg_list_t        *k_next;	    /**< Link to next */
+  msg_param_t       *k_items;	    /**< List of allowed items */
+  uint32_t           k_bitmap;	    /**< Bitmap of allowed methods. 
+				       @NEW_1_12_5 */
+};
+
+/**@ingroup sip_authentication_info
+ * @brief Structure for @AuthenticationInfo header.
+ *
+ * @deprecated Use struct msg_auth_info_s instead.
+ */
+struct sip_authentication_info_s
+{
+  sip_common_t        ai_common[1]; /**< Common fragment info */
+  sip_error_t        *ai_next;	    /**< Dummy link to next */
+  msg_param_t const  *ai_params;    /**< List of authentication info */
+};
+
+/**@ingroup sip_call_id 
+ * @brief Structure for @CallID (and @InReplyTo) header fields.
+ */
+struct sip_call_id_s {		
+  sip_common_t   i_common[1];	    /**< Common fragment info */
+  sip_call_id_t *i_next;	    /**< Link to next (In-Reply-To) */
+  char const    *i_id;		    /**< ID value */
+  uint32_t       i_hash;	    /**< Hash value (always nonzero) */
+};
+
+/**@ingroup sip_call_info
+ * @brief Structure for @CallInfo header.
+ */
+struct sip_call_info_s
+{
+  sip_common_t        ci_common[1]; /**< Common fragment info */
+  sip_call_info_t    *ci_next;	    /**< Link to next @CallInfo */
+  url_t               ci_url[1];    /**< URI to call info  */
+  msg_param_t const  *ci_params;    /**< List of parameters */
+  char const         *ci_purpose;   /**< Value of @b purpose parameter */
+};
+
+/**@ingroup sip_cseq
+ * @brief Structure for @CSeq header.
+ */
+struct sip_cseq_s
+{
+  sip_common_t   cs_common[1];	    /**< Common fragment info */
+  sip_error_t   *cs_next;	    /**< Link to next (dummy) */
+  uint32_t       cs_seq;	    /**< Sequence number */
+  sip_method_t   cs_method;	    /**< Method enum */
+  char const    *cs_method_name;    /**< Method name */
+};
+
+/**@ingroup sip_contact
+ * @brief Structure for @Contact header field.
+ */
+struct sip_contact_s
+{
+  sip_common_t        m_common[1];  /**< Common fragment info */
+  sip_contact_t      *m_next;	    /**< Link to next @Contact header */
+  char const         *m_display;    /**< Display name */
+  url_t               m_url[1];	    /**< SIP URL */
+  msg_param_t const  *m_params;	    /**< List of contact-params */
+  char const         *m_comment;    /**< Comment */
+
+  char const         *m_q;	    /**< @Priority */
+  char const         *m_expires;    /**< Expiration time */
+};
+
+/**@ingroup sip_content_length
+ * @brief Structure for @ContentLength header.
+ */
+struct sip_content_length_s
+{
+  sip_common_t   l_common[1];	    /**< Common fragment info */
+  sip_error_t   *l_next;	    /**< Link to next (dummy) */
+  uint32_t       l_length;	    /**< Length in bytes */
+};
+
+#if DOCUMENTATION_ONLY
+/**@ingroup sip_content_type
+ *
+ * @brief Structure for @ContentType header.
+ */
+struct sip_content_type_s
+{
+  sip_common_t        c_common[1];  /**< Common fragment info */
+  sip_error_t        *c_next;	    /**< Dummy link to next */
+  char const         *c_type;	    /**< Pointer to type/subtype */
+  char const         *c_subtype;    /**< Points after first slash in type */
+  msg_param_t const  *c_params;	    /**< List of parameters */
+};
+#endif
+
+/**@ingroup sip_date
+ * @brief Structure for @Date header.
+ */
+struct sip_date_s
+{
+  sip_common_t   d_common[1];	    /**< Common fragment info */
+  sip_date_t    *d_next;	    /**< Link to next (dummy) */
+  sip_time_t     d_time;	    /**< Seconds since Jan 1, 1900 */
+};
+
+/**@ingroup sip_error_info
+ * @brief Structure for @ErrorInfo header.
+ */
+struct sip_error_info_s
+{
+  sip_common_t        ei_common[1]; /**< Common fragment info */
+  sip_call_info_t    *ei_next;	    /**< Link to next @ErrorInfo */
+  url_t               ei_url[1];    /**< URI to error description */
+  msg_param_t const  *ei_params;    /**< List of parameters */
+};
+
+/**@ingroup sip_event
+ * @brief Structure for @Event header.
+ */
+struct sip_event_s 
+{
+  sip_common_t        o_common[1];  /**< Common fragment info */
+  sip_error_t        *o_next;	    /**< Link to next (dummy) */
+  char const *        o_type;	    /**< @Event type */
+  msg_param_t const  *o_params;	    /**< List of parameters */
+  char const         *o_id;	    /**< @Event ID */
+};
+
+/**@ingroup sip_expires
+ * @brief Structure for @Expires header.
+ */
+struct sip_expires_s
+{
+  sip_common_t        ex_common[1]; /**< Common fragment info */
+  sip_error_t        *ex_next;	    /**< Link to next (dummy) */
+  sip_time_t          ex_date;	    /**< Seconds since Jan 1, 1900 */
+# define ex_time ex_date
+  sip_time_t          ex_delta;	    /**< Delta seconds */
+};
+
+/**@ingroup sip_max_forwards
+ * @brief Structure for @MaxForwards header.
+ */
+struct sip_max_forwards_s
+{
+  sip_common_t        mf_common[1]; /**< Common fragment info */
+  sip_error_t        *mf_next;	    /**< Link to next (dummy) */
+  unsigned long       mf_count;	    /**< Forwarding count */
+};
+
+/**@ingroup sip_min_expires
+ * @brief Structure for @MinExpires header.
+ */
+struct sip_min_expires_s
+{
+  sip_common_t        me_common[1]; /**< Common fragment info */
+  sip_error_t        *me_next;	    /**< Link to next (dummy) */
+  unsigned long       me_delta;	    /**< Seconds */
+};
+
+/**@ingroup sip_rack
+ * @brief Structure for @b Rack header.
+ */
+struct sip_rack_s
+{
+  sip_common_t        ra_common;        /**< Common fragment info */
+  sip_error_t        *ra_next;		/**< Dummy link to next */
+  uint32_t            ra_response;	/**< Sequence number of response */
+  uint32_t            ra_cseq;		/**< Sequence number of request  */
+  sip_method_t        ra_method;	/**< Original request method */
+  char const         *ra_method_name;	/**< Original request method name */
+};
+
+/**@ingroup sip_refer_to
+ * @brief Structure for @ReferTo header.
+ */
+struct sip_refer_to_s
+{
+  sip_common_t        r_common[1];  /**< Common fragment info */
+  sip_error_t        *r_next;	    /**< Link to next (dummy) */
+  char const         *r_display;
+  url_t               r_url[1];	    /**< URI to reference */
+  msg_param_t const  *r_params;	    /**< List of parameters */
+};
+
+/**@ingroup sip_referred_by
+ * @brief Structure for @ReferredBy header.
+ */
+struct sip_referred_by_s
+{
+  sip_common_t        b_common[1];  /**< Common fragment info */
+  sip_error_t        *b_next;	    /**< Link to next (dummy) */
+  char const         *b_display;
+  url_t               b_url[1];	    /**< Referrer-URI */
+  msg_param_t const  *b_params;	    /**< List of parameters */
+  char const         *b_cid;	    /**< The cid parameter */
+};
+
+
+/**@ingroup sip_replaces
+ * @brief Structure for @Replaces header.
+ */
+struct sip_replaces_s
+{
+  sip_common_t        rp_common[1];   /**< Common fragment info */
+  sip_error_t        *rp_next;	      /**< Link to next (dummy) */
+  char const         *rp_call_id;     /**< @CallID of dialog to replace */
+  msg_param_t const  *rp_params;      /**< List of parameters */
+  char const         *rp_to_tag;      /**< Value of "to-tag" parameter */
+  char const         *rp_from_tag;    /**< Value of "from-tag" parameter */
+  unsigned            rp_early_only;  /**< early-only parameter */
+};
+
+
+/**@ingroup sip_retry_after
+ * @brief Structure for @RetryAfter header.
+ */
+struct sip_retry_after_s {
+  sip_common_t        af_common[1]; /**< Common fragment info */
+  sip_error_t        *af_next;	    /**< Link to next (dummy) */
+  sip_time_t          af_delta;	    /**< Seconds to before retry */
+  char const         *af_comment;   /**< Comment string */
+  msg_param_t const  *af_params;    /**< List of parameters */
+  char const         *af_duration;  /**< Value of "duration" parameter */
+};
+
+/**@ingroup sip_request_disposition
+ * @brief Structure for @RequestDisposition header.
+ */
+struct sip_request_disposition_s
+{
+  sip_common_t        rd_common[1]; /**< Common fragment info */
+  sip_error_t        *rd_next;	    /**< Link to next (dummy) */
+  msg_param_t        *rd_items;     /**< List of directives */
+};
+
+/**@ingroup sip_caller_preferences
+ * @brief Structure for @AcceptContact and @RejectContact header fields.
+ */
+struct sip_caller_prefs_s
+{
+  sip_common_t        cp_common[1];   /**< Common fragment info */
+  sip_caller_prefs_t *cp_next;	      /**< Link to next (dummy) */
+  msg_param_t const  *cp_params;      /**< List of parameters */
+  char const         *cp_q;           /**< @Priority */
+  unsigned            cp_require :1;  /**< Value of "require" parameter */
+  unsigned            cp_explicit :1; /**< Value of "explicit" parameter */
+};
+
+/**@ingroup sip_reason
+ * @brief Structure for @Reason header field.
+ */
+struct sip_reason_s
+{
+  sip_common_t        re_common[1]; /**< Common fragment info */
+  sip_reason_t       *re_next;	    /**< Link to next */
+  char const         *re_protocol;  /**< Protocol */
+  msg_param_t const  *re_params;    /**< List of reason parameters */
+  char const         *re_cause;	    /**< Value of cause parameter */
+  char const         *re_text;	    /**< Value of text parameter */
+};
+
+/**@ingroup sip_route
+ * @brief Structure for @Route and @RecordRoute header fields.
+ */
+struct sip_route_s
+{
+  sip_common_t        r_common[1];  /**< Common fragment info */
+  sip_route_t        *r_next;	    /**< Link to next */
+  char const         *r_display;    /**< Display name */
+  url_t               r_url[1];	    /**< @Route URL */
+  msg_param_t const  *r_params;	    /**< List of route parameters */
+};
+
+/**@ingroup sip_rseq 
+ * @brief Structure for @RSeq header.
+ */
+struct sip_rseq_s
+{
+  sip_common_t        rs_common[1];	/**< Common fragment info */
+  sip_error_t        *rs_next;		/**< Dummy link to next */
+  unsigned long       rs_response;	/**< Sequence number of response */
+};
+
+/**@ingroup sip_session_expires 
+ * @brief Structure for @SessionExpires header.
+ */
+struct sip_session_expires_s
+{
+  sip_common_t        x_common[1];	/**< Common fragment info */
+  sip_error_t        *x_next;		/**< Dummy link to next */
+  unsigned long       x_delta;		/**< Delta-seconds */
+  msg_param_t const  *x_params;		/**< List of parameters */
+  char const         *x_refresher;	/**< Value of "refresher"
+					 * parameter: UAS or UAC */
+};
+
+/**@ingroup sip_min_se 
+ * @brief Structure for @MinSE header.
+ */
+struct sip_min_se_s
+{
+  sip_common_t        min_common[1];	/**< Common fragment info */
+  sip_error_t        *min_next;		/**< Dummy link to next */
+  unsigned long       min_delta;	/**< Delta-seconds */
+  msg_param_t const  *min_params;	/**< List of extension parameters */
+};
+
+/**@ingroup sip_subscription_state 
+ * @brief Structure for @SubscriptionState header.
+ */
+struct sip_subscription_state_s
+{
+  sip_common_t        ss_common[1];   /**< Common fragment info */
+  sip_error_t        *ss_next;	      /**< Dummy link to next */
+  /** Subscription state: "pending", "active" or "terminated" */
+  char const         *ss_substate; 
+  msg_param_t const  *ss_params;      /**< List of parameters */
+  char const         *ss_reason;      /**< Reason for termination  */
+  char const         *ss_expires;     /**< Subscription lifetime */
+  char const         *ss_retry_after; /**< Value of retry-after parameter */
+};
+
+/**@ingroup sip_timestamp
+ * @brief Structure for @Timestamp header.
+ */
+struct sip_timestamp_s 
+{
+  sip_common_t        ts_common[1]; /**< Common fragment info */
+  sip_error_t        *ts_next;	    /**< Dummy link to next */
+  char const         *ts_stamp;	    /**< Original timestamp */
+  char const         *ts_delay;	    /**< Delay at UAS */
+};
+
+/**@ingroup sip_via
+ * @brief Structure for @Via header field.
+ */
+struct sip_via_s
+{
+  sip_common_t        v_common[1];  /**< Common fragment info */
+  sip_via_t          *v_next;	    /**< Link to next @Via header */
+  char const         *v_protocol;   /**< Application and transport protocol */
+  char const         *v_host;	    /**< Hostname */
+  char const         *v_port;	    /**< Port number */
+  msg_param_t const  *v_params;	    /**< List of via-params */
+  char const         *v_comment;    /**< Comment */
+  char const         *v_ttl;	    /**< Value of "ttl" parameter */
+  char const         *v_maddr;	    /**< Value of "maddr" parameter */
+  char const         *v_received;   /**< Value of "received" parameter*/
+  char const         *v_branch;	    /**< Value of "branch" parameter */
+  char const         *v_rport;	    /**< Value of "rport" parameter */
+  char const         *v_comp;	    /**< Value of "comp" parameter */
+};
+
+/**@ingroup sip_security_client
+ * @brief Structure for @SecurityClient, @SecurityServer, and
+ * @SecurityVerify headers.
+ */
+struct sip_security_agree_s
+{
+  sip_common_t        sa_common[1]; /**< Common fragment info */
+  struct sip_security_agree_s 
+                     *sa_next;	    /**< Link to next mechanism */
+  char const         *sa_mec;	    /**< Security mechanism */
+  msg_param_t const  *sa_params;    /**< List of mechanism parameters */
+  char const         *sa_q;	    /**< Value of q (preference) parameter */
+  char const         *sa_d_alg;	    /**< Value of d-alg parameter */
+  char const         *sa_d_qop;	    /**< Value of d-qop parameter */
+  char const         *sa_d_ver;	    /**< Value of d-ver parameter */
+};
+
+/**@ingroup sip_privacy
+ * @brief Structure for @Privacy header.
+ */
+struct sip_privacy_s
+{
+  sip_common_t       priv_common[1];/**< Common fragment info */
+  sip_error_t       *priv_next;	    /**< Dummy link */
+  msg_param_t const *priv_values;   /**< @Privacy values */
+};
+
+/* union representing any SIP header
+ * these are arrays of size 1 for easy casting
+ */
+union sip_header_u
+{
+  sip_common_t               sh_common[1]; 
+  struct
+  {
+    sip_common_t             shn_common;
+    sip_header_t            *shn_next;
+  }                          sh_header_next[1];
+#define sh_next              sh_header_next->shn_next
+#define sh_class sh_common->h_class
+#define sh_succ  sh_common->h_succ
+#define sh_prev  sh_common->h_prev
+#define sh_data  sh_common->h_data
+#define sh_len   sh_common->h_len
+
+  sip_addr_t                 sh_addr[1];
+  sip_auth_t                 sh_auth[1];
+  sip_generic_t              sh_generic[1];
+
+  sip_request_t              sh_request[1];
+  sip_status_t               sh_status[1];
+
+  sip_error_t                sh_error[1];
+
+  sip_via_t                  sh_via[1];
+  sip_route_t                sh_route[1];
+  sip_record_route_t         sh_record_route[1];
+  sip_max_forwards_t         sh_max_forwards[1];
+
+  sip_from_t                 sh_from[1];
+  sip_to_t                   sh_to[1];
+  sip_contact_t              sh_contact[1];
+  sip_call_id_t              sh_call_id[1];
+  sip_cseq_t                 sh_cseq[1];
+  sip_rseq_t                 sh_rseq[1];
+  sip_rack_t                 sh_rack[1];
+                             
+  sip_subject_t              sh_subject[1];
+  sip_priority_t             sh_priority[1];
+
+  sip_date_t                 sh_date[1];
+  sip_retry_after_t          sh_retry_after[1];
+  sip_timestamp_t            sh_timestamp[1];
+  sip_expires_t              sh_expires[1];
+  sip_min_expires_t          sh_min_expires[1];
+
+  sip_call_info_t            sh_call_info[1];
+  sip_organization_t         sh_organization[1];
+  sip_server_t               sh_server[1];
+  sip_user_agent_t           sh_user_agent[1];
+  sip_in_reply_to_t          sh_in_reply_to[1];
+
+  sip_accept_t               sh_accept[1];
+  sip_accept_encoding_t      sh_accept_encoding[1];
+  sip_accept_language_t      sh_accept_language[1];
+                             
+  sip_allow_t                sh_allow[1];
+  sip_require_t              sh_require[1];
+  sip_proxy_require_t        sh_proxy_require[1];
+  sip_supported_t            sh_supported[1];
+  sip_unsupported_t          sh_unsupported[1];
+
+  sip_event_t                sh_event[1];
+  sip_allow_events_t         sh_allow_events[1];
+  sip_subscription_state_t   sh_subscription_state[1];
+
+  sip_proxy_authenticate_t   sh_proxy_authenticate[1];
+  sip_proxy_authentication_info_t sh_proxy_authentication_info[1];
+  sip_proxy_authorization_t  sh_proxy_authorization[1]; 
+                             
+  sip_authorization_t        sh_authorization[1];
+  sip_www_authenticate_t     sh_www_authenticate[1];
+  sip_authentication_info_t  sh_authentication_info[1];
+
+  sip_error_info_t           sh_error_info[1];
+  sip_warning_t              sh_warning[1];
+
+  sip_refer_to_t             sh_refer_to[1];
+  sip_referred_by_t          sh_referred_by[1];
+  sip_replaces_t             sh_replaces[1];
+
+  /* Caller-Preferences */
+  sip_caller_prefs_t         sh_caller_prefs[1];
+  sip_request_disposition_t  sh_request_disposition[1];
+  sip_accept_contact_t       sh_accept_contact[1];
+  sip_reject_contact_t       sh_reject_contact[1];
+   
+  sip_session_expires_t      sh_session_expires[1];
+  sip_min_se_t               sh_min_se[1];
+
+  sip_path_t                 sh_path[1];
+  sip_service_route_t        sh_service_route[1];
+
+  sip_reason_t               sh_reason[1];
+
+  sip_security_client_t      sh_security_client[1];
+  sip_security_server_t      sh_security_server[1];
+  sip_security_verify_t      sh_security_verify[1];
+
+  sip_privacy_t              sh_privacy[1];
+
+  sip_etag_t                 sh_etag[1];
+  sip_if_match_t             sh_if_match[1];
+    
+  /* Entity headers */
+  sip_mime_version_t         sh_mime_version[1];
+  sip_content_type_t         sh_content_type[1];
+  sip_content_encoding_t     sh_content_encoding[1];
+  sip_content_language_t     sh_content_language[1];
+  sip_content_length_t       sh_content_length[1];
+  sip_content_disposition_t  sh_content_disposition[1];
+
+  sip_unknown_t              sh_unknown[1];
+
+  sip_separator_t            sh_separator[1];
+  sip_payload_t              sh_payload[1];
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SIP_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,98 @@
+/**@file sofia-sip/sip_extra.h.in
+ *  -*- C -*-
+ * Template for <sofia-sip/sip_extra.h>.
+ *
+ * @date Created: Thu Oct  5 19:10:58 EEST 2006
+ */
+
+/* -*- C -*-
+ *
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_EXTRA_H
+/** Defined when <sofia-sip/sip_extra.h> has been included. */
+#define SIP_EXTRA_H
+
+/**@file sofia-sip/sip_extra.h
+*
+ * @brief Extension headers for SIP.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct sip_refer_sub_s      sip_refer_sub_t;
+
+/**@ingroup sip_refer_sub
+ * @brief Structure for @ReferSub header.
+ */
+struct sip_refer_sub_s
+{
+  sip_common_t        rs_common[1];   	/**< Common fragment info */
+  sip_error_t        *rs_next;        	/**< Dummy link to next */
+  char const         *rs_value;       	/**< "true" or "false" */
+  msg_param_t const  *rs_params;      	/**< List of extension parameters */
+};
+
+typedef struct sip_suppress_body_if_match_s sip_suppress_body_if_match_t;
+
+/**@ingroup sip_suppress_body_if_match
+ * @brief Structure for @SuppressBodyIfMatch header.
+ */
+struct sip_suppress_body_if_match_s
+{
+  sip_common_t   sbim_common[1];	/**< Common fragment info */
+  sip_error_t   *sbim_next;		/**< Dummy link to next header */
+  char const    *sbim_tag;		/**< Entity-tag */
+};
+
+typedef struct sip_suppress_notify_if_match_s sip_suppress_notify_if_match_t;
+
+/**@ingroup sip_suppress_notify_if_match
+ * @brief Structure for @SuppressNotifyIfMatch header.
+ */
+struct sip_suppress_notify_if_match_s
+{
+  sip_common_t   snim_common[1];	/**< Common fragment info */
+  sip_error_t   *snim_next;		/**< Dummy link to next header */
+  char const    *snim_tag;		/**< Entity-tag */
+};
+
+
+
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SIP_EXTRA_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,78 @@
+/** -*- C -*- 
+ *
+ * @file sofia-sip/sip_hclasses.h.in
+ *
+ * Template for <sip_hclasses.h>.
+ */
+
+/* 
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_HCLASSES_H
+/** Defined when <sofia-sip/sip_hclasses.h> has been included. */
+#define SIP_HCLASSES_H
+
+/**@file sofia-sip/sip_hclasses.h
+ * @brief Declarations of SIP header classes.
+ * 
+ * #AUTO#
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jan 23 19:26:31 2003 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+
+enum { 
+  /**@ingroup sip_#xxxxxx# @internal 
+   *
+   * Hash of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#".
+   *
+   * @since New in #version#.
+   */
+  sip_#xxxxxx#_hash = #hash# 
+};
+
+/**Header class for @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#".
+ * 
+ * The header class sip_#xxxxxx#_class defines how a SIP
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" is parsed and printed.
+ * It also contains methods used by SIP parser and other functions to
+ * manipulate the #sip_#xxxxxx#_t header structure.
+ *
+ * @ingroup sip_#xxxxxx#
+ *
+ * @since New in #version#.
+ */
+SIP_DLL extern msg_hclass_t sip_#xxxxxx#_class[];
+
+
+SOFIA_END_DECLS
+#endif /* !defined SIP_HCLASSES_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,416 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_HEADER_H
+/**Defined when <sofia-sip/sip_header.h> has been included.*/
+#define SIP_HEADER_H 
+
+/**@file sofia-sip/sip_header.h 
+ *
+ * SIP parser library prototypes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date  Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+#ifndef _STRING_H
+#include <string.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Return built-in SIP parser object. */
+SOFIAPUBFUN msg_mclass_t *sip_default_mclass(void);
+
+/** Check that sip_t is a SIP structure (not RTSP or HTTP). @HIDE */
+#define sip_is_sip(sip) ((sip) && (sip)->sip_ident == SIP_PROTOCOL_TAG)
+
+/** Initializer for a SIP header object. @HIDE */
+#define SIP_HDR_INIT(name) {{{ 0, 0, sip_##name##_class }}}
+
+/** Initialize a SIP header structure. @HIDE */
+#define SIP_HEADER_INIT(h, sip_class, size)	       \
+  ((void)memset((h), 0, (size)),		       \
+   (void)(((sip_common_t *)(h))->h_class = (sip_class)),	\
+   (h))
+
+/** Serialize headers into the fragment chain. */
+SOFIAPUBFUN int sip_serialize(msg_t *msg, sip_t *sip);
+
+/** Encode a SIP message. */
+SOFIAPUBFUN issize_t sip_e(sip_t const *sip, int flags, char b[], isize_t size);
+
+/** Test if @a header is a pointer to a SIP header object. */
+SOFIAPUBFUN int sip_is_header(sip_header_t const *header);
+
+/** Convert the header @a h to a string allocated from @a home. */
+SOFIAPUBFUN char *sip_header_as_string(su_home_t *home,
+				       sip_header_t const *h);
+
+/** Add a duplicate of header object to a SIP message. */
+SOFIAPUBFUN int sip_add_dup(msg_t *, sip_t *, sip_header_t const *);
+
+/** Add a duplicate of header object to the SIP message. */
+SOFIAPUBFUN int sip_add_dup_as(msg_t *msg, sip_t *sip,
+			       msg_hclass_t *hc, sip_header_t const *o);
+
+/** Add duplicates of headers to the SIP message. */
+SOFIAPUBFUN int sip_add_headers(msg_t *msg, sip_t *sip, 
+				void const *extra, va_list headers);
+
+/** Add duplicates of headers from taglist to the SIP message. */
+SOFIAPUBFUN int sip_add_tl(msg_t *msg, sip_t *sip,
+			   tag_type_t tag, tag_value_t value, ...);
+
+/** Add duplicates of headers from taglist to the SIP message. */
+SOFIAPUBFUN int sip_add_tagis(msg_t *, sip_t *, tagi_t const **inout_list);
+
+/** Parse a string as a header and add it to the SIP message. */
+SOFIAPUBFUN int sip_add_make(msg_t *, sip_t *, msg_hclass_t *hc, char const *s);
+
+/** Convert headers from taglist as URL query. */
+SOFIAPUBFUN char *sip_headers_as_url_query(su_home_t *home,
+					   tag_type_t tag, tag_value_t value,
+					   ...);
+
+/** Convert URL query to a tag list. */
+SOFIAPUBFUN tagi_t *sip_url_query_as_taglist(su_home_t *home,
+					     char const *query,
+					     msg_mclass_t const *parser);
+
+/** Complete SIP message. */
+SOFIAPUBFUN int sip_complete_message(msg_t *msg);
+
+/** Clear encoded data. @HIDE */
+#define sip_fragment_clear(a) ((a)->h_data = NULL, (a)->h_len = 0)
+
+/* Use __attribute__ to allow argument checking for sip_header_format() */
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x) 
+#endif
+
+/** Make a SIP header with formatting provided. */
+SOFIAPUBFUN sip_header_t *sip_header_format(su_home_t *home, 
+					    msg_hclass_t *hc,
+					    char const *fmt,
+					    ...)
+  __attribute__((__format__ (printf, 3, 4)));
+
+/** Return current time */
+SOFIAPUBFUN sip_time_t sip_now(void);
+
+SOFIAPUBVAR char const sip_method_name_ack[];
+SOFIAPUBVAR char const sip_method_name_bye[];
+SOFIAPUBVAR char const sip_method_name_cancel[];
+SOFIAPUBVAR char const sip_method_name_invite[];
+SOFIAPUBVAR char const sip_method_name_options[];
+SOFIAPUBVAR char const sip_method_name_register[];
+SOFIAPUBVAR char const sip_method_name_info[];
+SOFIAPUBVAR char const sip_method_name_prack[];
+SOFIAPUBVAR char const sip_method_name_comet[];
+SOFIAPUBVAR char const sip_method_name_message[];
+SOFIAPUBVAR char const sip_method_name_subscribe[];
+SOFIAPUBVAR char const sip_method_name_notify[];
+SOFIAPUBVAR char const sip_method_name_refer[];
+
+/** @internal UDP transport version string. */ 
+SOFIAPUBVAR char const sip_transport_udp[];
+/** @internal TCP transport version string. */ 
+SOFIAPUBVAR char const sip_transport_tcp[];
+/** @internal SCTP transport version string. */ 
+SOFIAPUBVAR char const sip_transport_sctp[];
+/** @internal TLS transport version string. */ 
+SOFIAPUBVAR char const sip_transport_tls[];
+/** @internal SIP version string. */ 
+SOFIAPUBVAR char const sip_version_2_0[];
+
+#define SIP_VERSION_CURRENT sip_version_2_0
+
+/** SIP parser version */
+SOFIAPUBVAR char const sip_parser_version[];
+
+/** Get SIP service name */
+#define SIP_PORT(s) ((s) ? (s) : "5060")
+
+/** Get SIPS service name */
+#define SIPS_PORT(s) ((s) ? (s) : "5061")
+
+/** Return string corresponding to the method. */
+SOFIAPUBFUN char const *sip_method_name(sip_method_t method, char const *name);
+
+/** Return code corresponding to the method code */
+SOFIAPUBFUN sip_method_t sip_method_code(char const *name);
+
+SOFIAPUBVAR char const * const sip_method_names[];
+
+#define SIP_METHOD_NAME(method, name) \
+ ((method) == sip_method_unknown ? (name) : sip_method_name(method, name))
+
+#define sip_header_make(h, c, s) \
+  ((sip_header_t *)msg_header_make((h), (c), (s)))
+#define sip_header_vformat(h, c, f, a) \
+  ((sip_header_t *)msg_header_vformat((h), (c), (f), (a)))
+
+SOFIA_END_DECLS
+#ifndef SIP_PROTOS_H
+#include <sofia-sip/sip_protos.h>
+#endif
+SOFIA_BEGIN_DECLS
+
+/** Create a request line object. */
+SOFIAPUBFUN
+sip_request_t *sip_request_create(su_home_t *home,
+				  sip_method_t method, const char *name,
+				  url_string_t const *url,
+				  char const *version);
+
+/** Create a status line object. */
+SOFIAPUBFUN
+sip_status_t *sip_status_create(su_home_t *home,
+				unsigned status,
+				char const *phrase,
+				char const *version);
+
+/** Create a @CallID header object. */
+SOFIAPUBFUN sip_call_id_t *sip_call_id_create(su_home_t *home,
+					      char const *domain);
+
+/** Create a @CSeq header object.  */
+SOFIAPUBFUN sip_cseq_t *sip_cseq_create(su_home_t *, uint32_t seq, 
+					unsigned method, char const *name);
+
+/** Create a @Contact header object. */
+SOFIAPUBFUN sip_contact_t * sip_contact_create(su_home_t *, 
+					       url_string_t const *url, 
+					       char const *param,
+					       /* char const *params, */
+					       ...);
+
+/** Calculate expiration time of a @Contact header. */
+SOFIAPUBFUN sip_time_t sip_contact_expires(sip_contact_t const *m,
+					   sip_expires_t const *ex,
+					   sip_date_t const *date,
+					   sip_time_t def,
+					   sip_time_t now);
+
+/** Create a @ContentLength header object. */
+SOFIAPUBFUN
+sip_content_length_t *sip_content_length_create(su_home_t *, uint32_t n);
+
+/** Create an @Date header object. */
+SOFIAPUBFUN sip_date_t *sip_date_create(su_home_t *, sip_time_t t);
+
+/** Create an @Expires header object. */
+SOFIAPUBFUN sip_expires_t *sip_expires_create(su_home_t *, sip_time_t delta);
+
+/** Create a @Route header object. */
+SOFIAPUBFUN sip_route_t *sip_route_create(su_home_t *home, url_t const *url, 
+					  url_t const *maddr);
+
+/** Create a @RecordRoute header object. */
+SOFIAPUBFUN sip_record_route_t *sip_record_route_create(su_home_t *,
+							url_t const *rq_url,
+							url_t const *m_url);
+
+/** Create a @From header object. */
+SOFIAPUBFUN sip_from_t *sip_from_create(su_home_t *, url_string_t const *url);
+
+SOFIAPUBFUN int sip_from_tag(su_home_t *, sip_from_t *from, char const *tag);
+
+/** Create a @To header object. */
+SOFIAPUBFUN sip_to_t *sip_to_create(su_home_t *, url_string_t const *url);
+
+SOFIAPUBFUN int sip_to_tag(su_home_t *, sip_to_t *to, char const *tag);
+
+/** Create a @Via object. */ 
+SOFIAPUBFUN sip_via_t *sip_via_create(su_home_t *h,
+				      char const *host,
+				      char const *port, 
+				      char const *transport,
+				      /* char const *params */
+				      ...);
+
+/** Get transport protocol name. */
+#if SU_HAVE_INLINE
+su_inline char const *sip_via_transport(sip_via_t const *v)
+{
+  char const *tp = v->v_protocol;
+  if (tp) {
+    tp = strchr(tp, '/'); 
+    if (tp) {
+      tp = strchr(tp + 1, '/');
+      if (tp)
+	return tp + 1;
+    }
+  }
+  return NULL;
+}
+#else
+char const *sip_via_transport(sip_via_t const *v);
+#endif
+
+SOFIAPUBFUN char const *sip_via_port(sip_via_t const *v, int *using_rport);
+
+SOFIAPUBFUN
+sip_payload_t *sip_payload_create(su_home_t *, void const *data, isize_t len);
+
+/**@ingroup sip_payload
+ *
+ * Initialize a SIP payload structure with pointer to data and its length. 
+ *
+ * The SIP_PAYLOAD_INIT2() macro initializes a #sip_payload_t header
+ * structure with a pointer to data and its length in octets. For
+ * instance,
+ * @code 
+ *  sip_payload_t txt_payload = SIP_PAYLOAD_INIT2(txt, strlen(txt));
+ * @endcode
+ *
+ * The SIP_PAYLOAD_INIT2() macro can be used when creating a new payload
+ * from heap is not required, for instance, when the resulting payload
+ * structure is immediately copied.
+ *
+ * @HIDE 
+ */
+#define SIP_PAYLOAD_INIT2(data, length) \
+  {{{ 0, 0, sip_payload_class, data, length }, NULL, data, length }}
+
+/** Create a SIP separator line structure. */
+SOFIAPUBFUN sip_separator_t *sip_separator_create(su_home_t *home);
+
+/** Check that a required feature is supported. */
+SOFIAPUBFUN
+sip_unsupported_t *sip_has_unsupported(su_home_t *,
+				       sip_supported_t const *support, 
+				       sip_require_t const *require);
+
+SOFIAPUBFUN
+sip_unsupported_t *sip_has_unsupported2(su_home_t *,
+					sip_supported_t const *support,
+					sip_require_t const *by_require,
+					sip_require_t const *require);
+
+SOFIAPUBFUN
+sip_unsupported_t *
+sip_has_unsupported_any(su_home_t *,
+			sip_supported_t const *support,
+			sip_require_t const *by_require,
+			sip_proxy_require_t const *by_proxy_require,
+			sip_require_t const *require,
+			sip_require_t const *require2,
+			sip_require_t const *require3);
+
+/** Check that a feature is supported. */
+SOFIAPUBFUN
+int sip_has_supported(sip_supported_t const *support, char const *feature);
+
+/** Check that a feature is in the list. */
+SOFIAPUBFUN
+int sip_has_feature(msg_list_t const *supported, char const *feature);
+
+SOFIAPUBFUN int sip_is_allowed(sip_allow_t const *allow, 
+			       sip_method_t method, char const *name);
+
+/* ---------------------------------------------------------------------------
+ * Bitmasks for header classifications
+ */
+enum {
+  sip_mask_request = 1,
+  sip_mask_response = 2,
+  sip_mask_ua = 4,
+  sip_mask_proxy = 8,
+  sip_mask_registrar = 16,
+  sip_mask_100rel = 32,
+  sip_mask_events = 64,
+  sip_mask_timer = 128,
+  sip_mask_privacy = 256,
+  sip_mask_pref = 512,
+  sip_mask_publish = 1024
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Here are @deprecated functions and names for compatibility */
+
+/** Encode a SIP header field (name: contents CRLF). */
+SOFIAPUBFUN issize_t sip_header_e(char[], isize_t, sip_header_t const *, int);
+
+/** Decode a SIP header string (name: contents CRLF?). */
+SOFIAPUBFUN
+sip_header_t *sip_header_d(su_home_t *, msg_t const *, char const *);
+
+/** Encode contents of a SIP header field. */
+SOFIAPUBFUN issize_t sip_header_field_e(char[], isize_t, sip_header_t const *, int);
+
+/** Decode the string containing header field */
+SOFIAPUBFUN issize_t sip_header_field_d(su_home_t *, sip_header_t *, char *, isize_t);
+
+/** Calculate the size of a SIP header and associated memory areas. */
+SOFIAPUBFUN isize_t sip_header_size(sip_header_t const *h);
+
+/** Duplicate (deep copy) a SIP header or whole list. */ 
+SOFIAPUBFUN sip_header_t *sip_header_dup(su_home_t *, sip_header_t const *);
+
+/** Copy a SIP header or whole list. */
+SOFIAPUBFUN sip_header_t *sip_header_copy(su_home_t *, sip_header_t const *o);
+
+/** Add an event to @AllowEvents header. */
+SOFIAPUBFUN int sip_allow_events_add(su_home_t *, 
+				     sip_allow_events_t *ae, 
+				     char const *e);
+
+/** Add a parameter to a @Contact header object. */
+SOFIAPUBFUN int sip_contact_add_param(su_home_t *, sip_contact_t *,
+				      char const *param);
+
+SOFIAPUBFUN int sip_to_add_param(su_home_t *, sip_to_t *, char const *);
+
+SOFIAPUBFUN int sip_from_add_param(su_home_t *, sip_from_t *, char const *);
+
+/** Add a parameter to a @Via header object. */ 
+SOFIAPUBFUN int sip_via_add_param(su_home_t *, sip_via_t *, char const *);
+
+#define sip_from_make_url     sip_from_create
+#define sip_to_make_url       sip_to_create
+#define sip_params_find       msg_params_find
+
+SOFIA_END_DECLS
+
+#endif 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_PARSER_H
+/** Defined when <sofia-sip/sip_parser.h> has been included.*/
+#define SIP_PARSER_H 
+
+
+/**@ingroup sip_parser 
+ * @file sofia-sip/sip_parser.h
+ *
+ * SIP parser provider interface.
+ *
+ * This file contains functions and macros used to create a SIP parser using
+ * generic text message parser, and to define new SIP header classes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Mar  8 15:13:11 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+
+#ifndef MSG_PARSER_H
+#include <sofia-sip/msg_parser.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------------
+ * 1) Macros for defining boilerplate functions and structures for each header
+ */
+
+#define SIP_HDR_TEST(x)    ((x)->sh_class)
+
+/** Define a header class for a SIP header. @HIDE */
+#define SIP_HEADER_CLASS(c, l, s, params, kind, dup)		\
+  MSG_HEADER_CLASS(sip_, c, l, s, params, kind, sip_ ## dup, sip_ ## dup)
+
+/** Define a header class for a critical SIP header. @HIDE */
+#define SIP_HEADER_CLASS_C(c, l, s, params, kind, dup)	\
+  MSG_HEADER_CLASS_C(sip_, c, l, s, params, kind, sip_ ## dup, sip_ ## dup)
+
+/** Define a header class for headers without any extra data to copy. @HIDE  */
+#define SIP_HEADER_CLASS_G(c, l, s, kind) \
+  MSG_HEADER_CLASS(sip_, c, l, s, g_common, kind, msg_generic, sip_null)
+
+/** Define a header class for a msg_list_t kind of header. @HIDE */
+#define SIP_HEADER_CLASS_LIST(c, l, s, kind) \
+  MSG_HEADER_CLASS(sip_, c, l, s, k_items, kind, msg_list, sip_null)
+
+/** Define a authorization header class. @HIDE */
+#define SIP_HEADER_CLASS_AUTH(c, l, kind) \
+  MSG_HEADER_CLASS(sip_, c, l, "", au_params, kind, msg_auth, sip_null)
+
+#define sip_null_update NULL
+#define sip_any_update NULL
+
+/* ---------------------------------------------------------------------------
+ * 2) Prototypes for internal decoding/encoding functions
+ */
+
+/* Version string */
+SOFIAPUBFUN int sip_version_d(char **ss, char const **ver);
+SOFIAPUBFUN isize_t sip_version_xtra(char const *version);
+SOFIAPUBFUN void sip_version_dup(char **pp, char const **dd, char const *s);
+
+/* Transport identifiers */
+#define SIP_TRANSPORT_LEN(s) SIP_STRING_SIZE((s))
+SOFIAPUBFUN issize_t sip_transport_d(char **ss, char const **ttransport);
+SOFIAPUBFUN isize_t sip_transport_xtra(char const *transport);
+SOFIAPUBFUN void sip_transport_dup(char **pp, char const **dd, char const *s);
+
+/* Method */
+SOFIAPUBFUN sip_method_t sip_method_d(char **ss, char const **nname);
+
+/* Call-ID */
+SOFIAPUBFUN char *sip_word_at_word_d(char **ss);
+
+/** Extract SIP message body, including separator line. */
+SOFIAPUBFUN issize_t sip_extract_body(msg_t *, sip_t *, char b[], isize_t bsiz, int eos);
+
+SOFIAPUBFUN issize_t sip_any_route_d(su_home_t *, sip_header_t *, char *s, isize_t slen);
+SOFIAPUBFUN issize_t sip_any_route_e(char [], isize_t, sip_header_t const *, int flags);
+SOFIAPUBFUN isize_t sip_any_route_dup_xtra(sip_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *sip_any_route_dup_one(sip_header_t *dst,
+					sip_header_t const *src,
+					char *b, isize_t xtra);
+#define sip_any_route_update NULL
+
+SOFIAPUBFUN issize_t sip_name_addr_d(su_home_t *home,
+				     char **inout_s,
+				     char const **return_display,
+				     url_t *out_url,
+				     msg_param_t const **return_params,
+				     char const **return_comment);
+
+SOFIAPUBFUN issize_t sip_name_addr_e(char b[], isize_t bsiz, 
+				     int flags, 
+				     char const *display, 
+				     int always_ltgt, url_t const url[],
+				     msg_param_t const params[], 
+				     char const *comment);
+
+/* ---------------------------------------------------------------------------
+ * 3) Compatibility macros and functions
+ */
+
+#define sip_generic_d		msg_generic_d
+#define sip_generic_e		msg_generic_e
+
+#define sip_numeric_d		msg_numeric_d
+#define sip_numeric_e		msg_numeric_e
+
+#define sip_any_copy_xtra	msg_default_copy_xtra
+#define sip_any_copy_one	msg_default_copy_one
+#define sip_any_dup_xtra	msg_default_dup_xtra
+#define sip_any_dup_one		msg_default_dup_one
+
+#define sip_generic_dup_xtra	msg_generic_dup_xtra
+#define sip_generic_dup_one	msg_generic_dup_one
+
+
+#define	sip_auth_d              msg_auth_d         
+#define	sip_auth_e              msg_auth_e
+
+#define sip_header_dup_as	msg_header_dup_as
+#define sip_header_alloc        msg_header_alloc
+#define sip_header_copy_as	msg_header_copy_as
+
+#define SIP_ALIGN               MSG_ALIGN
+#define SIP_STRUCT_SIZE_ALIGN   MSG_STRUCT_SIZE_ALIGN
+#define SIP_STRUCT_ALIGN        MSG_STRUCT_ALIGN
+
+#define sip_comment_d		msg_comment_d
+#define sip_quoted_d(ss, qq)	msg_quoted_d(ss, qq)
+
+#define SIP_CHAR_E              MSG_CHAR_E
+#define SIP_STRING_LEN          MSG_STRING_LEN
+#define SIP_STRING_E		MSG_STRING_E
+#define SIP_STRING_DUP		MSG_STRING_DUP
+#define SIP_STRING_SIZE		MSG_STRING_SIZE
+#define SIP_NAME_E		MSG_NAME_E
+
+/* Parameters */
+#define SIP_PARAM_MATCH		MSG_PARAM_MATCH
+#define SIP_PARAM_MATCH_P	MSG_PARAM_MATCH_P
+
+/* Parameter lists */
+#define SIP_N_PARAMS            MSG_N_PARAMS
+#define sip_params_d		msg_params_d
+#define sip_params_dup		msg_params_dup
+#define SIP_PARAMS_NUM		MSG_PARAMS_NUM
+#define SIP_PARAMS_E		MSG_PARAMS_E
+#define SIP_PARAMS_SIZE		MSG_PARAMS_SIZE
+#define sip_params_count	msg_params_count
+#define sip_params_copy_xtra	msg_params_copy_xtra
+#define sip_params_copy		msg_params_copy
+
+#define sip_params_add      	msg_params_add
+#define sip_params_cmp      	msg_params_cmp
+#define sip_params_replace  	msg_params_replace
+
+SOFIAPUBFUN int sip_generic_xtra(sip_generic_t const *g);
+
+SOFIAPUBFUN sip_generic_t *sip_generic_dup(su_home_t *home, 
+					   msg_hclass_t *hc, 
+					   sip_generic_t const *u);
+
+SOFIAPUBFUN sip_generic_t *sip_generic_copy(su_home_t *home,
+					    msg_hclass_t *hc, 
+					    sip_generic_t const *o);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,367 @@
+/**@file sofia-sip/sip_protos.h.in
+ *
+ * Template for <sip_protos.h>.
+ */
+
+/* -*- C -*-
+ *
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_PROTOS_H
+/** Defined when <sofia-sip/sip_protos.h> has been included. */
+#define SIP_PROTOS_H 
+  
+/**@file sofia-sip/sip_protos.h
+ * 
+ * SIP prototypes and macros for each header.
+ * 
+ * #AUTO#
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#include <sofia-sip/su_config.h>
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+#ifndef SIP_HCLASSES_H
+#include <sofia-sip/sip_hclasses.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_INLINE
+/** Get SIP structure from msg. */
+su_inline
+sip_t *sip_object(msg_t const *msg)
+{
+  return (sip_t *)msg_public(msg, SIP_PROTOCOL_TAG);
+}
+
+/** Insert a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c sip_header_insert() inserts header or list of headers
+ * into a SIP message.  It also inserts them into the the message fragment
+ * chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status).  The Via
+ * headers are inserted after the request or status, and rest of the headers
+ * after request, status, or Via headers.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param sip SIP message structure to which header is added
+ * @param h   list of header(s) to be added
+ */
+su_inline
+int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h)
+{
+  return msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)h);
+}
+
+/** Remove a header from a SIP message. */ 
+su_inline
+int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h)
+{
+  return msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)h);
+}
+
+/** Return name of the header. */
+su_inline
+char const *sip_header_name(sip_header_t const *h, int compact)
+{
+  if (compact && h->sh_class->hc_short[0])
+    return h->sh_class->hc_short;
+  else
+    return h->sh_class->hc_name;
+}
+
+/** Return data after header structure. */
+su_inline
+void *sip_header_data(sip_header_t *h)
+{
+  return h && h != SIP_NONE ? h->sh_class->hc_size + (char *)h : NULL;
+}
+#else
+sip_t *sip_object(msg_t *msg);
+int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h);
+int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h);
+char const *sip_header_name(sip_header_t const *h, int compact);
+void *sip_header_data(sip_header_t *h);
+#endif
+
+/**@addtogroup sip_#xxxxxx#
+ * @{
+ */
+
+/** Parse a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#". @internal */
+SOFIAPUBFUN issize_t sip_#xxxxxx#_d(su_home_t *, msg_header_t *,
+				       char *s, isize_t slen);
+
+/** Print a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#". @internal */
+SOFIAPUBFUN issize_t sip_#xxxxxx#_e(char b[], isize_t bsiz,
+                    	            msg_header_t const *h, int flags);
+
+/**Access a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#"
+ * structure #sip_#xxxxxx#_t from #sip_t.
+ * 
+ * @since New in #version#.
+ */
+#define sip_#xxxxxx#(sip) \
+  ((sip_#xxxxxx#_t *)msg_header_access((msg_pub_t*)(sip), sip_#xxxxxx#_class))
+
+/**Initializer for structure #sip_#xxxxxx#_t.
+ * 
+ * A static #sip_#xxxxxx#_t structure for
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" must be initialized with
+ * the SIP_#XXXXXX#_INIT() macro. 
+ * For instance,
+ * @code 
+ * 
+ *  sip_#xxxxxx#_t sip_#xxxxxx# = SIP_#XXXXXX#_INIT;
+ * 
+ * @endcode
+ * @HI
+ *
+ * @since New in #version#.
+ */
+#define SIP_#XXXXXX#_INIT() SIP_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure #sip_#xxxxxx#_t.
+ * 
+ * An #sip_#xxxxxx#_t structure for
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" can be initialized with the
+ * sip_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ * 
+ *  sip_#xxxxxx#_t sip_#xxxxxx#;
+ * 
+ *  sip_#xxxxxx#_init(&sip_#xxxxxx#);
+ * 
+ * @endcode
+ * @HI
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_init(sip_#xxxxxx#_t x[1])
+{
+  return SIP_HEADER_INIT(x, sip_#xxxxxx#_class, sizeof(sip_#xxxxxx#_t));
+}
+#else
+#define sip_#xxxxxx#_init(x) \
+  SIP_HEADER_INIT(x, sip_#xxxxxx#_class, sizeof(sip_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of #sip_#xxxxxx#_t.
+ * 
+ * Check if the header class is an instance of
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" object and return true (nonzero),
+ * otherwise return false (zero).
+ * 
+ * @param header pointer to the header structure to be tested
+ * 
+ * @retval 1 (true) if the @a header is an instance of header #xxxxxx# 
+ * @retval 0 (false) otherwise
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline int sip_is_#xxxxxx#(sip_header_t const *header)
+{
+  return header && header->sh_class->hc_hash == sip_#xxxxxx#_hash;
+}
+#else
+int sip_is_#xxxxxx#(sip_header_t const *header);
+#endif
+
+#define sip_#xxxxxx#_p(h) sip_is_#xxxxxx#((h))
+
+
+/**Duplicate a list of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" header structures #sip_#xxxxxx#_t.
+ * 
+ * Duplicate a header
+ * structure @a hdr.  If the header structure @a hdr
+ * contains a reference (@c hdr->x_next) to a list of
+ * headers, all the headers in the list are duplicated, too.
+ * 
+ * @param home  memory home used to allocate new structure
+ * @param hdr   header structure to be duplicated
+ * 
+ * When duplicating, all parameter lists and non-constant
+ * strings attached to the header are copied, too.  The
+ * function uses given memory @a home to allocate all the
+ * memory areas used to copy the header.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = sip_#xxxxxx#_dup(home, sip->sip_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * A pointer to the
+ * newly duplicated #sip_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_dup(su_home_t *home, sip_#xxxxxx#_t const *hdr) 
+     __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+sip_#xxxxxx#_t *sip_#xxxxxx#_dup(su_home_t *home, sip_#xxxxxx#_t const *hdr)
+{ 
+  return (sip_#xxxxxx#_t *)
+    msg_header_dup_as(home, sip_#xxxxxx#_class, (msg_header_t const *)hdr);
+}
+#endif
+
+/**Copy a list of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" header structures #sip_#xxxxxx#_t.
+ * 
+ * The function sip_#xxxxxx#_copy() copies a header structure @a
+ * hdr.  If the header structure @a hdr contains a reference (@c
+ * hdr->h_next) to a list of headers, all the headers in that
+ * list are copied, too. The function uses given memory @a home
+ * to allocate all the memory areas used to copy the list of header
+ * structure @a hdr.
+ * 
+ * @param home    memory home used to allocate new structure
+ * @param hdr     pointer to the header structure to be copied
+ * 
+ * When copying, only the header structure and parameter lists attached to
+ * it are duplicated. The new header structure retains all the references to
+ * the strings within the old @a hdr header, including the encoding of the
+ * old header, if present.
+ * 
+ * @par Example
+ * @code
+ * 
+ *   #xxxxxx# = sip_#xxxxxx#_copy(home, sip->sip_#xxxxxx#);
+ * 
+ * @endcode
+ * 
+ * @return
+ * A pointer to newly copied header structure, or NULL upon an error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_copy(su_home_t *home, sip_#xxxxxx#_t const *hdr) 
+     __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+sip_#xxxxxx#_t *sip_#xxxxxx#_copy(su_home_t *home, sip_#xxxxxx#_t const *hdr) 
+{ 
+  return (sip_#xxxxxx#_t *)
+    msg_header_copy_as(home, sip_#xxxxxx#_class, (msg_header_t const *)hdr); 
+}
+#endif
+
+/**Make a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" structure #sip_#xxxxxx#_t.
+ * 
+ * The function sip_#xxxxxx#_make() makes a new
+ * #sip_#xxxxxx#_t header structure.  It allocates a new
+ * header structure, and decodes the string @a s as the
+ * value of the structure.
+ * 
+ * @param home memory home used to allocate new header structure.
+ * @param s    string to be decoded as value of the new header structure
+ * 
+ * @return
+ * A pointer to newly maked #sip_#xxxxxx#_t header structure, or NULL upon an
+ * error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline 
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_make(su_home_t *home, char const *s)
+     __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+  return (sip_#xxxxxx#_t *)sip_header_make(home, sip_#xxxxxx#_class, s);
+}
+#endif
+
+/**Make a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" from formatting result.
+ * 
+ * Make a new #sip_#xxxxxx#_t object using formatting result as its value. 
+ * The function first prints the arguments according to the format @a fmt
+ * specified. Then it allocates a new header structure, and parses the
+ * formatting result to the structure #sip_#xxxxxx#_t.
+ * 
+ * @param home   memory home used to allocate new header structure.
+ * @param fmt    string used as a printf()-style format
+ * @param ...    argument list for format
+ * 
+ * @return
+ * A pointer to newly
+ * makes header structure, or NULL upon an error.
+ * 
+ * @HIDE
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+     __attribute__((__malloc__, __format__ (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+  sip_header_t *h;
+  va_list ap;
+  
+  va_start(ap, fmt);
+  h = sip_header_vformat(home, sip_#xxxxxx#_class, fmt, ap);
+  va_end(ap);
+ 
+  return (sip_#xxxxxx#_t *)h;
+}
+#endif
+
+/** @} */
+
+SOFIA_END_DECLS
+#endif /* !defined(SIP_PROTOS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_STATUS_H
+/** Defined when <sofia-sip/sip_status.h> has been included. */
+#define SIP_STATUS_H 
+
+/**@addtogroup sip_status_codes
+ * @{ 
+ */
+/**@file sofia-sip/sip_status.h
+ *
+ * SIP status codes and standard phrases.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun  6 17:43:46 2000 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN char const *sip_status_phrase(int status);
+
+/** 100 Trying @HIDE */
+#define SIP_100_TRYING                  100, sip_100_Trying
+/** 180 Ringing @HIDE */
+#define SIP_180_RINGING                 180, sip_180_Ringing
+/** 181 Call Is Being Forwarded @HIDE */
+#define SIP_181_CALL_IS_BEING_FORWARDED 181, sip_181_Call_is_being_forwarded
+/** 182 Queued @HIDE */
+#define SIP_182_QUEUED                  182, sip_182_Queued
+/** 183 Session Progress @HIDE */
+#define SIP_183_SESSION_PROGRESS        183, sip_183_Session_progress
+/** 200 OK @HIDE */
+#define SIP_200_OK                      200, sip_200_OK
+/** 202 Accepted @HIDE */
+#define SIP_202_ACCEPTED                202, sip_202_Accepted
+/** 300 Multiple Choices @HIDE */
+#define SIP_300_MULTIPLE_CHOICES        300, sip_300_Multiple_choices
+/** 301 Moved Permanently @HIDE */
+#define SIP_301_MOVED_PERMANENTLY       301, sip_301_Moved_permanently
+/** 302 Moved Temporarily @HIDE */
+#define SIP_302_MOVED_TEMPORARILY       302, sip_302_Moved_temporarily
+/** 305 Use Proxy @HIDE */
+#define SIP_305_USE_PROXY               305, sip_305_Use_proxy
+/** 380 Alternative Service @HIDE */
+#define SIP_380_ALTERNATIVE_SERVICE     380, sip_380_Alternative_service
+/** 400 Bad Request @HIDE */
+#define SIP_400_BAD_REQUEST             400, sip_400_Bad_request
+/** 401 Unauthorized @HIDE */
+#define SIP_401_UNAUTHORIZED            401, sip_401_Unauthorized
+/** 402 Payment Required @HIDE */
+#define SIP_402_PAYMENT_REQUIRED        402, sip_402_Payment_required
+/** 403 Forbidden @HIDE */
+#define SIP_403_FORBIDDEN               403, sip_403_Forbidden
+/** 404 Not Found @HIDE */
+#define SIP_404_NOT_FOUND               404, sip_404_Not_found
+/** 405 Method Not Allowed @HIDE */
+#define SIP_405_METHOD_NOT_ALLOWED      405, sip_405_Method_not_allowed
+/** 406 Not Acceptable @HIDE */
+#define SIP_406_NOT_ACCEPTABLE          406, sip_406_Not_acceptable
+/** 407 Proxy Authentication Required @HIDE */
+#define SIP_407_PROXY_AUTH_REQUIRED     407, sip_407_Proxy_auth_required
+/** 408 Request Timeout @HIDE */
+#define SIP_408_REQUEST_TIMEOUT         408, sip_408_Request_timeout
+/** 409 Conflict @HIDE */
+#define SIP_409_CONFLICT                409, sip_409_Conflict
+/** 410 Gone @HIDE */
+#define SIP_410_GONE                    410, sip_410_Gone
+/** 411 Length Required @HIDE */
+#define SIP_411_LENGTH_REQUIRED         411, sip_411_Length_required
+/** 412 Precondition Failed @HIDE */
+#define SIP_412_PRECONDITION_FAILED     412, sip_412_Precondition_failed
+/** 413 Request Entity Too Large @HIDE */
+#define SIP_413_REQUEST_TOO_LARGE       413, sip_413_Request_too_large
+/** 414 Request-URI Too Long @HIDE */
+#define SIP_414_REQUEST_URI_TOO_LONG    414, sip_414_Request_uri_too_long
+/** 415 Unsupported Media Type @HIDE */
+#define SIP_415_UNSUPPORTED_MEDIA       415, sip_415_Unsupported_media
+/** 416 Unsupported URI Scheme @HIDE */
+#define SIP_416_UNSUPPORTED_URI         416, sip_416_Unsupported_uri
+/** 417 Unknown Resource-Priority @HIDE */
+#define SIP_417_RESOURCE_PRIORITY       417, sip_417_Resource_priority
+/** 420 Bad Extension @HIDE */
+#define SIP_420_BAD_EXTENSION           420, sip_420_Bad_extension
+/** 421 Extension Required @HIDE */
+#define SIP_421_EXTENSION_REQUIRED      421, sip_421_Extension_required
+/** 422 Session Timer Too Small @HIDE */
+#define SIP_422_SESSION_TIMER_TOO_SMALL 422, sip_422_Session_timer
+/** 423 Interval Too Brief @HIDE */
+#define SIP_423_INTERVAL_TOO_BRIEF      423, sip_423_Interval_too_brief
+#define SIP_423_REGISTRATION_TOO_BRIEF  423, sip_423_Interval_too_brief
+/** 480 Temporarily Unavailable @HIDE */
+#define SIP_480_TEMPORARILY_UNAVAILABLE 480, sip_480_Temporarily_unavailable
+/** 481 Call/Transaction Does Not Exist @HIDE */
+#define SIP_481_NO_TRANSACTION          481, sip_481_No_transaction
+#define SIP_481_NO_CALL                 481, sip_481_No_transaction
+/** 482 Loop Detected @HIDE */
+#define SIP_482_LOOP_DETECTED           482, sip_482_Loop_detected
+/** 483 Too Many Hops @HIDE */
+#define SIP_483_TOO_MANY_HOPS           483, sip_483_Too_many_hops
+/** 484 Address Incomplete @HIDE */
+#define SIP_484_ADDRESS_INCOMPLETE      484, sip_484_Address_incomplete
+/** 485 Ambiguous @HIDE */
+#define SIP_485_AMBIGUOUS               485, sip_485_Ambiguous
+/** 486 Busy Here @HIDE */
+#define SIP_486_BUSY_HERE               486, sip_486_Busy_here
+/** 487 Request Terminated @HIDE */
+#define SIP_487_REQUEST_TERMINATED      487, sip_487_Request_terminated
+#define SIP_487_REQUEST_CANCELLED       487, sip_487_Request_terminated
+/** 488 Not acceptable here @HIDE */
+#define SIP_488_NOT_ACCEPTABLE          488, sip_488_Not_acceptable
+/** 489 Bad Event @HIDE */
+#define SIP_489_BAD_EVENT               489, sip_489_Bad_event
+/** 490 Request Updated @HIDE */
+#define SIP_490_REQUEST_UPDATED         490, sip_490_Request_updated
+/** 491 Request Pending @HIDE */
+#define SIP_491_REQUEST_PENDING         491, sip_491_Request_pending
+/** 493 Undecipherable @HIDE */
+#define SIP_493_UNDECIPHERABLE          493, sip_493_Undecipherable
+/** 494 Security Agreement Required @HIDE */
+#define SIP_494_SECAGREE_REQUIRED       494, sip_494_Secagree_required
+
+/** 500 Internal Server Error @HIDE */
+#define SIP_500_INTERNAL_SERVER_ERROR   500, sip_500_Internal_server_error
+/** 501 Not Implemented @HIDE */
+#define SIP_501_NOT_IMPLEMENTED         501, sip_501_Not_implemented
+/** 502 Bad Gateway @HIDE */
+#define SIP_502_BAD_GATEWAY             502, sip_502_Bad_gateway
+/** 503 Service Unavailable @HIDE */
+#define SIP_503_SERVICE_UNAVAILABLE     503, sip_503_Service_unavailable
+/** 504 Gateway Time-out @HIDE */
+#define SIP_504_GATEWAY_TIME_OUT        504, sip_504_Gateway_time_out
+/** 505 Version Not Supported @HIDE */
+#define SIP_505_VERSION_NOT_SUPPORTED   505, sip_505_Version_not_supported
+/** 513 Message Too Large @HIDE */
+#define SIP_513_MESSAGE_TOO_LARGE       513, sip_513_Message_too_large
+/** 580 Precondition Failure @HIDE */
+#define SIP_580_PRECONDITION            580, sip_580_Precondition
+
+/** 600 Busy Everywhere @HIDE */
+#define SIP_600_BUSY_EVERYWHERE         600, sip_600_Busy_everywhere
+/** 603 Decline @HIDE */
+#define SIP_603_DECLINE                 603, sip_603_Decline
+/** 604 Does Not Exist Anywhere @HIDE */
+#define SIP_604_DOES_NOT_EXIST_ANYWHERE 604, sip_604_Does_not_exist_anywhere
+/** 606 Not Acceptable @HIDE */
+#define SIP_606_NOT_ACCEPTABLE          606, sip_606_Not_acceptable
+/** 687 Dialog terminated @HIDE */
+#define SIP_687_DIALOG_TERMINATED       687, sip_687_Dialog_terminated
+
+SOFIAPUBVAR char const sip_100_Trying[];
+
+SOFIAPUBVAR char const sip_180_Ringing[];
+SOFIAPUBVAR char const sip_181_Call_is_being_forwarded[];
+SOFIAPUBVAR char const sip_182_Queued[];
+SOFIAPUBVAR char const sip_183_Session_progress[];
+
+SOFIAPUBVAR char const sip_200_OK[];
+SOFIAPUBVAR char const sip_202_Accepted[];
+
+SOFIAPUBVAR char const sip_300_Multiple_choices[];
+SOFIAPUBVAR char const sip_301_Moved_permanently[];
+SOFIAPUBVAR char const sip_302_Moved_temporarily[];
+SOFIAPUBVAR char const sip_305_Use_proxy[];
+SOFIAPUBVAR char const sip_380_Alternative_service[];
+
+SOFIAPUBVAR char const sip_400_Bad_request[];
+SOFIAPUBVAR char const sip_401_Unauthorized[];
+SOFIAPUBVAR char const sip_402_Payment_required[];
+SOFIAPUBVAR char const sip_403_Forbidden[];
+SOFIAPUBVAR char const sip_404_Not_found[];
+SOFIAPUBVAR char const sip_405_Method_not_allowed[];
+SOFIAPUBVAR char const sip_406_Not_acceptable[];
+SOFIAPUBVAR char const sip_407_Proxy_auth_required[];
+SOFIAPUBVAR char const sip_408_Request_timeout[];
+SOFIAPUBVAR char const sip_409_Conflict[];
+SOFIAPUBVAR char const sip_410_Gone[];
+SOFIAPUBVAR char const sip_411_Length_required[];
+SOFIAPUBVAR char const sip_412_Precondition_failed[];
+SOFIAPUBVAR char const sip_413_Request_too_large[];
+SOFIAPUBVAR char const sip_414_Request_uri_too_long[];
+SOFIAPUBVAR char const sip_415_Unsupported_media[];
+SOFIAPUBVAR char const sip_416_Unsupported_uri[];
+SOFIAPUBVAR char const sip_417_Resource_priority[];
+SOFIAPUBVAR char const sip_420_Bad_extension[];
+SOFIAPUBVAR char const sip_421_Extension_required[];
+SOFIAPUBVAR char const sip_422_Session_timer[];
+SOFIAPUBVAR char const sip_423_Interval_too_brief[];
+SOFIAPUBVAR char const sip_480_Temporarily_unavailable[];
+SOFIAPUBVAR char const sip_481_No_transaction[];
+SOFIAPUBVAR char const sip_482_Loop_detected[];
+SOFIAPUBVAR char const sip_483_Too_many_hops[];
+SOFIAPUBVAR char const sip_484_Address_incomplete[];
+SOFIAPUBVAR char const sip_485_Ambiguous[];
+SOFIAPUBVAR char const sip_486_Busy_here[];
+SOFIAPUBVAR char const sip_487_Request_terminated[];
+SOFIAPUBVAR char const sip_488_Not_acceptable[];
+SOFIAPUBVAR char const sip_489_Bad_event[];
+SOFIAPUBVAR char const sip_490_Request_updated[];
+SOFIAPUBVAR char const sip_491_Request_pending[];
+SOFIAPUBVAR char const sip_493_Undecipherable[];
+SOFIAPUBVAR char const sip_494_Secagree_required[];
+
+SOFIAPUBVAR char const sip_500_Internal_server_error[];
+SOFIAPUBVAR char const sip_501_Not_implemented[];
+SOFIAPUBVAR char const sip_502_Bad_gateway[];
+SOFIAPUBVAR char const sip_503_Service_unavailable[];
+SOFIAPUBVAR char const sip_504_Gateway_time_out[];
+SOFIAPUBVAR char const sip_505_Version_not_supported[];
+SOFIAPUBVAR char const sip_513_Message_too_large[];
+SOFIAPUBVAR char const sip_580_Precondition[];
+
+SOFIAPUBVAR char const sip_600_Busy_everywhere[];
+SOFIAPUBVAR char const sip_603_Decline[];
+SOFIAPUBVAR char const sip_604_Does_not_exist_anywhere[];
+SOFIAPUBVAR char const sip_606_Not_acceptable[];
+SOFIAPUBVAR char const sip_687_Dialog_terminated[];
+
+SOFIA_END_DECLS
+
+#endif /** @} !defined(SIP_STATUS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,256 @@
+/**@file sofia-sip/sip_tag.h.in
+ *
+ * Template for <sip_tag.h>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_TAG_H
+/** Defined when <sofia-sip/sip_tag.h> has been included. */
+#define SIP_TAG_H
+
+/**@file sofia-sip/sip_tag.h
+ * @brief Tag class for SIP headers
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Test if tag type marks a sip_t structure. @HIDE */
+#define SIPTAG_P(tt)     ((tt)->tt_class == siphdrtag_class)
+/** Test if tag type marks a SIP header string. @HIDE */
+#define SIPTAG_STR_P(tt) ((tt)->tt_class == sipstrtag_class)
+/** Test if tag type marks a SIP header structure. @HIDE */
+#define SIPTAG_SIP_P(tt) ((tt)->tt_class == sipmsgtag_class)
+
+/** Test if tag item contains sip_t structure. @HIDE */
+#define SIPTAGI_P(t)     (SIPTAG_P((t)->t_tag))
+/** Test if tag item contains a SIP header string. @HIDE */
+#define SIPTAGI_STR_P(t) (SIPTAG_STR_P((t)->t_tag))
+/** Test if tag item contains a SIP header structure. @HIDE */
+#define SIPTAGI_SIP_P(t) (SIPTAG_SIP_P((t)->t_tag))
+
+/** Tag class for SIP headers */
+SOFIAPUBVAR tag_class_t siphdrtag_class[1];
+/** Tag class for string values of SIP headers */
+SOFIAPUBVAR tag_class_t sipstrtag_class[1];
+/** Tag class for SIP message */
+SOFIAPUBVAR tag_class_t sipmsgtag_class[1];
+
+/** Lists of SIP tags. */
+SOFIAPUBVAR tag_type_t sip_tag_list[], sip_tag_str_list[];
+
+/** Filter tag matching any sip tag. */
+#define SIPTAG_ANY()         siptag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t siptag_any;
+
+/** End of SIP headers */
+#define SIPTAG_END()         siptag_end, (tag_value_t)0
+SOFIAPUBVAR tag_typedef_t siptag_end;
+
+/**Tag list item for #sip_t object.
+ *
+ * The SIPTAG_SIP() macro is used to include a tag item for a #sip_t struct
+ * in the tag list.
+ *
+ * @param x pointer to a #sip_t message structure, or NULL.
+ *
+ * @HIDE
+ */
+#define SIPTAG_SIP(x)       siptag_sip, siptag_sip_v((x))
+
+/** Tag for @c sip_t */
+SOFIAPUBVAR tag_typedef_t siptag_sip;
+
+#define SIPTAG_SIP_REF(x)   siptag_sip_ref, siptag_sip_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_sip_ref;
+
+#if SU_HAVE_INLINE
+static inline
+tag_value_t siptag_sip_v(sip_t const *v) { return (tag_value_t)v; }
+static inline 
+tag_value_t siptag_sip_vr(sip_t const **vp) { return (tag_value_t)vp; }
+#else
+#define siptag_sip_v(v)   (tag_value_t)(v)
+#define siptag_sip_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * The SIPTAG_HEADER() macro is used to include a tag item containing an
+ * unknown SIP header in the tag list, e.g., 
+ * @code 
+ * sip_header_t *hdr;
+ *
+ * SIPTAG_HEADER(hdr).
+ * @endcode
+ *
+ * @param x pointer to a header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define SIPTAG_HEADER(x)       siptag_header, siptag_header_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t siptag_header;
+
+#define SIPTAG_HEADER_REF(x)   siptag_header_ref, siptag_header_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_header_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+siptag_header_v(sip_header_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+siptag_header_vr(sip_header_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define siptag_header_v(v)   (tag_value_t)(v)
+#define siptag_header_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * Macro is used to include a tag item containing an unknown extension
+ * header in the tag list, e.g.,
+ * @code
+ * SIPTAG_HEADER_STR("Remote-Party-ID: +358718008000")
+ * @endcode
+ *
+ * It is also possible to include multiple headers at once
+ * @code
+ * SIPTAG_HEADER_STR("P-Access-Network-Info: IEEE-802.11g;"
+ *                   "    access-point-id=00:11:5C:34:E5:C0\r\n"
+ "                   "P-Visited-Network-ID: other.net\r\n")
+ * @endcode
+ *
+ * (See @RFC3455 for more information about these headers.)
+ *
+ * @param s pointer to a string, or NULL.
+ *
+ * The corresponding tag item taking reference parameter is
+ * SIPTAG_HEADER_STR_REF().
+ *
+ * @HIDE
+ */
+#define SIPTAG_HEADER_STR(s)       siptag_header_str, tag_str_v((s))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t siptag_header_str;
+
+#define SIPTAG_HEADER_STR_REF(s)   siptag_header_str_ref, tag_str_vr(&(s))
+SOFIAPUBVAR tag_typedef_t siptag_header_str_ref;
+
+/**@ingroup sip_#xxxxxx#
+ *
+ * Tag list item for pointer to a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#"
+ * structure #sip_#xxxxxx#_t.
+ *
+ * The SIPTAG_#XXXXXX#() macro is used to include a tag item with a
+ * pointer to a #sip_#xxxxxx#_t structure in a tag list.
+ *
+ * @param x pointer to a #sip_#xxxxxx#_t structure, or NULL.
+ *
+ * The corresponding tag taking reference parameter is 
+ * SIPTAG_#XXXXXX#_REF().
+ *
+ * @since New in #version#.
+ *
+ * @HIDE
+ */
+#define SIPTAG_#XXXXXX#(x) siptag_#xxxxxx#, siptag_#xxxxxx#_v(x)
+
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#;
+
+/**@ingroup sip_#xxxxxx#
+ * Tag list item for reference to a 
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" pointer.
+ */
+#define SIPTAG_#XXXXXX#_REF(x) siptag_#xxxxxx#_ref, siptag_#xxxxxx#_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_ref;
+
+/**@ingroup sip_#xxxxxx#
+ *
+ * Tag list item for string with @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value.
+ *
+ * The SIPTAG_#XXXXXX#_STR() macro is used to include a tag item with a 
+ * string containing value of a #sip_#xxxxxx#_t header in a tag list.
+ *
+ * @param s pointer to a string containing 
+ *    @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value, or NULL.
+ *
+ * The string in SIPTAG_#XXXXXX#_STR() can be converted to a
+ * #sip_#xxxxxx#_t header structure by giving the string @a s has
+ * second argument to function sip_#xxxxxx#_make().
+ *
+ * The corresponding tag taking reference parameter is 
+ * SIPTAG_#XXXXXX#_STR_REF().
+ *
+ * @since New in #version#.
+ *
+ * @HIDE
+ */
+#define SIPTAG_#XXXXXX#_STR(s) siptag_#xxxxxx#_str, tag_str_v(s)
+
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str;
+
+/**@ingroup sip_#xxxxxx#
+ * Tag list item for reference to a
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" string.
+ */
+#define SIPTAG_#XXXXXX#_STR_REF(x) siptag_#xxxxxx#_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+siptag_#xxxxxx#_v(sip_#xxxxxx#_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+siptag_#xxxxxx#_vr(sip_#xxxxxx#_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define siptag_#xxxxxx#_v(v)   (tag_value_t)(v)
+#define siptag_#xxxxxx#_vr(vp) (tag_value_t)(vp)
+#endif
+
+SOFIA_END_DECLS
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_TAG_CLASS_H
+/** Defined when <sip_tag_class.h> have been included */
+#define SIP_TAG_CLASS_H 
+
+
+/**@SIP_TAG @{ */
+/**@file sofia-sip/sip_tag_class.h
+ *
+ * @brief Tag classes for SIP headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef MSG_TAG_CLASS_H
+#include <sofia-sip/msg_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Define a named tag type for SIP header @a t. */
+#define SIPHDRTAG_NAMED_TYPEDEF(n, t) \
+{{ TAG_NAMESPACE, #n, siphdrtag_class, \
+  (tag_value_t)sip_##t##_class }}
+
+/** Define a tag type for SIP header @a t. @HIDE */
+#define SIPHDRTAG_TYPEDEF(t) SIPHDRTAG_NAMED_TYPEDEF(t, t)
+
+/** Define a string tag type for SIP header @a t. @HIDE */
+#define SIPSTRTAG_TYPEDEF(t) \
+{{ TAG_NAMESPACE, #t "_str", sipstrtag_class, \
+  (tag_value_t)sip_##t##_class }}
+
+/** Define a tag type for SIP message @a t. @HIDE */
+#define SIPMSGTAG_TYPEDEF(t) \
+  {{ TAG_NAMESPACE, #t, sipmsgtag_class, \
+     (tag_value_t)SIP_PROTOCOL_TAG }}
+
+/**@internal Filter SIP header tag items. */ 
+SOFIAPUBFUN tagi_t *siptag_filter(tagi_t *dst, tagi_t const f[],
+				  tagi_t const *src, 
+				  void **bb);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,215 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_UTIL_H
+/** Defined when <sofia-sip/sip_util.h> has been included. */
+#define SIP_UTIL_H 
+
+/**@file sofia-sip/sip_util.h 
+ * @brief SIP utility functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef STRING0_H
+#include <sofia-sip/string0.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* @deprecated
+ * These are just wrappers around msg_params_*() functions. 
+ *
+ * Use msg_header_*_param() functions instead.
+ */
+SOFIAPUBFUN char const *sip_params_find(sip_param_t const pp[],
+					char const *token);
+SOFIAPUBFUN int sip_params_add(su_home_t *sh, 
+			       sip_param_t **pparams,
+			       char const *param);
+SOFIAPUBFUN int sip_params_cmp(sip_param_t const a[], sip_param_t const b[]);
+SOFIAPUBFUN int sip_params_replace(su_home_t *,
+				   sip_param_t **pparams, char const *param);
+
+SOFIAPUBFUN
+sip_contact_t *
+sip_contact_create_from_via_with_transport(su_home_t *home, 
+					   sip_via_t const *v,
+					   char const *user,
+					   char const *transport);
+
+SOFIAPUBFUN
+sip_contact_t *sip_contact_create_from_via(su_home_t *, sip_via_t const *,
+					   char const *user);
+
+SOFIAPUBFUN
+char *
+sip_contact_string_from_via(su_home_t *home,
+			    sip_via_t const *v,
+			    char const *user,
+			    char const *transport);
+
+SOFIAPUBFUN int sip_transport_has_tls(char const *transport_name);
+
+SOFIAPUBFUN int sip_response_terminates_dialog(int response_code,
+					       sip_method_t method,
+					       int *return_graceful_terminate);
+
+SOFIAPUBFUN int sip_sanity_check(sip_t const *sip);
+
+SOFIAPUBFUN unsigned sip_q_value(char const * q);
+
+SOFIAPUBFUN url_t *sip_url_dup(su_home_t *sh, url_t const *o);
+
+/**Add optional prefix and string to argument list if @a s is non-NULL. 
+ * @HIDE
+ */
+#define SIP_STRLOG(prefix, s) ((s) ? (prefix) : ""), ((s) ? (s) : "")
+
+SOFIAPUBFUN int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b);
+
+/* ----------------------------------------------------------------------
+ * Header-specific functions below
+ */
+
+SOFIAPUBFUN int sip_route_is_loose(sip_route_t const *r);
+SOFIAPUBFUN sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_reverse(su_home_t *, sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_fixdup(su_home_t *, sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_fix(sip_route_t *route);
+
+SOFIAPUBFUN sip_route_t *sip_route_fixdup_as(su_home_t *,
+					     msg_hclass_t *,
+					     sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_reverse_as(su_home_t *,
+					     msg_hclass_t *,
+					     sip_route_t const *);
+
+SOFIAPUBFUN sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip);
+
+/* ---------------------------------------------------------------------- */
+/* Caller preferences */
+
+/** Check callerprefs. */
+SOFIAPUBFUN int sip_prefs_matching(char const *pvalue,
+				   char const *nvalue, 		       
+				   int *return_parse_error);
+SOFIAPUBFUN int sip_is_callerpref(char const *param);
+
+/** Type of the SIP media tag */
+enum sp_type { 
+  sp_error = -1, 
+  sp_init,
+  sp_literal,
+  sp_string,
+  sp_range,
+};
+
+
+/** Possible values for SIP media tags */
+union sip_pref
+{
+  /** Type of the media tag */
+  enum sp_type sp_type;
+
+  /** Literal (tag="foo"). */
+  struct sp_literal {
+    enum sp_type spl_type; 
+    char const *spl_value;
+    usize_t spl_length;
+  } sp_literal;
+
+  /** String (tag="&lt;foo&gt;"). */
+  struct sp_string {
+    enum sp_type sps_type;
+    char const *sps_value;
+    usize_t sps_length;
+  } sp_string;
+
+  /** Numeric value or range (tag="#=1"; tag="#<=3"; tag="#>=-2"; tag="#1:6").
+   */
+  struct sp_range {
+    enum sp_type spr_type;
+    double spr_lower;
+    double spr_upper;
+  } sp_range;
+};
+
+/** Parse a single preference */
+SOFIAPUBFUN int sip_prefs_parse(union sip_pref *sp, 
+				char const **in_out_s, 
+				int *return_negation);
+
+/** Match preferences */
+SOFIAPUBFUN int sip_prefs_match(union sip_pref const *, union sip_pref const *);
+
+SOFIAPUBFUN int sip_contact_is_immune(sip_contact_t const *m);
+
+/**@internal
+ * Check if contact is immune to calleprefs.
+ * @deprecated Use sip_contact_is_immune() instead.
+ */
+#define sip_contact_immune(m) sip_contact_is_immune(m)
+
+SOFIAPUBFUN sip_contact_t *sip_contact_immunize(su_home_t *home, 
+						sip_contact_t const *m);
+
+SOFIAPUBFUN int sip_contact_reject(sip_contact_t const *m, 
+				   sip_reject_contact_t const *rc);
+
+SOFIAPUBFUN int sip_contact_accept(sip_contact_t const *m, 
+				   sip_accept_contact_t const *cp,
+				   unsigned *return_S,
+				   unsigned *return_N,
+				   int *return_error);
+
+SOFIAPUBFUN int sip_contact_score(sip_contact_t const *m,
+				  sip_accept_contact_t const *ac,
+				  sip_reject_contact_t const *rc);
+
+
+SOFIAPUBFUN int sip_aor_strip(url_t *url);
+
+/* sec-agree utility functions. */
+
+SOFIAPUBFUN int sip_security_verify_compare(sip_security_server_t const *s,
+					    sip_security_verify_t const *v,
+					    char const **return_d_ver);
+
+SOFIAPUBFUN 
+sip_security_client_t const *
+sip_security_client_select(sip_security_client_t const *client,
+			   sip_security_server_t const *server);
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SIP_UTIL_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Via: SIP/2.0/TCP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5 (NTA 1.0)
+Via: SIP/2.0/UDP 192.2.2.1:5060;received=[ffe0::FAB1]
+Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>;foo=bar
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+Hide: route
+Max-Forwards: 15
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Contact: sip:digest at 172.21.9.155
+Call-ID: 982773899-reg at 172.21.9.155
+CSeq: 2 REGISTER
+Subject: Barfoo
+Priority: emergency
+Date: Wed, 04 Apr 2001 17:38:38 GMT
+Retry-After: Wed, 04 Apr 2001 19:00:00 GMT (wake-up) ;duration=1800
+Timestamp: 986395257.13924321 3
+Expires: 180
+Also: sip:digestify at garage.sr.ntc.nokia.com
+Call-Info: <http://garage.sr.ntc.nokia.com/images/face.jpg>;purpose=icon
+Organization: Fuzzy Felines, Inc.
+Server: please
+User-Agent: Nokia Universal Killer Internet Application/2.0 (NUUKIA)
+In-Reply-To: 982773898-reg at 172.21.9.155
+Accept: text/plain
+Accept-Encoding: identity, deflate (???)
+Accept-Language: en
+Allow: any
+Require: all
+Proxy-Require: kinky, things
+Supported: sip-cc, sip-cc-01, timer
+Unsupported: everything
+Error-Info: <http://garage.sr.ntc.nokia.com/figure-1.jpg>
+Warning: 300 garage.sr.ntc.nokia.com IPv6 global addresses not available
+Warning: 330 garage.sr.ntc.nokia.com No IPv6 multicast, 330 garage.sr.ntc.nokia.com Only local IPv4 multicast available
+Authorization: Digest USERNAME="digest", REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==", RESPONSE="d9d7f1ae99a013cb05f319f0f678251d", URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+MIME-Version: 1.0
+Content-Type: text/plain;charset=US-ASCII
+Content-Encoding: identity
+Content-Disposition: render;handling=optional
+Content-Length: 31
+
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:John_Smith at tct.hut.fi SIP/2.0
+To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>
+  ; tag = deadbeef
+From: http://www.cs.columbia.edu
+Call-ID: 0ha0isndaksdj at 10.1.2.3
+CSeq : 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar="foo baa", sip:kuik at foo.invalid
+Via: SIP/2.0/UDP [aa:bb::1]:5061
+l: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+SIP/2.0 401 Unauthorized
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Via: SIP/2.0/UDP 172.21.9.155
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-ID: 982773899-reg at 172.21.9.155
+CSeq: 1 REGISTER
+WWW-Authenticate: Digest realm="garage.sr.ntc.nokia.com", 
+  nonce="MjAwMS0wMS0yMSAxNTowODo1OA==", algorithm=MD5, qop="auth"
+Content-Length: 0
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-Id: 982773899-reg at 172.21.9.155
+Cseq: 2 REGISTER
+Contact: sip:digest at 172.21.9.155
+Expires: 180
+Content-Length: 0
+Accept-Language: en
+Supported: sip-cc, sip-cc-01, timer
+User-Agent: Pingtel/0.8.0 (WinNT)
+Authorization: DIGEST USERNAME="digest",
+  REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==",
+  RESPONSE="d9d7f1ae99a013cb05f319f0f678251d",
+  URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-Id: 982773899-reg at 172.21.9.155
+Cseq: 2 REGISTER
+Contact: sip:digest at 172.21.9.155
+Expires: 180
+Content-Length: 0
+Accept-Language: en
+Supported: sip-cc, sip-cc-01, timer
+User-Agent: Pingtel/0.8.0 (WinNT)
+Authorization: Digest USERNAME="digest",
+  REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==",
+  RESPONSE="d9d7f1ae99a013cb05f319f0f678251d",
+  URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,27 @@
+INVITE sip:bob@[3ffe:1200:3012:c006:206:5bff:fe55:462f] SIP/2.0
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:0030:e0ff:fe40:6297]:5062
+     ;branch=z9hG4bKuNCTHs8Lumv
+     ;received=3ffe:1200:3012:c006:0030:e0ff:fe40:6297
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062
+     ;branch=z9hG4bKuNCTHs8Lumv
+     ;received=[3ffe:1200:3012:c006:210:a4ff:fe8d:6a46]
+From: <sip:alice@[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]>
+     ;tag=ud6a29947
+To: <sip:bob at example.com;maddr=[3ffe:1200:3012:c006:206:5bff:fe55:462f]>
+Call-ID: f89fa68e-5109-11d6-0581-0010A48D6A46
+CSeq: 2 INVITE
+Contact: <sip:[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062>
+Call-Info: <http://[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]/alice.gif>
+     ;purpose=icon;g-param=[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]
+Content-Type: application/sdp
+Content-Length: 239
+
+v=0
+o=alice 1804289383 2 IN IP6 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+s=-
+c=IN IP6 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+t=0 0
+m=audio 5004 RTP/AVP 96 97 98
+a=rtpmap:96 AMR/8000
+a=rtpmap:97 AMR-WB/16000
+a=rtpmap:98 GSM-EFR/8000

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+OPTIONS sip:bob at example.com SIP/2.0
+Via: SIP/2.0/UDP 172.21.40.44;branch=z9hG4bKitIIzAialKS
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062
+     ;branch=z9hG4bKJv+PsUQdfOb
+     ;received=172.21.40.24
+Record-Route: <sip:bob at example.com;maddr=172.21.40.44>
+Record-Route: <sip:bob at example.com
+     ;maddr=[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]>
+From: <sip:alice at example.com>;tag=ud6a29947
+To: <sip:bob at example.com>
+Call-ID: f3359e42-5109-11d6-998d-0010a47e1c0f
+CSeq: 1 OPTIONS
+Contact: <sip:[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062>
+Content-Length: 0
+Accept: 
+Allow: 
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+JUNK * SIP/1.0
+  
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+ACK sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: sip:j.user at host.company.com
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+INVITE sip:vivekg at chair.dnrc.bell-labs.com SIP/2.0
+  To :
+  sip:vivekg at chair.dnrc.bell-labs.com ;    tag    = 1a1b1f1H33n
+From   : "J Rosenberg \\\"" <sip:jdrosen at lucent.com>
+  ;
+ tag = 98asjd8
+CaLl-Id
+ : 0ha0isndaksdj at 10.1.1.1
+cseq: 8 INVITE
+Via  : SIP   /  2.0/  UDP 
+  135.180.130.133
+Subject :
+NewFangledHeader:   newfangled value
+ more newfangled value
+Content-Type: application/sdp
+v:  SIP  / 2.0  / TCP     12.3.4.5   ;
+  branch  =   9ikj8  ,
+  SIP  /    2.0   / UDP  1.2.3.4   ; hidden   
+m:"Quoted string \"\"" <sip:jdrosen at bell-labs.com> ; newparam = newvalue ;
+  secondparam = secondvalue  ; q = 0.33
+  (((nested comments) and (more)))   ,
+ tel:4443322

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,27 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: sip:j.user at host.company.com
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0
+
+
+
+INVITE sip:joe at company.com SIP/3.0
+To: sip:joe at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isnda977644900765 at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at COMPANY.COM;maddr=135.180.130.133;tag=foo
+From: sip:j.user at COMPANY.COM;x-param-0=0;x-param-1=1;x-param-2=2;x-param-3=3;x-param-4=4;x-param-5=5;x-param-6=6;x-param-7=7;x-param-8=8
+Call-ID: 0ha0isndaksdj at 10.0.2.2  
+Contact: *
+CSeq: 9 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:company.com SIP/2.0
+Via: SIP/2.0/UDP rama.research.nokia.com
+Via: SIP/2.0/UDP 135.180.130.133
+To: sip:j.user at COMPANY.COM;maddr=135.180.130.133;tag=foo
+From: sip:j.user at COMPANY.COM;tag=bar
+Call-ID: 0ha0isndaksdj at 10.0.2.2  
+Contact: *
+CSeq: 9 REGISTER
+Content-Length: 0

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+INVITE sip:user at company.com SIP/2.0
+CSeq: 0 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 135.180.130.133
+CSeq: 0 INVITE
+Call-ID: 98asdh at 10.1.1.1
+Call-ID: 98asdh at 10.1.1.2
+From: sip:caller at university.edu
+From: sip:caller at organization.org
+To: sip:user at company.com
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+s=My sesion
+t=2873397496 2873404696
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 135.180.130.133
+CSeq: 0 INVITE
+Call-ID: 98asdh at 10.1.1.2
+Expires: Thu, 44 Dec 19999 16:00:00 EDT
+From: sip:caller at university.edu
+To: sip:user at company.com
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 255.255.255.255;branch=0
+Via: SIP/2.0/UDP 135.180.130.57;branch=0
+Call-ID: 0384840201 at 10.1.1.1
+CSeq: 0 INVITE
+To: sip:user at company.com
+From: sip:user at university.edu;tag=2229
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 224.2.17.12/127
+m=audio 492170 RTP/AVP 0 4 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP 135.180.130.57;branch=0
+Via: SIP/2.0/UDP 255.255.255.255;branch=0
+Call-ID: 0384840201 at 10.1.1.1
+CSeq: 0 INVITE
+From: sip:user at company.com
+To: sip:user at university.edu;tag=2229
+Content-Type: application/sdp
+Content-Length: 139
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 224.2.17.12/127
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: <sip:j.user at company.com> ;tag=23444
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133;;,;
+Contact: "" <> ;,"Joe" <sip:joe at org.org>;;,,;;
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 9999
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: -999
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+asdpasd08asdsdk:;;asd
+ a0sdjhg8a0''...'';;;;
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: "Mr. J. User <sip:j.user at company.com>
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133:5050;branch=z9hG4bKkdjuw
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+INVITE sip:vivekg at chair.dnrc.bell-labs.com SIP/2.0
+ To :
+  sip:vivekg at chair.dnrc.bell-labs.com ;    tag    = 1a1b1f1H33n
+From   : "J Rosenberg \\\"" <sip:jdrosen at lucent.com>
+  ;
+ tag = 98asjd8
+CaLl-Id
+ : 0ha0isndaksdj at 10.1.1.1
+cseq: 8 INVITE
+Via  : SIP   /  2.0/  UDP 
+  135.180.130.133
+Subject :
+Content-Type: application/sdp
+
+v:  SIP  / 2.0  / TCP     12.3.4.5   ;
+  branch  =   9ikj8  ,
+  SIP  /    2.0   / UDP  1.2.3.4   ; hidden   
+m:"Quoted string \"\"" <sip:jdrosen at bell-labs.com> ; newparam = newvalue ;
+  secondparam = secondvalue  ; q = 0.33
+  (((nested comments) and (more)))   ,
+ tel:4443322

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j_user at company.com
+From: sip:caller at university.edu;tag=242etr
+Max-Forward: 6
+Call-ID: 0ha0isndaksdj at 10.1.1.1
+Require: newfeature1, newfeature2
+Proxy-Require: newfeature3, newfeature4
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+INVITE sip:user;par=u%40h.com at company.com SIP/2.0 
+To: sip:j_user at company.com 
+From: sip:caller at university.edu;tag=33242 
+Max-Forwards: 3 
+Call-ID: 0ha0isndaksdj at 10.1.1.1 
+CSeq: 8 INVITE 
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw 
+Content-Length: 0
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE <sip:user at company.com> SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 1 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com; transport=udp SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 2 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com  SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 3 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:sip%3Auser%40example.com at company.com;other-param=summit SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 4 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com?Route=%3Csip:sip.example.com%3E SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 5 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE name:user SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 6 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+OPTIONS sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: "caller"<sip:caller at example.com>
+Call-ID: 1234abcd at 10.0.0.1
+CSeq: 1 OPTIONS
+Via: SIP/2.0/UDP 135.180.130.133
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+OPTIONS sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: "caller"    <sip:caller at example.com>
+Call-ID: 1234abcd at 10.0.0.1
+CSeq: 2 OPTIONS
+Via: SIP/2.0/UDP 135.180.130.133
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 7 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Fri, 01 Jan 2010 16:00:00 EST
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+INVITE sip:John_Smith at tct.hut.fi SIP/2.0
+To: isbn:2983792873
+From: http://www.cs.columbia.edu
+Call-ID: 0ha0isndaksdj at 10.1.2.3
+CSeq : 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3>
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 8 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Thu, 01 Dec 1994 16:00:00 GMT
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 9 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Max-Forwards: 0
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: k345asrl3fdbv at 10.0.0.1
+CSeq: 1 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Contact: <sip:user at example.com?Route=%3Csip:sip.example.com%3E>
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: k345asrl3fdbv at 10.0.0.1
+CSeq: 1 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Contact: sip:user at example.com?Route=%3Csip:sip.example.com%3E
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,52 @@
+INVITE sip:user at company.com SIP/2.0
+To: "I have a user name of extreme proportion" <sip:user at company.com:6000;other-param=1234567890somethingelselong1234567890>
+From: sip:caller at university.edu
+Call-ID: kl24ahsd546folnyt2vbak9sad98u23naodiunzds09a3bqw0sdfbsk34poouymnae0043nsed09mfkvc74bd0cuwnms05dknw87hjpobd76f
+CSeq: 1 INVITE
+My-State: sldkjflzdsfaret0803adgaasd0afds0asdaasd
+Via: SIP/2.0/UDP sip33.example.com
+Via: SIP/2.0/UDP sip32.example.com
+Via: SIP/2.0/UDP sip31.example.com
+Via: SIP/2.0/UDP sip30.example.com
+Via: SIP/2.0/UDP sip29.example.com
+Via: SIP/2.0/UDP sip28.example.com
+Via: SIP/2.0/UDP sip27.example.com
+Via: SIP/2.0/UDP sip26.example.com
+Via: SIP/2.0/UDP sip25.example.com
+Via: SIP/2.0/UDP sip24.example.com
+Via: SIP/2.0/UDP sip23.example.com
+Via: SIP/2.0/UDP sip22.example.com
+Via: SIP/2.0/UDP sip21.example.com
+Via: SIP/2.0/UDP sip20.example.com
+Via: SIP/2.0/UDP sip19.example.com
+Via: SIP/2.0/UDP sip18.example.com
+Via: SIP/2.0/UDP sip17.example.com
+Via: SIP/2.0/UDP sip16.example.com
+Via: SIP/2.0/UDP sip15.example.com
+Via: SIP/2.0/UDP sip14.example.com
+Via: SIP/2.0/UDP sip13.example.com
+Via: SIP/2.0/UDP sip12.example.com
+Via: SIP/2.0/UDP sip11.example.com
+Via: SIP/2.0/UDP sip10.example.com
+Via: SIP/2.0/UDP sip9.example.com
+Via: SIP/2.0/UDP sip8.example.com
+Via: SIP/2.0/UDP sip7.example.com
+Via: SIP/2.0/UDP sip6.example.com
+Via: SIP/2.0/UDP sip5.example.com
+Via: SIP/2.0/UDP sip4.example.com
+Via: SIP/2.0/UDP sip3.example.com
+Via: SIP/2.0/UDP sip2.example.com
+Via: SIP/2.0/UDP sip1.example.com
+Via: SIP/2.0/UDP host.example.com;received=135.180.130.133;branch=C1C3344E2710000000E299E568E7potato10potato0potato0
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=3149328700 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+OPTIONS sip:135.180.130.133 SIP/2.0
+Via: SIP/2.0/UDP company.com:5604
+From: sip:iuser at company.com
+To: sip:user at 135.180.130.133
+Call-ID: 1804928587 at company.com
+CSeq: 1 OPTIONS
+Expires: 0 0l at company.com
+To: sip:user at 135.180.130.133
+Call-ID: 1804928587 at company.com
+CSeq: 1 OPTIONS
+Contact: sip:host.company.com
+Expires: 0xpires: 0sip:host.company.com
+Expires: 0
+Contact: sip:host.company.com
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+INVITE sip:+1-972-555-2222;phone-context=name%40domain;new=user?%22Route%3a%20X%40Y%3bZ=W%22 at gw1.wcom.com;user=phone SIP/2.0
+Via: SIP/2.0/UDP iftgw.there.com:5060
+From: sip:+1-303-555-1111 at ift.here.com;user=phone
+To: sip:+1-650-555-2222 at ss1.wcom.com;user=phone
+Call-ID: 1717 at ift.here.com
+CSeq: 56 INVITE
+Content-Type: application/sdp
+Content-Length: 348
+
+v=0
+o=faxgw1 2890844527 2890844527 IN IP4 iftgw.there.com
+s=Session SDP
+c=IN IP4 iftmg.there.com
+t=0 0
+m=image 49172 udptl t38
+a=T38FaxVersion:0
+a=T38maxBitRate:14400
+a=T38FaxFillBitRemoval:0
+a=T38FaxTranscodingMMR:0
+a=T38FaxTranscodingJBIG:0
+a=T38FaxRateManagement:transferredTCF
+a=T38FaxMaxBuffer:260
+a=T38FaxUdpEC:t38UDPRedundancy

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:bell-tel.com SIP/2.0
+Via: SIP/2.0/UDP saturn.bell-tel.com
+From: sip:watson at bell-tel.com
+To: sip:watson at bell-tel.com
+Call-ID: 70710 at saturn.bell-tel.com
+CSeq: 2 REGISTER
+Contact: sip:+1-972-555-2222 at gw1.wcom.com;user=phone
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:bell-tel.com SIP/2.0
+Via: SIP/2.0/UDP saturn.bell-tel.com
+From: sip:watson at bell-tel.com
+To: sip:watson at bell-tel.com
+Call-ID: 70710 at saturn.bell-tel.com
+CSeq: 3 REGISTER
+Contact: <sip:+1-972-555-2222 at gw1.wcom.com;user=phone>
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/2.0
+Via:     SIP/2.0/UDP c.bell-tel.com
+From:    A. Bell <sip:a.g.bell at bell-tel.com>
+To:      T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31414 at c.bell-tel.com
+CSeq:    1 INVITE
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Thu, 01 Dec 2040 16:00:00 GMT
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/2.0
+Via:     SIP/2.0/UDP c.bell-tel.com
+From:    Bell, Alexander <sip:a.g.bell at bell-tel.com>
+To:      Watson, Thomas <sip:t.watson at ieee.org>
+Call-ID: 31415 at c.bell-tel.com
+CSeq:    1 INVITE
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/7.0
+Max-Forwards:     70
+Via:     SIP/2.0/UDP c.bell-tel.com
+From:    A. Bell <sip:a.g.bell at bell-tel.com>
+To:      T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31416 at c.bell-tel.com
+CSeq:    1 INVITE
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+INVITE sip:t.watson at ieee.org SIP/7.0
+Via:     SIP/2.0/UDP c.bell-tel.com
+From:    A. Bell <sip:a.g.bell at bell-tel.com>
+To:      T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31417 at c.bell-tel.com
+CSeq:    1 INVITE
+
+
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j_user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+Accept: text/newformat
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88/127
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+b=CT:3455
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+INVITE sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/newformat
+Content-Length: 37
+
+<audio>
+ <pcmu port="443"/>
+</audio>

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+NEWMETHOD sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+NEWMETHOD sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu;tag=34525
+Max-Forwards: 6
+Call-ID: 0ha0isndaksdj at 10.0.1.1
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.1.1
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Authorization: Super-PGP ajsohdaosdh0asyhdaind08yasdknasd09asidhas0d8

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3276 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_test @internal
+ *
+ * @CFILE torture_sip.c  
+ *
+ * Unit-testing functions for SIP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Mar  6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T       struct sip_s
+#define MSG_HDR_T       union sip_header_u
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/url_tag.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/msg_mclass_hash.h>
+
+#include <sofia-sip/sip_extra.h>
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_sip.c";
+
+msg_mclass_t *test_mclass = NULL;
+
+static msg_t *read_message(int flags, char const string[]);
+
+int test_url_headers(void)
+{
+  BEGIN();
+  su_home_t *home;
+  char *s, *d;
+  tagi_t *t;
+  url_t *url;
+  sip_from_t const *f;
+  sip_accept_t const *ac;
+  sip_payload_t const *body;
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  s = sip_headers_as_url_query
+    (home,
+     SIPTAG_SUBJECT_STR(";"),
+     TAG_END());
+
+  TEST_1(s);
+  TEST_S(s, "subject=;");
+
+  s = sip_headers_as_url_query
+    (home,
+     SIPTAG_TO_STR("\"Joe\" <sip:joe at example.com>;tag=foofaa"),
+     SIPTAG_SUBJECT_STR("foo"),
+     TAG_END());
+
+  TEST_1(s);
+  TEST_S(s, "to=%22Joe%22%20%3Csip%3Ajoe at example.com%3E;tag%3Dfoofaa"
+	 "&subject=foo");
+
+  url = url_format(home, "sip:test at example.net?%s", s); TEST_1(url);
+
+  TEST_S(url->url_headers, s);
+
+  s = sip_headers_as_url_query
+    (home,
+     SIPTAG_FROM_STR("<sip:joe at example.com>"),
+     SIPTAG_ACCEPT_STR(""),
+     SIPTAG_PAYLOAD_STR("hello"),
+     SIPTAG_ACCEPT_STR(""),
+     TAG_END());
+
+  TEST_S(s, "from=%3Csip%3Ajoe at example.com%3E"
+	 "&accept="
+	 "&body=hello"
+	 "&accept=");
+
+  d = url_query_as_header_string(home, s);
+  TEST_S(d, "from:<sip:joe at example.com>\n"
+	 "accept:\n"
+	 "accept:\n"
+	 "\n"
+	 "hello");
+
+  t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
+
+  TEST_P(t[0].t_tag, siptag_from);    TEST_1(f = (void *)t[0].t_value);
+  TEST_P(t[1].t_tag, siptag_accept);  TEST_1(ac = (void *)t[1].t_value);
+  TEST_P(t[2].t_tag, siptag_payload); TEST_1(body = (void *)t[2].t_value);
+  TEST_P(t[3].t_tag, siptag_accept); 
+
+  s = "xyzzy=foo";
+
+  t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
+
+  TEST_P(t[0].t_tag, siptag_header_str);
+  TEST_1(d = (void *)t[0].t_value);
+  TEST_S(d, "foo");
+
+  TEST_1(!sip_headers_as_url_query(home, SIPTAG_SEPARATOR_STR(""), TAG_END()));
+
+  TEST_VOID(su_home_unref(home));
+
+  END();
+}
+
+int test_manipulation(void)
+{
+  BEGIN();
+
+  sip_content_length_t *l;
+  sip_payload_t *pl;
+  msg_t *msg, *msg0;
+  sip_t *sip;
+
+  msg0 = read_message(MSG_DO_EXTRACT_COPY, 
+    "MESSAGE sip:foo at bar SIP/2.0\r\n"
+    "To: Joe User <sip:foo at bar>\r\n"
+    "From: \"Bar Owner\" <sip:bar at foo>;tag=foobar\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq: 8 MESSAGE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Content-Length: 7\r\n"
+    "Content-Type: text/plain\r\n"
+    "\r\n"
+    "Heippa!");
+  TEST_1(msg0);
+  TEST_1(msg = msg_copy(msg0));
+  TEST_1(sip = sip_object(msg));
+
+  TEST_1(l = sip_content_length_make(msg_home(msg), "6"));
+  TEST_1(pl = sip_payload_make(msg_home(msg), "hello!"));
+
+  TEST_1(msg_header_replace(msg, NULL, 
+			    (void *)sip->sip_content_length, 
+			    (void *)l) >= 0);
+  TEST_1(msg_header_replace(msg, NULL, 
+			    (void *)sip->sip_payload, 
+			    (void *)pl) >= 0);
+
+  TEST(msg_serialize(msg, NULL), 0);
+  TEST_1(msg_prepare(msg) > 0);
+
+  msg_destroy(msg);
+  msg_destroy(msg0);
+
+  END();
+}
+
+int test_methods(void)
+{
+  int i;
+  char name[32];
+
+  BEGIN();
+
+  for (i = 1; sip_method_names[i]; i++) {
+    TEST_S(sip_method_names[i], sip_method_name(i, "foo"));
+  }
+
+  {
+    char version[] = "protocol /  version  ";
+    char *end = version + strlen(version);
+    char *s = version;
+    char const *result = NULL;
+
+    TEST(sip_version_d(&s, &result), 0);
+    TEST_P(s, end);
+    TEST_S(result, "protocol/version");
+  }
+
+  {
+    char udp[] = "SIP/ 2.0  /  udp";
+    char tcp[] = "SIP / 2.0  /  tcp";
+    char tls[] = "SIP / 2.0  /  tls";
+    char sctp[] = "SIP / 2.0  /  scTp";
+    char dtls[] = "SIP/2.0/TLS-UDP";
+    char tls_sctp[] = "SIP/2.0/TLS-SCTP";
+    char *s, *end;
+    char const *result = NULL;
+
+    s = udp; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, sip_transport_udp);
+
+    s = tcp; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, sip_transport_tcp);
+
+    s = tls; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, sip_transport_tls);
+
+    s = sctp; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, sip_transport_sctp);
+
+    s = dtls; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, "SIP/2.0/TLS-UDP");
+
+    s = tls_sctp; end = s + strlen(s);
+    TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+    TEST_S(result, "SIP/2.0/TLS-SCTP");
+  }
+  END();
+}
+
+/* Test <sip_basic.c> functions. */
+int test_basic(void)
+{
+  su_home_t *home = su_home_new(sizeof *home);
+
+  BEGIN();
+
+  TEST_1(home);
+  
+  {
+    sip_request_t *rq, *rq1;
+
+    rq = sip_request_make(home, "INVITE sip:joe at example.com SIP/2.1");
+    TEST_1(rq);
+    TEST(rq->rq_method, sip_method_invite);
+    TEST_S(rq->rq_method_name, "INVITE");
+    TEST_1(rq1 = sip_request_dup(home, rq));
+
+    su_free(home, rq);
+    su_free(home, rq1);
+    
+    rq = sip_request_make(home, "invite sip:joe at example.com SIP/2.0");
+    TEST_1(rq);
+    TEST(rq->rq_method, sip_method_unknown);
+    TEST_S(rq->rq_method_name, "invite");
+
+    TEST_1(rq1 = sip_request_dup(home, rq));
+
+    su_free(home, rq);
+    su_free(home, rq1);
+
+    TEST_1(!sip_request_create(home, sip_method_unknown, NULL, 
+			       (void *)"sip:joe at example.com", NULL));
+    TEST_1(rq = sip_request_create(home, sip_method_unknown, "invite", 
+				   (void *)"sip:joe at example.com", NULL));
+    TEST(rq->rq_method, sip_method_unknown);
+    TEST_S(rq->rq_method_name, "invite");
+    su_free(home, rq);
+
+    TEST_1(rq = sip_request_create(home, sip_method_unknown, "INVITE", 
+				   (void *)"sip:joe at example.com", NULL));
+    TEST(rq->rq_method, sip_method_invite);
+    TEST_S(rq->rq_method_name, "INVITE");
+
+    su_free(home, rq);
+
+    TEST_1(rq = sip_request_create(home, sip_method_invite, "foobar", 
+				   (void *)"sip:joe at example.com", NULL));
+    TEST(rq->rq_method, sip_method_invite);
+    TEST_S(rq->rq_method_name, "INVITE");
+
+    su_free(home, rq);
+  }
+
+  {
+    sip_status_t *st;
+
+    TEST_1(st = sip_status_make(home, "SIP/2.0 200 OK"));
+    su_free(home, st);
+
+    TEST_1(st = sip_status_make(home, "SIP/2.0 200"));
+    su_free(home, st);
+
+    TEST_1(!sip_status_make(home, "SIP2.0 200 OK"));
+    TEST_1(!sip_status_create(home, 99, NULL, "SIP/2.1"));
+    TEST_1(!sip_status_create(home, 700, NULL, "SIP/2.1"));
+    TEST_1(st = sip_status_create(home, 200, "Ok", "SIP/2.2"));
+    su_free(home, st);
+
+    TEST_1(st = sip_status_create(home, 200, NULL, "SIP/2.0"));
+    su_free(home, st);
+    TEST_1(st = sip_status_create(home, 200, NULL, NULL));
+    su_free(home, st);
+    TEST_1(st = sip_status_create(home, 699, NULL, NULL));
+    su_free(home, st);
+  }
+
+  {
+    sip_payload_t *pl;
+
+    TEST_1(pl = sip_payload_create(home, "foo", 3));
+    su_free(home, pl);
+
+    TEST_1(pl = sip_payload_create(home, NULL, 3));
+    su_free(home, pl);
+  }
+
+  {
+    sip_separator_t *sep;
+
+    TEST_1(!sip_separator_make(home, "foo"));
+    TEST_1(sep = sip_separator_create(home));
+    su_free(home, sep);
+  }
+
+
+  /* Test name-addr things */
+  {
+    su_home_t home[1] = { SU_HOME_INIT(home) };
+    char const *display;
+    url_t url[1];
+    char const * const *params;
+    char const *comment;
+    char const na[] = "Raaka Arska <tel:+358501970>;param=1;humppa (test) ";
+    char const na2[] = "tel:+358501970;param=1;humppa (test) ";
+    char *s, buf[sizeof(na)], ebuf[sizeof(na) + 32];
+
+    s = strcpy(buf, na);
+
+    TEST_1(sip_name_addr_d(home, &s, &display, url, &params, &comment) >= 0);
+    TEST_P(s, buf + strlen(na));
+    TEST_1(display);
+    TEST(url->url_type, url_tel);
+    TEST_1(params);
+    TEST_1(comment);
+
+    TEST_SIZE(sip_name_addr_e(ebuf, sizeof(ebuf), 0, display, 0, url, 
+			      params, comment), 
+	      strlen(na) - 1);
+    TEST_1(strncmp(na, ebuf, strlen(na) - 1) == 0);
+
+    s = strcpy(buf, na2);
+
+    TEST_1(sip_name_addr_d(home, &s, &display, url, &params, &comment) >= 0);
+    TEST_S(s, "");
+    TEST_P(s, buf + strlen(na2));
+    TEST_1(!display);
+    TEST(url->url_type, url_tel);
+    TEST_1(params);
+    TEST_1(comment);
+
+    su_home_deinit(home);
+  }
+
+  {
+    sip_from_t *f; sip_to_t *t, *t2;
+
+    TEST_1(f = sip_from_create(home, (void *)"sip:joe at bar"));
+    TEST_1(sip_from_add_param(home, f, NULL) == -1);
+    TEST_1(sip_from_add_param(home, f, "tag=tagged") == 0);
+    TEST_S(f->a_tag, "tagged");
+    TEST_1(sip_from_tag(home, f, "jxahudsf") == -1);
+    while (f->a_params && f->a_params[0])
+      msg_header_remove_param(f->a_common, f->a_params[0]);
+    TEST_P(f->a_tag, NULL);
+    TEST_1(sip_from_add_param(home, f, "test=1") == 0);
+    TEST_1(sip_from_tag(home, f, "jxahudsf") == 0);
+    TEST_S(f->a_tag, "jxahudsf");
+    su_free(home, f);
+
+    TEST_1(!sip_from_create(home, (void *)"sip:joe@[baa"));
+
+    TEST_1(f = sip_from_make(home, (void *)"sip:joe at bar (foo)"));
+    su_free(home, f);
+
+    TEST_1(f = sip_from_make(home, (void *)"<sip:joe at bar;tag=bar> (joe)"));
+    TEST_1(sip_from_tag(home, f, "tag=jxahudsf") == 0);
+    su_free(home, f);
+
+    TEST_1(t = sip_to_create(home, (void *)"<sip:joe at bar;tag=bar> (joe)"));
+    TEST_1(sip_to_tag(home, t, "tag=jxahudsf") == 0);
+    TEST_S(t->a_tag, "jxahudsf");
+    TEST(msg_header_replace_param(home, t->a_common, "tag=bar"), 1);
+    TEST_S(t->a_tag, "bar");
+
+    TEST_1(t2 = sip_to_dup(home, t));
+    TEST_S(t2->a_tag, "bar");
+
+    TEST(msg_header_remove_param(t->a_common, "tag"), 1);
+    TEST_P(t->a_tag, NULL);
+    TEST_1(sip_to_add_param(home, t, "tst=1") == 0);
+    TEST_P(t->a_tag, NULL);
+
+    su_free(home, t);
+  }
+
+  {
+    sip_call_id_t *i, *i0;
+    TEST_1(i = sip_call_id_create(home, "example.com"));
+    i->i_hash = 0;
+    TEST_1(i0 = sip_call_id_dup(home, i));
+    su_free(home, i);
+    TEST_1(i = sip_call_id_make(home, i0->i_id));
+    TEST(i->i_hash, i0->i_hash);
+    su_free(home, i);
+    su_free(home, i0);
+  }
+
+  {
+    sip_cseq_t *cs, *cs0;
+
+    TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_invite, "1nvite"));
+    TEST(cs->cs_seq, 123456789);
+    TEST(cs->cs_method, sip_method_invite);
+    TEST_S(cs->cs_method_name, "INVITE");
+
+    su_free(home, cs);
+
+    TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_invite, NULL));
+    TEST(cs->cs_seq, 123456789);
+    TEST(cs->cs_method, sip_method_invite);
+    TEST_S(cs->cs_method_name, "INVITE");
+    TEST_1(cs0 = sip_cseq_dup(home, cs));
+
+    su_free(home, cs);
+    su_free(home, cs0);
+
+    TEST_1(!sip_cseq_create(home, 123456789, sip_method_unknown, NULL));
+
+    TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_unknown, 
+				"invite"));
+    TEST(cs->cs_seq, 123456789);
+    TEST(cs->cs_method, sip_method_unknown);
+    TEST_S(cs->cs_method_name, "invite");
+    TEST_1(cs0 = sip_cseq_dup(home, cs));
+
+    su_free(home, cs);
+    su_free(home, cs0);
+  }
+
+  {
+    sip_contact_t *m, *m0;
+
+    TEST_1(!sip_contact_make(home, ",,"));
+    
+    TEST_1(m = sip_contact_create(home, (void *)"sip:joe at bar", 
+				  "q=0.2", 
+				  "+message",
+				  NULL));
+    TEST_S(m->m_q, "0.2");
+
+    TEST_1(m0 = sip_contact_dup(home, m));
+
+    TEST_1(sip_contact_add_param(home, m, "q=0.5") >= 0);
+    TEST_1(sip_contact_add_param(home, m, "video=FALSE") >= 0);
+    TEST_1(sip_contact_add_param(home, m, NULL) == -1);
+    TEST_1(sip_contact_add_param(home, NULL, "video=FALSE") == -1);
+    TEST_1(sip_contact_add_param(home, m, "audio=FALSE") == 0);
+    TEST_1(sip_contact_add_param(home, m, "expires=0") == 0);
+
+    TEST_S(m->m_q, "0.5");
+    TEST_S(m->m_expires, "0");
+    
+    TEST_1(!sip_contact_create(home, (void *)"sip:joe@[baa",
+			       "audio", "video", NULL));
+
+    TEST_1(sip_header_format(home, sip_contact_class, "*"));
+
+    su_free(home, m);
+    su_free(home, m0);
+  }
+
+  {
+    sip_via_t *v;
+    char *s;
+
+    v = sip_via_make(home, "SIP/2.0/UDP domain.invalid:5060"); TEST_1(v);
+    s = sip_contact_string_from_via(home, v, NULL, v->v_protocol);
+    TEST_S(s, "<sip:domain.invalid:5060;transport=udp>");
+    su_free(home, v), su_free(home, s);
+
+    TEST_1(sip_transport_has_tls("SIP/2.0/TLS-SCTP"));
+    TEST_1(sip_transport_has_tls("TLS-UDP"));
+
+    v = sip_via_make(home, "SIP/2.0/TLS-SCTP domain.invalid"); TEST_1(v);
+    s = sip_contact_string_from_via(home, v, NULL, v->v_protocol);
+    TEST_S(s, "<sips:domain.invalid;transport=tls-sctp>");
+    su_free(home, v), su_free(home, s);
+  }
+
+  {
+    sip_expires_t *ex;
+
+    TEST_1(!sip_expires_make(home, "-12+1"));
+
+    TEST_1(ex = sip_expires_make(home, "4294967297")); /* XXX */
+    su_free(home, ex);
+
+    TEST_1(ex = sip_expires_make(home, "Wed, 25 Mar 2004 14:49:29 GMT")); 
+    su_free(home, ex);
+
+    TEST_1(ex = sip_expires_create(home, 3600));
+    su_free(home, ex);
+  }
+
+  {
+    sip_retry_after_t *ra;
+    char const *s;
+
+    TEST_1(!(ra = sip_retry_after_make(home, "50 (foo")));
+    TEST_1(ra = sip_retry_after_make(home, "50 (foo) ; duration = 13"));
+    TEST_S(ra->af_duration, "13");
+    TEST_S(ra->af_comment, "foo");
+    TEST(msg_header_remove_param(ra->af_common, "duration"), 1);
+    TEST_P(ra->af_duration, NULL);
+
+    s = sip_header_as_string(home, (void*)ra);
+    TEST_S(s, "50 (foo)");
+
+    TEST(msg_header_add_param(home, ra->af_common, "x=z"), 0);
+    s = sip_header_as_string(home, (void*)ra);
+    TEST_S(s, "50 (foo) ;x=z");
+
+    su_free(home, ra);
+  }
+
+  {
+    sip_date_t *d;
+
+    TEST_1(!(d = sip_date_make(home, "Mon, 30 Feb 1896 23:59:59 GMT")));
+    su_free(home, d);
+
+    TEST_1(d = sip_date_create(home, (1<<30)));
+    su_free(home, d);
+
+    TEST_1(d = sip_date_create(home, 0));
+    TEST_1(d->d_time != 0);
+    su_free(home, d);
+  }
+
+  {
+    sip_route_t *r, *r0;
+
+    TEST_1(!sip_route_make(home, "<sip:foo@[bar:50>;lr"));
+    TEST_1(r = sip_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+    TEST_1(r0 = sip_route_dup(home, r));
+
+    TEST_1(sip_route_fix(r));
+    TEST_1(url_has_param(r->r_url, "lr"));
+
+    su_free(home, r); 
+    TEST_1(r = sip_route_create(home, r0->r_url, r0->r_url));
+
+    su_free(home, r); su_free(home, r0);
+  }
+
+  {
+    sip_record_route_t *r, *r0;
+
+    TEST_1(!sip_record_route_make(home, "<sip:foo@[bar:50>;lr"));
+    TEST_1(!sip_record_route_make(home, "<sip:foo@[baa::1]>;lr bar, sip:foo"));
+    TEST_1(r = sip_record_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+    TEST_1(r0 = sip_record_route_dup(home, r));
+    su_free(home, r);
+
+    TEST_1(r = sip_route_create(home, r0->r_url, r0->r_url));
+
+    su_free(home, r), su_free(home, r0);
+  }
+
+  {
+    sip_via_t *v, *v0;
+
+    TEST_1(!sip_via_make(home, ",,"));
+    TEST_1(!sip_via_make(home, "SIP// host:5060 (foo),"));
+    TEST_1(!sip_via_make(home, "SIP/2.0/TCP host:5060 (foo) bar,"));
+    TEST_1(!sip_via_make(home, "SIP/2.0/TCP [3ffe::1:5060 (foo),"));
+    
+    TEST_1(v = sip_via_create(home, "bar.com", 
+			      "50600", 
+			      "SIP/2.0/UDP",
+			      "hidden",
+			      "rport=50601",
+			      "comp=sigcomp",
+			      "branch=1",
+			      "q=0.2",
+			      NULL));
+    TEST_S(v->v_branch, "1");
+    TEST_S(v->v_rport, "50601");
+    TEST_S(v->v_comp, "sigcomp");
+
+    TEST_1(v = sip_via_make(home, "SIP/2.0/UDP bar.com:50600"
+			    " ;hidden;rport=50601;comp=sigcomp;branch=1;ttl=15"
+			    " ; maddr=[::227.0.0.1]"
+			    " (This is a comment) "));
+    TEST_S(v->v_ttl, "15");
+    TEST_S(v->v_maddr, "[::227.0.0.1]");
+    TEST_S(v->v_branch, "1");
+    TEST_S(v->v_rport, "50601");
+    TEST_S(v->v_comp, "sigcomp");
+    
+    TEST_1(v0 = sip_via_dup(home, v));
+
+    TEST(msg_header_add_param(home, v->v_common, "rport"), 0);
+    TEST_S(v->v_rport, "");
+    TEST(msg_header_remove_param(v->v_common, "comp"), 1);
+    TEST_P(v->v_comp, NULL);
+    TEST(msg_header_remove_param(v->v_common, "ttl"), 1);
+    TEST_P(v->v_ttl, NULL);
+    TEST(msg_header_remove_param(v->v_common, "maddr"), 1);
+    TEST_P(v->v_maddr, NULL);
+    TEST(msg_header_remove_param(v->v_common, "rport"), 1);
+    TEST_P(v->v_rport, NULL);
+    TEST(msg_header_remove_param(v->v_common, "branch"), 1);
+    TEST_P(v->v_branch, NULL);
+
+    TEST_1(sip_via_add_param(home, v, "video=FALSE") == 0);
+    TEST_1(sip_via_add_param(home, v, NULL) == -1);
+    TEST_1(sip_via_add_param(home, NULL, "video=FALSE") == -1);
+    TEST_1(sip_via_add_param(home, v, "audio=FALSE") == 0);
+    TEST_1(sip_via_add_param(home, v, "branch=0") == 0);
+
+    su_free(home, v);
+    su_free(home, v0);
+
+    TEST_1(v = sip_via_create(home, "bar.com", 
+			      "50600", 
+			      NULL,
+			      "rport=50601",
+			      "branch=1",
+			      "q=0.2",
+			      NULL));
+    TEST_S(v->v_protocol, "SIP/2.0/UDP");
+    su_free(home, v);
+
+  }
+
+  {
+    sip_call_info_t *ci, *ci0;
+
+    TEST_1(ci = sip_call_info_make(home, 
+				   "<http://www.nokia.com>;purpose=info"));
+    TEST_S(ci->ci_purpose, "info");
+    TEST_1(ci0 = sip_call_info_dup(home, ci));
+    TEST_S(ci0->ci_purpose, "info");
+    TEST_1(ci->ci_purpose != ci0->ci_purpose);
+
+    TEST(msg_header_remove_param(ci->ci_common, "purpose"), 1);
+    TEST_P(ci->ci_purpose, NULL);
+
+    su_free(home, ci);
+    su_free(home, ci0);
+  }
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_sip_msg_class(msg_mclass_t const *mc)
+{
+  int i, j, N;
+  msg_hclass_t *hc;
+
+  BEGIN();
+
+  N = mc->mc_hash_size;
+
+  /* check hashes */
+  for (i = 0; i < N; i++) {
+    if (!(hc = mc->mc_hash[i].hr_class))
+      continue;
+    for (j = i + 1; j < N; j++) {
+      if (!mc->mc_hash[j].hr_class)
+	continue;
+      if (hc->hc_hash == mc->mc_hash[j].hr_class->hc_hash) {
+	fprintf(stderr, "\t%s and %s have same hash\n",
+		hc->hc_name, mc->mc_hash[j].hr_class->hc_name);
+	return 1;
+      }
+    }
+  }
+
+  /* Check parser table sanity */
+  for (i = 0; i < N; i++) {
+    /* Verify each header entry */
+    hc = mc->mc_hash[i].hr_class;
+    
+    if (hc == NULL)
+      continue;
+
+    /* Short form */
+    if (hc->hc_short[0])
+      TEST_P(mc->mc_short[hc->hc_short[0] - 'a'].hr_class, hc);
+
+    /* Long form */
+    j = msg_header_name_hash(hc->hc_name, NULL);
+    TEST(j, hc->hc_hash);
+
+    for (j = MC_HASH(hc->hc_name, N); j != i; j = (j + 1) % N)
+      TEST_1(mc->mc_hash[j].hr_class);
+
+  }
+
+  END();
+
+  return 0;
+}
+
+msg_t *read_message(int flags, char const buffer[])
+{
+  size_t n;
+  int m;
+  msg_t *msg;
+  msg_iovec_t iovec[2];
+
+  n = strlen(buffer);
+  if (n == 0) 
+    return NULL;
+
+  msg = msg_create(test_mclass, flags);
+  if (msg_recv_iovec(msg, iovec, 2, n, 1) < 0) {
+    perror("msg_recv_iovec");
+  }
+  memcpy(iovec->mv_base, buffer, n);
+  msg_recv_commit(msg, n, 1);
+
+  m = msg_extract(msg);
+
+  return msg;
+}
+
+static int test_encoding(void)
+{
+  msg_header_t *h, *h1;
+  msg_common_t *c;
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "SUBSCRIBE sip:foo at bar SIP/2.0\r\n"
+    "To: Joe User <sip:foo at bar>\r\n"
+    "From: \"Bar Owner\" <sip:bar at foo>;tag=foobar\r\n"
+    "P-Asserted-Identity: <sip:bar at foo>\r\n"
+    "P-Preferred-Identity: <sip:bar-owner at foo>\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq: 8 SUBSCRIBE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Extension-Header: extended, more\r\n"
+    "Reason: Q.850;cause=16;text=\"Terminated\"\r\n"
+    "Contact: <sip:bar at pc.foo:5060>\r\n"
+    "Date: Wed, 25 Mar 2004 14:49:29 GMT\r\n"
+    "Max-Forwards: 80\r\n"
+    "Min-Expires: 30\r\n"
+    "Retry-After: 48 (this is a comment) ;duration=321\r\n"
+    "Route: <sip:proxy.bar;maddr=172.21.40.40>\r\n"
+    "Request-Disposition: proxy\r\n"
+    "Accept-Contact: *;audio\r\n"
+    "Reject-Contact: *;video\r\n"
+    "Expires: 1200\r\n"
+    "Event: presence;id=1\r\n"
+    "In-Reply-To: {0h!a0i\"sndaksdj}@[kjsafi3], {0h!a0i\"snj}@[kjsfi3]\r\n"
+    "Organization: Nuoret Banaani-Kotkat y.r.\r\n"
+    "Priority: urgent\r\n"
+    "Subject: ynk\r\n"
+    "Timestamp: 3289129810.798259\r\n"
+    "SIP-If-Match: foobar\r\n"
+    "Proxy-Requires: prefs\r\n"
+    "Supported: vnd.nokia\r\n"
+    "User-Agent: Unknown Subscriber (1.0) Tonto (2.0)\r\n"
+    "Accept: application/pidf+xml;version=1.0\r\n"
+    "Accept-Encoding: gzip\r\n"
+     /* Test loop below cannot encode multiple Accept-Language on one line */
+    "Accept-Language: "/* "fi, "*/"en;q=0.2\r\n"
+    "RAck: 421413 214214 INVITE\r\n"
+    "Referred-By: <sips:bob at biloxi.example.com>\r\n"
+    "Replaces: 12345601 at atlanta.example.com;from-tag=314159;to-tag=1234567\r\n"
+    "Authorization: Digest realm=\"foo\"\r\n"
+    "Proxy-Authorization: Digest realm=\"foo\"\r\n"
+    "Security-Client: tls\r\n"
+    "Security-Verify: tls;q=0.2\r\n"
+    "Privacy: none\r\n"
+    "Content-Length: 7\r\n"
+    "Content-Encoding: gzip, deflate, identity\r\n"
+    "Content-Disposition: filter\r\n"
+    "Content-Language: fi\r\n"
+    "MIME-Version: 1.0\r\n"
+    "Min-SE: 123\r\n"
+    "Session-Expires: 1200\r\n"
+    "Content-Type: text/plain\r\n"
+    "Refer-Sub: true\r\n"
+    "Suppress-Body-If-Match: humppa\r\n"
+    "Suppress-Notify-If-Match: zumppa\r\n"
+    "\r\n"
+    "Heippa!");
+  sip = sip_object(msg);
+
+  TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+  for (h = (msg_header_t *)sip->sip_request; h; h = h->sh_succ) {
+    char b[80];
+    size_t n;
+
+    if (h == (msg_header_t*)sip->sip_payload)
+      break;
+
+    TEST_1(h1 = msg_header_dup(home, h));
+    n = msg_header_e(b, sizeof b, h1, 0);
+    TEST_SIZE(n, h->sh_len);
+    TEST_M(b, h->sh_data, n);
+    su_free(home, h1);
+  }
+
+  msg_destroy(msg), msg = NULL;
+
+  /* Note: this should be canonic! */
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "SIP/2.0 200 Ok\r\n"
+    "To: Joe User <sip:foo at bar>;tag=deadbeef\r\n"
+    "From: sip:bar at foo;tag=foobar\r\n"
+    "Call-ID: {0h!a0i\"sndaksdj}@[kjsafi3]\r\n"
+    "CSeq: 8912734 SUBSCRIBE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Extension-Header: extended, more\r\n"
+    "Reason: SIP;cause=400;text=\"Bad Message\"\r\n"
+    "Contact: <sip:bar at pc.foo:5060>;audio\r\n"
+    "Date: Wed, 25 Mar 2004 14:49:29 GMT\r\n"
+    "Max-Forwards: 80\r\n"
+    "Min-Expires: 30\r\n"
+    "Expires: Wed, 25 Mar 2004 15:49:29 GMT\r\n"
+    "Retry-After: 48;duration=321\r\n"
+    "Record-Route: <sip:record-route at proxy.bar;maddr=172.21.40.40>\r\n"
+    "Event: presence;id=1\r\n"
+    "Allow-Events: presence, presence.winfo\r\n"
+    "Subscription-State: active;expires=1800\r\n"
+    "Call-Info: <http://www.bar.com/xcap/joe/>;purpose=xcap\r\n"
+    "Error-Info: <http://www.bar.com/xcap/joe/errors>;param=xcap\r\n"
+    "Server: None\r\n"		     
+    "Timestamp: 3289129810.798259 0.084054\r\n"
+    "SIP-ETag: foobar\r\n"
+    "SIP-If-Match: foobar\r\n"
+    "Requires: vnd.nokia\r\n"
+    "Unsupported: vnd.nokia.pic\r\n"
+    "Accept-Disposition: filter\r\n"
+    "Warning: 399 presence.bar:5060 \"Unimplemented filter\"\r\n"
+    "RSeq: 421414\r\n"
+    "Refer-To: <sip:hsdf at cdwf.xcfw.com?Subject=test&Organization=Bar>\r\n"
+    "WWW-Authenticate: Digest realm=\"foo\"\r\n"
+    "Proxy-Authenticate: Digest realm=\"foo\"\r\n"
+    "Security-Server: tls;q=0.2\r\n"
+    "Session-Expires: 1200;refresher=uac\r\n"
+    "Content-Length: 7\r\n"
+    "Content-Type: text/plain;charset=iso8859-1\r\n"
+    "\r\n"
+    "Heippa!");
+  sip = sip_object(msg);
+
+  TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+  for (h = (msg_header_t *)sip->sip_status; h; h = h->sh_succ) {
+    char b[80];
+    size_t n;
+
+    if (h == (sip_header_t*)sip->sip_payload)
+      break;
+
+    TEST_1(h1 = sip_header_dup(home, h));
+    n = sip_header_e(b, sizeof b, h1, 0);
+    TEST_SIZE(n, h->sh_len);
+    TEST_M(b, h->sh_data, n);
+    su_free(home, h1);
+  }
+
+  TEST_1(sip->sip_etag);
+  TEST_S(sip->sip_etag->g_value, "foobar");
+  TEST_1(sip->sip_if_match);
+
+  msg_destroy(msg), msg = NULL;
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  msg = read_message(0, 
+		     "SIP/2.0 200 Ok\r\n"
+		     "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+		     "Via: SIP/2.0/UDP 135.180.130.130:5060\r\n"
+		     "To: Joe User <sip:foo at bar>;tag=deadbeef\r\n"
+		     "From: sip:bar at foo;tag=foobar\r\n"
+		     "Call-ID: {0h!a0i\"sndaksdj}@[kjsafi3]\r\n"
+		     "CSeq: 8912734 SUBSCRIBE\r\n"
+		     "Record-Route: <sip:135.180.130.133;lr>\r\n"
+		     "Record-Route: <sip:135.180.130.130;lr>\r\n"
+		     "Content-Length: 0\r\n"
+		     "\r\n");
+		    
+  sip = sip_object(msg);
+
+  TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+  sip->sip_flags |= MSG_FLG_COMPACT;
+
+  TEST_1(msg_prepare(msg) != 0);
+
+  TEST_1(c = sip->sip_status->st_common);
+  TEST_M(c->h_data, "SIP/2.0 200 Ok\r\n", c->h_len);
+  
+  TEST_1(c = sip->sip_to->a_common);
+  TEST_M(c->h_data, "t:Joe User<sip:foo at bar>;tag=deadbeef\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_from->a_common);
+  TEST_M(c->h_data, "f:sip:bar at foo;tag=foobar\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_call_id->i_common);
+  TEST_M(c->h_data, "i:{0h!a0i\"sndaksdj}@[kjsafi3]\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_cseq->cs_common);
+  TEST_M(c->h_data, "CSeq:8912734 SUBSCRIBE\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_via->v_common);
+  TEST_M(c->h_data, "v:SIP/2.0/UDP 135.180.130.133,SIP/2.0/UDP 135.180.130.130:5060\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_via->v_next->v_common);
+  TEST_SIZE(c->h_len, 0); TEST_1(c->h_data);
+
+  TEST_1(c = sip->sip_record_route->r_common);
+  TEST_M(c->h_data, "Record-Route:<sip:135.180.130.133;lr>,<sip:135.180.130.130;lr>\r\n", c->h_len);
+
+  TEST_1(c = sip->sip_record_route->r_next->r_common);
+  TEST_SIZE(c->h_len, 0); TEST_1(c->h_data);
+
+  TEST_1(c = sip->sip_content_length->l_common);
+  TEST_M(c->h_data, "l:0\r\n", c->h_len);
+
+  END();
+}
+
+#define XTRA(xtra, h) SU_ALIGN(xtra) + sip_header_size((sip_header_t*)h)
+
+/** Test header filtering and duplicating */
+int tag_test(void)
+{
+  su_home_t *home = su_home_new(sizeof(*home));
+  sip_request_t *request = 
+    sip_request_make(home, "INVITE sip:joe at example.com SIP/2.0");
+  sip_to_t *to = sip_to_make(home, 
+			     "Joe User <sip:joe.user at example.com;param=1>"
+			     ";tag=12345678");
+  sip_via_t *via = sip_via_make(home,
+				"SIP/2.0/UDP sip.example.com"
+				";maddr=128.12.9.254"
+				";branch=289412978y641.321312");
+  url_t *url = url_hdup(home, 
+    (url_t *)"sip:test:pass at example.com;baz=1?foo&bar");
+
+  tagi_t *lst, *dup;
+  size_t xtra;
+  tag_value_t v;
+
+  BEGIN();
+
+  su_home_check(home);
+
+  TEST_1(home && request && to && via);
+
+  lst = tl_list(SIPTAG_REQUEST(request),
+		SIPTAG_TO(to), 
+		SIPTAG_VIA(via),
+		URLTAG_URL(url),
+		TAG_NULL());
+
+  xtra = 0;
+  xtra += XTRA(xtra, request); 
+  xtra += XTRA(xtra, to); 
+  xtra += XTRA(xtra, via); 
+  xtra += SU_ALIGN(xtra) + sizeof(*url) + url_xtra(url);
+
+  TEST_SIZE(tl_len(lst), 5 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(lst, 0), xtra);
+
+  dup = tl_adup(NULL, lst);
+
+  TEST(dup != NULL, 1);
+  TEST_SIZE(tl_len(dup), 5 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(dup, 0), xtra);
+
+  if (tstflags & tst_verbatim)
+    tl_print(stdout, "dup:\n", dup);
+
+  su_free(NULL, dup);
+  tl_vfree(lst);
+
+  TEST_1(t_scan(siptag_request, home, "INVITE sip:example.org SIP/2.0", &v));
+  TEST_1(request = (void *)v);
+  TEST_1(request->rq_common->h_class == sip_request_class);
+  TEST_S(request->rq_method_name, "INVITE");
+  TEST_S(request->rq_version, "SIP/2.0");
+  
+  TEST_1(t_scan(siptag_to, home, "Example <sip:example.org>;tag=foo", &v));
+  TEST_1(to = (void *)v);
+  TEST_1(to->a_common->h_class == sip_to_class);
+  TEST_S(to->a_display, "Example");
+  TEST_S(to->a_tag, "foo");
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+/** Test advanced tag features */
+static int parser_tag_test(void)
+{
+  tagi_t *lst, *dup, *filter1, *filter2, *filter3, *filter4;
+  tagi_t *b1, *b2, *b3, *b4;
+
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+  size_t xtra;
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home);
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+"SIP/2.0 401 Unauthorized\r\n"
+"Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5\r\n"
+"Via: SIP/2.0/UDP 172.21.9.155\r\n"
+"Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>\r\n"
+"From: sip:digest at garage.sr.ntc.nokia.com\r\n"
+"To: sip:digest at garage.sr.ntc.nokia.com\r\n"
+"Call-ID: 982773899-reg at 172.21.9.155\r\n"
+"CSeq: 1 REGISTER\r\n"
+"WWW-Authenticate: Digest realm=\"garage.sr.ntc.nokia.com\",\r\n"
+"  nonce=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", algorithm=MD5, qop=\"auth\"\r\n"
+"Proxy-Authenticate: Digest realm=\"IndigoSw\", domain=\"sip:indigosw.com\", "
+"nonce=\"V2VkIEF1ZyAxNSAxODoxMzozMiBCU1QgMjAwMVtCQDJkYjE5ZA==\", "
+"opaque=\"NzA3ZjJhYzU4MGY3MzU0MQ==\", stale=false, "
+"algorithm=md5, algorithm=sha1, qop=\"auth\"\r\n" 
+/* , qop=\"auth, auth-int\"\r */
+"\r\n");
+
+  sip = sip_object(msg);
+
+  TEST_1(home && msg && sip);
+  TEST_1(sip->sip_size >= sizeof *sip);
+
+  TEST_1(sip_is_status((sip_header_t *)sip->sip_status));
+  TEST_1(sip_is_via((sip_header_t *)sip->sip_via));
+  TEST_1(sip_is_via((sip_header_t *)sip->sip_via->v_next));
+  TEST_1(sip_is_record_route((sip_header_t *)sip->sip_record_route));
+  TEST_1(sip_is_from((sip_header_t *)sip->sip_from));
+  TEST_1(sip_is_to((sip_header_t *)sip->sip_to));
+  TEST_1(sip_is_call_id((sip_header_t *)sip->sip_call_id));
+  TEST_1(sip_is_cseq((sip_header_t *)sip->sip_cseq));
+  TEST_1(sip_is_www_authenticate(
+    (sip_header_t *)sip->sip_www_authenticate));
+
+  TEST_1(sip_complete_message(msg) == 0);
+
+  TEST_1(sip_is_content_length((sip_header_t *)sip->sip_content_length));
+
+  TEST_P(sip->sip_content_length->l_common->h_succ, sip->sip_separator);
+
+  lst = tl_list(SIPTAG_VIA(sip->sip_via), 
+		SIPTAG_RECORD_ROUTE(sip->sip_record_route), 
+		TAG_SKIP(2), 
+		SIPTAG_CSEQ(sip->sip_cseq), 
+		SIPTAG_PAYLOAD(sip->sip_payload), 
+		TAG_NULL());
+  filter1 = tl_list(SIPTAG_VIA(0), 
+		    TAG_NULL());
+  filter2 = tl_list(SIPTAG_CALL_ID(0), 
+		    SIPTAG_FROM(0),
+		    SIPTAG_ROUTE(0),
+		    SIPTAG_CSEQ(0),
+		    TAG_NULL());
+  filter3 = tl_list(SIPTAG_CSEQ(0), 
+		    SIPTAG_CONTENT_LENGTH(0), 
+		    TAG_NULL());
+  filter4 = tl_list(SIPTAG_STATUS(0),
+		    SIPTAG_VIA(0),
+		    SIPTAG_RECORD_ROUTE(0),
+		    SIPTAG_FROM(0),
+		    SIPTAG_TO(0),
+		    SIPTAG_CALL_ID(0),
+		    SIPTAG_CSEQ(0),
+		    SIPTAG_WWW_AUTHENTICATE(0),
+		    SIPTAG_PROXY_AUTHENTICATE(0),
+		    SIPTAG_CONTENT_LENGTH(0),
+		    TAG_NULL());
+
+  TEST_1(lst && filter1 && filter2 && filter3 && filter4);
+
+  b1 = tl_afilter(home, filter1, lst);
+  TEST_SIZE(tl_len(b1), 2 * sizeof(tagi_t));
+  TEST_1(((sip_via_t *)b1->t_value)->v_next);
+  xtra = sip_header_size((sip_header_t *)sip->sip_via);
+  xtra += SU_ALIGN(xtra);
+  xtra += sip_header_size((sip_header_t *)sip->sip_via->v_next);
+  TEST_SIZE(tl_xtra(b1, 0), xtra);
+
+  dup = tl_adup(home, lst);
+
+  TEST_SIZE(tl_len(dup), tl_len(lst));
+  TEST_SIZE(tl_xtra(dup, 0), tl_xtra(lst, 0));
+
+  tl_vfree(lst);
+
+  lst = tl_list(SIPTAG_SIP(sip), TAG_NULL());
+
+  b2 = tl_afilter(home, filter2, lst);
+  TEST_SIZE(tl_len(b2), 4 * sizeof(tagi_t));
+  xtra = 0;
+  xtra += XTRA(xtra, sip->sip_call_id);
+  xtra += XTRA(xtra, sip->sip_from);
+  xtra += XTRA(xtra, sip->sip_cseq);
+  TEST_SIZE(tl_xtra(b2, 0), xtra);
+
+  b3 = tl_afilter(home, filter3, lst);
+
+  TEST_SIZE(tl_len(b3), 3 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b3, 0), 
+	    sizeof(sip_content_length_t) + sizeof(sip_cseq_t));
+
+  b4 = tl_afilter(home, filter4, lst);
+  TEST_SIZE(tl_len(b4), 11 * sizeof(tagi_t));
+  xtra = 0;
+  xtra += XTRA(xtra, sip->sip_status); 
+  xtra += XTRA(xtra, sip->sip_via); 
+  xtra += XTRA(xtra, sip->sip_via->v_next); 
+  xtra += XTRA(xtra, sip->sip_record_route);
+  xtra += XTRA(xtra, sip->sip_from); 
+  xtra += XTRA(xtra, sip->sip_to); 
+  xtra += XTRA(xtra, sip->sip_call_id); 
+  xtra += XTRA(xtra, sip->sip_cseq); 
+  xtra += XTRA(xtra, sip->sip_www_authenticate); 
+  xtra += XTRA(xtra, sip->sip_proxy_authenticate); 
+  xtra += XTRA(xtra, sip->sip_content_length); 
+  TEST_SIZE(tl_xtra(b4, 0), xtra);
+
+  tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3); tl_vfree(filter4);
+  tl_vfree(lst);
+
+  su_home_check(home);
+
+  su_free(home, b4);
+  su_free(home, b3); 
+  su_free(home, b2); 
+  su_free(home, dup);
+  su_free(home, b1); 
+
+  su_home_check(home);
+
+  su_home_unref(home);
+
+  msg_destroy(msg);
+
+  END();
+}
+
+/** Test error messages */
+static int response_phrase_test(void)
+{
+  BEGIN();
+  {
+    struct { int status; char const *phrase; } const errors[] = 
+      {
+	{ SIP_100_TRYING },
+	{ SIP_180_RINGING },
+	{ SIP_181_CALL_IS_BEING_FORWARDED },
+       	{ SIP_182_QUEUED },
+       	{ SIP_183_SESSION_PROGRESS },
+       	{ SIP_200_OK },
+       	{ SIP_202_ACCEPTED },
+       	{ SIP_300_MULTIPLE_CHOICES },
+       	{ SIP_301_MOVED_PERMANENTLY },
+       	{ SIP_302_MOVED_TEMPORARILY },
+       	{ SIP_305_USE_PROXY },
+       	{ SIP_380_ALTERNATIVE_SERVICE },
+       	{ SIP_400_BAD_REQUEST },
+       	{ SIP_401_UNAUTHORIZED },
+       	{ SIP_402_PAYMENT_REQUIRED },
+       	{ SIP_403_FORBIDDEN },
+       	{ SIP_404_NOT_FOUND },
+       	{ SIP_405_METHOD_NOT_ALLOWED },
+       	{ SIP_406_NOT_ACCEPTABLE },
+       	{ SIP_407_PROXY_AUTH_REQUIRED },
+       	{ SIP_408_REQUEST_TIMEOUT },
+       	{ SIP_409_CONFLICT },
+       	{ SIP_410_GONE },
+       	{ SIP_411_LENGTH_REQUIRED },
+       	{ SIP_413_REQUEST_TOO_LARGE },
+       	{ SIP_414_REQUEST_URI_TOO_LONG },
+       	{ SIP_415_UNSUPPORTED_MEDIA },
+       	{ SIP_416_UNSUPPORTED_URI },
+       	{ SIP_420_BAD_EXTENSION },
+       	{ SIP_421_EXTENSION_REQUIRED },
+       	{ SIP_422_SESSION_TIMER_TOO_SMALL },
+       	{ SIP_423_INTERVAL_TOO_BRIEF },
+       	{ SIP_423_REGISTRATION_TOO_BRIEF },
+       	{ SIP_480_TEMPORARILY_UNAVAILABLE },
+       	{ SIP_481_NO_TRANSACTION },
+       	{ SIP_481_NO_CALL },
+       	{ SIP_482_LOOP_DETECTED },
+       	{ SIP_483_TOO_MANY_HOPS },
+       	{ SIP_484_ADDRESS_INCOMPLETE },
+       	{ SIP_485_AMBIGUOUS },
+       	{ SIP_486_BUSY_HERE },
+       	{ SIP_487_REQUEST_TERMINATED },
+       	{ SIP_487_REQUEST_CANCELLED },
+       	{ SIP_488_NOT_ACCEPTABLE },
+       	{ SIP_489_BAD_EVENT },
+       	{ SIP_491_REQUEST_PENDING },
+       	{ SIP_493_UNDECIPHERABLE },
+       	{ SIP_500_INTERNAL_SERVER_ERROR },
+       	{ SIP_501_NOT_IMPLEMENTED },
+       	{ SIP_502_BAD_GATEWAY },
+       	{ SIP_503_SERVICE_UNAVAILABLE },
+       	{ SIP_504_GATEWAY_TIME_OUT },
+       	{ SIP_505_VERSION_NOT_SUPPORTED },
+       	{ SIP_513_MESSAGE_TOO_LARGE },
+       	{ SIP_600_BUSY_EVERYWHERE },
+       	{ SIP_603_DECLINE },
+       	{ SIP_604_DOES_NOT_EXIST_ANYWHERE },
+       	{ SIP_606_NOT_ACCEPTABLE },
+	{ 0, NULL }
+      };
+    int i;
+
+    for (i = 0; errors[i].status; i++)
+      TEST_S(errors[i].phrase, sip_status_phrase(errors[i].status));
+  }
+  END();
+}
+
+/** Test parser and header manipulation */
+static int parser_test(void)
+{
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+
+  sip_route_t *r;
+
+  sip_request_t        sip_request[1] = { SIP_REQUEST_INIT() };
+  sip_status_t         sip_status[1]  = { SIP_STATUS_INIT() };
+  sip_header_t         sip_unknown[1]  = { SIP_UNKNOWN_INIT() };
+  sip_separator_t      sip_separator[1] = { SIP_SEPARATOR_INIT() };     
+  sip_payload_t        sip_payload[1] = { SIP_PAYLOAD_INIT() };
+  sip_via_t            sip_via[1] = { SIP_VIA_INIT() };
+  sip_route_t          sip_route[1] = { SIP_ROUTE_INIT() };		
+  sip_record_route_t   sip_record_route[1] = { SIP_RECORD_ROUTE_INIT() };
+  sip_max_forwards_t   sip_max_forwards[1] = { SIP_MAX_FORWARDS_INIT() };
+  sip_from_t           sip_from[1] = { SIP_FROM_INIT() };
+  sip_to_t             sip_to[1] = { SIP_TO_INIT() };
+  sip_call_id_t        sip_call_id[1] = { SIP_CALL_ID_INIT() };
+  sip_cseq_t           sip_cseq[1] = { SIP_CSEQ_INIT() };
+  sip_contact_t        sip_contact[1] = { SIP_CONTACT_INIT() };
+						
+  sip_expires_t        sip_expires[1] = { SIP_EXPIRES_INIT() };
+  sip_date_t           sip_date[1] = { SIP_DATE_INIT() };
+  sip_retry_after_t    sip_retry_after[1] = { SIP_RETRY_AFTER_INIT() };
+  sip_timestamp_t      sip_timestamp[1] = { SIP_TIMESTAMP_INIT() };
+  sip_subject_t        sip_subject[1] = { SIP_SUBJECT_INIT() };
+  sip_priority_t       sip_priority[1] = { SIP_PRIORITY_INIT() };
+		           		
+  sip_call_info_t      sip_call_info[1] = { SIP_CALL_INFO_INIT() };
+  sip_organization_t   sip_organization[1] = { SIP_ORGANIZATION_INIT() };
+  sip_server_t         sip_server[1] = { SIP_SERVER_INIT() };
+  sip_user_agent_t     sip_user_agent[1] = { SIP_USER_AGENT_INIT() };
+  sip_in_reply_to_t    sip_in_reply_to[1] = { SIP_IN_REPLY_TO_INIT() };
+		           		
+  sip_accept_t         sip_accept[1] = { SIP_ACCEPT_INIT() };
+  sip_accept_encoding_t sip_accept_encoding[1] = { SIP_ACCEPT_ENCODING_INIT() };
+  sip_accept_language_t sip_accept_language[1] = { SIP_ACCEPT_LANGUAGE_INIT() };
+   
+  sip_session_expires_t sip_session_expires[1] = { SIP_SESSION_EXPIRES_INIT() };
+  sip_min_se_t sip_min_se[1] = { SIP_MIN_SE_INIT() };   
+
+  sip_allow_t          sip_allow[1] = { SIP_ALLOW_INIT() };
+  sip_require_t        sip_require[1] = { SIP_REQUIRE_INIT() };
+  sip_proxy_require_t  sip_proxy_require[1] = { SIP_PROXY_REQUIRE_INIT() };
+  sip_supported_t      sip_supported[1] = { SIP_SUPPORTED_INIT() };
+  sip_unsupported_t    sip_unsupported[1] = { SIP_UNSUPPORTED_INIT() };
+#if SIP_HAVE_ENCRYPTION
+  sip_encryption_t     sip_encryption[1] = { SIP_ENCRYPTION_INIT() };
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+  sip_response_key_t   sip_response_key[1] = { SIP_RESPONSE_KEY_INIT() };
+#endif
+
+  sip_proxy_authenticate_t  sip_proxy_authenticate[1] = { SIP_PROXY_AUTHENTICATE_INIT() };
+  sip_proxy_authorization_t sip_proxy_authorization[1] = { SIP_PROXY_AUTHORIZATION_INIT() };
+  sip_authorization_t  sip_authorization[1] = { SIP_AUTHORIZATION_INIT() };
+  sip_www_authenticate_t sip_www_authenticate[1] = { SIP_WWW_AUTHENTICATE_INIT() };
+  sip_error_info_t     sip_error_info[1] = { SIP_ERROR_INFO_INIT() };
+  sip_warning_t        sip_warning[1] = { SIP_WARNING_INIT() };
+		       
+  sip_mime_version_t   sip_mime_version[1] = { SIP_MIME_VERSION_INIT() };
+  sip_content_type_t   sip_content_type[1] = { SIP_CONTENT_TYPE_INIT() };
+  sip_content_encoding_t sip_content_encoding[1] = { SIP_CONTENT_ENCODING_INIT() };
+  sip_content_disposition_t sip_content_disposition[1] = { SIP_CONTENT_DISPOSITION_INIT() };
+  sip_content_length_t sip_content_length[1] = { SIP_CONTENT_LENGTH_INIT() };
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home);
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "INVITE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+    "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+    "  ; tag = deadbeef\r\n"
+    "From: http://www.cs.columbia.edu\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq : 8 INVITE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Route: <sip:1 at a;lr>, sip:2 at b;lr=2, <sip:3 at c;lr=3>\r\n"
+    "Route: <sip:1 at d;lr=4>\r\n"
+    "Route: sip:2 at e;lr=5, <sip:3 at f;lr=6>\r\n"
+    "Route: <sip:1 at g;lr=7>, <sip:2 at h>;lr=8\r\n"
+    "Content-Type: application/sdp\r\n"
+    "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\"foo baa\", sip:kuik at foo.invalid\r\n"
+    "Via: SIP/2.0/UDP [aa:bb::1]:5061\r\n"
+    "\r\n"
+    "v=0\r\n"
+    "o=mhandley 29739 7272939 IN IP4 126.5.4.3\r\n"
+    "c=IN IP4 135.180.130.88\r\n"
+    "m=audio 492170 RTP/AVP 0 12\r\n"
+    "m=video 3227 RTP/AVP 31\r\n"
+    "a=rtpmap:31 LPC\r\n");
+
+  sip = sip_object(msg);
+
+  TEST_1(home && msg && sip);
+
+  TEST_1(sip_is_request((sip_header_t *)sip->sip_request));
+  TEST_1(sip->sip_via); TEST_1(sip->sip_via->v_next);
+  TEST_1(sip->sip_via->v_next->v_next == NULL);
+  TEST_1(sip_sanity_check(sip) == 0);
+
+  TEST_1(r = sip->sip_route); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(!r->r_next);
+
+  TEST_1(r = sip_route_fix(sip->sip_route)); TEST_1(!r->r_common->h_data);
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data); 
+  TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data); 
+  TEST_1(!r->r_next);
+
+  /* Quiet lots of warnings */
+  #define _msg_header_offset msg_header_offset
+  #define msg_header_offset(msg, sip, h) \
+    _msg_header_offset(msg, (msg_pub_t *)sip, (msg_header_t *)h)
+
+  TEST_P(msg_header_offset(msg, sip, sip_request), &sip->sip_request);
+  TEST_P(msg_header_offset(msg, sip, sip_status), &sip->sip_status);
+  TEST_P(msg_header_offset(msg, sip, sip_unknown), &sip->sip_unknown);
+  TEST_P(msg_header_offset(msg, sip, sip_separator), &sip->sip_separator);
+  TEST_P(msg_header_offset(msg, sip, sip_payload), &sip->sip_payload);
+  TEST_P(msg_header_offset(msg, sip, sip_via), &sip->sip_via);
+  TEST_P(msg_header_offset(msg, sip, sip_route), &sip->sip_route);
+  TEST_P(msg_header_offset(msg, sip, sip_record_route),
+	 &sip->sip_record_route);
+  TEST_P(msg_header_offset(msg, sip, sip_max_forwards),
+	 &sip->sip_max_forwards);
+  TEST_P(msg_header_offset(msg, sip, sip_from), &sip->sip_from);
+  TEST_P(msg_header_offset(msg, sip, sip_to), &sip->sip_to);
+  TEST_P(msg_header_offset(msg, sip, sip_call_id), &sip->sip_call_id);
+  TEST_P(msg_header_offset(msg, sip, sip_cseq), &sip->sip_cseq);
+  TEST_P(msg_header_offset(msg, sip, sip_contact), &sip->sip_contact);
+						
+  TEST_P(msg_header_offset(msg, sip, sip_expires), &sip->sip_expires);
+  TEST_P(msg_header_offset(msg, sip, sip_date), &sip->sip_date);
+  TEST_P(msg_header_offset(msg, sip, sip_retry_after), &sip->sip_retry_after);
+  TEST_P(msg_header_offset(msg, sip, sip_timestamp), &sip->sip_timestamp);
+  TEST_P(msg_header_offset(msg, sip, sip_subject), &sip->sip_subject);
+  TEST_P(msg_header_offset(msg, sip, sip_priority), &sip->sip_priority);
+		           		
+  TEST_P(msg_header_offset(msg, sip, sip_call_info), &sip->sip_call_info);
+  TEST_P(msg_header_offset(msg, sip, sip_organization),
+	 &sip->sip_organization);
+  TEST_P(msg_header_offset(msg, sip, sip_server), &sip->sip_server);
+  TEST_P(msg_header_offset(msg, sip, sip_user_agent), &sip->sip_user_agent);
+  TEST_P(msg_header_offset(msg, sip, sip_in_reply_to), &sip->sip_in_reply_to);
+		           		
+  TEST_P(msg_header_offset(msg, sip, sip_accept), &sip->sip_accept);
+  TEST_P(msg_header_offset(msg, sip, sip_accept_encoding),
+	 &sip->sip_accept_encoding);
+  TEST_P(msg_header_offset(msg, sip, sip_accept_language),
+	 &sip->sip_accept_language);
+
+  TEST_P(msg_header_offset(msg, sip, sip_session_expires),
+	 &sip->sip_session_expires);
+  TEST_P(msg_header_offset(msg, sip, sip_min_se), &sip->sip_min_se);   
+   
+  TEST_P(msg_header_offset(msg, sip, sip_allow), &sip->sip_allow);
+  TEST_P(msg_header_offset(msg, sip, sip_require), &sip->sip_require);
+  TEST_P(msg_header_offset(msg, sip, sip_proxy_require),
+	 &sip->sip_proxy_require);
+  TEST_P(msg_header_offset(msg, sip, sip_supported), &sip->sip_supported);
+  TEST_P(msg_header_offset(msg, sip, sip_unsupported), &sip->sip_unsupported);
+#if SIP_HAVE_ENCRYPTION
+  TEST(msg_header_offset(msg, sip, sip_encryption), &sip->sip_encryption);
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+  TEST(msg_header_offset(msg, sip, sip_response_key), &sip->sip_response_key);
+#endif
+
+  TEST_P(msg_header_offset(msg, sip, sip_proxy_authenticate),
+	 &sip->sip_proxy_authenticate);
+  TEST_P(msg_header_offset(msg, sip, sip_proxy_authorization),
+	 &sip->sip_proxy_authorization);
+  TEST_P(msg_header_offset(msg, sip, sip_authorization),
+	 &sip->sip_authorization);
+  TEST_P(msg_header_offset(msg, sip, sip_www_authenticate),
+	 &sip->sip_www_authenticate);
+  TEST_P(msg_header_offset(msg, sip, sip_error_info), &sip->sip_error_info);
+  TEST_P(msg_header_offset(msg, sip, sip_warning), &sip->sip_warning);
+		       
+  TEST_P(msg_header_offset(msg, sip, sip_mime_version), &sip->sip_mime_version);
+  TEST_P(msg_header_offset(msg, sip, sip_content_type), &sip->sip_content_type);
+  TEST_P(msg_header_offset(msg, sip, sip_content_encoding),
+	 &sip->sip_content_encoding);
+  TEST_P(msg_header_offset(msg, sip, sip_content_disposition),
+	 &sip->sip_content_disposition);
+  TEST_P(msg_header_offset(msg, sip, sip_content_length),
+	 &sip->sip_content_length);
+
+  TEST_SIZE(sip_request_class->hc_params, 0);
+  TEST_SIZE(sip_status_class->hc_params, 0);
+  TEST_SIZE(sip_unknown_class->hc_params, 0);
+  TEST_SIZE(sip_separator_class->hc_params, 0);
+  TEST_SIZE(sip_payload_class->hc_params, 0);
+  TEST_SIZE(sip_via_class->hc_params, offsetof(sip_via_t, v_params));
+  TEST_SIZE(sip_route_class->hc_params, offsetof(sip_route_t, r_params));
+  TEST_SIZE(sip_record_route_class->hc_params, 
+	    offsetof(sip_record_route_t, r_params));
+
+  TEST_SIZE(sip_max_forwards_class->hc_params, 0);
+  TEST_SIZE(sip_from_class->hc_params, offsetof(sip_from_t, a_params));
+  TEST_SIZE(sip_to_class->hc_params, offsetof(sip_to_t, a_params));
+  TEST_SIZE(sip_call_id_class->hc_params, 0);
+  TEST_SIZE(sip_cseq_class->hc_params, 0);
+  TEST_SIZE(sip_contact_class->hc_params, offsetof(sip_contact_t, m_params));
+						
+  TEST_SIZE(sip_expires_class->hc_params, 0);
+  TEST_SIZE(sip_date_class->hc_params, 0);
+  TEST_SIZE(sip_retry_after_class->hc_params, 
+	    offsetof(sip_retry_after_t, af_params));
+  TEST_SIZE(sip_timestamp_class->hc_params, 0);
+  TEST_SIZE(sip_subject_class->hc_params, 0);
+  TEST_SIZE(sip_priority_class->hc_params, 0);
+		           		
+  TEST_SIZE(sip_call_info_class->hc_params, 
+	    offsetof(sip_call_info_t, ci_params));
+  TEST_SIZE(sip_organization_class->hc_params, 0);
+  TEST_SIZE(sip_server_class->hc_params, 0);
+  TEST_SIZE(sip_user_agent_class->hc_params, 0);
+
+  TEST_SIZE(sip_in_reply_to_class->hc_params, 
+	    offsetof(sip_in_reply_to_t, k_items));
+  TEST_SIZE(sip_accept_class->hc_params, offsetof(sip_accept_t, ac_params));
+  TEST_SIZE(sip_accept_encoding_class->hc_params, 
+	    offsetof(sip_accept_encoding_t, aa_params));
+  TEST_SIZE(sip_accept_language_class->hc_params, 
+	    offsetof(sip_accept_language_t, aa_params));
+   
+  TEST_SIZE(sip_session_expires_class->hc_params,
+	    offsetof(sip_session_expires_t, x_params));
+  TEST_SIZE(sip_min_se_class->hc_params, offsetof(sip_min_se_t, min_params));
+
+  TEST_SIZE(sip_allow_class->hc_params, offsetof(sip_allow_t, k_items));
+  TEST_SIZE(sip_require_class->hc_params, offsetof(sip_require_t, k_items));
+  TEST_SIZE(sip_proxy_require_class->hc_params, 
+	    offsetof(sip_proxy_require_t, k_items));
+  TEST_SIZE(sip_supported_class->hc_params, 
+	    offsetof(sip_supported_t, k_items));
+  TEST_SIZE(sip_unsupported_class->hc_params, 
+	    offsetof(sip_unsupported_t, k_items));
+
+#if SIP_HAVE_ENCRYPTION
+  TEST_SIZE(sip_encryption_class->hc_params, 
+	    offsetof(sip_encryption_t, au_params));
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+  TEST_SIZE(sip_response_key_class->hc_params, 
+	    offsetof(sip_response_key_t, au_params));
+#endif
+  TEST_SIZE(sip_proxy_authenticate_class->hc_params,  
+	    offsetof(sip_proxy_authenticate_t, au_params));
+  TEST_SIZE(sip_proxy_authorization_class->hc_params,  
+	    offsetof(sip_proxy_authorization_t, au_params));
+  TEST_SIZE(sip_authorization_class->hc_params,  
+	    offsetof(sip_authorization_t, au_params));
+  TEST_SIZE(sip_www_authenticate_class->hc_params,  
+	    offsetof(sip_www_authenticate_t, au_params));
+
+  TEST_SIZE(sip_error_info_class->hc_params, 
+	    offsetof(sip_error_info_t, ei_params));
+  TEST_SIZE(sip_warning_class->hc_params, 0);
+		       
+  TEST_SIZE(sip_mime_version_class->hc_params, 0);
+  TEST_SIZE(sip_content_type_class->hc_params, 
+	    offsetof(sip_content_type_t, c_params));
+  TEST_SIZE(sip_content_encoding_class->hc_params, 
+	    offsetof(sip_content_encoding_t, k_items));
+  TEST_SIZE(sip_content_disposition_class->hc_params, 
+	    offsetof(sip_content_disposition_t, cd_params));
+  TEST_SIZE(sip_content_length_class->hc_params, 0);
+
+  msg_destroy(msg);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static int count(sip_common_t *h)
+{
+  sip_header_t *sh = (sip_header_t *)h;
+  unsigned n;
+  
+  for (n = 0; sh; sh = sh->sh_next)
+    n++;
+  
+  return n;
+}
+
+static int len(sip_common_t *h)
+{
+  sip_header_t *sh = (sip_header_t *)h;
+  unsigned n;
+
+  for (n = 0; sh; sh = sh->sh_next) {
+    if (n) n +=2;
+    n += sip_header_field_e(NULL, 0, sh, 0);
+  }
+
+  return n;
+}
+
+static int sip_header_test(void)
+{
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+  void const *x;
+  sip_via_t *v, *v0;
+  tagi_t const *tl;
+  tagi_t *tl0;
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home);
+
+  TEST_1(msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "MESSAGE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+    "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+    "  ; tag = deadbeef\r\n"
+    "From:h<http://www.cs.columbia.edu>\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq : 8 MESSAGE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+    "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+    "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+    "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, <sip:kuik at foo.invalid>, sip:barf\r\n"
+    "Via: SIP/2.0/UDP [aa:bb::1]:5061\r\n"
+    "Record-Route: Test Element <sip:[defa::00:12]:5061>;param=12+1\r\n"
+    "Record-Route: sip:135.180.130.133,<sip:135.180.130.131;transport=tcp>,\r\n"
+    "\t,Test Element <sip:[defa::00:12]:5061>;param=12+1\r\n"
+    "Path: Test <sip:[defa::00:12]:5061>\r\n"
+    "Service-Route: Test <sip:[defa::00:12]:5061>\r\n"
+    "Route: ,\r\n"
+    "Unknown-Extension: hip\r\n"
+    "Hide: hop\r\n"
+    "Max-Forwards: 12\r\n"
+    "Min-Expires: 150\r\n"
+    "Timestamp: 10.010 0.000100\r\n"
+    "Suppress-Body-If-Match: humppa \t\r\n"
+    "Suppress-Notify-If-Match: zumppa\r\n"
+    " \r\n"
+    "Content-Type: application/sdp\r\n"
+    "\r\n"
+    "v=0\r\n"
+    "o=mhandley 29739 7272939 IN IP4 126.5.4.3\r\n"
+    "c=IN IP4 135.180.130.88\r\n"
+    "m=audio 492170 RTP/AVP 0 12\r\n"
+    "m=video 3227 RTP/AVP 31\r\n"
+    "a=rtpmap:31 LPC\r\n"));
+
+  TEST_1(sip = sip_object(msg));
+
+  TEST(count(sip->sip_request->rq_common), 1);
+  TEST(count(sip->sip_to->a_common), 1);
+  TEST(count(sip->sip_from->a_common), 1);
+  TEST(count(sip->sip_cseq->cs_common), 1);
+  TEST(count(sip->sip_call_id->i_common), 1);
+  TEST(count(sip->sip_via->v_common), 4);
+  TEST(count(sip->sip_contact->m_common), 3);
+  TEST(count(sip->sip_content_type->c_common), 1);
+  TEST(count(sip->sip_route->r_common), 0);
+  TEST(count(sip->sip_record_route->r_common), 4);
+  TEST(count(sip->sip_unknown->un_common), 2);
+  TEST(count(sip->sip_error->er_common), 1);
+  TEST(count(sip->sip_max_forwards->mf_common), 1);
+  TEST(count(sip->sip_min_expires->me_common), 1);
+  TEST(count(sip->sip_timestamp->ts_common), 1);
+
+  TEST_S(sip->sip_contact->m_display, "Joe Bob Briggs");
+  TEST_1(sip->sip_contact->m_next->m_display != NULL);
+  TEST_S(sip->sip_contact->m_next->m_display, "");
+  TEST_1(sip->sip_contact->m_next->m_next->m_display == NULL);
+
+  TEST(sip->sip_max_forwards->mf_count, 12);
+  TEST(sip->sip_min_expires->me_delta, 150);
+
+  {
+    sip_suppress_body_if_match_t *sbim;
+    sip_suppress_notify_if_match_t *snim;
+
+    TEST_1(sbim = sip_suppress_body_if_match(sip));
+    TEST_S(sbim->sbim_tag, "humppa");
+
+    TEST_SIZE(offsetof(msg_generic_t, g_value),
+	      offsetof(sip_suppress_body_if_match_t, sbim_tag));
+
+    TEST_1(snim = sip_suppress_notify_if_match(sip));
+    TEST_S(snim->snim_tag, "zumppa");
+
+    TEST_SIZE(offsetof(msg_generic_t, g_value),
+	      offsetof(sip_suppress_notify_if_match_t, snim_tag));
+  }
+
+  TEST_1(sip->sip_from->a_display);
+  TEST_S(sip->sip_from->a_display, "h");
+
+  v0 = sip->sip_via;
+
+  TEST_1(v = sip_via_copy(home, v0));
+  TEST(len(v->v_common), len(v0->v_common));
+  for (; v && v0; v = v->v_next, v0 = v0->v_next) {
+    if (v->v_params)
+      TEST_1(v->v_params != v0->v_params);
+    if (v->v_branch)
+      TEST_1(v->v_branch == v0->v_branch);
+  }
+  TEST_1(v == NULL && v0 == NULL);
+  
+  v0 = sip->sip_via;
+  
+  TEST_1(v = sip_via_dup(home, v0));
+  TEST(len(v->v_common), len(v0->v_common));
+  for (; v && v0; v = v->v_next, v0 = v0->v_next) {
+    if (v->v_params)
+      TEST_1(v->v_params != v0->v_params);
+    if (v->v_branch)
+      TEST_1(v->v_branch != v0->v_branch);
+  }
+  TEST_1(v == NULL && v0 == NULL);
+
+  TEST(sip_add_dup(msg, sip, (sip_header_t *)sip->sip_max_forwards), 0);
+  /* Max-Forwards is last header? */
+  TEST_P(sip->sip_max_forwards, sip->sip_content_type->c_common->h_succ);
+
+  TEST(sip_to_tag(home, sip->sip_to, sip->sip_to->a_tag), 0);
+  TEST(sip_to_tag(home, sip->sip_to, "tag=deadbeef"), 0);
+  TEST(sip_to_tag(home, sip->sip_to, "foofaa"), -1);
+
+  msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_payload);
+
+  TEST(sip_add_tl(msg, sip, 
+		  SIPTAG_FROM(SIP_NONE),
+		  SIPTAG_VIA(SIP_NONE),
+		  SIPTAG_VIA_STR("SIP/2.0/SCTP foo.bar.com:5060;branch=foo"),
+		  SIPTAG_TO_STR("<sip:foo at bar>"),
+		  SIPTAG_HEADER_STR("Authorization: Basic foobar\n"
+				    "Priority:\n urgent"),
+		  SIPTAG_HEADER_STR("Accept: foo/bar\n"
+				    "\n"
+				    "test payload\n"),
+		  SIPTAG_TIMESTAMP(sip->sip_timestamp),
+		  SIPTAG_END(),
+		  SIPTAG_REFER_TO_STR("<sip:foo at bar>"),
+		  TAG_END()), 0);
+  TEST_1(sip->sip_from == NULL);
+  TEST_1(sip->sip_via); TEST_1(sip->sip_via->v_next == NULL);
+  TEST_S(sip->sip_via->v_protocol, "SIP/2.0/SCTP");
+  TEST_1(sip->sip_authorization);
+  TEST_1(sip->sip_priority);
+  TEST_1(sip->sip_payload);
+  TEST_S(sip->sip_payload->pl_data, "test payload\n");
+  TEST_1(sip->sip_timestamp);
+  TEST_S(sip->sip_timestamp->ts_stamp, "10.010");
+  TEST_S(sip->sip_timestamp->ts_delay, "0.000100");
+  TEST_1(!sip->sip_refer_to);
+
+  TEST_1(tl = tl0 = tl_list(SIPTAG_TO_STR("<sip:foo at bar>"),
+			    SIPTAG_END(),
+			    SIPTAG_REFER_TO_STR("<sip:foo at bar>"),
+			    TAG_END()));
+  /* sip_add_tagis should stop after SIPTAG_END() */
+  TEST(sip_add_tagis(msg, sip, &tl), 0);
+  TEST_P(tl, tl0 + 2);
+
+  tl_free(tl0);
+
+  TEST_P(sip_timestamp_make(home, "+1"), NULL);
+  TEST_P(sip_timestamp_make(home, "1.0e6 13.0"), NULL);
+  TEST_1(sip_timestamp_make(home, "1.0 .001"));
+  TEST_P(sip_timestamp_make(home, ".0001 13.0"), NULL);
+
+  TEST_1(x = sip->sip_path);
+  TEST_1(sip_add_make(msg, sip, sip_path_class, "<sip:135.180.130.133>") == 0);
+  TEST_P(x, sip->sip_path->r_next);
+
+  TEST_1(x = sip->sip_service_route);
+  TEST_1(sip_add_make(msg, sip, sip_service_route_class, 
+		      "<sip:135.180.130.133>") == 0);
+  TEST_P(x, sip->sip_service_route);
+  TEST_1(sip->sip_service_route->r_next);
+
+  /* Detect parsing errors */
+  TEST_1(!sip_cseq_make(home, "21874624876976 INVITE"));
+  TEST_1(!sip_cseq_make(home, "218746INVITE"));
+  
+  msg_destroy(msg), msg = NULL;
+
+  su_home_unref(home), home = NULL;
+
+  END();
+}
+
+static int test_bad_packet(void)
+{
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home);
+
+  TEST_1(msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "MESSAGE <sip:John_Smith at tct.hut.fi> SIP/2.0\r\n"
+    "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+    "  ; tag = deadbeef\r\n"
+    "From:h<http://www.cs.columbia.edu>\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq : 8 MESSAGE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+    "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+    "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+    "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, sip:kuik at foo.invalid\r\n"
+    "Via: SIP/2.0/UDP [aa:bb::1]:5061\0\0"));
+
+  TEST_1(sip = sip_object(msg));
+
+  TEST(count(sip->sip_request->rq_common), 1);
+  TEST(count(sip->sip_to->a_common), 1);
+  TEST(count(sip->sip_from->a_common), 1);
+  TEST(count(sip->sip_cseq->cs_common), 1);
+  TEST(count(sip->sip_call_id->i_common), 1);
+  TEST(count(sip->sip_via->v_common), 4);
+  TEST(count(sip->sip_route->r_common), 0);
+
+  TEST(sip->sip_request->rq_url->url_type, url_invalid);
+
+  su_home_unref(home), home = NULL;
+
+  msg_destroy(msg), msg = NULL;
+
+  END();
+}
+
+static int test_sip_list_header(void)
+{
+  msg_t *msg;
+  sip_t *sip;
+  su_home_t *home;
+  sip_allow_t *a;
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home);
+
+  TEST_1(msg = read_message(0, 
+    "MESSAGE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+    "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+    "From: <sip:joe at doe.org>;tag=foobar\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq : 8 MESSAGE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+    "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+    "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+    "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, <sip:kuik at foo.invalid>, sip:barf\r\n"
+    "Allow: INVITE\r\n"
+    "Allow: ACK\r\n"
+    "Allow: CANCEL\r\n"
+    "Allow: BYE\r\n"
+    "Allow: OPTIONS\r\n"
+    "Allow: MESSAGE\r\n"
+    "Allow: KUIK\r\n"
+    "Max-Forwards: 12\r\n"
+    "Content-Type: text/plain\r\n"
+    "\r\n"
+    "hello\r\n"));
+
+  TEST_1(sip = sip_object(msg));
+  TEST_1(a = sip->sip_allow);
+  TEST_1(a->k_items);
+  TEST_1(a->k_next == NULL);
+
+  TEST_1(sip_is_allowed(a, SIP_METHOD_INVITE));
+  TEST_1(!sip_is_allowed(a, SIP_METHOD_PUBLISH));
+  TEST_1(sip_is_allowed(a, SIP_METHOD(KUIK)));
+  TEST_1(!sip_is_allowed(a, SIP_METHOD(kuik)));
+
+  TEST_1(a = sip_allow_make(home, ""));
+  TEST_S(sip_header_as_string(home, (void *)a), "");
+
+  TEST_1(a = sip_allow_make(home, "INVITE, PUBLISH"));
+
+  TEST_1(sip_is_allowed(a, SIP_METHOD_INVITE));
+
+  /* Test with list header */
+  TEST_1(msg_header_add_dup(msg, NULL, (msg_header_t *)a) == 0);
+
+  TEST_1(a = sip_allow_make(home, "MESSAGE, SUBSCRIBE"));
+
+  TEST_1(msg_header_add_dup(msg, NULL, (msg_header_t *)a) == 0);
+
+  TEST_1(msg_header_add_make(msg, NULL, sip_allow_class, "kuik") == 0);
+
+  TEST_1(a = sip->sip_allow);
+  TEST_1(a->k_items);
+  TEST_S(a->k_items[0], "INVITE");
+  TEST_S(a->k_items[1], "ACK");
+  TEST_S(a->k_items[2], "CANCEL");
+  TEST_S(a->k_items[3], "BYE");
+  TEST_S(a->k_items[4], "OPTIONS");
+  TEST_S(a->k_items[5], "MESSAGE");
+  TEST_S(a->k_items[6], "KUIK");
+  TEST_S(a->k_items[7], "PUBLISH");
+  TEST_S(a->k_items[8], "SUBSCRIBE");
+  TEST_S(a->k_items[9], "kuik");
+  TEST_P(a->k_items[10], NULL);
+
+  msg_destroy(msg), msg = NULL;
+
+  su_home_unref(home), home = NULL;
+
+  END();
+}
+
+static int test_prack(void)
+{
+  /* Test RAck and RSeq */
+  su_home_t *home;
+  sip_rack_t *rack, *rack0;
+  sip_rseq_t *rseq, *rseq0;
+  
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(rack = sip_rack_make(home, "1 2 INVITE"));
+  TEST(rack->ra_response, 1);
+  TEST(rack->ra_cseq, 2);
+  TEST(rack->ra_method, sip_method_invite);
+  TEST_S(rack->ra_method_name, "INVITE");
+  TEST_1(rseq = sip_rseq_make(home, "3"));
+  TEST(rseq->rs_response, 3);
+
+  TEST_1(rack0 = sip_rack_dup(home, rack));
+  TEST_P(rack0->ra_method_name, rack->ra_method_name);
+  TEST_1(rseq0 = sip_rseq_dup(home, rseq));
+  
+  TEST_1(rack = sip_rack_make(home, "4\r\n\t5\r\n\tEXTRA"));
+  TEST(rack->ra_response, 4);
+  TEST(rack->ra_cseq, 5);
+  TEST(rack->ra_method, sip_method_unknown);
+  TEST_S(rack->ra_method_name, "EXTRA");
+  TEST_1(rseq = sip_rseq_make(home, "  6  "));
+  TEST(rseq->rs_response, 6);
+  
+  TEST_1(rack0 = sip_rack_dup(home, rack));
+  TEST_1(rack0->ra_method_name != rack->ra_method_name);
+  TEST_1(rseq0 = sip_rseq_dup(home, rseq));
+
+  su_home_unref(home);
+  
+  END();
+}
+
+/* Test MIME headers */
+static int test_accept(void)
+{
+  /* Test Accept header */
+  sip_accept_t *ac, *ac0;
+  sip_accept_encoding_t *aa;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(ac = ac0 = sip_accept_make(home, "image / jpeg ; q = 0.6,, image/png, image/*, */*  "));
+  TEST_S(ac->ac_type, "image/jpeg");
+  TEST_S(ac->ac_subtype, "jpeg");
+  TEST_1(ac->ac_params && ac->ac_params[0]);
+  TEST_S(ac->ac_params[0], "q=0.6");
+  TEST_S(ac->ac_q, "0.6");
+
+  TEST_1(ac = ac->ac_next);
+  TEST_S(ac->ac_type, "image/png");
+  TEST_S(ac->ac_subtype, "png");
+
+  TEST_1(ac = ac->ac_next);
+  TEST_S(ac->ac_type, "image/*");
+  TEST_S(ac->ac_subtype, "*");
+
+  TEST_1(aa = sip_accept_encoding_make(home, "gzip"));
+  TEST_1(aa = sip_accept_encoding_make(home, "gzip;q=1.0,deflate;q=1.0"));
+  TEST_S(aa->aa_value, "gzip"); TEST_S(aa->aa_q, "1.0");
+  TEST_1(aa->aa_next);
+  TEST_S(aa->aa_next->aa_value, "deflate"); 
+  TEST_1(aa = sip_accept_encoding_make(home, ","));
+  TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+  TEST_1(aa = sip_accept_encoding_make(home, ""));
+  TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+
+  TEST_1(aa = sip_accept_language_make(home, "fi"));
+  TEST_1(aa = sip_accept_language_make(home, "fi;q=1.0,sv;q=1.0"));
+  TEST_S(aa->aa_value, "fi"); TEST_S(aa->aa_q, "1.0");
+  TEST_1(aa->aa_next);
+  TEST_S(aa->aa_next->aa_value, "sv"); 
+  TEST_1(aa = sip_accept_language_make(home, ","));
+  TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+  TEST_1(aa = sip_accept_language_make(home, ""));
+  TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static int test_content_disposition(void)
+{
+  /* Test Accept header */
+  sip_content_disposition_t *cd, *cd0;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(cd = cd0 = sip_content_disposition_make(home, "sip-cgi ; action = store;handling=required  "));
+  TEST_S(cd->cd_type, "sip-cgi");
+  TEST_1(cd->cd_params && cd->cd_params[0] && cd->cd_params[1] && !cd->cd_params[2]);
+  TEST_S(cd->cd_params[0], "action=store");
+  TEST_S(cd->cd_params[1], "handling=required");
+  TEST_S(cd->cd_handling, "required");
+  TEST_1(cd->cd_required);
+  TEST_1(!cd->cd_optional);
+
+  su_home_unref(home);
+  END();
+}
+
+int test_retry_after(void)
+{
+  /* Test Session-Expires header */
+  sip_retry_after_t *af, *af0;
+  su_home_t *home;
+  char buf[64];
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(af = sip_retry_after_make(home, "1800"));
+  TEST(af->af_delta, 1800);
+  TEST_1(af = sip_retry_after_make(home, "1800(foo); duration = 3600"));
+  TEST_1(af->af_params && af->af_params[0]);
+  TEST_S(af->af_comment, "foo");
+  TEST_S(af->af_params[0], "duration=3600");
+  TEST_S(af->af_duration, "3600");
+
+  TEST_1(af0 = sip_retry_after_dup(home, af));
+  TEST_1(af0->af_params && af0->af_params[0]);
+  TEST_S(af0->af_comment, "foo");
+  TEST_S(af0->af_params[0], "duration=3600");
+  TEST_S(af0->af_duration, "3600");
+
+  TEST_1(sip_retry_after_e(buf, sizeof(buf), (sip_header_t *)af0, 0));
+
+  TEST_S(buf, "1800 (foo) ;duration=3600");
+
+  su_home_unref(home);
+
+  END();
+}
+
+int test_session_expires(void)
+{
+  /* Test Session-Expires header */
+  sip_session_expires_t *x, *x0;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(x = x0 = sip_session_expires_make(home, "1800"));
+  TEST(x->x_delta, 1800);
+  TEST_1(x = x0 = sip_session_expires_make(home, "1800 ; refresher = uas"));
+  TEST_1(x->x_params && x->x_params[0]);
+  TEST_S(x->x_params[0], "refresher=uas");
+  TEST_S(x->x_refresher, "uas");
+
+  su_home_unref(home);
+
+  END();
+}
+
+int test_min_se(void)
+{
+  /* Test Min-SE header */
+  sip_min_se_t *min, *min0;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(min = min0 = sip_min_se_make(home, "1800"));
+  TEST(min->min_delta, 1800);
+  TEST_1(min = sip_min_se_dup(home, min0));
+  TEST(min->min_delta, 1800);
+  TEST_1(min = sip_min_se_copy(home, min0));
+  TEST(min->min_delta, 1800);
+
+  TEST_1(min = sip_min_se_make(home, "1999 ; foo = bar"));
+  TEST(min->min_delta, 1999);
+  TEST_1(min->min_params);
+  TEST_S(min->min_params[0], "foo=bar");
+
+  TEST_1(min0 = sip_min_se_dup(home, min));
+  TEST(min0->min_delta, 1999);
+  TEST_1(min0->min_params);
+  TEST_S(min0->min_params[0], "foo=bar");
+
+  su_home_unref(home);
+
+  END();
+}
+   
+int test_refer(void)
+{
+  sip_refer_to_t *r, *r0;
+  sip_referred_by_t *b, *b0;
+  sip_replaces_t *rp, *rp0;
+  char const *s0;
+
+  su_home_t *home;
+
+  BEGIN();
+
+  char const m[] = 
+    "REFER sip:10.3.3.104 SIP/2.0\r\n"
+    "Via: SIP/2.0/UDP 10.3.3.8;branch=z9hG4bKb8389b4c1BA8899\r\n"
+    "From: \"Anthony Minessale\" <sip:polycom500 at 10.3.3.104>;tag=5AA04E0-66CFC37F\r\n"
+    "To: <sip:3001 at 10.3.3.104>;user=phone;tag=j6Fg9y7t8KNrF\r\n"
+    "CSeq: 4 REFER\r\n"
+    "Call-ID: a14822a4-5932e3ea-d7f37191 at 10.3.3.8\r\n"
+    "Contact: <sip:polycom500 at 10.3.3.8>\r\n"
+    "User-Agent: PolycomSoundPointIP-SPIP_500-UA/1.4.1\r\n"
+    "Refer-To: <sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%40"
+      "10.3.3.8%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF>\r\n"
+    "Referred-By: \"Anthony Minessale\" <sip:polycom500 at 10.3.3.104>\r\n"
+    "Refer-Sub: true\r\n"
+    "Max-Forwards: 70\r\n"
+    "Content-Length: 0\r\n"
+    "\r\n";
+  msg_t *msg;
+  sip_t *sip;
+  msg_iovec_t *iovec;
+  isize_t veclen, i, size;
+  char *back;
+  sip_refer_sub_t *rs;
+
+  TEST_1(home = su_home_create());
+
+  /* Check that Refer-Sub has already been added to our parser */
+  TEST_1(msg_mclass_insert_with_mask(test_mclass, sip_refer_sub_class, 
+				     0, 0) == -1);
+  
+  msg = read_message(0, m); TEST_1(msg); TEST_1(sip = sip_object(msg));
+  TEST_1(sip->sip_refer_to);
+  TEST_S(sip->sip_refer_to->r_url->url_headers,
+	 "Replaces=7d84c014-321368da-efa90f41%40"
+	 "10.3.3.8%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF");
+
+  TEST_1(rs = sip_refer_sub(sip));
+  TEST_S(rs->rs_value, "true");
+
+  TEST_SIZE(msg_prepare(msg), strlen(m));
+  TEST_1(veclen = msg_iovec(msg, NULL, ISIZE_MAX));
+  TEST_1(iovec = su_zalloc(msg_home(home), veclen * (sizeof iovec[0])));
+  TEST_SIZE(msg_iovec(msg, iovec, veclen), veclen);
+  
+  for (i = 0, size = 0; i < veclen; i++)
+    size += iovec[i].mv_len;
+  
+  TEST_1(back = su_zalloc(msg_home(msg), size + 1));
+
+  for (i = 0, size = 0; i < veclen; i++) {
+    memcpy(back + size, iovec[i].mv_base, iovec[i].mv_len);
+    size += iovec[i].mv_len;
+  }
+  back[size] = '\0';
+  
+  TEST_S(back, m);
+
+  TEST_1(r = r0 = sip_refer_to_make(home, "http://example.com;foo=bar"));
+  TEST(r->r_url->url_type, url_http);
+  TEST_1(r->r_params);
+  TEST_S(r->r_params[0], "foo=bar");
+  r = sip_refer_to_dup(home, r0);
+  TEST(r->r_url->url_type, url_http);
+  TEST_1(r->r_params);
+  TEST_S(r->r_params[0], "foo=bar");
+
+  TEST_1(r = r0 = sip_refer_to_make(home, s0 = "<http://example.com>"));
+  TEST_S(r->r_display, "");
+  TEST(r->r_url->url_type, url_http);
+  TEST_P(r->r_params, NULL);
+  r = sip_refer_to_dup(home, r0);
+  TEST_S(r->r_display, "");
+  TEST(r->r_url->url_type, url_http);
+  TEST_P(r->r_params, NULL);
+  TEST_S(sip_header_as_string(home, (sip_header_t*)r), s0);
+
+  TEST_1(r = r0 = sip_refer_to_make(home, 
+				    "Web Site <http://example.com>;foo=bar"));
+  TEST_S(r->r_display, "Web Site");
+  TEST(r->r_url->url_type, url_http);
+  TEST_1(r->r_params);
+  TEST_S(r->r_params[0], "foo=bar");
+  TEST_P(r->r_params[1], NULL);
+  r = sip_refer_to_dup(home, r0);
+  TEST(r->r_url->url_type, url_http);
+  TEST_1(r->r_params);
+  TEST_S(r->r_params[0], "foo=bar");
+  TEST_P(r->r_params[1], NULL);
+
+  /* Test bad replaces without <> */
+  {
+    char const s[] =
+      "sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%4010.3.3.8"
+      "%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF" "\r\n";
+    char *str;
+
+    TEST_1(r = r0 = sip_refer_to_make(home, s));
+    msg_fragment_clear(r->r_common);
+    TEST_1(str = sip_header_as_string(home, (void *)r));
+    TEST_S(str, 
+	   "<"
+	   "sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%4010.3.3.8"
+	   "%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF"
+	   ">");
+  }
+
+  su_home_unref(home);
+    
+  TEST_1(home = su_home_create());
+  TEST_1(b = b0 = sip_referred_by_make(home, 
+				      "sip:joe at example.edu;param=value"));
+  TEST_P(b->b_display, NULL);
+  TEST_1(b->b_params);
+  TEST_P(b->b_cid, NULL);
+
+  TEST_1(b = sip_referred_by_make(home, 
+				  "John Doe <sip:joe at example.edu>"
+				  ";cid=\"foo at bar\""));
+  TEST_S(b->b_display, "John Doe");
+  TEST_1(b->b_params);
+  TEST_1(b->b_cid);
+  TEST_S(b->b_params[0] + 4, b->b_cid);
+
+  b = sip_referred_by_dup(home, b0 = b);
+
+  TEST_1(b);
+  TEST_S(b->b_display, "John Doe");
+  TEST_1(b->b_cid);
+  TEST_S(b->b_params[0] + 4, b->b_cid);
+  TEST_S(b->b_cid, b0->b_cid);
+
+  TEST(msg_header_replace_param(home, b->b_common, "cid=cid:8u432658725"), 1);
+  TEST_S(b->b_cid, "cid:8u432658725");
+  TEST(msg_header_remove_param(b->b_common, "cid"), 1);
+  TEST_P(b->b_cid, NULL);
+  
+  /* XXX */
+#define WORD ALPHA DIGIT "-.!%*_+`'~()<>:\\\"/[]?{}"
+  rp = sip_replaces_make(home, WORD "@" WORD ";to-tag=foo;from-tag=bar"
+			 ";early-only = yes-please   ");
+
+  TEST_1(rp);
+  TEST_S(rp->rp_call_id, WORD "@" WORD);
+  TEST_S(rp->rp_to_tag, "foo");
+  TEST_S(rp->rp_from_tag, "bar");
+  TEST(rp->rp_early_only, 1);
+
+  rp = sip_replaces_dup(home, rp0 = rp);
+
+  TEST_1(rp);
+  TEST_S(rp->rp_call_id, WORD "@" WORD);
+  TEST_S(rp->rp_to_tag, "foo");
+  TEST_S(rp->rp_from_tag, "bar");
+  TEST(rp->rp_early_only, 1);
+
+  TEST(msg_header_replace_param(home, rp->rp_common, "early-only"), 1);
+  TEST(rp->rp_early_only, 1);
+  TEST(msg_header_remove_param(rp->rp_common, "from-tag"), 1);
+  TEST_P(rp->rp_from_tag, NULL);
+  TEST(msg_header_remove_param(rp->rp_common, "to-tag"), 1);
+  TEST_P(rp->rp_to_tag, NULL);
+
+  su_home_unref(home);
+
+  END();
+}
+
+static int test_features(void)
+{
+  /* Test Proxy-Required, Require, Supported, and Unsupported headers */
+  sip_proxy_require_t *pr;
+  sip_require_t *r;
+  sip_supported_t *s;
+  sip_unsupported_t *u, *u1;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+  TEST_1(pr = sip_proxy_require_make(home, "foo, bar, baz, dig, dug"));
+  TEST_1(r = sip_require_make(home, "dig, dug"));
+  TEST_1(s = sip_supported_make(home, "foo, baz, dug"));
+
+  TEST_1(pr->k_items); TEST_S(pr->k_items[0], "foo");
+  TEST_1(r->k_items); TEST_S(r->k_items[0], "dig");
+  TEST_1(s->k_items); TEST_S(s->k_items[0], "foo");
+
+  TEST_1(u = sip_has_unsupported(home, s, pr));
+  TEST_1(u->k_items); 
+  TEST_S(u->k_items[0], "bar");  
+  TEST_S(u->k_items[1], "dig");  
+  TEST_P(u->k_items[2], NULL);  
+
+  TEST_1(u1 = sip_has_unsupported(home, s, r));
+  TEST_1(u1->k_items); TEST_S(u1->k_items[0], "dig"); TEST_1(!u1->k_items[1]);
+
+  TEST_1(sip_has_supported(s, "foo"));
+  TEST_1(sip_has_supported(s, "baz"));
+  TEST_1(sip_has_supported(s, "dug"));
+  TEST_1(!sip_has_supported(s, "dig"));
+  TEST_1(!sip_has_supported(s, "dag.2"));
+  TEST_1(sip_has_supported(s, NULL));
+  TEST_1(sip_has_supported(NULL, NULL));
+  TEST_1(!sip_has_supported(NULL, "foo"));
+
+  su_home_unref(home);
+  END();
+}
+
+#if 0
+static int sip_time_test(void)
+{
+  sip_contact_t *m;
+  sip_expires_t *ex;
+  sip_date_t *date = NULL;
+  sip_time_t default = 3600;
+  BEGIN();
+
+  sip_time_t sip_contact_expires(sip_contact_t const *m,
+				 sip_expires_t const *ex,
+				 sip_date_t const *date,
+				 sip_time_t def,
+				 sip_time_t now);
+
+  
+  END();
+}
+#endif
+
+static int test_events(void)
+{
+  sip_event_t *o;
+  sip_allow_events_t *ae;
+  sip_subscription_state_t *ss;
+  su_home_t *home;
+  msg_t *msg;
+  sip_t *sip;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+
+  TEST_1((o = sip_event_make(home, "presence;id=1")));
+  TEST_S(o->o_type, "presence");
+  TEST_S(o->o_id, "1");
+
+  TEST(msg_header_remove_param(o->o_common, "ix=0"), 0);
+  TEST_S(o->o_id, "1");
+  TEST(msg_header_remove_param(o->o_common, "id"), 1);
+  TEST_P(o->o_id, NULL);
+  TEST(msg_header_replace_param(home, o->o_common, "id=32"), 0);
+  TEST_S(o->o_id, "32");
+
+  TEST_1((ae = sip_allow_events_make(home, "presence, presence.winfo, foo")));
+  TEST_1(ae->k_items);
+  TEST_S(ae->k_items[0], "presence");
+  TEST_S(ae->k_items[1], "presence.winfo");
+  TEST_S(ae->k_items[2], "foo");
+  TEST_P(ae->k_items[3], 0);
+  TEST(sip_allow_events_add(home, ae, "event3"), 0);
+  TEST_S(ae->k_items[3], "event3");
+  TEST(sip_allow_events_add(home, ae, "event4"), 0);
+  TEST_S(ae->k_items[4], "event4");
+  TEST(sip_allow_events_add(home, ae, "event5"), 0);
+  TEST_S(ae->k_items[5], "event5");
+  TEST(sip_allow_events_add(home, ae, "event6"), 0);
+  TEST_S(ae->k_items[6], "event6");
+  TEST(sip_allow_events_add(home, ae, "event7"), 0);
+  TEST_S(ae->k_items[7], "event7");
+  TEST(sip_allow_events_add(home, ae, "event8"), 0);
+  TEST_S(ae->k_items[8], "event8");
+
+  TEST_1((ss = 
+	 sip_subscription_state_make(home, "terminated ; reason=timeout")));
+  TEST_S(ss->ss_substate, "terminated");
+  TEST_S(ss->ss_reason, "timeout");
+
+  TEST(msg_header_replace_param(home, ss->ss_common, "reason=TimeOut"), 1);
+  TEST_S(ss->ss_reason, "TimeOut");
+  TEST(msg_header_remove_param(ss->ss_common, "reasom"), 0);
+  TEST_S(ss->ss_reason, "TimeOut");
+  TEST(msg_header_remove_param(ss->ss_common, "reason"), 1);
+  TEST_P(ss->ss_reason, NULL);
+  TEST(msg_header_replace_param(home, ss->ss_common, "expires=200"), 0);
+  TEST(msg_header_replace_param(home, ss->ss_common, "retry-after=10"), 0);
+  TEST_S(ss->ss_expires, "200");
+  TEST_S(ss->ss_retry_after, "10");
+
+  TEST_1((ss = 
+	 sip_subscription_state_make(home, "active;expires=2")));
+  TEST_S(ss->ss_substate, "active");
+  TEST_S(ss->ss_expires, "2");
+
+  TEST_1((ss = 
+	  sip_subscription_state_make(home, "terminated;retry-after=3600")));
+  TEST_S(ss->ss_substate, "terminated");
+  TEST_P(ss->ss_expires, NULL);
+  TEST_S(ss->ss_retry_after, "3600");
+
+  TEST_1((ss = sip_subscription_state_dup(home, ss)));
+  TEST_S(ss->ss_substate, "terminated");
+  TEST_P(ss->ss_expires, NULL);
+  TEST_S(ss->ss_retry_after, "3600");
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "SIP/2.0 202 Accepted\r\n"
+    "To: <sip:foo at bar>;tag=deadbeef\r\n"
+    "From: <sip:bar at foo>;\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq: 8 SUBSCRIBE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Event: foo;id=1\r\n"
+    "Allow-Events: bar, foo, zap\r\n"
+    "Subscription-State: terminated;reason=probation;retry-after=100000\r\n"
+    "Content-Length: 0\r\n"
+    "\r\n");
+
+  sip = sip_object(msg);
+
+  TEST_1(msg);
+  TEST_1(sip);
+  TEST_1(sip->sip_event);
+  TEST_1(sip->sip_allow_events);
+  TEST_1(sip->sip_event->o_type);
+  TEST_S(sip->sip_event->o_type, "foo");
+  TEST_1(sip->sip_event->o_id);
+  TEST_S(sip->sip_event->o_id, "1");
+  TEST_1(sip->sip_allow_events);
+
+  su_home_unref(home);
+  msg_destroy(msg), msg = NULL;
+
+  END();
+}
+
+static int test_route(void)
+{
+  sip_record_route_t *r0, *r1;
+  sip_record_route_t *rr;
+  sip_path_t *p, *p0;
+  sip_service_route_t *sr, *sr0;
+
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+
+  TEST_1((rr = sip_record_route_make(home, "sip:foo.bar;lr")));
+  TEST_1(rr->r_params);
+
+  TEST_1((r0 = sip_record_route_make(home, "<sip:0 at foo.bar:555;lr>")));
+  TEST_P(r0->r_params, NULL);
+  TEST_1(r0->r_url->url_params);
+
+  TEST_1((r1 = sip_record_route_make(home, "<sip:1 at foo.bar:666"
+				    ";maddr=127.0.0.1>")));
+  TEST_P(r1->r_params, NULL);
+  TEST_1(r1->r_url->url_params);
+
+  TEST_1((rr = sip_record_route_create(home, r0->r_url, r1->r_url)));
+  TEST_S(rr->r_url->url_user, "0");
+  TEST_S(rr->r_url->url_port, "666");
+  TEST_S(rr->r_url->url_params, "maddr=127.0.0.1");
+
+  TEST_1((rr = sip_record_route_create(home, r1->r_url, r0->r_url)));
+  TEST_S(rr->r_url->url_user, "1");
+  TEST_S(rr->r_url->url_port, "555");
+  TEST_S(rr->r_url->url_params, "lr;maddr=foo.bar");
+
+  TEST_1(!sip_path_make(home, "<sip:foo@[bar:50>;lr"));
+  TEST_1(p = sip_path_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+  TEST_1(p0 = sip_path_dup(home, p));
+
+  su_free(home, p); 
+  su_free(home, p0);
+
+  TEST_1(!sip_service_route_make(home, "<sip:foo@[bar:50>;lr"));
+  TEST_1(!sip_service_route_make(home, 
+				 "<sip:foo@[baa::1]>;lr bar, sip:foo"));
+
+  TEST_1(sr = sip_service_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+  TEST_1(sr0 = sip_service_route_dup(home, sr));
+  su_free(home, sr);
+
+  TEST_1(sr = sip_service_route_make(home, "sip:foo@[baa::1]:5060;lr"));
+  
+  su_free(home, sr);
+  su_free(home, sr0);
+
+  su_home_unref(home);
+
+  END();
+}
+
+/* Test Request-Disposition header */
+int test_request_disposition(void)
+{
+  sip_request_disposition_t *rd;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+
+  TEST_1(rd = sip_request_disposition_make(home, "proxy, recurse, parallel"));
+  TEST_S(rd->rd_items[1], "recurse");
+
+  su_home_unref(home);
+
+  END();
+}
+
+#include <float.h>
+
+int test_caller_prefs(void)
+{
+  sip_accept_contact_t *ac;
+  sip_accept_contact_t *cp;
+  sip_reject_contact_t *rejc;
+  su_home_t *home;
+  char const *s;
+  int negate, error;
+  unsigned S, N;
+  union sip_pref sp[1], a[1];
+  sip_contact_t *m, *m0, *m1, *m2;
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  TEST_1(!sip_is_callerpref("attendant"));
+  TEST_1(sip_is_callerpref("audio"));
+  TEST_1(sip_is_callerpref("automata"));
+  TEST_1(sip_is_callerpref("class"));
+  TEST_1(sip_is_callerpref("duplex"));
+  TEST_1(sip_is_callerpref("data"));
+  TEST_1(sip_is_callerpref("control"));
+  TEST_1(sip_is_callerpref("mobility"));
+  TEST_1(sip_is_callerpref("description"));
+  TEST_1(sip_is_callerpref("events"));
+  TEST_1(sip_is_callerpref("priority"));
+  TEST_1(sip_is_callerpref("methods"));
+  TEST_1(sip_is_callerpref("schemes"));
+  TEST_1(sip_is_callerpref("application"));
+  TEST_1(sip_is_callerpref("video"));
+  TEST_1(sip_is_callerpref("actor"));
+  TEST_1(!sip_is_callerpref("+actor"));
+  TEST_1(!sip_is_callerpref("msgserver"));
+  TEST_1(sip_is_callerpref("language"));
+  TEST_1(sip_is_callerpref("isfocus"));
+  TEST_1(sip_is_callerpref("type"));
+  TEST_1(!sip_is_callerpref("uri-user"));
+  TEST_1(!sip_is_callerpref("uri-domain"));
+  TEST_1(!sip_is_callerpref(NULL));
+  TEST_1(sip_is_callerpref("+"));
+  TEST_1(sip_is_callerpref("+foo"));
+  
+  /* Booleans (treated as literals) */
+  s = "TRUE"; 
+  negate = 2; memset(sp, 0, sizeof sp);
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_literal);
+  TEST_S(sp->sp_literal.spl_value, "TRUE"); TEST_1(!negate);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(!sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_init);
+  
+  s = "FALSE"; 
+  negate = 2; memset(sp, 0, sizeof sp);
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_literal);
+  TEST_S(sp->sp_literal.spl_value, "FALSE"); TEST_1(!negate);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(!sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_init);
+  
+  s = "\"!TRUE,!FALSE\""; negate = 0;
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_literal); TEST_1(negate);
+  
+  /* Literal */
+  s = "\" !oukki , doukki  \""; negate = 0; memset(sp, 0, sizeof sp);
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_literal);
+  TEST_SIZE(sp->sp_literal.spl_length, 5);
+  TEST_M(sp->sp_literal.spl_value, "oukki", 5); TEST_1(negate);
+  
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_literal);
+  TEST_SIZE(sp->sp_literal.spl_length, 6);
+  TEST_M(sp->sp_literal.spl_value, "doukki", 6); TEST_1(!negate);
+
+  TEST_1(!sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_init);
+
+  /* Strings */
+  s = "\" !<oukki> , <douK\\\"ki  >\""; 
+  negate = 0; memset(sp, 0, sizeof sp);
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_string);
+  TEST_SIZE(sp->sp_string.sps_length, 5);
+  TEST_M(sp->sp_string.sps_value, "oukki", 5); TEST_1(negate);
+  
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_string);
+  TEST_SIZE(sp->sp_string.sps_length, 10);
+  TEST_M(sp->sp_string.sps_value, "douK\\\"ki  ", 10); TEST_1(!negate);
+  
+  TEST_1(!sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_init);
+
+  /* Numeric */
+  s = "\" !#=6, #<=3, #>=6, !#<=6, #1:6.5\"";
+  negate = 0; memset(sp, 0, sizeof sp);
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_range);
+  TEST_D(sp->sp_range.spr_lower, 6.0);
+  TEST_D(sp->sp_range.spr_upper, 6.0);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(negate);
+
+  *a = *sp;
+    
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_range);
+  TEST_D(sp->sp_range.spr_lower, DBL_MIN);
+  TEST_D(sp->sp_range.spr_upper, 3.0);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(!negate);
+
+  TEST_1(!sip_prefs_match(a, sp));
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_range);
+  TEST_D(sp->sp_range.spr_lower, 6.0);
+  TEST_D(sp->sp_range.spr_upper, DBL_MAX);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(!negate);
+
+  TEST_1(sip_prefs_match(a, sp));
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_range);
+  TEST_D(sp->sp_range.spr_lower, DBL_MIN);
+  TEST_D(sp->sp_range.spr_upper, 6.0);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(negate);
+
+  TEST_1(sip_prefs_match(a, sp));
+
+  TEST_1(sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_range);
+  TEST_D(sp->sp_range.spr_lower, 1.0);
+  TEST_D(sp->sp_range.spr_upper, 6.5);
+  TEST_1(sip_prefs_match(sp, sp));
+  TEST_1(!negate);
+
+  TEST_1(sip_prefs_match(a, sp));
+
+  TEST_1(!sip_prefs_parse(sp, &s, &negate));
+  TEST(sp->sp_type, sp_init);
+
+  error = 12;
+
+  TEST_1(sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"", 
+			    "\"INVITE\"", &error)); 
+  TEST_1(!sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"", 
+			     "\"BYE\"", &error)); 
+  TEST(error, 12);
+  TEST_1(sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"", 
+			     "\"invite\"", &error)); 
+  TEST_1(sip_prefs_matching("\"!INVITE,MESSAGE,SUBSCRIBE\"", 
+			     "\"foo\"", &error)); 
+  TEST_1(sip_prefs_matching("TRUE", "", &error));
+  TEST_1(sip_prefs_matching("", "", &error));
+  TEST_1(!sip_prefs_matching("FALSE", "", &error));
+  TEST(error, 12);
+  TEST_1(sip_prefs_matching("FALSE", "FALSE", &error));
+
+  /* Lax when receiving... */
+  TEST_1(sip_prefs_matching("\"FALSE\"", "FALSE", &error));  /* XXX */
+  TEST_1(sip_prefs_matching("\"TRUE\"", "TRUE", &error));  /* XXX */
+
+  TEST_1(!sip_prefs_matching("\"!INVITE\"", "\"INVITE\"", &error));
+  TEST_1(!sip_prefs_matching("\"!INVITE\"", "\"invite\"", &error));
+  TEST_1(sip_prefs_matching("\"!<INVITE>\"", "\"<invite>\"", &error));
+  TEST_1(!sip_prefs_matching("\"INVITE\"", "\"!INVITE\"", &error));
+  TEST_1(sip_prefs_matching("\"!INVITE\"", "\"INVITE,MESSAGE\"", &error));
+  TEST_1(sip_prefs_matching("\"!INVITE,!MESSAGE\"", 
+			     "\"INVITE,MESSAGE\"", &error));
+  TEST_1(sip_prefs_matching("\"!MESSAGE\"", "\"INVITE,MESSAGE\"", &error));
+  TEST_1(!sip_prefs_matching("\"<foo>,<bar>\"", 
+			     "\"<FOO>,<BAR>\"", &error)); 
+  TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"foo,bar\"", &error)); 
+  TEST_1(sip_prefs_matching("\"#=1\"", "\"#<=2\"", &error)); 
+  TEST_1(sip_prefs_matching("\"#1:2\"", "\"#<=2\"", &error)); 
+  TEST_1(!sip_prefs_matching("\"#1:2\"", "\"!#>=1,!#<=2\"", &error)); 
+  TEST_1(!sip_prefs_matching("\"#=0,#=1\"", "\"<FOO>,<BAR>\"", &error)); 
+  TEST(error, 12);
+
+  error = 12;
+  TEST_1(!sip_prefs_matching("\"<foo>,#=1\"", "\"<FOO>,<BAR>\"", &error)); 
+  TEST(error, -1);
+
+  error = 12;
+  TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"<foo>,#=1\"", &error)); 
+  TEST(error, -1);
+
+  error = 12;
+  TEST_1(!sip_prefs_matching("\"<foo>,bar\"", "\"<FOO>,<BAR>\"", &error)); 
+  TEST(error, -1);
+
+  error = 12;
+  TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"<foo>,#12:12\"", &error)); 
+  TEST(error, -1);
+
+  {
+    char const *params[] = {
+      "methods=\"INVITE,MESSAGE,SUBSCRIBE\"",
+      "events=\"presence,presence.winfo\"",
+      "description=\"<PC>\"",
+      "language=\"!en,de\"",
+      "schemes=\"sip\"",
+      "+res-x=\"#=640\"",
+      "+res-y=\"#=480\"",
+      NULL
+    };
+
+    TEST_1(sip_is_callerpref(params[0]));
+    TEST_1(sip_is_callerpref(params[1]));
+    TEST_1(sip_is_callerpref(params[2]));
+    TEST_1(sip_is_callerpref(params[3]));
+    TEST_1(sip_is_callerpref(params[4]));
+    TEST_1(sip_is_callerpref(params[5]));
+    TEST_1(sip_is_callerpref(params[6]));
+    TEST_1(!sip_is_callerpref(params[7])); /* NULL */
+    TEST_1(!sip_is_callerpref("method=\"foo\""));
+    TEST_1(!sip_is_callerpref("+methods=\"foo\""));
+  }
+
+  TEST_1(m = sip_contact_make(home, 
+			      "<sip:1 at domain>;video;audio;type=\"<video/H263>\","
+			      "<sip:2 at domain>;video=FALSE;audio;text,"
+			      "<sip:3 at domain>;text;audio=FALSE"));
+
+  m0 = m, m1 = m->m_next, m2 = m->m_next->m_next;
+
+  TEST_1(ac = sip_accept_contact_make(home, "*;type=\"<video/H263>\";video"));
+  TEST_S(ac->cp_params[0], "type=\"<video/H263>\"");
+  TEST_S(ac->cp_params[1], "video");
+  TEST_P(ac->cp_params[2], NULL);
+
+  TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+  TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error));
+  TEST_1(sip_contact_accept(m2, ac, &S, &N, &error)); TEST(S, 0); TEST(N, 2);
+
+  TEST_1(ac = sip_accept_contact_make(home, "sip:127.0.0.1:5060;video;audio"));
+  TEST_S(ac->cp_params[0], "video");
+  TEST_S(ac->cp_params[1], "audio");
+  TEST_P(ac->cp_params[2], NULL);
+
+  TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+  TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error));
+  TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error)); 
+
+  TEST_1(ac = sip_accept_contact_make(home, 
+				      "Joe the Luser "
+				      "<sip:127.0.0.1:5060>;video;audio"));
+  TEST_S(ac->cp_params[0], "video");
+  TEST_S(ac->cp_params[1], "audio");
+  TEST_P(ac->cp_params[2], NULL);
+
+  TEST_1(ac = sip_accept_contact_make(home, 
+				      "video;audio;explicit"));
+  TEST_S(ac->cp_params[0], "video");
+  TEST_S(ac->cp_params[1], "audio");
+  TEST_S(ac->cp_params[2], "explicit");
+  TEST_P(ac->cp_params[3], NULL);
+
+  TEST_1(ac = sip_accept_contact_make(home, 
+				      "video = foo ;audio;explicit"));
+  TEST_S(ac->cp_params[0], "video=foo");
+  TEST_S(ac->cp_params[1], "audio");
+  TEST_S(ac->cp_params[2], "explicit");
+  TEST_P(ac->cp_params[3], NULL);
+
+  TEST_1(ac = sip_accept_contact_make(home, 
+				      "video = \"bar\" ;audio;explicit"));
+  TEST_S(ac->cp_params[0], "video=\"bar\"");
+  TEST_S(ac->cp_params[1], "audio");
+  TEST_S(ac->cp_params[2], "explicit");
+  TEST_P(ac->cp_params[3], NULL);
+  
+  TEST_1(cp = sip_accept_contact_make(home, 
+				     "*;audio;video;require;explicit;q=1.0,"
+				     "*;audio;require;q=0.8"
+				     ));
+
+  TEST_1(ac = sip_accept_contact_dup(home, cp));
+
+  TEST_S(ac->cp_params[0], "audio");
+  TEST_S(ac->cp_params[1], "video");
+  TEST_S(ac->cp_params[2], "require");
+  TEST_S(ac->cp_params[3], "explicit");
+  TEST_S(ac->cp_params[4], "q=1.0");
+  TEST_P(ac->cp_params[5], NULL);
+
+  /* TEST_S(ac->cp_q, "1.0"); */
+  TEST(ac->cp_require, 1);
+  TEST(ac->cp_explicit, 1);
+
+  TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+  /* Explicit has short-circuit evaluation */
+  TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error)); 
+  TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error)); 
+
+  TEST_1(ac = ac->cp_next);
+
+  TEST_S(ac->cp_params[0], "audio");
+  TEST_S(ac->cp_params[1], "require");
+  TEST_S(ac->cp_params[2], "q=0.8");
+  TEST_P(ac->cp_params[3], NULL);
+
+  TEST(ac->cp_explicit, 0);
+
+  TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 1); TEST(N, 1);
+  TEST_1(sip_contact_accept(m1, ac, &S, &N, &error)); TEST(S, 1); TEST(N, 1);
+  TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error));
+
+  TEST_P(ac->cp_next, NULL);
+
+  TEST_1(rejc = sip_reject_contact_make(home, 
+					"*;type=\"<video/H263>\";video=TRUE"));
+  TEST_S(rejc->cp_params[0], "type=\"<video/H263>\"");
+  TEST_S(rejc->cp_params[1], "video=TRUE");
+
+  TEST_1(sip_contact_reject(m0, rejc));
+  TEST_1(!sip_contact_reject(m1, rejc));
+  TEST_1(!sip_contact_reject(m2, rejc));
+
+  TEST_1(!sip_contact_immune(m0));
+  m0 = sip_contact_immunize(home, m0); TEST_1(m0); 
+  TEST_1(sip_contact_immune(m0));
+
+  TEST_1(!sip_contact_immune(m1));
+  m1 = sip_contact_immunize(home, m1); TEST_1(m1);
+  TEST_1(sip_contact_immune(m1));
+
+  TEST_1(!sip_contact_immune(m2));
+  m2 = sip_contact_immunize(home, m2); TEST_1(m2);
+  TEST_1(sip_contact_immune(m2));
+
+  m = sip_contact_make(home, "<sip:test.domain>;+test;+audio");
+  TEST_1(!sip_contact_immune(m));
+  m1 = sip_contact_immunize(home, m); TEST_1(m1);
+  TEST_1(sip_contact_immune(m1));
+
+  TEST_S(m->m_params[0], "+test");
+  TEST_S(m->m_params[1], "+audio");
+  TEST_P(m->m_params[2], NULL);
+
+  TEST_S(m1->m_params[0], "+audio");
+  TEST_P(m1->m_params[1], NULL);
+
+  TEST_1(ac = sip_accept_contact_make(home, "*;q=0.9;require;explicit"));
+  /* TEST_S(ac->cp_q, "0.9"); */
+  TEST_1(ac->cp_require);
+  TEST_1(ac->cp_explicit);
+
+  TEST(msg_header_remove_param(ac->cp_common, "Q"), 1);
+  /* TEST(ac->cp_q, NULL); */
+  TEST(msg_header_remove_param(ac->cp_common, "require="), 1);
+  TEST(ac->cp_require, 0);
+  TEST(msg_header_remove_param(ac->cp_common, "require="), 0);
+  TEST(ac->cp_require, 0);
+  TEST(msg_header_remove_param(ac->cp_common, "explicit=true"), 1);
+  TEST(ac->cp_explicit, 0);
+  TEST(msg_header_replace_param(home, ac->cp_common, "explicit=true"), 0);
+  TEST(ac->cp_explicit, 1);
+
+  su_home_zap(home);
+
+  END();
+}
+
+
+static int test_callerpref_scoring(void)
+{
+  sip_accept_contact_t *ac;
+  sip_reject_contact_t *rejc;
+  su_home_t *home;
+  int S;
+  sip_contact_t *m, *m1, *m2, *m3, *m4, *m5;
+
+  char const contact[] = 
+    "sip:u1 at h.example.com;audio;video;methods=\"INVITE,BYE\";q=0.2,"
+    "sip:u2 at h.example.com;audio=\"FALSE\";"
+    "methods=\"INVITE\";actor=\"msg-taker\";q=0.2,"
+    "sip:u3 at h.example.com;audio;actor=\"msg-taker\";"
+    "methods=\"INVITE\";video;q=0.3,"
+    "sip:u4 at h.example.com;audio;methods=\"INVITE,OPTIONS\";q=0.2,"
+    "sip:u5 at h.example.com;q=0.5";
+
+  char const reject[] = 
+    "*;actor=\"msg-taker\";video";
+
+  char const accept[] = 
+    "*;audio;require,"
+    "*;video;explicit,"
+    "*;methods=\"BYE\";class=\"business\";q=1.0";
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+
+  TEST_1(m = sip_contact_make(home, contact));
+  m1 = m, m2 = m->m_next, m3 = m->m_next->m_next, m4 = m->m_next->m_next->m_next,
+    m5 = m->m_next->m_next->m_next->m_next;
+  TEST_1(rejc = sip_reject_contact_make(home, reject));
+  TEST_1(ac = sip_accept_contact_make(home, accept));
+
+  S = sip_contact_score(m1, ac, rejc); TEST(S, 1000 * 5 / 6 + 1);
+  S = sip_contact_score(m2, ac, rejc); TEST(S, 0);
+  S = sip_contact_score(m3, ac, rejc); TEST_1(S < 0);
+  S = sip_contact_score(m4, ac, rejc); TEST(S, 1000 / 2);
+  S = sip_contact_score(m5, ac, rejc); TEST(S, 1000);
+
+  su_home_zap(home);
+
+  END();
+}
+
+static int test_reason(void)
+{
+  sip_reason_t *re;
+  su_home_t *home;
+  msg_t *msg;
+  sip_t *sip;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+
+  TEST_1((re = sip_reason_make(home, "SIP;cause=200;text=\"Ok\"")));
+  TEST_S(re->re_protocol, "SIP");
+  TEST_S(re->re_cause, "200");
+  TEST_S(re->re_text, "\"Ok\"");
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "BYE sip:foo at bar SIP/2.0\r\n"
+    "To: <sip:foo at bar>;tag=deadbeef\r\n"
+    "From: <sip:bar at foo>;\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq: 8 SUBSCRIBE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Reason: SIP ;cause=200 ;text=\"Call completed elsewhere\"\r\n"
+    "Reason: Q.850 ;cause=16 ;text=\"Terminated\"\r\n ,,"
+    "SIP ; cause = 600 ;text\t\r\n =  \"Busy Everywhere\" \t \r\n"
+    "Reason: SIP ;cause=580 ;text=\"Precondition Failure\"\r\n"
+    "Content-Length: 0\r\n"
+    "\r\n");
+
+  sip = sip_object(msg);
+
+  TEST_1(msg); 
+  TEST_1(sip);
+  TEST_1(re = sip->sip_reason);
+  TEST_S(re->re_protocol, "SIP");
+  TEST_S(re->re_cause, "200");
+  TEST_S(re->re_text, "\"Call completed elsewhere\"");
+  TEST_1(re = re->re_next);
+  TEST_S(re->re_protocol, "Q.850");
+  TEST_S(re->re_cause, "16");
+  TEST_S(re->re_text, "\"Terminated\"");
+  TEST_1(re = re->re_next);
+  TEST_S(re->re_protocol, "SIP");
+  TEST_S(re->re_cause, "600");
+  TEST_S(re->re_text, "\"Busy Everywhere\"");
+  TEST_1(re = re->re_next);
+  TEST_S(re->re_protocol, "SIP");
+  TEST_S(re->re_cause, "580");
+  TEST_S(re->re_text, "\"Precondition Failure\"");
+  TEST_1(!(re = re->re_next));
+
+  TEST_1(re = sip->sip_reason);
+  TEST(msg_header_replace_param(home, re->re_common, "cause=202"), 1);
+  TEST_S(re->re_cause, "202");
+  TEST(msg_header_replace_param(home, re->re_common, "text=\"foo\""), 1);
+  TEST_S(re->re_text, "\"foo\"");
+  TEST(msg_header_remove_param(re->re_common, "cause=444"), 1);
+  TEST_P(re->re_cause, NULL);
+  TEST(msg_header_remove_param(re->re_common, "text=\"bar\""), 1);
+  TEST_P(re->re_text, NULL);
+  TEST(msg_header_remove_param(re->re_common, "cause=444"), 0);
+  TEST(msg_header_remove_param(re->re_common, "text=\"bar\""), 0);
+
+  /* Not a token */
+  TEST_1(!sip_reason_make(home, "\"nSIP\";cause=200;text=\"Ok\""));
+  /* Empty list */ 
+  TEST_1(!sip_reason_make(home, ","));
+  /* no protocol token */
+  TEST_1(!sip_reason_make(home, "cause=16;text=\"call cleared\""));
+
+  /* Empty parameter */
+  TEST_1(!sip_reason_make(home, "SIP;cause=200;;text=\"Ok\""));
+  /* no semicolon after token */
+  TEST_1(!sip_reason_make(home, "SIP cause=200;text=\"Ok\""));
+  /* extra semicolon after parameters */
+  TEST_1(!sip_reason_make(home, "SIP ;cause=200;text=\"Ok\";"));
+
+  su_home_unref(home);
+  msg_destroy(msg), msg = NULL;
+
+  END();
+}
+
+static int test_warning(void)
+{
+  sip_warning_t *w;
+  su_home_t *home;
+
+  BEGIN();
+
+  TEST_1(home = su_home_create());
+
+  TEST_1((w = sip_warning_make(home, 
+			       "399 host:5060 \"Ok\", "
+			       "399 [::1]:39999 \"foo\\\" bar\"")));
+  TEST(w->w_code, 399);
+  TEST_S(w->w_host, "host");
+  TEST_S(w->w_port, "5060");
+  TEST_S(w->w_text, "Ok");
+  TEST_1(w = w->w_next);
+
+  TEST(w->w_code, 399);
+  TEST_S(w->w_host, "[::1]");
+  TEST_S(w->w_port, "39999");
+  TEST_S(w->w_text, "foo\" bar");
+  TEST_1(w->w_next == NULL);
+
+  TEST_S(sip_header_as_string(home, (sip_header_t *)w), 
+	 "399 [::1]:39999 \"foo\\\" bar\"");
+
+  su_home_unref(home);
+
+  END();
+}
+
+
+static int test_sec_ext(void)
+{
+  su_home_t *home;
+
+  sip_security_client_t *sac;
+  sip_security_server_t *sas;
+  sip_security_verify_t *sav;
+  sip_privacy_t *priv;
+
+  msg_t *msg;
+  sip_t *sip;
+
+  BEGIN();
+
+  msg = read_message(MSG_DO_EXTRACT_COPY, 
+    "BYE sip:foo at bar SIP/2.0\r\n"
+    "To: <sip:foo at bar>;tag=deadbeef\r\n"
+    "From: <sip:bar at foo>;\r\n"
+    "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+    "CSeq: 8 SUBSCRIBE\r\n"
+    "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+    "Content-Length: 0\r\n"
+    "\r\n");
+
+  sip = sip_object(msg);
+
+  TEST_1(home = msg_home(msg));
+  
+  TEST_1(sac = sip_security_client_make(home, "digest;q=0.5,ipsec-3gpp"));
+  TEST_S(sac->sa_mec, "digest");
+  TEST_S(sac->sa_q, "0.5");
+  TEST_1(sac = sac->sa_next);
+  TEST_S(sac->sa_mec, "ipsec-3gpp");
+
+  TEST_1((sas = sip_security_server_make(home, "digest;q=0.5")));
+  TEST_S(sas->sa_mec, "digest");
+  TEST_S(sas->sa_q, "0.5");
+
+  TEST_1((sav = sip_security_verify_make(home, "digest;q=0.5")));
+  TEST_S(sav->sa_mec, "digest");
+  TEST_S(sav->sa_q, "0.5");
+
+  TEST_1((sav = sip_security_verify_make
+	  (home, "digest;q=0.1;d-alg=SHA1;d-qop=auth;"
+	   "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"")));
+  TEST_S(sav->sa_mec, "digest");
+  TEST_S(sav->sa_q, "0.1");
+  TEST_S(sav->sa_d_alg, "SHA1");
+  TEST_S(sav->sa_d_qop, "auth");
+  TEST_S(sav->sa_d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+  /* Test for accepting liberally.. */
+  TEST_1(priv = sip_privacy_make(home, "header,media"));
+  TEST_1(priv = sip_privacy_make(home, ";header;media"));
+
+  TEST_1(!(priv = sip_privacy_make(home, "none explicit")));
+
+  TEST_1((priv = sip_privacy_make(home, "header;media")));
+  TEST_1(priv->priv_values);
+  TEST_S(priv->priv_values[0], "header");
+  TEST_S(priv->priv_values[1], "media");
+
+  msg_destroy(msg);
+
+  END();
+}
+ 
+
+static int test_utils(void)
+{
+  sip_from_t *f;
+  su_home_t *home;
+  sip_security_server_t *secs;
+  sip_security_verify_t *secv;
+  msg_param_t d_ver = NULL;
+
+  BEGIN();
+
+  TEST_1(home = su_home_new(sizeof *home));
+  TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555"
+			   ";ttl=1;user=IP;maddr=::1;lr=TRUE;transport=TCP"
+			   ";test=1?accept-contact=*;audio;video;explicit>"));
+  TEST_1(sip_aor_strip(f->a_url) == 0);
+  TEST_1(f->a_url->url_port == NULL);
+  TEST_S(f->a_url->url_params, "user=IP;test=1");
+  TEST_1(f->a_url->url_headers == NULL);
+
+  TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;ttl=1>"));
+  TEST_1(sip_aor_strip(f->a_url) == 0);
+  TEST_1(f->a_url->url_params == NULL);
+
+  TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;test=1;ttl=1>"));
+  TEST_1(sip_aor_strip(f->a_url) == 0);
+  TEST_S(f->a_url->url_params, "test=1");
+
+  TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;;test=1;>"));
+  TEST_1(sip_aor_strip(f->a_url) == 0);
+  TEST_S(f->a_url->url_params, "test=1");
+
+  TEST_1(secs = sip_security_server_make(home, "Digest"));
+  TEST_1(secv = 
+	 sip_security_verify_make(home, 
+				  "Digest;"
+				  "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""));
+  
+  TEST_1(sip_security_verify_compare(secs, secv, &d_ver) == 0);
+  TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+  TEST_1(secs = 
+	 sip_security_server_make(home, 
+				  "TLS;q=1,"
+				  "Digest;q=0.1;"
+				  "d-alg=MD5;d-qop=\"auth,auth-int\","
+				  "Digest;d-alg=AKA-MD5;q=0.9"
+				  ));
+  TEST_1(secv = 
+	 sip_security_verify_make(home, 
+				  "TLS;q=1,"
+				  "Digest ; q = 0.1;"
+				  "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";"
+				  "d-alg = MD5 ; d-qop = \"auth,auth-int\","
+				  "Digest ; d-alg=AKA-MD5;q=0.9"));
+
+  TEST_1(sip_security_verify_compare(secs, secv, &d_ver) == 0);
+  TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+  TEST_1(sip_security_verify_compare(secs->sa_next, secv, &d_ver) != 0);
+  TEST_1(sip_security_verify_compare(secs, secv->sa_next, &d_ver) != 0);
+  d_ver = "kuik";
+  TEST_1(sip_security_verify_compare(secs->sa_next, secv->sa_next, &d_ver) 
+	 == 0);
+  TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+  d_ver = "kuik";
+  TEST_1(sip_security_verify_compare(secs->sa_next->sa_next, 
+				     secv->sa_next->sa_next, &d_ver) 
+	 == 0);
+  TEST_1(d_ver == NULL);
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+char *lastpart(char *path)
+{
+  if (strchr(path, '/')) 
+    return strrchr(path, '/') + 1;
+  else
+    return path;
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  name = lastpart(argv[0]);  /* Set our name */
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  if (!test_mclass)
+    test_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0);
+
+  retval |= test_url_headers(); fflush(stdout);
+  retval |= test_manipulation(); fflush(stdout);
+  retval |= test_methods(); fflush(stdout);
+  retval |= test_basic(); fflush(stdout);
+  retval |= test_sip_msg_class(test_mclass); fflush(stdout);
+  retval |= test_encoding(); fflush(stdout);
+  retval |= test_events(); fflush(stdout);
+  retval |= test_reason(); fflush(stdout);
+  retval |= tag_test(); fflush(stdout);
+  retval |= parser_tag_test(); fflush(stdout);
+  retval |= response_phrase_test(); fflush(stdout);
+  retval |= parser_test(); fflush(stdout);
+  retval |= sip_header_test(); fflush(stdout);
+  retval |= test_bad_packet(); fflush(stdout);
+  retval |= test_sip_list_header(); fflush(stdout);
+  retval |= test_prack(); fflush(stdout);
+  retval |= test_accept(); fflush(stdout);
+  retval |= test_content_disposition(); fflush(stdout);
+  retval |= test_features(); fflush(stdout);
+  retval |= test_retry_after(); fflush(stdout);
+  retval |= test_session_expires(); fflush(stdout);
+  retval |= test_min_se(); fflush(stdout);
+  retval |= test_refer(); fflush(stdout);
+  retval |= test_route(); fflush(stdout);
+  retval |= test_request_disposition(); fflush(stdout);
+  retval |= test_caller_prefs(); fflush(stdout);
+  retval |= test_callerpref_scoring(); fflush(stdout);
+  retval |= test_warning(); fflush(stdout);
+
+  retval |= test_sec_ext(); fflush(stdout);
+
+  retval |= test_utils(); fflush(stdout);
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,645 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@IFILE validator.c  
+ *
+ * SIP parser tester. This uses output
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Wed Mar 21 19:12:13 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sofia-sip/su_types.h>
+#include <sofia-sip/su_alloc_stat.h>
+
+#include <sofia-sip/su_time.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/url_tag.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/msg_buffer.h>
+
+char const *name = "validator";
+
+typedef struct {
+  unsigned o_verbose : 1;	/**< Be verbose */
+  unsigned o_very_verbose : 1;	/**< Be very verbose */
+  unsigned o_requests : 1;	/**< Only requests */
+  unsigned o_responses : 1;	/**< Only responses */
+  unsigned o_decode : 1;	/**< Only try to decode, 
+				   print error if unknown headers */
+  unsigned o_print : 1;		/**< Print whole message */
+  unsigned o_times : 1;		/**< Generate timing information */
+  unsigned o_memstats : 1;	/**< Generate memory statistics */
+  unsigned o_histogram : 1;	/**< Generate histograms */
+  unsigned o_sipstats : 1;	/**< Generate header statistics  */
+  unsigned o_vsipstats : 1;	/**< Generate verbatim header statistics */
+  unsigned : 0;
+  unsigned o_flags;		/**< Message flags */
+} options_t;
+
+typedef struct {
+  size_t N;
+  uint32_t bsize;
+  double buckets[32768];
+} histogram_t;
+
+static
+histogram_t *histogram_create(uint64_t max, uint32_t bsize)
+{
+  size_t N = (max + bsize - 1) / bsize;
+  histogram_t *h = calloc(1, offsetof(histogram_t, buckets[N + 1]));
+  if (!h) { perror("calloc"); exit(1); }
+  h->N = N, h->bsize = bsize;
+  return h;
+}
+
+static
+double *histogram_update(histogram_t *h, uint32_t n)
+{
+  if (h->bsize > 1)
+    n /= h->bsize;
+    
+  if (n < h->N)
+    return &h->buckets[n];
+  else
+    return &h->buckets[h->N];
+}
+
+static void
+histogram_div(histogram_t *h, histogram_t const *n)
+{
+  size_t i;
+  assert(h->N == n->N); assert(h->bsize == n->bsize);
+  
+  for (i = 0; i <= h->N; i++) {
+    if (n->buckets[i]) {
+      h->buckets[i] /= n->buckets[i];
+    }
+    else {
+      assert(h->buckets[i] == 0);
+    }
+  }
+}
+
+typedef struct {
+  uint64_t number;
+  uint64_t headers;
+  uint64_t payloads;
+  uint64_t pl_bytes;
+} sipstat_t;
+
+typedef struct {
+  sipstat_t req, resp;
+  histogram_t *hist_headers;
+} sipstats_t;
+
+typedef struct {
+  char const *name;
+  char const *sep;
+  uint64_t  messages;
+  uint64_t  bytes;
+  uint64_t  errors;
+  uint32_t  files;
+  double    time;
+  options_t options[1];
+
+  /* Statistics */
+  histogram_t *hist_msgsize;
+  histogram_t *hist_mallocs;
+  histogram_t *hist_memsize;
+  histogram_t *hist_nheaders;
+  sipstats_t   sipstats[1];
+  su_home_stat_t hs[1];
+
+  uint64_t     est_fail, est_succ, est_slack;
+} context_t;
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-vdp]\n", 
+	  name);
+  exit(2);
+}
+
+char *lastpart(char *path)
+{
+  char *p = strrchr(path, '/');
+
+  if (p) 
+    return p + 1;
+  else
+    return path;
+}
+
+msg_mclass_t *mclass = NULL;
+
+int validate_file(int fd, char const *name, context_t *ctx);
+int validate_dump(char *, off_t, context_t *ctx);
+int report(context_t const *ctx);
+static void memstats(msg_t *, uint32_t msize, context_t *ctx);
+static void sipstats(msg_t *, uint32_t msize, sipstats_t *ss, context_t *ctx);
+
+int main(int argc, char *argv[])
+{
+  context_t ctx[1] =  {{ 0 }};
+  options_t *o = ctx->options;
+
+  name = lastpart(argv[0]);  /* Set our name */
+
+  for (; argv[1]; argv++) {
+    if (argv[1][0] == 0)
+      usage();
+    else if (argv[1][0] != '-')
+      break;
+    else if (argv[1][1] == 0) {
+      argv++; break;
+    }
+    else if (strcmp(argv[1], "-v") == 0) 
+      o->o_very_verbose = o->o_verbose, o->o_verbose = 1;
+    else if (strcmp(argv[1], "-d") == 0) 
+      o->o_decode = 1;		/* Decode only */
+    else if (strcmp(argv[1], "-p") == 0) 
+      o->o_print = 1;
+    else if (strcmp(argv[1], "-q") == 0) 
+      o->o_requests = 1;
+    else if (strcmp(argv[1], "-Q") == 0) 
+      o->o_responses = 1;
+    else if (strcmp(argv[1], "-t") == 0) 
+      o->o_times = 1;
+    else if (strcmp(argv[1], "-m") == 0) 
+      o->o_memstats = 1;
+    else if (strcmp(argv[1], "-s") == 0) 
+      o->o_vsipstats = o->o_sipstats, o->o_sipstats = 1;
+    else if (strcmp(argv[1], "-h") == 0) 
+      o->o_histogram = 1;
+    else
+      usage();
+  }
+
+  if (o->o_requests && o->o_responses)
+    usage();
+
+  if (!mclass)
+    mclass = sip_default_mclass();
+
+  if (argv[1]) {
+    for (; argv[1]; argv++) {
+      int fd = open(argv[1], O_RDONLY, 000);
+      if (fd == -1)
+	perror(argv[1]), exit(1);
+      if (validate_file(fd, argv[1], ctx))
+	exit(1);
+      close(fd);
+    }
+  }
+  else
+    validate_file(0, "", ctx);
+
+  report(ctx);
+  
+  exit(0);
+}
+
+
+int validate_file(int fd, char const *name, context_t *ctx)
+{
+  void *p;
+  off_t size;
+  int retval;
+
+  ctx->name = name;
+  if (strlen(name))
+    ctx->sep = ": ";
+  else
+    ctx->sep = "";
+
+  ctx->files++;
+
+  size = lseek(fd, 0, SEEK_END);
+
+  if (size < 1)
+    return 0;
+  if (size > INT_MAX) {
+    fprintf(stderr, "%s%stoo large file to map\n", ctx->name, ctx->sep);
+    return -1;
+  }
+
+#ifndef _WIN32
+  p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0L);
+  if (p == NULL) {
+    perror("mmap");
+    return -1;
+  }
+
+  retval = validate_dump(p, size, ctx);
+  munmap(p, size);
+  return retval;
+
+#else
+  errno = EINVAL;
+  perror("mmap not implemented");
+  return -1;
+#endif    
+
+}
+
+static inline 
+void nul_terminate(char *b, off_t size)
+{
+  char *end;
+
+  /* NUL-terminate */
+  for (end = b + size - 1; end != b; end--)
+    if (*end == '\v')
+      break;
+
+  *end = '\0';
+}
+
+static inline
+int search_msg(char **bb, char const *protocol)
+{
+  int linelen, plen = strlen(protocol);
+  char *b = *bb;
+
+  for (;;) {
+    if (!b[0])
+      return 0;
+
+    if (strncmp(b, protocol, plen) == 0 && b[plen] == ' ')
+      return 1;			/* status */
+
+    linelen = strcspn(b, "\r\n");
+    
+    if (linelen > plen + 1 && 
+	b[linelen - plen - 1] == ' ' && 
+	strncmp(b + linelen - plen, protocol, plen) == 0)
+      return 1;			/* request */
+
+    b += linelen + strspn(b + linelen, "\r\n");
+    *bb = b;
+  }
+}
+
+int validate_dump(char *b, off_t size, context_t *ctx)
+{
+  size_t n = 0, N = 0;
+  struct message { 
+    char *b;
+    int   size;
+  } *msgs = NULL;
+  uint64_t time0, time1;
+  options_t *o = ctx->options;
+  int maxsize = 0;
+
+  nul_terminate(b, size);
+
+  /* Split dump file to messages */
+  while (search_msg(&b, SIP_VERSION_CURRENT)) {
+    int msize = strcspn(b, "\v");
+    int linelen = strcspn(b, "\r\n");
+
+    if (o->o_responses &&
+	memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) != 0)
+      ;
+    else if (o->o_requests && 
+	memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) == 0)
+      ;
+    else {
+      if (o->o_very_verbose)
+	printf("message "MOD_ZU": %.*s\n", n, linelen, b);
+
+      if (n == N) {
+	N *= 2; if (n == N) N = 16;
+      
+	msgs = realloc(msgs, sizeof(*msgs) * N);
+	if (msgs == NULL) {
+	  perror("realloc");
+	  exit(1);
+	}
+      }
+      msgs[n].b = b; msgs[n].size = msize;
+      n++;
+      
+      ctx->bytes += msize;
+      
+      if (msize > maxsize)
+	maxsize = msize;
+    }
+    
+    b += msize; if (*b) *b++ = '\0';
+  }
+
+  ctx->messages += N = n;
+
+  if (o->o_histogram) {
+    ctx->hist_msgsize = histogram_create(maxsize, 64);
+
+    if (o->o_memstats) {
+      ctx->hist_mallocs = histogram_create(maxsize, 64);
+      ctx->hist_memsize = histogram_create(maxsize, 64);
+    }
+
+    if (o->o_sipstats) {
+      ctx->sipstats->hist_headers = histogram_create(64, 1);
+      ctx->hist_nheaders = histogram_create(maxsize, 64);
+    }
+  }
+
+  time0 = su_nanocounter();
+
+  for (n = 0; n < N; n++) {
+    msg_t *msg = msg_create(mclass, o->o_flags);
+    int m;
+
+    if (msg == NULL) {
+      perror("msg_create"); exit(1);
+    }
+
+    if (o->o_memstats)
+      su_home_init_stats(msg_home(msg));
+    
+    msg_buf_set(msg, msgs[n].b, msgs[n].size + 1);
+    msg_buf_commit(msg, msgs[n].size, 1);
+    
+    su_home_preload(msg_home(msg), 1, msgs[n].size + 384);
+
+    m = msg_extract(msg);
+
+    if (m < 0) {
+      fprintf(stderr, "%s%sparsing error in message "MOD_ZU"\n", 
+	      ctx->name, ctx->sep, n);
+      ctx->errors++;
+    }
+    else {
+      if (ctx->hist_msgsize)
+	*histogram_update(ctx->hist_msgsize, msgs[n].size) += 1;
+
+      if (o->o_sipstats)
+	sipstats(msg, msgs[n].size, ctx->sipstats, ctx);
+
+      if (o->o_memstats)
+	memstats(msg, msgs[n].size, ctx);
+    }
+
+    msg_destroy(msg);
+  }
+  
+  time1 = su_nanocounter();
+
+  if (o->o_times) {
+    double dur = (time1 - time0) * 1E-9;
+
+    ctx->time += dur;
+
+    printf("%s%s"MOD_ZU" messages in %g seconds (%g msg/sec)\n"
+	   "      parse speed %.1f Mb/s (on Ethernet wire %.1f Mb/s)\n",
+	   ctx->name, ctx->sep, N, dur, (double)N / dur,
+	   (double)ctx->bytes * 8 / ctx->time / 1e6,
+	   ((double)ctx->bytes + N * (16 + 20 + 8)) * 8 / ctx->time / 1e6);
+  }
+
+  free(msgs);
+
+  return 0;
+}
+
+typedef unsigned longlong ull;
+
+static
+void report_memstats(char const *title, su_home_stat_t const hs[1])
+{
+  printf("%s%smemory statistics\n", title, strlen(title) ? " " : "");
+  if (hs->hs_allocs.hsa_number)
+    printf("\t"LLU" allocs, "LLU" bytes, "LLU" rounded,"
+	   " "LLU" max\n",
+	   (ull)hs->hs_allocs.hsa_number, (ull)hs->hs_allocs.hsa_bytes,
+	   (ull)hs->hs_allocs.hsa_rbytes, (ull)hs->hs_allocs.hsa_maxrbytes);
+  if (hs->hs_frees.hsf_number)
+    printf("\t"LLU" frees, "LLU" bytes, rounded to "LLU" bytes\n",
+	   (ull)hs->hs_frees.hsf_number, (ull)hs->hs_frees.hsf_bytes,
+	   (ull)hs->hs_frees.hsf_rbytes);
+  if (hs->hs_rehash || hs->hs_clones)
+    printf("\t"LLU" rehashes, "LLU" clones\n", 
+	   (ull)hs->hs_rehash, (ull)hs->hs_clones);
+}
+
+void memstats(msg_t *msg, uint32_t msize, context_t *ctx)
+{
+  options_t *o = ctx->options;
+  su_home_stat_t hs[1];
+
+  su_home_get_stats(msg_home(msg), 1, hs, sizeof(hs));
+  su_home_stat_add(ctx->hs, hs);
+
+  if (o->o_histogram) {
+    *histogram_update(ctx->hist_mallocs, msize) += hs->hs_allocs.hsa_number;
+    *histogram_update(ctx->hist_memsize, msize) += hs->hs_allocs.hsa_maxrbytes;
+  }
+
+  {
+    int estimate = msize + 384;
+    int slack = estimate - hs->hs_allocs.hsa_maxrbytes;
+
+    if (slack < 0)
+      ctx->est_fail++;
+    else {
+      ctx->est_succ++;
+      ctx->est_slack += slack;
+    }
+  }
+
+  if (o->o_very_verbose)
+    report_memstats(ctx->name, hs);
+}
+
+void report_sipstat(char const *what, sipstat_t const *sss)
+{
+  printf("%s: "LLU" with %.1f headers (total "LLU")\n",
+	 what, (ull)sss->number, (double)sss->headers / sss->number, 
+	 (ull)sss->headers);
+  if (sss->payloads)
+    printf("\t"LLU" with body of %.1f bytes (total "LLU")\n",
+	   (ull)sss->payloads, (double)sss->pl_bytes / sss->payloads, 
+	   (ull)sss->payloads);
+}
+
+void sipstats(msg_t *msg, uint32_t msize, sipstats_t *ss, context_t *ctx)
+{
+  options_t *o = ctx->options;
+  msg_pub_t *m = msg_object(msg);
+  sip_t const *sip = sip_object(msg);
+  msg_header_t *h;
+  sipstat_t *sss;
+  size_t n, bytes;
+
+  if (!sip)
+    return;
+
+  if (m->msg_request) {
+    sss = &ss->req;
+    h = m->msg_request;
+  }
+  else if (m->msg_status) {
+    sss = &ss->resp;
+    h = m->msg_status;
+  }
+  else {
+    return;
+  }
+
+  sss->number++;
+
+  /* Count headers */
+  for (n = 0, h = h->sh_succ; h && !sip_is_separator((sip_header_t *)h); h = h->sh_succ) 
+    n++;
+
+  sss->headers += n;
+
+  bytes = sip->sip_payload ? (size_t)sip->sip_payload->pl_len : 0;
+
+  if (bytes) {
+    sss->payloads++;
+    sss->pl_bytes += bytes;
+  }
+
+  if (ctx->hist_nheaders) {
+    *histogram_update(ctx->hist_nheaders, msize) += n;
+    *histogram_update(ss->hist_headers, n) += 1;
+  }
+
+  if (o->o_very_verbose)
+    printf("%s%s"MOD_ZU" headers, "MOD_ZU" bytes in payload\n",
+	   ctx->name, ctx->sep, n, bytes);
+}
+
+void report_histogram(char const *title, histogram_t const *h)
+{
+  size_t i, min_i, max_i;
+
+  for (i = 0; i < h->N && h->buckets[i] == 0.0; i++)
+    ;
+  min_i = i;
+
+  for (i = h->N - 1; i >= 0 && h->buckets[i] == 0.0; i--)
+    ;
+  max_i = i;
+  
+  if (min_i >= max_i)
+    return;
+
+  printf("%s histogram\n", title);
+  for (i = min_i; i < max_i; i++)
+    printf("\t"MOD_ZU".."MOD_ZU": %.1f\n", i * h->bsize, (i + 1) * h->bsize, h->buckets[i]);
+
+  if (h->buckets[h->N])
+    printf("\t"MOD_ZU"..: %.1f\n", h->N * h->bsize, h->buckets[h->N]);
+}
+
+int report(context_t const *ctx)
+{
+  const options_t *o = ctx->options;
+  uint64_t n = ctx->messages;
+
+  if (!n)
+    return -1;
+
+  printf("total "LLU" messages with "LLU" bytes (mean size "LLU")\n",
+	 (ull)n, (ull)ctx->bytes, (ull)(ctx->bytes / n));
+
+  if (ctx->hist_msgsize)
+    report_histogram("Message size", ctx->hist_msgsize);
+
+  if (o->o_times && ctx->files > 1) 
+    printf("total "LLU" messages in %g seconds (%g msg/sec)\n",
+	   (ull)n, ctx->time, (double)n / ctx->time);
+
+  if (o->o_sipstats) {
+    const sipstats_t *ss = ctx->sipstats;
+    report_sipstat("requests", &ss->req);
+    report_sipstat("responses", &ss->resp);
+
+    if (ctx->hist_nheaders) {
+      histogram_div(ctx->hist_nheaders, ctx->hist_msgsize);
+      report_histogram("Number of headers", ctx->hist_nheaders);
+    }
+  }
+
+  if (o->o_memstats) {
+    su_home_stat_t hs[1];
+
+    *hs = *ctx->hs;
+    report_memstats("total", hs);
+    
+    /* Calculate mean */
+    hs->hs_clones /= n; hs->hs_rehash /= n;
+    hs->hs_allocs.hsa_number /= n; hs->hs_allocs.hsa_bytes /= n;
+    hs->hs_allocs.hsa_rbytes /= n; hs->hs_allocs.hsa_maxrbytes /= n;
+    hs->hs_frees.hsf_number /= n; hs->hs_frees.hsf_bytes /= n;
+    hs->hs_frees.hsf_rbytes /= n;
+    hs->hs_blocks.hsb_number /= n; hs->hs_blocks.hsb_bytes /= n;
+    hs->hs_blocks.hsb_rbytes /= n;
+
+    report_memstats("mean", hs);
+
+    printf("\testimator fails %.1f%% times (mean slack %.0f bytes)\n", 
+	   100 * (double)ctx->est_fail / (ctx->est_fail + ctx->est_succ),
+	   (double)ctx->est_slack / ctx->est_succ);
+
+    if (ctx->hist_memsize) {
+      histogram_div(ctx->hist_memsize, ctx->hist_msgsize);
+      report_histogram("Allocated memory", ctx->hist_memsize);
+    }
+  }
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,325 @@
+2006-01-18  Martti Mela  <martti.mela at nokia.com>
+
+   * soa.c: removed #include <netat/sysglue.h> (with __APPLE_CC__)
+
+2006-01-17  Martti Mela  <martti.mela at nokia.com>
+
+   * if no EPROTO is found in OS X, redefine to EPROTOTYPE
+
+    M ./libsofia-sip-ua/soa/soa.c +8
+
+2005-10-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+   * Restore version numbers after our offer is rejected.
+
+    M ./libsofia-sip-ua/soa/soa_static.c +3
+
+2005-10-15  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated API of soa_get_local_sdp() and friends.
+  
+  Added parameter for returning SDP C structure to soa_get_capability_sdp(),
+  soa_get_remote_sdp(), soa_get_user_sdp(), and soa_get_local_sdp().
+
+    M ./libsofia-sip-ua/soa/soa.c -35 +58
+    M ./libsofia-sip-ua/soa/soa.h -4 +8
+    M ./libsofia-sip-ua/soa/test_soa.c -17 +18
+
+  * Updated SOA_VALID_ACTIONS().
+
+    M ./libsofia-sip-ua/soa/soa.c -1 +13
+
+  * Added soa_name.
+
+    M ./libsofia-sip-ua/soa/soa.c +1
+    M ./libsofia-sip-ua/soa/soa_session.h +1
+    M ./libsofia-sip-ua/soa/soa_static.c +1
+
+  * Removed annoying "last modified".
+
+    M ./libsofia-sip-ua/soa/soa.c -1
+    M ./libsofia-sip-ua/soa/soa.h -1
+    M ./libsofia-sip-ua/soa/soa_add.h -1
+    M ./libsofia-sip-ua/soa/soa_asynch.c -1
+    M ./libsofia-sip-ua/soa/soa_session.h -1
+    M ./libsofia-sip-ua/soa/soa_static.c -1
+    M ./libsofia-sip-ua/soa/soa_tag.c -1
+    M ./libsofia-sip-ua/soa/soa_tag.h -1
+    M ./libsofia-sip-ua/soa/test_soa.c -1
+
+  * Logging each API call except predicates.
+
+    M ./libsofia-sip-ua/soa/soa.c -5 +99
+
+  * Naming soa_sip_require() and soa_sip_supported() consistently.
+  The SIP headers are called Require and Supported.
+
+    M ./libsofia-sip-ua/soa/soa.c -6 +6
+    M ./libsofia-sip-ua/soa/soa.h -2 +2
+    M ./libsofia-sip-ua/soa/soa_asynch.c -2 +2
+    M ./libsofia-sip-ua/soa/soa_session.h -4 +4
+    M ./libsofia-sip-ua/soa/soa_static.c -2 +2
+    M ./libsofia-sip-ua/soa/test_soa.c -2 +2
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+	
+  * Updated SOA_VALID_ACTIONS().
+
+    M ./libsofia-sip-ua/soa/soa.c -1 +13
+  	      
+  * Added soa_name.
+
+    M ./libsofia-sip-ua/soa/soa.c +1
+    M ./libsofia-sip-ua/soa/soa_session.h +1
+    M ./libsofia-sip-ua/soa/soa_static.c +1
+
+  * Removed annoying "last modified".
+
+    M ./libsofia-sip-ua/soa/soa.c -1
+    M ./libsofia-sip-ua/soa/soa.h -1
+    M ./libsofia-sip-ua/soa/soa_add.h -1
+    M ./libsofia-sip-ua/soa/soa_asynch.c -1
+    M ./libsofia-sip-ua/soa/soa_session.h -1
+    M ./libsofia-sip-ua/soa/soa_static.c -1
+    M ./libsofia-sip-ua/soa/soa_tag.c -1
+    M ./libsofia-sip-ua/soa/soa_tag.h -1
+    M ./libsofia-sip-ua/soa/test_soa.c -1
+
+  * Logging each API call except predicates.
+
+    M ./libsofia-sip-ua/soa/soa.c -5 +99
+
+
+  * Naming soa_sip_require() and soa_sip_supported() consistently.
+  The SIP headers are called Require and Supported.
+
+    M ./libsofia-sip-ua/soa/soa.c -6 +6
+    M ./libsofia-sip-ua/soa/soa.h -2 +2
+    M ./libsofia-sip-ua/soa/soa_asynch.c -2 +2
+    M ./libsofia-sip-ua/soa/soa_session.h -4 +4
+    M ./libsofia-sip-ua/soa/soa_static.c -2 +2
+    M ./libsofia-sip-ua/soa/test_soa.c -2 +2
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added more logging.
+
+    M ./libsofia-sip-ua/soa/soa_static.c -1 +17
+
+  * Using SDP O/A result to determine media activity.
+
+    M ./libsofia-sip-ua/soa/soa.c -2 +2
+
+  * Sanitized soa_sdp_upgrade_is_needed().
+
+    M ./libsofia-sip-ua/soa/soa_static.c -27 +11
+
+  * Fixed active tests.
+
+    M ./libsofia-sip-ua/soa/test_soa.c -36 +36
+
+  * Fixed soa_get_paramlist() for complex cases.
+
+    M ./libsofia-sip-ua/soa/soa.c -1 +1
+
+2005-09-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added SOATAG_ACTIVE_* stuff.
+
+    M ./libsofia-sip-ua/soa/soa_tag.c +98
+    M ./libsofia-sip-ua/soa/soa_tag.h +31
+
+  * Removed mss-related tags.
+
+    M ./libsofia-sip-ua/soa/soa_tag.c -263
+    M ./libsofia-sip-ua/soa/soa_tag.h -89
+
+  * Using sdp tags to pass session descriptions.
+
+    M ./libsofia-sip-ua/soa/soa.c -1 +1
+    M ./libsofia-sip-ua/soa/soa_tag.c -6 +5
+    M ./libsofia-sip-ua/soa/soa_tag.h -17 +20
+    M ./libsofia-sip-ua/soa/test_soa.c +20
+
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Returning remote sdp via soa_get_paramlist().
+
+    M soa.c +5
+
+  * soa_get_paramlist() just returns NULL if given NULL session.
+
+    M soa.c -6 +4
+
+  * Returning local and user SDP via tags.
+
+    M soa.c -5 +17
+
+  * Keeping track of soa instance name.
+
+    M soa.c -2 +13
+    M soa_session.h +1
+
+  * Always upgrading a freshly created session.
+
+    M soa_static.c -1 +1
+
+  * Updated documentation. Glare.
+
+    M soa.docs -10 +79
+
+  * Added (selective!) hold, media upgrade.
+
+    M soa_session.h +2
+    M soa_static.c -52 +174
+    M test_soa.c -4 +65
+
+  * Added more bits to activity (so we can indicate SOA_ACTIVE_REJECTED).
+
+    M soa_session.h -4 +4
+
+  * Updated the mode update: keep track of rejected status, too.
+
+    M soa.c -20 +28
+
+  * Bump ss_user_version if parameters change.
+
+    M soa.c -2 +9
+
+  * Removed soa_static_actions.
+
+    M soa_static.c -24
+
+  * Updated API to handle separately user-supplied SDP and negotiated SDP.
+
+    M soa.c -146 +180
+    M soa.h -11 +18
+    M soa_session.h -36 +30
+    M soa_static.c -73 +475
+    M test_soa.c -22 +40
+
+  * Not using soa_static_actions.
+
+    M test_soa.c -1 +1
+
+  * Updated soa_static_get_paramlist() prototype.
+
+    M soa_static.c -3 +16
+
+  * Removed last traces of "default".
+
+    M soa.c -51 +1
+    M soa_add.h -2
+
+  * Added tag parameters to soa_get_paramlist() prototype.
+
+    M soa.c -9 +23
+    M soa.h -1 +2
+    M soa_session.h -2 +4
+    M test_soa.c -1 +1
+
+  * Not testing asynch.
+
+    M test_soa.c +6
+
+  * Not testing removed parameters.
+
+    M test_soa.c -13 +20
+
+  * Not compiling soa_asynch.c
+
+    M Makefile.am -1 +1
+
+  * Include "soa_tag.h" in "soa_session.h", too.
+
+    M soa_session.h +3
+
+  * Moved tags to soa_tag.h
+
+    M soa.h -200
+
+  * Removed mss-related parameters. Added hold.
+
+    M soa.c -117 +12
+    M soa_session.h -13 +1
+
+  * Renamed "local" as "user".
+
+    M soa_asynch.c -7 +7
+
+  * Added soatag_user_sdp().
+
+    M soa_tag.c -10 +42
+
+  * Added soa_tag.h.
+
+    A soa_tag.h
+
+2005-09-26  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Updated call flows.
+
+    M soa.docs -57 +67
+
+  * Added some code for soa_static_generate_offer().
+
+    M soa_static.c -18 +60
+
+  * Fixed soa_static_set_local_sdp().
+
+    M soa_static.c -1 +1
+
+  * Added setter functions for sdp in soa_static.
+
+    M soa_static.c -6 +44
+
+  * Using explicit soa_set_local_sdp() with "static" soa instance.
+
+    M test_soa.c -3 +9
+
+  * Added session sdp: soa_get_session_sdp(), soatag_session_sdp.
+
+    M soa.h +16
+
+  * Comments.
+
+    M soa.c -2 +2
+
+  * Not expanding "local" sdp with o=, s=, t= and c=.
+
+    M soa.c -45
+
+  * Added local/remote/session sdp to soa_get_params().
+
+    M soa.c +11
+
+  * Added handling of soatag_local_sdp tag.
+
+    M soa.c -2 +25
+
+  * Added session description ss_desc
+
+    M soa_session.h +2
+
+  * Added soatag_local_sdp and soatag_remote_sdp.
+
+    M soa.h +12
+    M soa_tag.c +32
+
+2005-09-22  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* soa.c (soa_get_remote_version): Added.
+
+	* soa.c (soa_get_local_version): Added.
+
+	* soa_session.h: Added ssd_version field to
+	soa_description struct.
+
+2005-09-19  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* soa_static.c: Fix generating offers.
+
+2005-08-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Updated API. Added tester.
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+PROJECT_NAME         = "soa"
+OUTPUT_DIRECTORY     = ../docs/html/soa
+
+INPUT 		     = soa.docs sofia-sip/soa.h sofia-sip/soa_add.h soa.c
+INPUT		    += sofia-sip/soa_tag.h soa_tag.c
+
+ at INCLUDE             = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/docs.doxytags=../docs
+TAGFILES            += ../docs/su.doxytags=../su
+TAGFILES            += ../docs/ipt.doxytags=../ipt
+TAGFILES            += ../docs/bnf.doxytags=../bnf
+TAGFILES            += ../docs/url.doxytags=../url
+TAGFILES            += ../docs/msg.doxytags=../msg
+TAGFILES            += ../docs/sip.doxytags=../sip
+TAGFILES            += ../docs/sresolv.doxytags=../sresolv
+TAGFILES            += ../docs/tport.doxytags=../tport
+TAGFILES            += ../docs/nta.doxytags=../nta
+TAGFILES            += ../docs/sdp.doxytags=../sdp
+TAGFILES            += ../docs/nua.doxytags=../nua
+
+GENERATE_TAGFILE     = ../docs/soa.doxytags
+
+ALIASES 	    += soa="@ref index \"soa\""
+# When GENERATE_TAGFILE=YES, we should use \ref main
+#ALIASES 	    += soa="@ref main \"soa\""
+
+ at INCLUDE = ../sip/sip.doxyaliases

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+#
+# Makefile.am for soa module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../sdp -I../sdp \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsoa.la
+
+check_PROGRAMS =	test_soa
+
+TESTS = 		test_soa
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		soa_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/soa.h sofia-sip/soa_session.h \
+			sofia-sip/soa_add.h sofia-sip/soa_tag.h
+
+libsoa_la_SOURCES = 	soa.c soa_static.c \
+			soa_tag.c soa_tag_ref.c 
+
+COVERAGE_INPUT = 	$(libsoa_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libsoa.la \
+			../sip/libsip.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../sdp/libsdp.la \
+			../ipt/libipt.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_soa_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile soa.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS =		LIST=soa_tag_list
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,713 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for soa module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libsoa_la_SOURCES) test_soa.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_soa$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/soa
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsoa_la_LIBADD =
+am_libsoa_la_OBJECTS = soa.lo soa_static.lo soa_tag.lo soa_tag_ref.lo
+libsoa_la_OBJECTS = $(am_libsoa_la_OBJECTS)
+test_soa_SOURCES = test_soa.c
+test_soa_OBJECTS = test_soa.$(OBJEXT)
+test_soa_LDADD = $(LDADD)
+test_soa_DEPENDENCIES = libsoa.la ../sip/libsip.la ../msg/libmsg.la \
+	../url/liburl.la ../sdp/libsdp.la ../ipt/libipt.la \
+	../bnf/libbnf.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsoa_la_SOURCES) test_soa.c
+DIST_SOURCES = $(libsoa_la_SOURCES) test_soa.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../sdp -I../sdp \
+			-I$(srcdir)/../sip -I../sip \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsoa.la
+TESTS = test_soa
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = soa_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/soa.h sofia-sip/soa_session.h \
+			sofia-sip/soa_add.h sofia-sip/soa_tag.h
+
+libsoa_la_SOURCES = soa.c soa_static.c \
+			soa_tag.c soa_tag_ref.c 
+
+COVERAGE_INPUT = $(libsoa_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsoa.la \
+			../sip/libsip.la \
+			../msg/libmsg.la \
+			../url/liburl.la \
+			../sdp/libsdp.la \
+			../ipt/libipt.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_soa_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile soa.docs $(BUILT_SOURCES)
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+TAG_DLL_FLAGS = LIST=soa_tag_list
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/soa/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/soa/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsoa.la: $(libsoa_la_OBJECTS) $(libsoa_la_DEPENDENCIES) 
+	$(LINK)  $(libsoa_la_LDFLAGS) $(libsoa_la_OBJECTS) $(libsoa_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_soa$(EXEEXT): $(test_soa_OBJECTS) $(test_soa_DEPENDENCIES) 
+	@rm -f test_soa$(EXEEXT)
+	$(LINK) $(test_soa_LDFLAGS) $(test_soa_OBJECTS) $(test_soa_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_static.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_soa.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2318 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa.c
+ * @brief Sofia SDP Offer/Answer Engine interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug  3 20:27:15 EEST 2005
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_wait.h>
+
+#include "sofia-sip/soa.h"
+#include "sofia-sip/sdp.h"
+#include "sofia-sip/soa_session.h"
+#include "sofia-sip/soa_add.h"
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_errno.h>
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+typedef unsigned longlong ull;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "soa";
+#endif
+
+/* ======================================================================== */
+
+/* Internal prototypes */
+void soa_set_activity(soa_session_t *ss,
+		      sdp_media_t const *,
+		      int remote);
+
+static inline int soa_media_is_ready(soa_session_t const *ss);
+
+enum soa_sdp_kind { 
+  soa_capability_sdp_kind,
+  soa_user_sdp_kind,
+  soa_remote_sdp_kind
+};
+
+static int soa_set_sdp(soa_session_t *ss, 
+		       enum soa_sdp_kind what,
+		       sdp_session_t const *sdp0,
+		       char const *sdp_str, issize_t str_len);
+
+/* ======================================================================== */
+
+#define SOA_VALID_ACTIONS(a)					\
+  ((a)->sizeof_soa_session_actions >= (int)sizeof (*actions) && \
+   (a)->sizeof_soa_session >= (int)sizeof(soa_session_t) &&     \
+   (a)->soa_name != NULL &&					\
+   (a)->soa_init != NULL &&					\
+   (a)->soa_deinit != NULL &&					\
+   (a)->soa_set_params != NULL &&				\
+   (a)->soa_get_params != NULL &&				\
+   (a)->soa_get_paramlist != NULL &&				\
+   (a)->soa_media_features != NULL &&				\
+   (a)->soa_sip_require != NULL &&				\
+   (a)->soa_sip_supported != NULL &&				\
+   (a)->soa_remote_sip_features != NULL &&			\
+   (a)->soa_set_capability_sdp != NULL &&			\
+   (a)->soa_set_remote_sdp != NULL &&				\
+   (a)->soa_set_user_sdp != NULL &&				\
+   (a)->soa_generate_offer != NULL &&				\
+   (a)->soa_generate_answer != NULL &&				\
+   (a)->soa_process_answer != NULL &&				\
+   (a)->soa_process_reject != NULL &&				\
+   (a)->soa_activate_session != NULL &&				\
+   (a)->soa_deactivate_session != NULL &&			\
+   (a)->soa_terminate_session != NULL)
+
+/* ======================================================================== */
+
+/**@var SOA_DEBUG
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The SOA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ *
+ * @sa <su_debug.h>, su_log_global, SOFIA_DEBUG
+ */
+extern char const SOA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b soa module.
+ *
+ * The soa_log is the log object used by @b soa module. The level of
+ * #soa_log is set using #SOA_DEBUG environment variable.
+ */
+su_log_t soa_log[] = { SU_LOG_INIT("soa", "SOA_DEBUG", SU_DEBUG) };
+
+/* Add " around string */
+#define NICE(s) s ? "\"" : "", s ? s : "(nil)", s ? "\"" : ""
+
+/* ======================================================================== */
+
+/* API Functions */
+
+struct soa_namenode
+{
+  struct soa_namenode const *next;
+  char const *basename;
+  struct soa_session_actions const *actions;
+};
+
+#define SOA_NAMELISTLEN (16)
+
+static struct soa_namenode const soa_default_node =
+  {
+    NULL, "default", &soa_default_actions
+  };
+
+static struct soa_namenode const *soa_namelist = &soa_default_node;
+
+/** Add a named soa backend */
+int soa_add(char const *name,
+	    struct soa_session_actions const *actions)
+{
+  struct soa_namenode const *n;
+  struct soa_namenode *e;
+
+  SU_DEBUG_9(("soa_add(%s%s%s, %p) called\n", NICE(name), actions));
+
+  if (name == NULL || actions == NULL)
+    return su_seterrno(EFAULT);
+
+  if (!SOA_VALID_ACTIONS(actions))
+    return su_seterrno(EINVAL);
+
+  for (n = soa_namelist; n; n = n->next) {
+    if (strcasecmp(name, n->basename) == 0)
+      return 0;
+  }
+
+  e = malloc(sizeof *e); if (!e) return -1;
+
+  e->next = soa_namelist;
+  e->basename = name;
+  e->actions = actions;
+
+  soa_namelist = e;
+
+  return 0;
+}
+
+/** Search for a named backend */
+struct soa_session_actions const *soa_find(char const *name)
+{
+  SU_DEBUG_9(("soa_find(%s%s%s) called\n", NICE(name)));
+
+  if (name) {
+    struct soa_namenode const *n;
+    size_t baselen = strcspn(name, ":/");
+
+    for (n = soa_namelist; n; n = n->next) {
+      if (strncasecmp(name, n->basename, baselen) == 0)
+	break;
+    }
+
+    if (n == NULL)
+      return (void)su_seterrno(ENOENT), NULL;
+
+    return n->actions;
+  }
+
+  return NULL;
+}
+
+/* ======================================================================== */
+
+/** Create a soa session. */
+soa_session_t *soa_create(char const *name,
+			  su_root_t *root,
+			  soa_magic_t *magic)
+{
+  struct soa_session_actions const *actions = &soa_default_actions;
+
+  soa_session_t *ss;
+  size_t namelen;
+
+  SU_DEBUG_9(("soa_create(\"%s\", %p, %p) called\n",
+	      name ? name : "default", root, magic));
+
+  if (name && name[0]) {
+    struct soa_namenode const *n;
+    size_t baselen = strcspn(name, ":/");
+
+    for (n = soa_namelist; n; n = n->next) {
+      if (strncasecmp(name, n->basename, baselen) == 0)
+	break;
+    }
+    if (n == NULL)
+      return (void)su_seterrno(ENOENT), NULL;
+
+    actions = n->actions; assert(actions);
+  }
+  else
+    name = "default";
+
+  assert(SOA_VALID_ACTIONS(actions));
+
+  if (root == NULL)
+    return (void)su_seterrno(EFAULT), NULL;
+
+  namelen = strlen(name) + 1;
+  
+  ss = su_home_new(actions->sizeof_soa_session + namelen);
+  if (ss) {
+    ss->ss_root = root;
+    ss->ss_magic = magic;
+    ss->ss_actions = actions;
+    ss->ss_name = strcpy((char *)ss + actions->sizeof_soa_session, name);
+
+    if (ss->ss_actions->soa_init(name, ss, NULL) < 0)
+      ss->ss_actions->soa_deinit(ss), ss = NULL;
+  }
+
+  return ss;
+}
+
+/** Create a copy of a @soa session object. */
+soa_session_t *soa_clone(soa_session_t *parent_ss,
+			 su_root_t *root,
+			 soa_magic_t *magic)
+{
+  soa_session_t *ss;
+  size_t namelen;
+
+  SU_DEBUG_9(("soa_clone(%s::%p, %p, %p) called\n",
+	      parent_ss ? parent_ss->ss_actions->soa_name : "",
+	      parent_ss, root, magic));
+
+  if (parent_ss == NULL || root == NULL)
+    return (void)su_seterrno(EFAULT), NULL;
+
+  namelen = strlen(parent_ss->ss_name) + 1;
+
+  ss = su_home_new(parent_ss->ss_actions->sizeof_soa_session + namelen);
+  if (ss) {
+    ss->ss_root = root;
+    ss->ss_magic = magic;
+    ss->ss_actions = parent_ss->ss_actions;
+    ss->ss_name = strcpy((char *)ss + ss->ss_actions->sizeof_soa_session,
+			 parent_ss->ss_name);
+
+    if (ss->ss_actions->soa_init(NULL, ss, parent_ss) < 0)
+      ss->ss_actions->soa_deinit(ss), ss = NULL;
+  }
+
+  return ss;
+}
+
+/** Increase reference count */
+soa_session_t *soa_session_ref(soa_session_t *ss)
+{
+  SU_DEBUG_9(("soa_session_ref(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+  return su_home_ref(ss->ss_home);
+}
+
+/** Decrease reference count */
+void soa_session_unref(soa_session_t *ss)
+{
+  SU_DEBUG_9(("soa_session_unref(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+  su_home_unref(ss->ss_home);
+}
+
+/* Initialize session */
+int soa_base_init(char const *name,
+		     soa_session_t *ss,
+		     soa_session_t *parent)
+{
+  if (parent) {
+#define DUP(d, dup, s) if ((s) && !((d) = dup(ss->ss_home, (s)))) return -1
+    su_home_t *home = ss->ss_home;
+
+    if (soa_description_dup(home, ss->ss_caps, parent->ss_caps) < 0)
+      return -1;
+    if (soa_description_dup(home, ss->ss_user, parent->ss_user) < 0)
+      return -1;
+    if (soa_description_dup(home, ss->ss_local, parent->ss_local) < 0)
+      return -1;
+    if (soa_description_dup(home, ss->ss_remote, parent->ss_remote) < 0)
+      return -1;
+
+    DUP(ss->ss_address, su_strdup, parent->ss_address);
+    ss->ss_af = parent->ss_af;
+    DUP(ss->ss_hold, su_strdup, parent->ss_hold);
+
+    DUP(ss->ss_cname, su_strdup, parent->ss_cname);
+
+    ss->ss_srtp_enable = parent->ss_srtp_enable;
+    ss->ss_srtp_confidentiality = parent->ss_srtp_confidentiality;
+    ss->ss_srtp_integrity = parent->ss_srtp_integrity;
+  }
+
+  return 0;
+}
+
+/** Destroy a session. */
+void soa_destroy(soa_session_t *ss)
+{
+  SU_DEBUG_9(("soa_destroy(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss) {
+    ss->ss_active = 0;
+    ss->ss_terminated++;
+    ss->ss_actions->soa_deinit(ss);
+    su_home_unref(ss->ss_home);
+  }
+}
+
+void soa_base_deinit(soa_session_t *ss)
+{
+  (void)ss;
+}
+
+/** Set parameters.
+ *
+ * @param ss soa session object
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return Number of parameters set, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_AUDIO_AUX() (currently for "default" only),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int n;
+
+  SU_DEBUG_9(("soa_set_params(%s::%p, ...) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  ta_start(ta, tag, value);
+
+  n = ss->ss_actions->soa_set_params(ss, ta_args(ta));
+
+  ta_end(ta);
+
+  return n;
+}
+
+/**Base method for setting parameters.
+ *
+ * @param ss   soa session object
+ * @param tags  tag item list
+ *
+ * @return Number of parameters set, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_base_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+  int n, change_session = 0;
+
+  sdp_session_t const *caps_sdp, *user_sdp;
+  char const *caps_sdp_str, *user_sdp_str;
+
+  int af;
+  char const *media_address, *hold;
+  int rtp_select, rtp_sort;
+  int rtp_mismatch;
+  int srtp_enable, srtp_confidentiality, srtp_integrity;
+
+  af = ss->ss_af;
+
+  hold = ss->ss_hold;
+  media_address = ss->ss_address;
+
+  rtp_select = (int)ss->ss_rtp_select;
+  rtp_sort = (int)ss->ss_rtp_sort;
+  rtp_mismatch = ss->ss_rtp_mismatch;
+
+  srtp_enable = ss->ss_srtp_enable;
+  srtp_confidentiality = ss->ss_srtp_confidentiality;
+  srtp_integrity = ss->ss_srtp_integrity;
+
+  caps_sdp = user_sdp = NONE;
+  caps_sdp_str = user_sdp_str = NONE;
+
+  n = tl_gets(tags,
+
+	      SOATAG_CAPS_SDP_REF(caps_sdp),
+	      SOATAG_CAPS_SDP_STR_REF(caps_sdp_str),
+
+	      SOATAG_USER_SDP_REF(user_sdp),
+	      SOATAG_USER_SDP_STR_REF(user_sdp_str),
+
+	      SOATAG_AF_REF(af),
+	      SOATAG_ADDRESS_REF(media_address),
+	      SOATAG_HOLD_REF(hold),
+
+	      SOATAG_RTP_SELECT_REF(rtp_select),
+	      SOATAG_RTP_SORT_REF(rtp_sort),
+	      SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+	      SOATAG_SRTP_ENABLE_REF(srtp_enable),
+	      SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+	      SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+
+	      TAG_END());
+
+  if (n <= 0)
+    return n;
+
+  if (caps_sdp != NONE || caps_sdp_str != NONE) {
+    if (caps_sdp == NONE) caps_sdp = NULL;
+    if (caps_sdp_str == NONE) caps_sdp_str = NULL;
+
+    if (caps_sdp || caps_sdp_str) {
+      if (soa_set_capability_sdp(ss, caps_sdp, caps_sdp_str, -1) < 0) {
+	return -1;
+      }
+    }
+    else {
+      soa_description_free(ss, ss->ss_caps);
+    }
+  }
+
+  if (user_sdp != NONE || user_sdp_str != NONE) {
+    if (user_sdp == NONE) user_sdp = NULL;
+    if (user_sdp_str == NONE) user_sdp_str = NULL;
+
+    if (user_sdp || user_sdp_str) {
+      if (soa_set_user_sdp(ss, user_sdp, user_sdp_str, -1) < 0) {
+	return -1;
+      }
+      if (ss->ss_caps->ssd_str == NULL)
+	soa_set_capability_sdp(ss, user_sdp, user_sdp_str, -1);
+    }
+    else {
+      soa_description_free(ss, ss->ss_user);
+    }
+  }
+
+  if (af < SOA_AF_ANY || af > SOA_AF_IP6_IP4) 
+    af = ss->ss_af;
+
+  if (rtp_select < SOA_RTP_SELECT_SINGLE || rtp_select > SOA_RTP_SELECT_ALL)
+    rtp_select = (int)ss->ss_rtp_select;
+  if (rtp_sort < SOA_RTP_SORT_DEFAULT || rtp_sort > SOA_RTP_SORT_REMOTE)
+    rtp_sort = (int)ss->ss_rtp_sort;
+  rtp_mismatch = rtp_mismatch != 0;
+
+  srtp_enable = srtp_enable != 0;
+  srtp_confidentiality = srtp_confidentiality != 0;
+  srtp_integrity = srtp_integrity != 0;
+
+  change_session 
+    =  af != (int)ss->ss_af
+    || rtp_select != (int)ss->ss_rtp_select
+    || rtp_sort != (int)ss->ss_rtp_sort
+    || rtp_mismatch != (int)ss->ss_rtp_mismatch
+    || srtp_enable != (int)ss->ss_srtp_enable
+    || srtp_confidentiality != (int)ss->ss_srtp_confidentiality
+    || srtp_integrity != (int)ss->ss_srtp_integrity
+    ;
+
+  ss->ss_af = af;
+
+  ss->ss_rtp_select = rtp_select;
+  ss->ss_rtp_sort = rtp_sort;
+  ss->ss_rtp_mismatch = rtp_mismatch;
+
+  ss->ss_srtp_enable = srtp_enable;
+  ss->ss_srtp_confidentiality = srtp_confidentiality;
+  ss->ss_srtp_integrity = srtp_integrity;
+
+  if (str0casecmp(media_address, ss->ss_address)) {
+    su_free(ss->ss_home, (void *)ss->ss_address);
+    ss->ss_address = su_strdup(ss->ss_home, media_address);
+    change_session = 1;
+  }
+
+  if (hold == (char const *)1)
+    hold = "*";
+
+  if (str0casecmp(hold, ss->ss_hold)) {
+    su_free(ss->ss_home, (void *)ss->ss_hold);
+    ss->ss_hold = su_strdup(ss->ss_home, hold);
+    change_session = 1;
+  }
+
+  if (change_session)
+    ss->ss_user_version++;
+
+  return n;
+}
+
+/** Get tagged parameters.
+ *
+ * @param ss soa session object
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return Number of parameters get, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(),
+ * SOATAG_LOCAL_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_AUDIO_AUX() (currently for "default" only),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_get_params(soa_session_t const *ss,
+		   tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int n;
+
+  SU_DEBUG_9(("soa_get_params(%s::%p, ...) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  ta_start(ta, tag, value);
+
+  n = ss->ss_actions->soa_get_params(ss, ta_args(ta));
+
+  ta_end(ta);
+
+  return n;
+}
+
+/**Base method for getting tagged parameters.
+ *
+ * @param ss soa session object
+ * @param tags   tag item list
+ *
+ * @return Number of parameters get, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(),
+ * SOATAG_LOCAL_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_base_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+  int n;
+
+  n = tl_tgets(tags,
+	       SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp),
+	       SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str),
+
+	       SOATAG_USER_SDP(ss->ss_user->ssd_sdp),
+	       SOATAG_USER_SDP_STR(ss->ss_user->ssd_str),
+
+	       SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp),
+	       SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str),
+
+	       SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp),
+	       SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed),
+
+	       SOATAG_AF(ss->ss_af),
+	       SOATAG_ADDRESS(ss->ss_address),
+	       SOATAG_HOLD(ss->ss_hold),
+
+	       SOATAG_RTP_SELECT((int)ss->ss_rtp_select),
+	       SOATAG_RTP_SORT((int)ss->ss_rtp_sort),
+	       SOATAG_RTP_MISMATCH(ss->ss_rtp_mismatch),
+
+	       SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
+	       SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
+	       SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
+
+	       TAG_END());
+
+  return n;
+}
+
+/** Return a list of parameters. */
+tagi_t *soa_get_paramlist(soa_session_t const *ss,
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  tagi_t *params = NULL;
+
+  SU_DEBUG_9(("soa_get_paramlist(%s::%p, ...) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss) {
+    ta_start(ta, tag, value);
+    params = ss->ss_actions->soa_get_paramlist(ss, ta_tags(ta));
+    ta_end(ta);
+  }
+
+  return params;
+}
+
+
+/** Base bethod for getting list of parameters. */
+tagi_t *soa_base_get_paramlist(soa_session_t const *ss, 
+			       tag_type_t tag, tag_value_t value, 
+			       ...)
+{
+  ta_list ta;
+  tagi_t *params;
+
+  if (ss == NULL)
+    return NULL;
+  
+  ta_start(ta, tag, value);
+
+  params = tl_llist(
+		   TAG_IF(ss->ss_caps->ssd_sdp,
+			  SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp)),
+		   TAG_IF(ss->ss_caps->ssd_str,
+			  SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str)),
+
+		   TAG_IF(ss->ss_user->ssd_sdp,
+			  SOATAG_USER_SDP(ss->ss_user->ssd_sdp)),
+		   TAG_IF(ss->ss_user->ssd_str,
+			  SOATAG_USER_SDP_STR(ss->ss_user->ssd_str)),
+
+		   TAG_IF(ss->ss_local->ssd_sdp,
+			  SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp)),
+		   TAG_IF(ss->ss_user->ssd_str,
+			  SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str)),
+
+		   TAG_IF(ss->ss_remote->ssd_sdp,
+			  SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp)),
+		   TAG_IF(ss->ss_remote->ssd_str,
+			  SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed)),
+
+		   SOATAG_AF(ss->ss_af),
+		   TAG_IF(ss->ss_address, 
+			  SOATAG_ADDRESS(ss->ss_address)),
+
+		   SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
+		   SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
+		   SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
+
+		   ta_tags(ta));
+
+  ta_end(ta);
+
+  return params;
+}
+
+#include <sofia-sip/sip_status.h>
+
+/** Convert @soa error to a SIP response code and phrase. */ 
+int soa_error_as_sip_response(soa_session_t *ss,
+			      char const **return_phrase)
+{
+  SU_DEBUG_9(("soa_error_as_sip_response(%s::%p, ...) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss == NULL || ss->ss_status < 400 || ss->ss_status >= 700) {
+    if (return_phrase)
+      *return_phrase = sip_500_Internal_server_error;
+    return 500;
+  }
+
+  if (return_phrase)
+    *return_phrase = ss->ss_phrase;
+  return ss->ss_status;
+}
+
+/** Convert @soa error to a SIP @Reason header. */ 
+char const *soa_error_as_sip_reason(soa_session_t *ss)
+{
+  char const *phrase;
+  int status;
+  char *reason;
+
+  SU_DEBUG_9(("soa_error_as_sip_reason(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss == NULL)
+    return "SIP;cause=500;text=\"Internal Server Error\"";
+
+  status = soa_error_as_sip_response(ss, &phrase);
+
+  reason = su_sprintf(ss->ss_home, "SIP;cause=%u;text=\"%s\"", status, phrase);
+  
+  if (ss->ss_reason)
+    su_free(ss->ss_home, reason);
+
+  return ss->ss_reason = reason;
+}
+
+
+/** Return SIP @Warning code and text. */
+int soa_get_warning(soa_session_t *ss, char const **return_text)
+{
+  if (!ss)
+    return 0;
+
+  if (!ss->ss_wcode)
+    return 0;
+
+  if (return_text)
+    *return_text = ss->ss_warning;
+
+  return ss->ss_wcode;
+}
+
+/** Return SDP description of capabilities.
+ *
+ * @param ss  pointer to @soa session
+ * @param return_sdp      return value for capability SDP structure 
+ * @param return_sdp_str  return value for capability SDP string
+ * @param return_len  return value for length of capability SDP string
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa @RFC3261 section 11, soa_set_capability_sdp(), 
+ * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(), 
+ * nua_options(), #nua_i_options
+ */
+int soa_get_capability_sdp(soa_session_t const *ss,
+			   sdp_session_t const **return_sdp,
+			   char const **return_sdp_str,
+			   isize_t *return_len)
+{
+  sdp_session_t const *sdp;
+  char const *sdp_str;
+
+  SU_DEBUG_9(("soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss,
+	      return_sdp, return_sdp_str, return_len));
+
+  if (ss == NULL)
+    return (void)su_seterrno(EFAULT), -1;
+
+  sdp = ss->ss_caps->ssd_sdp;
+  sdp_str = ss->ss_caps->ssd_str;
+
+  if (sdp == NULL)
+    return 0;
+  if (return_sdp)
+    *return_sdp = sdp;
+  if (return_sdp_str)
+    *return_sdp_str = sdp_str;
+  if (return_len)
+    *return_len = strlen(sdp_str);
+
+  return 1;
+}
+
+
+/** Set capability SDP. 
+ *
+ * Capability SDP is used instead of user SDP when generating OPTIONS
+ * responses describing media capabilities. 
+ *
+ * @param ss  pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and user version
+ *           returned by soa_get_user_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa @RFC3261 section 11, soa_get_capability_sdp(),
+ * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(), 
+ * nua_options(), #nua_i_options
+ */
+int soa_set_capability_sdp(soa_session_t *ss, 
+			   sdp_session_t const *sdp,
+			   char const *str, issize_t len)
+{
+  SU_DEBUG_9(("soa_set_capability_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+  return soa_set_sdp(ss, soa_capability_sdp_kind, sdp, str, len);
+}
+
+/** Set capabilities */
+int 
+soa_base_set_capability_sdp(soa_session_t *ss, 
+			    sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+  sdp_origin_t o[1] = {{ sizeof(o) }};
+  sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
+  char c_address[64];
+  sdp_time_t t[1] = {{ sizeof(t) }};
+  sdp_media_t *m;
+
+  if (sdp->sdp_origin)
+    *o = *sdp->sdp_origin;
+  else
+    o->o_address = c0;
+
+  sdp->sdp_origin = o;
+
+  if (soa_init_sdp_origin(ss, o, c_address) < 0)
+    return -1;
+
+  if (!sdp->sdp_subject)
+    sdp->sdp_subject = "-";
+
+  sdp->sdp_time = t;
+
+  /* Set port to zero - or should we check that port is already zero? */
+  for (m = sdp->sdp_media; m; m = m->m_next)
+    m->m_port = 0;
+
+  c = sdp->sdp_origin->o_address;
+
+  if (sdp->sdp_connection == NULL) {
+    for (m = sdp->sdp_media; m; m = m->m_next)
+      if (m->m_connections == NULL)
+	break;
+    if (m)
+      sdp->sdp_connection = c;
+  }
+
+  return soa_description_set(ss, ss->ss_caps, sdp, str0, len0);
+}
+
+/**Return user SDP description.
+ *
+ * <i>User SDP</i> is used as basis for SDP Offer/Answer negotiation. It can
+ * be very minimal template, consisting just m= line containing media name,
+ * transport protocol port number and list of supported codecs.
+ *
+ * The SDP used as an offer or answer (generated by soa_generate_answer() or
+ * soa_generate_offer()) is known as <i>local SDP</i> and it is available
+ * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
+ * tags.
+ *
+ * @param ss  pointer to @soa session
+ * @param return_sdp SDP  session structure return value
+ * @param return_sdp_str  return value for pointer to string 
+ *                        containing the user SDP session description
+ * @param return_len  return value for user SDP session description string
+ *                    length 
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len 
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_get_local_sdp(), soa_set_user_sdp(), soa_get_user_version(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_get_remote_sdp(),
+ * soa_get_capability_sdp()
+ */
+int soa_get_user_sdp(soa_session_t const *ss,
+		     sdp_session_t const **return_sdp,
+		     char const **return_sdp_str,
+		     isize_t *return_len)
+{
+  sdp_session_t const *sdp;
+  char const *sdp_str;
+
+  SU_DEBUG_9(("soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss,
+	      return_sdp, return_sdp_str, return_len));
+
+  if (ss == NULL)
+    return (void)su_seterrno(EFAULT), -1;
+
+  sdp = ss->ss_user->ssd_sdp;
+  sdp_str = ss->ss_user->ssd_str;
+
+  if (sdp == NULL)
+    return 0;
+  if (return_sdp)
+    *return_sdp = sdp;
+  if (return_sdp_str)
+    *return_sdp_str = sdp_str;
+  if (return_len)
+    *return_len = strlen(sdp_str);
+
+  return 1;
+}
+
+/**Returns the version number of user session description. The version
+ * numbering starts from zero and it is incremented each time
+ * soa_set_user_sdp() or soa_set_params() modifies user SDP.
+ *
+ * @param ss  pointer to @soa session
+
+ * @return Sequence number of user SDP.
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), soa_set_params(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR()
+ */
+int soa_get_user_version(soa_session_t const *ss)
+{
+  assert(ss != NULL);
+  return ss ? (int)ss->ss_user_version : -1;
+} 
+
+/**Store user SDP to soa session. 
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, consisting just m= line containing media name, transport
+ * protocol port number and list of supported codecs.
+ *
+ * The SDP used as an offer or answer (generated by soa_generate_answer() or
+ * soa_generate_offer()) is known as <i>local SDP</i> and it is available
+ * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
+ * tags.
+ *
+ * @param ss  pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
+ * string @a str is calculated using strlen().
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and user version
+ *           returned by soa_get_user_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa soa_get_user_sdp(), soa_get_user_version(), soa_set_params(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_generate_offer(),
+ * soa_generate_answer(), soa_get_local_sdp(), soa_set_capability_sdp(),
+ * soa_set_remote_sdp()
+ */
+int soa_set_user_sdp(soa_session_t *ss, 
+		     sdp_session_t const *sdp,
+		     char const *str, issize_t len)
+{
+  SU_DEBUG_9(("soa_set_user_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+  return soa_set_sdp(ss, soa_user_sdp_kind, sdp, str, len);
+}
+
+/** Set user SDP (base version). */
+int soa_base_set_user_sdp(soa_session_t *ss, 
+			  sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+  ++ss->ss_user_version;
+  return soa_description_set(ss, ss->ss_user, sdp, str0, len0);
+}
+
+/**Return remote SDP description of the session.
+ *
+ * <i>Remote SDP</i> is used, together with <i>User SDP</i> as basis for SDP
+ * Offer/Answer negotiation.
+ *
+ * @param ss  pointer to @soa session
+ * @param return_sdp SDP  session structure return value
+ * @param return_sdp_str  return value for pointer to string 
+ *                        containing the user SDP session description
+ * @param return_len  return value for user SDP session descrioption string
+ *                    length 
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len 
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_version(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
+ * soa_get_local_sdp(), soa_get_user_sdp(), soa_get_capability_sdp().
+ */
+int soa_get_remote_sdp(soa_session_t const *ss,
+		       sdp_session_t const **return_sdp,
+		       char const **return_sdp_str,
+		       isize_t *return_len)
+{
+  sdp_session_t const *sdp;
+  char const *sdp_str;
+
+  SU_DEBUG_9(("soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss,
+	      return_sdp, return_sdp_str, return_len));
+
+  if (ss == NULL)
+    return (void)su_seterrno(EFAULT), -1;
+
+  sdp = ss->ss_remote->ssd_sdp;
+  sdp_str = ss->ss_remote->ssd_str;
+
+  if (sdp == NULL)
+    return 0;
+  if (return_sdp)
+    *return_sdp = sdp;
+  if (return_sdp_str)
+    *return_sdp_str = sdp_str;
+  if (return_len)
+    *return_len = strlen(sdp_str);
+
+  return 1;
+}
+
+/**Returns the version number of remote session description. The version
+ * numbering starts from zero and it is incremented each time
+ * soa_set_remote_sdp() or soa_set_params() modifies remote SDP.
+ *
+ * @param ss  pointer to @soa session
+
+ * @return Sequence number of remote SDP.
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), soa_set_params(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR()
+ */
+int soa_get_remote_version(soa_session_t const *ss)
+{
+  assert(ss != NULL);
+  return ss->ss_remote_version;
+} 
+
+/** Set remote SDP (offer or answer).
+ *
+ * <i>Remote SDP</i> is an SDP offer or answer received from the remote end. 
+ * It is used together with <i>User SDP</i> as basis for SDP Offer/Answer
+ * negotiation in soa_generate_answer() or soa_process_answer(). Remote SDP
+ * can be set using soa_set_params() and SOATAG_REMOTE_SDP() or
+ * SOATAG_REMOTE_SDP_STR() tags, too.
+ *
+ * If the SDP Offer/Answer negotiation step cannot be completed and the
+ * received remote offer or answer should be ignored, call
+ * soa_clear_remote_sdp().
+ *
+ * @param ss  pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
+ * string @a str is calculated using strlen().
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and remote version
+ *           returned by soa_get_remote_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa soa_has_received_sdp(), soa_get_remote_sdp(),
+ * soa_get_remote_version(), soa_set_params(), SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
+ * soa_clear_remote_sdp(), soa_init_offer_answer(), soa_get_local_sdp(),
+ * soa_set_user_sdp(), soa_set_capability_sdp().
+ */
+int soa_set_remote_sdp(soa_session_t *ss, 
+		       sdp_session_t const *sdp,
+		       char const *str, issize_t len)
+{
+  SU_DEBUG_9(("soa_set_remote_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+  return soa_set_sdp(ss, soa_remote_sdp_kind, sdp, str, len);
+}
+
+/** Base method for setting the remote SDP (offer or answer). */
+int soa_base_set_remote_sdp(soa_session_t *ss,
+			    int new_version,
+			    sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+  /* This is cleared in soa_generate_answer() or soa_process_answer(). */
+  ss->ss_unprocessed_remote = 1;
+
+  if (!new_version)
+    return 0;
+    
+  soa_set_activity(ss, sdp->sdp_media, 1);
+
+  ss->ss_remote_version++;
+  
+  return soa_description_set(ss, ss->ss_remote, sdp, str0, len0);
+}
+
+/** Clear remote SDP.
+ *
+ * Remote SDP (offer or answer) should be cleared after a it has been stored
+ * in the SDP session object using soa_set_remote_sdp() or soa_set_params(),
+ * but the SDP Offer/Answer negotiation step (soa_generate_answer() or
+ * soa_process_answer()) cannot be completed.
+ *
+ * @param ss  pointer to @soa session
+ *
+ * @retval 0  when successful
+ * @retval -1 upon an error
+ *
+ * @sa soa_init_offer_answer(), soa_set_remote_sdp(),
+ * soa_has_received_sdp(), soa_set_params(), SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
+ * soa_process_reject().
+ */
+int soa_clear_remote_sdp(soa_session_t *ss)
+{
+  SU_DEBUG_9(("soa_clear_remote_sdp(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (!ss)
+    return (void)su_seterrno(EFAULT), -1;
+
+  ss->ss_unprocessed_remote = 0;
+
+  return 0;
+}
+
+/** Check if remote SDP has been saved but it has not been processed.
+ *
+ * @sa soa_init_offer_answer(), soa_set_remote_sdp(), soa_generate_answer(),
+ * soa_process_answer(), soa_clear_remote_sdp().
+ */
+int soa_has_received_sdp(soa_session_t const *ss)
+{
+  return ss && ss->ss_unprocessed_remote;
+}
+
+
+/**Get local SDP.
+ *
+ * The <i>local SDP</i> is used as an offer or answer and it is generated by
+ * soa_generate_offer() or soa_generate_answer(), respectively. It can be
+ * retrieved using soa_get_params() or soa_get_paramlist() with
+ * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR() tags.
+ *
+ * @param ss  pointer to @soa session
+ * @param return_sdp SDP  session structure return value
+ * @param return_sdp_str  return value for pointer to string 
+ *                        containing the user SDP session description
+ * @param return_len  return value for user SDP session descrioption string
+ *                    length 
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len 
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_generate_offer(), soa_generate_answer(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
+ * soa_get_user_sdp(), soa_get_remote_sdp(), soa_get_capability_sdp().
+ */
+int soa_get_local_sdp(soa_session_t const *ss,
+		      sdp_session_t const **return_sdp,
+		      char const **return_sdp_str,
+		      isize_t *return_len)
+{
+  sdp_session_t const *sdp;
+  char const *sdp_str;
+
+  SU_DEBUG_9(("soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss,
+	      return_sdp, return_sdp_str, return_len));
+
+  if (ss == NULL)
+    return (void)su_seterrno(EFAULT), -1;
+
+  sdp = ss->ss_local->ssd_sdp;
+  sdp_str = ss->ss_local->ssd_str;
+
+  if (sdp == NULL)
+    return 0;
+  if (return_sdp)
+    *return_sdp = sdp;
+  if (return_sdp_str)
+    *return_sdp_str = sdp_str;
+  if (return_len)
+    *return_len = strlen(sdp_str);
+
+  return 1;
+}
+
+/**Initialize the offer/answer state machine.
+ *
+ * @param ss  pointer to @soa session
+ *
+ * @retval 0  when successful
+ * @retval -1 upon an error
+ */
+int soa_init_offer_answer(soa_session_t *ss)
+{
+  int complete;
+
+  SU_DEBUG_9(("soa_init_offer_answer(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (!ss)
+    return 0;
+
+  complete = ss->ss_complete;
+
+  ss->ss_complete = 0;
+  ss->ss_offer_sent = 0;
+  ss->ss_offer_recv = 0;
+  ss->ss_answer_sent = 0;
+  ss->ss_answer_recv = 0;
+
+  ss->ss_unprocessed_remote = 0;
+
+  return complete;
+}
+
+/** Return list of media fetures. */
+char **soa_media_features(soa_session_t *ss, int live, su_home_t *home)
+{
+  SU_DEBUG_9(("soa_media_features(%s::%p, %u, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, live, home));
+
+  if (ss)
+    return ss->ss_actions->soa_media_features(ss, live, home);
+  else
+    return (void)su_seterrno(EFAULT), NULL;
+}
+
+char **soa_base_media_features(soa_session_t *ss, int live, su_home_t *home)
+{
+  return su_zalloc(home, 8 * sizeof (char **));
+}
+
+char const * const * soa_sip_require(soa_session_t const *ss)
+{
+  SU_DEBUG_9(("soa_sip_require(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss)
+    return ss->ss_actions->soa_sip_require(ss);
+  else
+    return (void)su_seterrno(EFAULT), NULL;
+}
+
+char const * const * soa_base_sip_require(soa_session_t const *ss)
+{
+  static char const *null = NULL;
+  return &null;
+}
+
+char const * const * soa_sip_supported(soa_session_t const *ss)
+{
+  SU_DEBUG_9(("soa_sip_supported(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  if (ss)
+    return ss->ss_actions->soa_sip_supported(ss);
+  else
+    return (void)su_seterrno(EFAULT), NULL;
+}
+
+char const * const * soa_base_sip_supported(soa_session_t const *ss)
+{
+  static char const *null = NULL;
+  return &null;
+}
+
+int soa_remote_sip_features(soa_session_t *ss,
+			    char const * const * supported,
+			    char const * const * require)
+{
+  SU_DEBUG_9(("soa_remote_sip_features(%s::%p, %p, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, supported, require));
+
+  if (ss)
+    return ss->ss_actions->soa_remote_sip_features(ss, supported, require);
+  else
+    return (void)su_seterrno(EFAULT), -1;
+}
+
+int soa_base_remote_sip_features(soa_session_t *ss,
+				    char const * const * supported,
+				    char const * const * require)
+{
+  return 0;
+}
+
+
+/**Generate offer.
+ *
+ * When generating the offer the user SDP is augmented with the required SDP
+ * lines (v=, o=, t=, c=, a=rtpmap, etc.).
+ *
+ * The resulting SDP is also known as <i>local SDP</i>. It is available with
+ * soa_get_local_sdp() or with soa_get_params() and soa_get_paramlist() tags
+ * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR().
+ *
+ * The user SDP has been stored to the soa session with soa_set_user_sdp()
+ * or with soa_set_params() tags SOATAG_USER_SDP() or SOATAG_USER_SDP_STR(). 
+ * There are various other parameters directing the generation of offer, set
+ * by soa_set_params().
+ *
+ * @param ss pointer to session object
+ * @param always always send offer (even if offer/answer has been completed)
+ * @param completed pointer to callback function which is invoked when
+ *                  operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_generate_offer(soa_session_t *ss,
+		       int always,
+		       soa_callback_f *completed)
+{
+  SU_DEBUG_9(("soa_generate_offer(%s::%p, %u, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, always, completed));
+
+  /** @ERROR EFAULT Bad address. */
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  /** @ERROR An operation is already in progress */
+  if (ss->ss_in_progress)
+    return su_seterrno(EALREADY), -1;
+
+  /** @ERROR EPROTO We have received offer, now we should send answer */
+  if (ss->ss_offer_recv && !ss->ss_answer_sent)
+    return su_seterrno(EPROTO), -1;
+
+  /** @ERROR EPROTO We have received SDP, but it has not been processed */
+  if (soa_has_received_sdp(ss))
+    return su_seterrno(EPROTO), -1;
+
+  /** @ERROR EPROTO We have sent an offer, but have received no answer */
+  if (ss->ss_offer_sent && !ss->ss_answer_recv)
+    return su_seterrno(EPROTO), -1;
+
+  /** @ERROR EPROTO We have received offer. */
+  if (ss->ss_unprocessed_remote)
+    return su_seterrno(EPROTO), -1;
+
+  /* We should avoid actual operation unless always is true */
+  (void)always;  /* We always regenerate offer */
+
+  return ss->ss_actions->soa_generate_offer(ss, completed);
+  /** @sa soa_init_offer_answer(), soa_set_user_sdp(), soa_get_local_sdp(),
+   * soa_set_remote_sdp(), soa_process_answer(), soa_process_reject(),
+   * soa_generate_answer(), soa_set_params(), soa_get_params(),
+   * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+   * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+   */
+}
+
+int soa_base_generate_offer(soa_session_t *ss,
+			    soa_callback_f *completed)
+{
+  sdp_session_t const *sdp = ss->ss_local->ssd_sdp;
+
+  (void)completed;
+
+  if (!sdp)
+    return -1;
+
+  soa_set_activity(ss, sdp->sdp_media, 0);
+
+  ss->ss_offer_sent = 1;
+  ss->ss_answer_recv = 0;
+
+  return 0;
+}
+
+/**Process offer, generate answer.
+ *
+ * When generating the offer the soa session combines remote offer with
+ * <i>user SDP</i>. There are various other parameters directing the
+ * generation of answer, set by soa_set_params().
+ *
+ * Before calling soa_generate_answer() the remote SDP offer should have
+ * been stored into the soa session @a ss with soa_set_remote_sdp() or with
+ * the soa_set_params() tags SOATAG_REMOTE_SDP() or SOATAG_REMOTE_SDP_STR().
+ *
+ * Also, the <i>user SDP</i> should have been stored into @a ss with
+ * soa_set_user_sdp() or with the soa_set_params() tags SOATAG_USER_SDP() or
+ * SOATAG_USER_SDP_STR().
+ *
+ * The resulting SDP is also known as <i>local SDP</i>. It is available with
+ * soa_get_local_sdp() or with the soa_get_params() or soa_get_paramlist()
+ * tags SOATAG_LOCAL_SDP() and SOATAG_LOCAL_SDP_STR().
+ *
+ * @param ss  pointer to session object
+ * @param completed  pointer to callback function which is invoked when
+ *                   operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_generate_answer(soa_session_t *ss,
+			soa_callback_f *completed)
+{
+  SU_DEBUG_9(("soa_generate_answer(%s::%p, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  /** @ERROR An operation is already in progress. */
+  if (ss->ss_in_progress)
+    return su_seterrno(EALREADY), -1;
+
+  /** @ERROR EPROTO We have sent an offer, but have received no answer. */
+  if (ss->ss_offer_sent && !ss->ss_answer_recv)
+    return su_seterrno(EPROTO), -1;
+
+  /** @ERROR EPROTO We have not received offer. */
+  if (!ss->ss_unprocessed_remote)
+    return su_seterrno(EPROTO), -1;
+
+  return ss->ss_actions->soa_generate_answer(ss, completed);
+
+  /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+   * soa_get_local_sdp(), soa_process_reject(), soa_generate_offer(),
+   * soa_set_params(), soa_get_params(), soa_get_paramlist(),
+   * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), SOATAG_REMOTE_SDP(),
+   * SOATAG_REMOTE_SDP_STR().
+   */
+}
+
+/** Base method for processing offer, generating answer. */
+int soa_base_generate_answer(soa_session_t *ss,
+			     soa_callback_f *completed)
+{
+  sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+  sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
+  sdp_session_t *rsession;
+
+  (void)completed;
+
+  if (!l_sdp || !r_sdp)
+    return -1;
+  rsession = sdp_session_dup(ss->ss_home, r_sdp);
+  if (!rsession)
+    return -1;
+
+  if (ss->ss_rsession)
+    su_free(ss->ss_home, ss->ss_rsession);
+  ss->ss_rsession = rsession;
+
+  soa_set_activity(ss, l_sdp->sdp_media, 0);
+  soa_set_activity(ss, r_sdp->sdp_media, 1);
+
+  ss->ss_offer_recv = 1;
+  ss->ss_answer_sent = 1;
+  ss->ss_complete = 1;
+  ss->ss_unprocessed_remote = 0;
+
+  return 0;
+}
+
+/** Complete offer-answer after receiving answer. 
+ *
+ * The SDP offer/answer negotiation is completed after receiving answer from
+ * remote end. The answer is combined with the offer, and the application
+ * should activate the media and codecs according to the negotiation result,
+ * available as <i>local SDP</i>.
+ *
+ * @param ss  pointer to session object
+ * @param completed  pointer to callback function which is invoked when
+ *                   operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_process_answer(soa_session_t *ss,
+		       soa_callback_f *completed)
+{
+  SU_DEBUG_9(("soa_process_answer(%s::%p, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  /** @ERROR An operation is already in progress. */
+  if (ss->ss_in_progress)
+    return su_seterrno(EALREADY), -1;
+
+  /** @ERROR EPROTO We have not sent an offer 
+      or already have received answer. */
+  if (!ss->ss_offer_sent || ss->ss_answer_recv)
+    return su_seterrno(EPROTO), -1;
+
+  /** @ERROR EPROTO We have not received answer. */
+  if (!ss->ss_unprocessed_remote)
+    return su_seterrno(EPROTO), -1;
+
+  /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+   * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
+   * soa_process_reject(), soa_set_params(), soa_get_params(),
+   * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+   * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+   */
+
+  return ss->ss_actions->soa_process_answer(ss, completed);
+}
+
+/** Base method for completing offer-answer after receiving answer.
+ */
+int soa_base_process_answer(soa_session_t *ss,
+			    soa_callback_f *completed)
+{
+  sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+  sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
+  sdp_session_t *rsession;
+
+  (void)completed;
+
+  if (!l_sdp || !r_sdp)
+    return -1;
+  rsession = sdp_session_dup(ss->ss_home, r_sdp);
+  if (!rsession)
+    return -1;
+
+  if (ss->ss_rsession)
+    su_free(ss->ss_home, ss->ss_rsession);
+  ss->ss_rsession = rsession;
+
+  soa_set_activity(ss, l_sdp->sdp_media, 0);
+  soa_set_activity(ss, r_sdp->sdp_media, 1);
+
+  ss->ss_answer_recv = 1;
+  ss->ss_complete = 1;
+  ss->ss_unprocessed_remote = 0;
+
+  return 0;
+}
+
+/** Process rejection of offer. 
+ *
+ * If the SDP offer was rejected (e.g., an offer in re-INVITE asked remote
+ * end to add video to the session but the request was rejected), the
+ * session should be restored to the state it was before last offer-answer
+ * negotation round with soa_process_reject().
+ *
+ * @param ss  pointer to session object
+ * @param completed  pointer to callback function which is invoked when
+ *                   operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_process_reject(soa_session_t *ss,
+		       soa_callback_f *completed)
+{
+  SU_DEBUG_9(("soa_process_reject(%s::%p, %p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  /** @ERROR An operation is already in progress. */
+  if (ss->ss_in_progress)
+    return su_seterrno(EALREADY), -1;
+
+  /** @ERROR EPROTO We have not sent an offer 
+      or already have received answer. */
+  if (!ss->ss_offer_sent || ss->ss_answer_recv)
+    return su_seterrno(EPROTO), -1;
+
+  /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+   * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
+   * soa_process_answer(), soa_set_params(), soa_get_params(),
+   * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+   * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+   */
+
+  return ss->ss_actions->soa_process_reject(ss, completed);
+}
+
+/** Base method for processing rejection of offer.
+ */
+int soa_base_process_reject(soa_session_t *ss,
+			    soa_callback_f *completed)
+{
+  sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+
+  (void)completed;
+
+  if (!l_sdp)
+    return -1;
+
+  soa_set_activity(ss, l_sdp->sdp_media, 0);
+
+  ss->ss_offer_sent = 0;
+
+  return 0;
+}
+
+/** Activate session. 
+ *
+ * Mark soa session as active.
+ *
+ * @retval 0 when operation was successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_activate(soa_session_t *ss, char const *option)
+{
+  SU_DEBUG_9(("soa_activate(%s::%p, %s%s%s) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, NICE(option)));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return -1;
+
+  ss->ss_active = 1;
+
+  return ss->ss_actions->soa_activate_session(ss, option);
+}
+
+int soa_base_activate(soa_session_t *ss, char const *option)
+{
+  (void)ss;
+  (void)option;
+  return 0;
+}
+
+/** Deactivate session.
+ *
+ * Mark soa session as inactive.
+ *
+ * @retval 0 when operation was successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_deactivate(soa_session_t *ss, char const *option)
+{
+  SU_DEBUG_9(("soa_deactivate(%s::%p, %s%s%s) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss, NICE(option)));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return -1;
+
+  ss->ss_active = 0;
+
+  return ss->ss_actions->soa_deactivate_session(ss, option);
+}
+
+int soa_base_deactivate(soa_session_t *ss, char const *option)
+{
+  (void)ss;
+  (void)option;
+  return 0;
+}
+
+/** Terminate session. */
+void soa_terminate(soa_session_t *ss, char const *option)
+{
+  SU_DEBUG_9(("soa_terminate(%s::%p) called\n",
+	      ss ? ss->ss_actions->soa_name : "", ss));
+
+  /** @ERROR EFAULT Bad address as @a ss. */
+  if (ss == NULL)
+    return;
+
+  ss->ss_active = 0;
+  ss->ss_terminated++;
+
+  ss->ss_actions->soa_terminate_session(ss, option);
+}
+
+void soa_base_terminate(soa_session_t *ss, char const *option)
+{
+  (void)option;
+
+  soa_init_offer_answer(ss);
+  ss->ss_oa_rounds = 0;
+
+  soa_description_free(ss, ss->ss_remote);
+  soa_set_activity(ss, NULL, 0);
+  soa_set_activity(ss, NULL, 1);
+}
+
+/** Return true if the SDP Offer/Answer negotation is complete.
+ *
+ * The soa_init_offer_answer() clears the completion flag.
+ */
+int soa_is_complete(soa_session_t const *ss)
+{
+  return ss && ss->ss_complete;
+}
+
+/** Return true if audio has been activated. */
+int soa_is_audio_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_local_activity->ma_audio : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if video has been activated. */
+int soa_is_video_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_local_activity->ma_video : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if image sharing has been activated. */
+int soa_is_image_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_local_activity->ma_image : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if messaging session has been activated. */
+int soa_is_chat_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_local_activity->ma_chat : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if remote audio is active (not on hold). */
+int soa_is_remote_audio_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_remote_activity->ma_audio : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if remote video is active (not on hold). */
+int soa_is_remote_video_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_remote_activity->ma_video : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if image sharing is active (not on hold). */
+int soa_is_remote_image_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_remote_activity->ma_image : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if chat session is active (not on hold). */
+int soa_is_remote_chat_active(soa_session_t const *ss)
+{
+  return ss ? ss->ss_remote_activity->ma_chat : SOA_ACTIVE_DISABLED;
+}
+
+/* ======================================================================== */
+/* Methods used by soa instances */
+
+int soa_set_status(soa_session_t *ss, int status, char const *phrase)
+{
+  if (ss) {
+    ss->ss_status = status, ss->ss_phrase = phrase;
+    ss->ss_wcode = 0, ss->ss_warning = NULL;
+  }
+  return -1;
+}
+
+int soa_set_warning(soa_session_t *ss, int code, char const *text)
+{
+  if (ss)
+    ss->ss_wcode = code, ss->ss_warning = text;
+  return -1;
+}
+
+static inline
+int soa_media_is_ready(soa_session_t const *ss)
+{
+  XXX;
+  return 0;
+  /* return ss && ss->ss_session != NULL; */
+}
+
+void soa_set_activity(soa_session_t *ss,
+		      sdp_media_t const *m,
+		      int remote)
+{
+  struct soa_media_activity *ma;
+  sdp_connection_t const *c;
+  int mode;
+  int ma_audio = SOA_ACTIVE_DISABLED;
+  int ma_video = SOA_ACTIVE_DISABLED;
+  int ma_chat = SOA_ACTIVE_DISABLED;
+  int ma_image = SOA_ACTIVE_DISABLED;
+  int *p;
+
+  remote = !!remote;
+
+  ma = remote ? ss->ss_remote_activity : ss->ss_local_activity;
+
+  for (; m; m = m->m_next) {
+    if (m->m_type == sdp_media_audio)
+      p = &ma_audio;
+    else if (m->m_type == sdp_media_video)
+      p = &ma_video;
+    else if (m->m_type == sdp_media_image)
+      p = &ma_image;
+    else if (strcasecmp(m->m_type_name, "message") == 0)
+      p = &ma_chat;
+    else
+      continue;
+
+    if (m->m_rejected) {
+      if (*p < 0)
+	*p = SOA_ACTIVE_REJECTED;
+      continue;
+    }
+
+    mode = m->m_mode;
+
+    c = sdp_media_connections((sdp_media_t *)m);
+
+    if (remote != (c && c->c_mcast))
+      mode = ((mode << 1) & 2) | ((mode >> 1) & 1);
+
+    if (*p < 0)
+      *p = mode;
+    else
+      *p |= mode;
+  }
+
+  ma->ma_audio = ma_audio;
+  ma->ma_video = ma_video;
+  ma->ma_image = ma_image;
+  ma->ma_chat = ma_chat;
+}
+
+/* ----------------------------------------------------------------------*/
+/* Handle SDP */
+
+
+/**
+ * Parses and stores session description
+ * 
+ * @param ss instance pointer
+ * @param what caps, local or remote
+ * @param sdp0 new sdp (parsed)
+ * @param sdp_str new sdp (unparsed)
+ * @param str_len length on unparsed data
+ **/
+static
+int soa_set_sdp(soa_session_t *ss, 
+		enum soa_sdp_kind what,
+		sdp_session_t const *sdp0,
+		char const *sdp_str, issize_t str_len)
+{
+  struct soa_description *ssd;
+  int flags, new_version, retval;
+  sdp_parser_t *parser = NULL;
+  sdp_session_t sdp[1];
+
+  switch (what) {
+  case soa_capability_sdp_kind:
+    ssd = ss->ss_caps;
+    flags = sdp_f_config;
+    break;
+  case soa_user_sdp_kind:
+    ssd = ss->ss_user;
+    flags = sdp_f_config;
+    break;
+  case soa_remote_sdp_kind:
+    ssd = ss->ss_remote;
+    flags = sdp_f_mode_0000;
+    break;
+  default:
+    return -1;
+  }
+
+  if (sdp_str && str_len == -1)
+    str_len = strlen(sdp_str);
+
+  if (sdp0)
+    new_version = sdp_session_cmp(sdp0, ssd->ssd_sdp) != 0;
+  else if (sdp_str)
+    new_version = !ssd->ssd_unparsed ||
+      str0ncmp(sdp_str, ssd->ssd_unparsed, str_len) != 0 ||
+      ssd->ssd_unparsed[str_len] != '\0';
+  else
+    return (void)su_seterrno(EINVAL), -1;
+
+  if (!new_version) {
+    if (what == soa_remote_sdp_kind) {
+      *sdp = *ssd->ssd_sdp;
+      /* XXX - should check changes by soa_set_remote_sdp */
+      return ss->ss_actions->soa_set_remote_sdp(ss, new_version, 
+						sdp, sdp_str, str_len);
+    }
+    return 0;
+  } 
+
+  if (sdp0) {
+    /* note: case 1 - src in parsed form */
+    *sdp = *sdp0;
+  } 
+  else /* if (sdp_str) */ {
+    /* note: case 2 - src in unparsed form */
+    parser = sdp_parse(ss->ss_home, sdp_str, str_len, flags | sdp_f_anynet);
+
+    if (sdp_parsing_error(parser)) {
+      sdp_parser_free(parser);
+      return soa_set_status(ss, 400, "Bad Session Description");
+    }
+
+    *sdp = *sdp_session(parser);
+  }
+ 
+  switch (what) {
+  case soa_capability_sdp_kind:
+    retval = ss->ss_actions->soa_set_capability_sdp(ss, sdp, sdp_str, str_len);
+    break;
+  case soa_user_sdp_kind:
+    retval =  ss->ss_actions->soa_set_user_sdp(ss, sdp, sdp_str, str_len);
+    break;
+  case soa_remote_sdp_kind:
+    retval = ss->ss_actions->soa_set_remote_sdp(ss, 1, sdp, sdp_str, str_len);
+    break;
+  default:
+    retval = soa_set_status(ss, 500, "Internal Error");
+    break;
+  }
+
+  if (parser)
+    sdp_parser_free(parser);
+
+  return retval;
+}
+
+
+/** Set session descriptions. */
+int soa_description_set(soa_session_t *ss,
+			struct soa_description *ssd,
+			sdp_session_t *sdp,
+			char const *sdp_str,
+			isize_t str_len)
+{
+  int retval = -1;
+
+  sdp_printer_t *printer = NULL;
+  sdp_session_t *sdp_new;
+  char *sdp_str_new;
+  char *sdp_str0_new;
+
+  void *tbf1, *tbf2, *tbf3, *tbf4;
+
+  /* Store description in three forms: unparsed, parsed and reprinted */
+
+  sdp_new = sdp_session_dup(ss->ss_home, sdp);
+  printer = sdp_print(ss->ss_home, sdp, NULL, 0, 0);
+  sdp_str_new = (char *)sdp_message(printer);
+  if (sdp_str)
+    sdp_str0_new = su_strndup(ss->ss_home, sdp_str, str_len);
+  else
+    sdp_str0_new = sdp_str_new;
+  
+  if (sdp_new && printer && sdp_str_new && sdp_str0_new) {
+    tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
+    tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
+
+    ssd->ssd_sdp = sdp_new;
+    ssd->ssd_printer = printer;
+    ssd->ssd_str = sdp_str_new;
+    ssd->ssd_unparsed = sdp_str0_new;      
+
+    retval = 1;
+  }
+  else {
+    tbf1 = sdp_new, tbf2 = printer, tbf3 = sdp_str_new, tbf4 = sdp_str0_new;
+  }
+  
+  su_free(ss->ss_home, tbf1);
+  sdp_printer_free(tbf2);
+  if (tbf3 != tbf4)
+    su_free(ss->ss_home, tbf4);
+
+  return retval;
+}
+
+
+/** Duplicate a session descriptions. */
+int soa_description_dup(su_home_t *home, 
+			struct soa_description *ssd,
+			struct soa_description const *ssd0)
+{
+  if (ssd0->ssd_sdp) {
+    ssd->ssd_sdp = sdp_session_dup(home, ssd0->ssd_sdp);
+    ssd->ssd_printer = sdp_print(home, ssd->ssd_sdp, NULL, 0, 0);
+    ssd->ssd_str = (char *)sdp_message(ssd->ssd_printer);
+    if (ssd0->ssd_str != ssd0->ssd_unparsed)
+      ssd->ssd_unparsed = su_strdup(home, ssd0->ssd_unparsed);
+    else
+      ssd->ssd_unparsed = ssd->ssd_str;
+  }
+
+  return 0;
+}
+
+/** Free session descriptions. */
+void soa_description_free(soa_session_t *ss, 
+			  struct soa_description *ssd)
+{
+  void *tbf1, *tbf2, *tbf3, *tbf4;
+
+  tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
+  tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
+
+  memset(ssd, 0, sizeof *ssd);
+
+  su_free(ss->ss_home, tbf1);
+  sdp_printer_free(tbf2);
+  if (tbf3 != tbf4)
+    su_free(ss->ss_home, tbf4);
+}
+
+
+/** Initialize SDP o= line */
+int
+soa_init_sdp_origin(soa_session_t *ss, sdp_origin_t *o, char buffer[64])
+{
+  sdp_connection_t *c;
+
+  if (ss == NULL || o == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  assert(o->o_address);
+
+  if (!o->o_username)
+    o->o_username = "-";
+
+  if (o->o_id == 0)
+    su_randmem(&o->o_id, sizeof o->o_id);
+  o->o_id &= ((unsigned longlong)1 << 63) - 1;
+
+  if (o->o_version == 0)
+    su_randmem(&o->o_version, sizeof o->o_version);
+  o->o_version &= ((unsigned longlong)1 << 63) - 1;
+
+  c = o->o_address;
+
+  if (!c->c_nettype ||
+      !c->c_address ||
+      strcmp(c->c_address, "") == 0 ||
+      strcmp(c->c_address, "0.0.0.0") == 0 ||
+      strcmp(c->c_address, "::") == 0 ||
+      !host_is_local(c->c_address)) {
+    return soa_init_sdp_connection(ss, c, buffer);
+  }
+
+  return 0;
+}
+
+/** Search for an local address item from string provided by user */
+static
+su_localinfo_t *li_in_list(su_localinfo_t *li0, char const **llist)
+{
+  char const *list = *llist;
+  size_t n;
+
+  if (!list)
+    return NULL;
+
+  while ((n = strcspn(list, ", "))) {
+    su_localinfo_t *li;
+
+    for (li = li0; li; li = li->li_next) {
+      if (strncasecmp(li->li_canonname, list, n) == 0 &&
+	  li->li_canonname[n] == '\0')
+	break;
+    }
+
+    list += n; while (list[0] == ' ' || list[0] == ',') list++;
+    *llist = list;
+
+    if (li)
+      return li;
+  }
+
+  return NULL;
+}
+
+
+/** Obtain a local address for SDP connection structure */
+int
+soa_init_sdp_connection(soa_session_t *ss,
+			sdp_connection_t *c,
+			char buffer[64])
+{
+  su_localinfo_t *res, hints[1] = {{ LI_CANONNAME | LI_NUMERIC }};
+  su_localinfo_t *li, *li4, *li6;
+  char const *address;
+  int ip4, ip6, error;
+
+  if (ss == NULL || c == NULL)
+    return su_seterrno(EFAULT), -1;
+
+  address = ss->ss_address;
+
+  if (host_is_ip_address(address)) {
+    /* Use the application-specified address -
+     * do not check that it is found from the local address list */
+    c->c_nettype = sdp_net_in;
+    
+    if (host_is_ip4_address(address))
+      c->c_addrtype = sdp_addr_ip4;
+    else
+      c->c_addrtype = sdp_addr_ip6;
+    
+    if (!host_is_ip6_reference(address)) {
+      c->c_address = strcpy(buffer, address);
+    }
+    else {
+      /* Remove brackets [] around the reference */
+      size_t len = strlen(address + 1);
+      c->c_address = memcpy(buffer, address + 1, len - 1);
+      buffer[len - 1] = '\0'; 
+    }
+    return 0;
+  }
+
+  /* XXX - using LI_SCOPE_LINK requires some tweaking */
+  hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_LINK */;
+
+  switch (ss->ss_af) {
+  case SOA_AF_IP4_ONLY:
+    hints->li_family = AF_INET, ip4 = 1, ip6 = 0;
+    break;
+
+#if HAVE_SIN6
+  case SOA_AF_IP6_ONLY:
+    hints->li_family = AF_INET6, ip6 = 1, ip4 = 0;
+    break;
+  case SOA_AF_IP4_IP6:
+    ip4 = 2, ip6 = 1;
+    break;
+  case SOA_AF_IP6_IP4:
+    ip4 = 1, ip6 = 2;
+    break;
+#endif
+  default:
+    ip4 = ip6 = 1;
+  }
+
+  for (res = NULL; res == NULL;) {
+    if ((error = su_getlocalinfo(hints, &res)) < 0 
+	&& error != ELI_NOADDRESS) {
+      SU_DEBUG_1(("%s: su_localinfo: %s\n", __func__,
+		  su_gli_strerror(error)));
+      return -1;
+    }
+    if (hints->li_scope & LI_SCOPE_HOST)
+      break;
+    hints->li_scope |= LI_SCOPE_HOST;
+  }
+
+  if (!(ip4 & ip6 && c->c_nettype == sdp_net_in))
+    /* Use ss_af preference */;
+  else if (c->c_addrtype == sdp_addr_ip4)
+    ip4 = 2, ip6 = 1;
+  else if (c->c_addrtype == sdp_addr_ip6)
+    ip6 = 2, ip4 = 1;
+
+  if (address)
+    SU_DEBUG_3(("%s: searching for %s from list \"%s\"\n",
+		__func__, ip6 && !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : "",
+		address));
+
+  li = res, li4 = NULL, li6 = NULL;
+
+  for (;;) {
+    if (address)
+      li = li_in_list(li, &address);
+
+    if (!li)
+      break;
+#if HAVE_SIN6
+    else if (li->li_family == AF_INET6) {
+      if (ip6 >= ip4)
+	break;
+      else if (!li6)
+	li6 = li;		/* Best IP6 address */
+    }
+#endif
+    else if (li->li_family == AF_INET) {
+      if (ip4 > ip6)
+	break;
+      else if (!li4)
+	li4 = li;		/* Best IP4 address */
+    }
+
+    if (!address)
+      li = li->li_next;
+  }
+
+  if (li == NULL)
+    li = li4;
+  if (li == NULL)
+    li = li6;
+
+  if (li == NULL)
+    ;
+  else if (li->li_family == AF_INET)
+    c->c_nettype = sdp_net_in,  c->c_addrtype = sdp_addr_ip4;
+#if HAVE_SIN6
+  else if (li->li_family == AF_INET6)
+    c->c_nettype = sdp_net_in,  c->c_addrtype = sdp_addr_ip6;
+#endif
+
+  if (li) {
+    assert(strlen(li->li_canonname) < 64);
+    c->c_address = strcpy(buffer, li->li_canonname);
+  }
+
+  su_freelocalinfo(res);
+
+  if (!li)
+    return -1;
+  else
+    return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,887 @@
+/**@MODULEPAGE "soa" - SDP Offer/Answer Engine Module
+
+ at section soa_meta Module Information
+
+The Sofia SIP @b soa module consists of an asynchronous SDP Offer/Answer engine
+library. The interface to library is defined in <soa.h>.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section soa_oveview Using soa engine
+
+SIP uses SDP and a negotiation procedure known as "SDP
+Offer-Answer Model" to establish the multimedia sessions. The
+SDP Offer-Answer negotiation is specified in 
+<a href="http://ietf.org/rfc/rfc3264.txt">RFC 3264</a>.
+
+The soa engine is implemented in object-oriented manner. The default soa
+object just implements the basic SDP negotiation and basic SIP call model. A
+more complex soa object implementation can manipulate the call model and
+initiate actions on behalf of application.
+
+ at section soa_model SDP Offer/Answer Model
+
+The basic capabilities provided by Offer/Answer mechanism include
+-# generating SDP offer (section 5)
+-# processing SDP offer, generating SDP answer (section 6)
+-# processing SDP answer (section 7)
+-# modifying session (section 8)
+-# indicating capabilities (section 9)
+
+The offerer indicates its capabilities in the offer: 
+- the media streams it wants to establish
+- transport addresses it uses to receive by media streams 
+  (IP addresses, port numbers, transport protocols) 
+- the codecs used by particular streams
+- codec parameters (for instance, codec profile used by H.263)
+
+The answerer indicates which parts of the offer are acceptable to
+it in the answer:
+- the media streams it agrees to establish
+- transport addresses answerer uses to receive by media streams 
+- the codecs and codec parameters used by particular streams
+
+Note that the capabilites indicate what the party generating the
+SDP is prepared to receive. They can send anything the other end
+accepts.
+
+There may be other things, like encryption keys included in the
+session description.
+
+The advanced capabilities are required by more complicated negotiation
+involving two or more offer-answer rounds. For instance, an extension known
+as session <i>preconditions</i> is defined
+<a href="http://ietf.org/rfc/rfc3312.txt">RFC 3312</a>.
+Another example of two-phase negotiation is presented in RFC
+3264 section 10.2, showing how a single codec can be selected. 
+
+ at section soa_motivation SOA Design 
+
+Why to have simple interface? Is it not simple enough to include SDP offer
+with your INVITE, and act on SDP answer in 200 OK?
+
+Our design goal is to allow application to follow the simple call
+model, regardless of the underlying complications - early
+sessions, preconditions, session timers, 3rd party call control. 
+In other words, we would like a have a simple "cooked" interface
+toward naive applications even if the underlying call follows the
+byzantine call model chosen by 3GPP.
+
+ at section soa_with_sip Using SDP Offer/Answer with SIP
+
+Using SDP Offer/Answer with SIP is specified in 
+<a href="http://ietf.org/rfc/rfc3261.txt">RFC 3261</a>, 
+<a href="http://ietf.org/rfc/rfc3262.txt">RFC 3262 (100rel and PRACK)</a>, and
+<a href="http://ietf.org/rfc/rfc3211.txt">RFC 3311 (UPDATE)</a>.
+
+There is a @ref soa_sdp_oa_use_cases "separate page listing scenarios".
+
+The rules for sending offers:
+- offer may be sent in INVITE
+- if there was no offer in INVITE, offer MUST be sent in first
+  reliable response to INVITE
+- offer may be sent in 100rel (reliable 1XX series response)
+- offer may be sent in PRACK
+- offer may be sent in UPDATE
+
+PRACK may only be sent when an unacknowledged 100rel (reliable 1XX
+series response) is received. UPDATE may be sent during early or
+established dialog. 
+
+Only one INVITE request may be pending within a dialog. Only one
+non-INVITE request may be pending within a dialog (in one
+direction): it is not possible to send UPDATE if no final response
+has been received to PRACK.
+
+If there is already an offer/answer exchange in progress, no offer
+MUST be sent. Offer/answer exchange is in progress if offer has
+been sent but no answer has been received, or if an offer has been
+received but no answer has been generated.
+
+The rules for sending answer:
+- when offer is received with INVITE
+  - answer MAY be sent with next end-to-end 1XX or 2XX response
+  - answer MUST be sent in a reliable response (100rel or 2XX)
+- when offer is received in 2XX response
+  - answer MUST be sent in ACK
+- when offer is received with 100rel response
+  - answer MUST be sent with PRACK
+- when offer is received with PRACK or UPDATE
+  - answer MUST be sent with 2XX response to PRACK or UPDATE
+
+Offer or answer in PRACK MUST be processed even if we have already
+sent 2XX to INVITE.
+
+The rules for receiving answer:
+- if offer was sent in INVITE, first session description in any
+  non-error response to INVITE is treated as the answer
+- if offer was sent in 2XX response, session description in
+  ACK is answer 
+- if offer was sent in 100rel response, session description in
+  PRACK is answer 
+- if offer was sent in PRACK or UPDATE, session description in 
+  2XX response is answer
+
+Rules for situations when endpoint MUST ignore the SDP: 
+- If offer was sent in INVITE, only the first session description in
+  any non-error (1XX or 2XX) response to INVITE is processed, rest
+  are ignored
+- If no offer was sent in 2XX response to INVITE, SDP in ACK is ignored
+- If no offer was sent in PRACK, SDP in response to it is ignored
+- If no offer was sent in UPDATE, SDP in response to it is ignored
+
+The re-INVITEs and UPDATEs are sent for two different purposes:
+updating or modifying SIP state, or updating or modifying the
+associated session. Session timer extension (not yet an rfc) is an
+example of the first. Putting a call on hold, or adding video to
+audio-only call is an example of the second. So, upon receiving
+re-INVITE, there might be quite different things happening. The
+application can just return a 200 OK with previous SDP, sometimes
+it must indicate call being on hold and sometimes ask user for
+permission (for adding video).
+
+Rules for resolving glare (both endpoints trying to send offer at the same
+time):
+- if a offer is received while UAS has generated an offer, 
+  it must be rejected (with SIP 491 response).
+
+ at section soa_use_cases SOA and SDP Offer/Answer Scenarios
+
+Note that due to limitations in space
+- soa_set_params() is referred as @c set_params
+- soa_set_remote_sdp() is referred as @c set_remote
+- soa_generate_offer() followed by soa_get_session_sdp() 
+  is referred as @c gen_offer  
+- soa_generate_answer() followed by soa_get_session_sdp() 
+  is referred as @c gen_answer 
+- soa_process_answer() is referred as @c proc_answer 
+
+ at subsection soa_uc_basic_out Basic Call Out
+
+This is the "basic" outbound call model.
+
+<pre>
+       APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|----INVITE---->|		|			|
+ 2	|		|--set_params-->|			|
+ 3      |		|---gen_offer-->|			|
+ 4	|		|		|			|
+ 5	|		|-------------------INVITE(sdp offer)-->|
+ 6      |		|		|			|
+ 7	|		|		|			|
+ 8      |		|		|     			|
+ 9      |		|< - - - - - - - - - - 180 Ringing - - -|
+10      |< - - 180 - - -|		|			|
+11      |		|		|			|
+12      |		|<-------------------200(sdp answer)----|
+13	|		|--set_remote-->|			|
+14	|		|--proc_answer->|			|
+15	|<-----200------|		|			|
+16      |		|               | 			|
+17      |		|----activate-->|			|
+18	|<----active----|		|			|
+19	|		|-------------------------ACK---------->|
+20	|		|		|			|
+21	|		|		|			|
+22	|		|		|			|
+        |		|		|			|
+</pre>
+
+ at subsection soa_uc_basic_in Basic Call In
+
+This is the "basic" inbound call model.
+
+<pre>
+       APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|		|<------------------INVITE(sdp offer)---|
+ 2      |		|		|			|
+ 3	|		|--set_remote-->|			|
+ 4      |		|		|			|
+ 5	|<---INVITE-----|		|			|
+ 6      |		|		|			|
+ 7      |		|		|			|
+ 8	|- - -180- - - >|		|			|
+ 9	|		|- - - - - - - - - - 180 Ringing - - - >|
+10      |		|		|			|
+11      |		|		|			|
+12	|-----200------>|		|			|
+13	|		|--set_params-->|			|
+14      |		|		|			|
+15	|		|--gen_answer-->|			|
+16	|		|               |			|
+17	|<----active----|		|			|
+18	|		|----activate-->|			|
+19	|		|--------------------200 (sdp answer)-->|
+20	|		|		|			|
+21	|		|		|	 		|
+22	|		|<------------------------ACK-----------|
+23	|<-----ACK------|		|			|
+24	|		|		|			|
+	|		|		|			|
+</pre>
+
+ at subsection soa_uc_basic_3p 3rd Party Call In 
+
+The 3rd-party call model just reverses the O/A roles of callee and caller.
+
+<pre>
+ t     APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|		|<----------------------INVITE----------|
+ 2	|    		|		|			|
+ 3      |<---INVITE-----|		|			|
+ 4	|		|		|			|
+ 5	|		|		|			|
+ 6      |    		|		|			|
+ 7	|----200 OK---->|   		|			|
+ 8      |		|--set_params-->|			|
+ 9      |		| 		|			|
+10      |		|--gen_offer--->|			|
+11	|		|		|			|
+12      |		|		|			|
+13      |		|----------------------200 (off) ------>|
+14	|		|		|			|
+15	|		|		|	 		|
+16	|     		|<---------------------ACK (ans)--------|
+17      |		|--set_remote-->|			|
+18	|		|--proc_answer->|			|
+19	|<----ACK-------|		|			|
+20	|<----active----|		|			|
+21	|		|----activate-->|			|
+22      |		|		|			|
+        |		|		|			|
+</pre>
+
+ at subsection soa_uc_early_out Callout with Early Media
+
+It is possible to establish media session before call is completed. In this
+case, the 180 Ringing contains the SDP answer. A copy of SDP answer is
+included in the 200 OK response, too, because the 180 Ringing is not
+acknowledged and it may be lost.
+
+This is preferred to the basic call model above, as the endpoints has more
+time to establish the media session.
+
+<pre>
+ t     APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|----INVITE---->|		|			|
+ 2      |		|--set_params-->|			|
+ 3	|		|               |			|
+ 4      |		|--gen_offer--->|			|
+ 5	|		|               |			|
+ 6      |		|		|			|
+ 7      |		|-------------------INVITE(sdp offer)-->|
+ 8	|		|		|			|
+ 9	|		|		|			|
+10      |		|		|			|
+11      |		|<-------------------180(sdp answer)----|
+12      |		|--set_remote-->|			|
+13	|<-----180------|--proc_answer->|	    		|
+14	|   		|		|			|
+15      |		|		|			|
+16	|		|		|			|
+17	|		|<-----------------200(copy of answer)--|
+18	|	(copy is ignored)	|			|
+19	|		|		|			|
+20	|<-----200------|		|			|
+21	|		|----activate-->|			|
+22	|<----active----|		|			|
+23	|		|-------------------------ACK---------->|
+24	|		|		|			|
+	|		|		|			|
+</pre>
+
+ at subsection soa_uc_early_in Call In Establishing Early Media
+
+The mirror of the previous scenario:
+
+<pre>
+ t     APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|		|<------------------INVITE(sdp offer)---|
+ 2      |		|--set_remote-->|			|
+ 3	|<---INVITE-----|		|			|
+ 4      |		|		|			|
+ 5      |   		|		|			|
+ 6	|---180 Ring--->|   		|			|
+ 7      |		|--set_params-->|			|
+ 8      |		|--gen_offer--->| 			|
+ 9      |		|	     (Note 1)			|
+10      |		|		|			|
+11      |		|-------------------180 (sdp answer)--->|
+12	|		|		|			|
+13	|		|		|			|
+14	|		|		|			|
+15	|----200 OK---->|		|			|
+16	|		|--set_params-->|			|
+17	|		|		|			|
+18	|		|		|			|
+19	|		|-----------------200 (copy of answer)->|
+20	|		|----activate-->|			|
+21	|<----active----|		|			|
+22	|		|<------------------------ACK-----------|
+23	|<-----ACK------|		|			|
+24      |		|		|			|
+	|		|		|			|
+</pre>
+<b>Note 1:</b> the user expectation (set by ordinary telephone) here is
+that callee sends a ringing tone towards caller and discards any media sent
+by caller until the call is accepted (200 OK is sent towards caller).
+
+ at subsection soa_uc_100rel_out Call Out with PRACK
+
+Here is second alternative establishing media session before call is
+completed. In this case, the 180 Ringing contains the SDP answer. The 180
+Ringing is now sent reliably. In other words, it is acknowledged by a PRACK
+request.
+
+<pre>
+ t     APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|----INVITE---->|		|			|
+ 2      |		|--set_params-->|			|
+ 3	|		|               |			|
+ 4      |		|--gen_offer--->|			|
+ 5	|		|		|			|
+ 6      |		|		|			|
+ 7      |		|-------------------INVITE(sdp offer)-->|
+ 8	|		|		|			|
+ 9	|		|		|			|
+10      |		|<-------------------183(sdp answer)----|
+11      |		|--set_remote-->|			|
+12      |		|--proc_answer->|			|
+13	|<-----183------|		|	    		|
+14	|   		|		|			|
+15      |		|-----------------------PRACK---------->|
+16	|		|<--------------------200/PRACK---------|
+17	|<--200/PRACK---|		|			|
+18	|		|		|			|
+19	|		|		|			|
+20	|		|<--------------------180 Ringing-------|
+21	|<-----180------|		|			|
+22	|		|-----------------------PRACK---------->|
+23	|		|<--------------------200/PRACK---------|
+24	|<--200/PRACK---|		|			|
+25	|		|		|			|
+26	|		|		|			|
+27	|		|<----------------------200 OK----------|
+28      |<--200/INVITE--|		|			|
+29	|		|----activate-->|			|
+30	|<----active----|		|			|
+31	|		|-----------------------ACK------------>|
+32	|		|		|			|
+	|		|		|			|
+</pre>
+
+ at subsection soa_uc_100rel_in Call In with PRACK
+
+The mirror of the previous scenario:
+
+<pre>
+ t     APPL	       NUA	       SOA		      REMOTE
+	|		|		|			|
+ 0      |		|		|			|
+ 1	|		|<------------------INVITE(sdp offer)---|
+ 2      |		|--set_remote-->|			|
+ 3	|<---INVITE-----|		|			|
+ 4      |		|		|			|
+ 5      |   		|		|			|
+ 6	|-183 Progress->|   		|			|
+ 7      |		|--set_params-->|			|
+ 8      |		|--gen_answer-->|			|
+ 9	|		|		|			|
+10      |		|-------------------183 (sdp answer)--->|
+11      |		|		|			|
+12      |		|<----------------------PRACK-----------|
+13      |<----PRACK-----|		|			|
+14	|		|---------------------200/PRACK-------->|
+15	|		|		|			|
+16      |--180 Ringing->|   		|			|
+17      |		|---------------------180 Ringing------>|
+18	|		|		|			|
+19      |		|<----------------------PRACK-----------|
+20      |<----PRACK-----|		|			|
+21	|		|---------------------200/PRACK-------->|
+22      |		|		|			|
+23      |		|		|			|
+24      |		|		|			|
+25      |----200 OK---->|		|			|
+26      |		|----activate-->|			|
+27      |<----active----|		|			|
+28      |		|---------------------200/INVITE------->|
+29      |		|		|			|
+30      |		|<-----------------------ACK------------|
+31      |<-----ACK------|		|			|
+32      |		|		|			|
+        |		|		|			|
+</pre>
+
+<b>Note 1:</b> the user expectation (set by ordinary telephone) here is that
+callee sends a ringing tone towards caller and discards any media sent by
+callee until the call is accepted at t=26 (200 OK is sent towards caller).
+
+The application starts to alert user at t=13 when it knows that the
+media session has been successfully established.
+
+*/
+
+/**
+ at page soa_sdp_oa_use_cases Use Cases for SIP and SDP Offer/Answer
+
+This page contains a list of use cases or call scenarios for SIP and SDP
+Offer/Answer. 
+
+There are a few call scenarios that we expect to see when dealing with more
+telephone-like side of SIP: 
+- calling to existing PSTN networks (early session)
+- doing resource reservations
+- calling to 3G IMS
+- call hunting
+- having external party setting up your call, etc.
+
+ at section soa_use_case_1 Case #1: Basic Call
+
+This is the basic SIP call model with the most simple offer-answer exchange.
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			|
+	|			|
+	|< - - 180 Ringing - - -|
+	|			|
+	|			|
+	|<----200 (answer)------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+ at section soa_use_case_2 Case #2: Early Media
+
+Another case, slightly more complex. The SDP answer is sent with
+180 Ringing in order to establish an "early session". B might
+not be a SIP phone, but a gateway to PSTN, for instance. Using this
+"early session" B can play tones like "burr-burr" or "the
+subscriber you tried to reach is not in the coverage...":
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			|
+	|			|
+	|<----180 (answer)------|
+	|			|
+	|			|
+	|<----200 (answer')-----|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+After receiving answer in 180 Ringing, A simply ignores SDP in
+subsequent responses.
+
+Nothing special here, right? But SIP is not so simple,
+unfortunately. There are hairy cases because of "early sessions",
+"forking", "preconditions" and other reasons.
+
+Now lets go through some hairy cases.
+
+ at section soa_use_case_3 Case #3: Early Dialog, Early Media
+
+This case is a call using 100rel, early dialog and early media. It
+is used when the session should be established before call alerts.
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			|
+	|<----183 (answer)------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|<---------180----------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|			|
+	|			|
+	|<---------200----------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+ at section soa_use_case_4 Case #4: UPDATE with Offer
+
+This is a call model with two rounds of offer/answer and 100rel. 
+It can be used, for instance, when the endpoints have to make sure
+that there are enough network capacity for the call to succeed. 
+They can establish a new radio bearer, for instance, before
+progressing with the call. The initial offer would contain SDP
+attribute "inactive", the second "sendrev":
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			| 
+	|			| 
+	|<----183 (answer)------| 
+	|--------PRACK--------->|
+	|<-----200/PRACK--------|
+	|			|
+	|			|
+	|----UPDATE (offer2)--->|
+	|<-200/UPDATE (answer2)-|
+	|			|
+	|<---------180----------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|			|
+	|<---------200----------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+
+ at section soa_use_case_5 Case #5: 2nd Offer in PRACK
+
+Alternative 1 to above, two rounds of offer/answer and 100rel, no
+UPDATE. It can used, for instance, when caller wants to make sure
+there is only one audio or video codec that is used during the
+call. The initial offer would contain SDP attribute "inactive";
+the second "sendrev":
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			|
+	|<----183 (answer)------|
+	|-----PRACK(offer2)---->|
+	|<--200/PRACK(answer2)--|
+	|			|
+	|			|
+	|<---------180----------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|			|
+	|<---------200----------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+
+ at section soa_use_case_6 Case #6: Callee Making 2nd Offer 
+
+Alternative 2 to above: two rounds of offer/answer and 100rel, but
+now it is B who wants to do two rounds and initiates second
+Offer-Answer exchange:
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer)---->|
+	|			|
+	|<----183 (answer)------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|			|
+	|<---UPDATE (offer2)----|
+	|-200/UPDATE (answer2)->|
+	|			|
+	|<---------180----------|
+	|--------PRACK--------->|
+	|<-----200/PRACK------->|
+	|			|
+	|			|
+	|<---------200----------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+
+ at section soa_use_case_7 Case #7: 3GPP Call Model
+
+Here is a third alternative, know as "3GPP call model", where
+there is not 2 but 3 offer-answer rounds, allowing A and B to do
+precise resource reservations after they have agreed on media,
+codecs and transport addresses used during the call:
+
+<pre>
+        	A		        B
+        	|			|
+        	|----INVITE (offer)---->|
+        	|			| 
+        	|			| 
+        	|<----183 (answer)------| 
+        	|-----PRACK(offer2)---->|
+        	|<--200/PRACK(answer2)--|
+        	|			|
+        << resource reservations are done now >>
+        	|			|
+        	|----UPDATE (offer3)--->|
+        	|<-200/UPDATE (answer3)-|
+        	|			|
+        	|<---------180----------|
+        	|--------PRACK--------->|
+        	|<-----200/PRACK------->|
+        	|			|
+        	|			|
+        	|<---------200----------|
+        	|----------ACK--------->|
+        	|			|
+        	|			|
+</pre>
+
+
+ at section soa_use_case_8 Case #8: Forking
+
+Now, another complication. Here B has two terminals, let say,
+fixed (B1) and mobile (B2) phone, both alert when B receives a
+call using procedure known as forking:
+
+<pre>
+	A		   B's proxy		B1		B2
+	|			|		|		|
+	|----INVITE (offer)---->|		|		|
+	|			|-INVITE (off)->|		|
+	|			|-----------INVITE (off)------->|
+	|			|		|		|
+	|			|<--180 (ans1)--|		|
+	|<------180 (ans1)------|		|		|
+	|			|		|		|
+	|			|<----------180 (ans2)----------|
+	|<------180 (ans2)------|		|		|
+	|			|		|		|
+	|			|		|		|
+	|			|<----------200 (ans2')---------|
+	|<------200 (ans2')-----|		|		|
+	|			|----CANCEL---->|		|
+	|			|<--200/CANCEL--|		|
+	|			|<-----487------|		|
+	|			|		|		|
+	|----------ACK----------------------------------------->|
+	|			|		|		|
+	|			|		|		|
+</pre>
+
+Here we have two calls initially established, but the call to B1
+along with "early session" is should be dropped when B2 picks up
+the call (and 200 OK is returned).
+
+ at section soa_use_case_9 Case #9: 3rd Party Call Control
+
+Now something different: 3rd party call model, where "C"
+establishes the call:
+
+<pre>
+	A		        C		        B
+	|			|			|
+	|<-------INVITE---------|			|
+	|			|			|
+	|			|			|
+	|------200 (offer)----->|  	  		|
+	|			|----INVITE (offer)---->|
+	|			|			|
+	|			|			|
+	|			|<-----200 (answer)-----|
+	|<-----ACK (answer)-----|			|
+	|			|     			|
+	|			|----------ACK--------->|
+	|			|			|
+</pre>
+
+ at section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE
+
+The session is upgraded: a new media is added to the session. 
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer1)--->|
+	|			|
+	|			|
+	|< - - 180 Ringing - - -|
+	|			|
+	|			|
+	|<----200 (answer2)-----|
+	|----------ACK--------->|
+	|			|
+	|			|
+	|			|
+	|			|
+	|----INVITE (offer2)--->|
+	|			|
+	|<----200 (answer2)-----|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+ at section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE
+
+The session upgraded is rejected.
+
+<pre>
+	A		        B
+	|			|
+	|----INVITE (offer1)--->|
+	|			|
+	|			|
+	|< - - 180 Ringing - - -|
+	|			|
+	|			|
+	|<----200 (answer2)-----|
+	|----------ACK--------->|
+	|			|
+	|			|
+	|			|
+	|			|
+	|----INVITE (offer2)--->|
+	|			|
+	|<---------488----------|
+	|----------ACK--------->|
+	|			|
+	|			|
+</pre>
+
+
+*/
+
+/** @typedef struct soa_session soa_session_t;
+
+ at brief "soa" session object. 
+
+The @soa session object is responsible for
+ at ref soa_with_sip "SDP offer/answer negotiation"
+defined in @RFC3264. The session object is used to
+store the SDP template from user, remote SDP received from the network and
+the negotiation result, local SDP.
+
+ at par Functions used to create, copy and destroy "soa" session objects:
+ at code
+soa_session_t *soa_create(char const *name, su_root_t *, soa_magic_t *);
+
+soa_session_t *soa_clone(soa_session_t *, su_root_t *, soa_magic_t *);
+
+void soa_destroy(soa_session_t *);
+ at endcode
+
+ at par Functions used to set and get parameters for "soa" session objects:
+ at code
+int soa_set_params(soa_session_t *ss,
+                   tag_type_t tag, tag_value_t value, ...);
+int soa_get_params(soa_session_t const *ss, 
+                   tag_type_t tag, tag_value_t value, ...);
+
+tagi_t *soa_get_paramlist(soa_session_t const *ss,
+                          tag_type_t tag, tag_value_t value, ...);
+ at endcode
+
+ at par Functions used to obtain status information from "soa" session objects:
+ at code
+int soa_error_as_sip_response(soa_session_t *soa, 
+                              char const **return_phrase);
+
+char const *soa_error_as_sip_reason(soa_session_t *soa);
+
+int soa_get_warning(soa_session_t *ss, char const **return_phrase);
+ at endcode
+
+
+ at par Functions used to store and retrieve SDP descriptions: 
+ at code
+int soa_set_capability_sdp(soa_session_t *ss, 
+                           struct sdp_session_s const *sdp,
+                           char const *str, issize_t len);
+
+int soa_get_capability_sdp(soa_session_t const *ss,
+                           struct sdp_session_s const **return_sdp,
+                           char const **return_sdp_str,
+                           isize_t *return_len);
+
+int soa_set_remote_sdp(soa_session_t *ss, 
+                       struct sdp_session_s const *sdp,
+                       char const *str, issize_t len);
+
+int soa_get_remote_sdp(soa_session_t const *ss,
+                       struct sdp_session_s const **return_sdp,
+                       char const **return_sdp_str,
+                       isize_t *return_len);
+
+int soa_clear_remote_sdp(soa_session_t *ss);
+
+int soa_get_remote_version(soa_session_t const *ss);
+
+int soa_set_user_sdp(soa_session_t *ss, 
+                     struct sdp_session_s const *sdp,
+                     char const *str, issize_t len);
+
+int soa_get_user_sdp(soa_session_t const *ss,
+                     struct sdp_session_s const **return_sdp,
+                     char const **return_sdp_str,
+                     isize_t *return_len);
+
+int soa_get_user_version(soa_session_t const *ss);
+
+int soa_get_local_sdp(soa_session_t const *ss,
+                      struct sdp_session_s const **return_sdp,
+                      char const **return_sdp_str,
+                      isize_t *return_len);
+ at endcode
+
+
+ at par Functions for executing Offer/Answer negotiation steps:
+ at code
+int soa_init_offer_answer(soa_session_t *ss);
+int soa_generate_offer(soa_session_t *, int always, soa_callback_f *);
+int soa_generate_answer(soa_session_t *, soa_callback_f *);
+int soa_process_answer(soa_session_t *, soa_callback_f *);
+int soa_process_reject(soa_session_t *, soa_callback_f *);
+int soa_is_complete(soa_session_t const *ss);
+ at endcode
+
+ at par Functions for signaling events of session signaling:
+ at code
+int soa_activate(soa_session_t *, char const *option);
+int soa_deactivate(soa_session_t *, char const *option);
+void soa_terminate(soa_session_t *, char const *option);
+ at endcode
+These functions are used to activate actions taken by @soa, for instance,
+a COMEDIA connection is established with soa_activate().
+
+ at par Functions for Checking Activated Media:
+ at code
+int soa_is_audio_active(soa_session_t const *ss);
+int soa_is_video_active(soa_session_t const *ss);
+
+int soa_is_remote_audio_active(soa_session_t const *ss);
+int soa_is_remote_video_active(soa_session_t const *ss);
+ at endcode
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_asynch.c
+ *
+ * @brief Static implementation of Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 16 17:06:06 EEST 2005
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+struct soa_asynch_complete;
+
+#define SU_MSG_ARG_T struct soa_asynch_completed
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+
+#include "sofia-sip/soa.h"
+#include <sofia-sip/sdp.h>
+#include "sofia-sip/soa_session.h"
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+typedef struct soa_asynch_session
+{
+  soa_session_t sss_session[1];
+}
+soa_asynch_session_t;
+
+struct soa_asynch_completed
+{
+  soa_session_t *completed_session;
+  unsigned       completed_terminated;
+  int          (*completed_call)(soa_session_t *, soa_callback_f *);
+};
+
+static int soa_asynch_init(char const *, soa_session_t *, soa_session_t *);
+static void soa_asynch_deinit(soa_session_t *);
+static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags);
+static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags);
+static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss);
+static int soa_asynch_generate_offer(soa_session_t *ss,
+				    soa_callback_f *completed);
+static int soa_asynch_generate_answer(soa_session_t *ss,
+				     soa_callback_f *completed);
+static int soa_asynch_process_answer(soa_session_t *ss,
+					    soa_callback_f *completed);
+static int soa_asynch_activate(soa_session_t *ss, char const *option);
+static int soa_asynch_deactivate(soa_session_t *ss, char const *option);
+static void soa_asynch_terminate(soa_session_t *ss, char const *option);
+
+struct soa_session_actions const soa_asynch_actions =
+  {
+    (sizeof soa_asynch_actions),
+    sizeof (struct soa_asynch_session),
+    soa_asynch_init,
+    soa_asynch_deinit,
+    soa_asynch_set_params,
+    soa_asynch_get_params,
+    soa_asynch_get_paramlist,
+    soa_base_media_features,
+    soa_base_sip_require,
+    soa_base_sip_supported,
+    soa_base_remote_sip_features,
+    soa_base_set_capability_sdp,
+    soa_base_set_remote_sdp,
+    soa_base_set_local_sdp,
+    soa_asynch_generate_offer,
+    soa_asynch_generate_answer,
+    soa_asynch_process_answer,
+    soa_asynch_activate,
+    soa_asynch_deactivate,
+    soa_asynch_terminate
+  };
+
+/* Initialize session */
+static int soa_asynch_init(char const *name,
+			   soa_session_t *ss,
+			   soa_session_t *parent)
+{
+  return soa_base_init(name, ss, parent);
+}
+
+static void soa_asynch_deinit(soa_session_t *ss)
+{
+  soa_base_deinit(ss);
+}
+
+static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+  return soa_base_set_params(ss, tags);
+}
+
+static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+  return soa_base_get_params(ss, tags);
+}
+
+static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss)
+{
+  return soa_base_get_paramlist(ss);
+}
+
+static void soa_asynch_completed(su_root_magic_t *magic,
+				 su_msg_r msg,
+				 struct soa_asynch_completed *arg)
+{
+  soa_session_t *ss = arg->completed_session;
+
+  if (arg->completed_terminated == ss->ss_terminated) {
+    if (ss->ss_in_progress) {
+      soa_callback_f *completed = ss->ss_in_progress;
+      ss->ss_in_progress = NULL;
+
+      /* Update local activity */
+      if (arg->completed_call(ss, NULL) < 0)
+	/* XXX - Process error */;
+      
+      completed(ss->ss_magic, ss);
+    }
+  }
+
+  soa_session_unref(ss);
+}
+
+static int soa_asynch_generate_offer(soa_session_t *ss,
+				     soa_callback_f *completed)
+{
+  sdp_session_t *sdp;
+  sdp_media_t *m;
+  uint16_t port = 5004;
+  su_msg_r msg;
+
+  if (ss->ss_user->ssd_sdp == NULL) {
+    if (ss->ss_caps->ssd_unparsed == NULL)
+      return soa_set_status(ss, 500, "No local session available");
+  }
+
+  if (ss->ss_user->ssd_sdp)
+    return 0;			/* We are done */
+
+  /* Generate a dummy SDP offer based on our capabilities */
+  if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
+    return -1;
+  sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
+
+  for (m = sdp->sdp_media; m; m = m->m_next)
+    if (m->m_port == 0)
+      m->m_port = port, port += 2;
+
+  /* We pretend to be asynchronous */
+  if (su_msg_create(msg,
+		    su_root_task(ss->ss_root),
+		    su_root_task(ss->ss_root),
+		    soa_asynch_completed,
+		    sizeof (struct soa_asynch_completed)) == -1)
+    return soa_set_status(ss, 500, "Internal error");
+
+  su_msg_data(msg)->completed_session = soa_session_ref(ss);
+  su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+  su_msg_data(msg)->completed_call = soa_base_generate_offer;
+
+  su_msg_send(msg);
+
+  ss->ss_in_progress = completed;
+
+  return 1;			/* Indicate caller of async operation */
+}
+
+static int soa_asynch_generate_answer(soa_session_t *ss,
+				      soa_callback_f *completed)
+{
+  sdp_session_t *sdp;
+  sdp_media_t *m;
+  uint16_t port = 5004;
+  su_msg_r msg;
+
+  if (ss->ss_user->ssd_sdp == NULL) {
+    if (ss->ss_caps->ssd_unparsed == NULL)
+      return soa_set_status(ss, 500, "No local session available");
+  }
+
+  if (ss->ss_user->ssd_sdp)
+    return 0;			/* We are done */
+
+  /* Generate a dummy SDP offer based on our capabilities */
+  if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
+    return -1;
+  sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
+
+  for (m = sdp->sdp_media; m; m = m->m_next)
+    if (m->m_port == 0)
+      m->m_port = port, port += 2;
+
+  /* We pretend to be asynchronous */
+  if (su_msg_create(msg,
+		    su_root_task(ss->ss_root),
+		    su_root_task(ss->ss_root),
+		    soa_asynch_completed,
+		    sizeof (struct soa_asynch_completed)) == -1)
+    return soa_set_status(ss, 500, "Internal error");
+
+  su_msg_data(msg)->completed_session = soa_session_ref(ss);
+  su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+  su_msg_data(msg)->completed_call = soa_base_generate_answer;
+
+  su_msg_send(msg);
+
+  ss->ss_in_progress = completed;
+
+  return 1;			/* Indicate caller of async operation */
+}
+
+static int soa_asynch_process_answer(soa_session_t *ss,
+					    soa_callback_f *completed)
+{
+  su_msg_r msg;
+
+  /* We pretend to be asynchronous */
+  if (su_msg_create(msg,
+		    su_root_task(ss->ss_root),
+		    su_root_task(ss->ss_root),
+		    soa_asynch_completed,
+		    sizeof (struct soa_asynch_completed)) == -1)
+    return soa_set_status(ss, 500, "Internal error");
+
+  su_msg_data(msg)->completed_session = soa_session_ref(ss);
+  su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+  su_msg_data(msg)->completed_call = soa_base_process_answer;
+
+  su_msg_send(msg);
+
+  ss->ss_in_progress = completed;
+
+  return 1;			/* Indicate caller of async operation */
+}
+
+
+static int soa_asynch_activate(soa_session_t *ss, char const *option)
+{
+  return soa_base_activate(ss, option);
+}
+
+static int soa_asynch_deactivate(soa_session_t *ss, char const *option)
+{
+  return soa_base_deactivate(ss, option);
+}
+
+static void soa_asynch_terminate(soa_session_t *ss, char const *option)
+{
+  ss->ss_in_progress = NULL;
+  soa_description_free(ss, ss->ss_user);
+  soa_base_terminate(ss, option);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1251 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_static.c
+ *
+ * @brief Static implementation of Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 16 17:06:06 EEST 2005
+ *
+ * @par Use-cases
+ *  1. no existing session
+ *    a) generating offer (upgrade with user-SDP)
+ *    b) generating answer (upgrade with remote-SDP, rejects with user-SDP)
+ *  2. session exists
+ *    a) generating offer: 
+ *       upgrades with user-SDP
+ *    b) generating answer: 
+ *       upgrades with remote-SDP, rejects with user-SDP
+ *    c) processing answer: 
+ *       rejects with user-SDP, no upgrades
+ *
+ * Upgrading session with user SDP:
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+struct soa_static_complete;
+
+#define SU_MSG_ARG_T struct soa_static_completed
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/string0.h>
+#include <sofia-sip/bnf.h>
+
+#include "sofia-sip/soa.h"
+#include <sofia-sip/sdp.h>
+#include "sofia-sip/soa_session.h"
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+#if !HAVE_STRCASESTR
+char *strcasestr(const char *haystack, const char *needle);
+#endif
+
+typedef struct soa_static_session
+{
+  soa_session_t sss_session[1];
+  char *sss_audio_aux;
+}
+soa_static_session_t;
+
+static int soa_static_init(char const *, soa_session_t *, soa_session_t *);
+static void soa_static_deinit(soa_session_t *);
+static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags);
+static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags);
+static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
+					tag_type_t tag, tag_value_t value, 
+					...);
+static int soa_static_set_capability_sdp(soa_session_t *ss, 
+				       sdp_session_t *sdp,
+				       char const *, isize_t);
+static int soa_static_set_remote_sdp(soa_session_t *ss, 
+				   int new_version,
+				   sdp_session_t *sdp,
+				   char const *, isize_t);
+static int soa_static_set_user_sdp(soa_session_t *ss, 
+				   sdp_session_t *sdp,
+				   char const *, isize_t);
+static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *);
+
+static int soa_static_activate(soa_session_t *ss, char const *option);
+static int soa_static_deactivate(soa_session_t *ss, char const *option);
+static void soa_static_terminate(soa_session_t *ss, char const *option);
+
+struct soa_session_actions const soa_default_actions = 
+  {
+    (sizeof soa_default_actions),
+    sizeof (struct soa_static_session),
+    "static",
+    soa_static_init,
+    soa_static_deinit,
+    soa_static_set_params,
+    soa_static_get_params,
+    soa_static_get_paramlist,
+    soa_base_media_features,
+    soa_base_sip_require,
+    soa_base_sip_supported,
+    soa_base_remote_sip_features,
+    soa_static_set_capability_sdp,
+    soa_static_set_remote_sdp,
+    soa_static_set_user_sdp,
+    soa_static_generate_offer,
+    soa_static_generate_answer,
+    soa_static_process_answer,
+    soa_static_process_reject,
+    soa_static_activate,
+    soa_static_deactivate,
+    soa_static_terminate
+  };
+
+/* Initialize session */
+static int soa_static_init(char const *name,
+			   soa_session_t *ss,
+			   soa_session_t *parent)
+{
+  return soa_base_init(name, ss, parent);
+}
+
+static void soa_static_deinit(soa_session_t *ss)
+{
+  soa_base_deinit(ss);
+}
+
+static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+  char const *audio_aux = sss->sss_audio_aux;
+  int n, m;
+
+  n = tl_gets(tags,
+	      SOATAG_AUDIO_AUX_REF(audio_aux),
+	      TAG_END());
+
+  if (n > 0 && str0casecmp(audio_aux, sss->sss_audio_aux)) {
+    char *s = su_strdup(ss->ss_home, audio_aux), *tbf = sss->sss_audio_aux;
+    if (s == NULL && audio_aux != NULL)
+      return -1;
+    sss->sss_audio_aux = s;
+    if (tbf)
+      su_free(ss->ss_home, tbf);
+  }
+
+  m = soa_base_set_params(ss, tags);
+  if (m < 0)
+    return m;
+
+  return n + m;
+}
+
+static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+  int n, m;
+
+  n = tl_tgets(tags,
+	       SOATAG_AUDIO_AUX(sss->sss_audio_aux),
+	       TAG_END());
+  m = soa_base_get_params(ss, tags);
+  if (m < 0)
+    return m;
+
+  return n + m;
+}
+
+static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
+					tag_type_t tag, tag_value_t value, 
+					...)
+{
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+  ta_list ta;
+  tagi_t *tl;
+
+  ta_start(ta, tag, value);
+
+  tl = soa_base_get_paramlist(ss,
+			      TAG_IF(sss->sss_audio_aux,
+				     SOATAG_AUDIO_AUX(sss->sss_audio_aux)),
+			      TAG_NEXT(ta_args(ta)));
+
+  ta_end(ta);
+
+  return tl;
+}
+
+static int soa_static_set_capability_sdp(soa_session_t *ss, 
+					 sdp_session_t *sdp,
+					 char const *sdp_str, 
+					 isize_t sdp_len)
+{
+  return soa_base_set_capability_sdp(ss, sdp, sdp_str, sdp_len);
+}
+
+
+static int soa_static_set_remote_sdp(soa_session_t *ss, 
+				     int new_version,
+				     sdp_session_t *sdp,
+				     char const *sdp_str, 
+				     isize_t sdp_len)
+{
+  return soa_base_set_remote_sdp(ss, new_version, sdp, sdp_str, sdp_len);
+}
+
+
+static int soa_static_set_user_sdp(soa_session_t *ss, 
+				   sdp_session_t *sdp,
+				   char const *sdp_str, 
+				   isize_t sdp_len)
+{
+  return soa_base_set_user_sdp(ss, sdp, sdp_str, sdp_len);
+}
+
+/** Generate a rejected m= line */
+sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home, 
+					 sdp_media_t const *m,
+					 sdp_session_t *sdp,
+					 int include_all_codecs)
+{
+  sdp_media_t rejected[1] = {{ sizeof (rejected) }};
+
+  rejected->m_type = m->m_type;
+  rejected->m_type_name = m->m_type_name;
+  rejected->m_port = 0;
+  rejected->m_proto = m->m_proto;
+  rejected->m_proto_name = m->m_proto_name;
+
+  if (include_all_codecs) {
+    rejected->m_rtpmaps = m->m_rtpmaps;
+  }
+
+  rejected->m_rejected = 1;
+
+  return sdp_media_dup(home, rejected, sdp);
+}
+
+/** Expand a @a truncated SDP.
+ */
+sdp_session_t *soa_sdp_expand_media(su_home_t *home,
+				    sdp_session_t const *truncated,
+				    sdp_session_t const *complete)
+{
+  sdp_session_t *expanded;
+  sdp_media_t **m0;
+  sdp_media_t * const *m1;
+
+  expanded = sdp_session_dup(home, truncated);
+
+  if (expanded) {
+    for (m0 = &expanded->sdp_media, m1 = &complete->sdp_media;
+	 *m1;
+	 m1 = &(*m1)->m_next) {
+      if (!*m0) {
+	*m0 = soa_sdp_make_rejected_media(home, *m1, expanded, 0);
+	if (!*m0)
+	  return NULL;
+      }
+      m0 = &(*m0)->m_next;
+    }
+  }
+
+  return expanded;
+}
+
+/** Check if @a session should be upgraded with @a remote */ 
+int soa_sdp_upgrade_is_needed(sdp_session_t const *session,
+			      sdp_session_t const *remote)
+{
+  sdp_media_t const *rm, *lm;
+
+  if (!remote)
+    return 0;
+  if (!session)
+    return 1;
+
+  for (rm = remote->sdp_media, lm = session->sdp_media; 
+       rm && lm ; rm = rm->m_next, lm = lm->m_next) {
+    if (rm->m_rejected)
+      continue;
+    if (lm->m_rejected)
+      break;
+  }
+
+  return rm != NULL;
+}
+
+/** Check if codec is in auxiliary list */
+int soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary)
+{
+  char const *codec;
+  size_t clen, alen;
+  char const *match;
+
+  if (!rm || !rm->rm_encoding || !auxiliary)
+    return 0;
+
+  codec = rm->rm_encoding;
+
+  clen = strlen(codec), alen = strlen(auxiliary);
+
+  if (clen > alen)
+    return 0;
+
+  for (match = auxiliary;
+       (match = strcasestr(match, codec));
+       match = match + 1) {
+    if (IS_ALPHANUM(match[clen]) || match[clen] == '-')
+      continue;
+    if (match != auxiliary &&
+	(IS_ALPHANUM(match[-1]) || match[-1] == '-'))
+      continue;
+    return 1;
+  }
+
+  return 0;
+}
+
+
+/** Find first matching media in table. */
+sdp_media_t *soa_sdp_matching(soa_session_t *ss, 
+			      sdp_media_t *mm[],
+			      sdp_media_t const *with,
+			      int *return_common_codecs)
+{
+  int i, j = -1;
+  sdp_media_t *m;
+  sdp_rtpmap_t const *rm;
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+  char const *auxiliary;
+
+  auxiliary = with->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+  /* Looking for a single codec */
+  if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL)
+    auxiliary = NULL;
+
+  for (i = 0; mm[i]; i++) {
+    if (!sdp_media_match_with(mm[i], with))
+      continue;
+    
+    if (!sdp_media_uses_rtp(with))
+      break;
+
+    if (!return_common_codecs)
+      break;
+
+    /* Check also rtpmaps  */
+    for (rm = mm[i]->m_rtpmaps; rm; rm = rm->rm_next) {
+      /* Ignore auxiliary codecs */
+      if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary))
+	continue;
+
+      if (sdp_rtpmap_find_matching(with->m_rtpmaps, rm))
+	break;
+    }
+    if (rm)
+      break;
+    if (j == -1)
+      j = i;
+  }
+
+  if (return_common_codecs)
+    *return_common_codecs = mm[i] != NULL;
+
+  if (mm[i] == NULL && j != -1)
+    i = j;			/* return m= line without common codecs */
+
+  m = mm[i];
+
+  for (; mm[i]; i++)
+    mm[i] = mm[i + 1];
+
+  return m;
+}
+
+/** Set payload types in @a l_m according to the values in @a r_m.
+ * 
+ * @retval number of common codecs
+ */
+int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m, 
+			  sdp_media_t const *r_m)
+{
+  sdp_rtpmap_t *lrm, **next_lrm;
+  sdp_rtpmap_t const *rrm;
+
+  int local_codecs = 0, common_codecs = 0;
+
+  unsigned char dynamic_pt[128];
+  unsigned pt;
+
+  for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
+    if (lrm->rm_any) {
+      /* Remove codecs known only by pt number */
+      *next_lrm = lrm->rm_next;
+      continue;
+    }
+    else {
+      next_lrm = &lrm->rm_next;
+    }
+
+    local_codecs++;
+
+    rrm = sdp_rtpmap_find_matching(r_m->m_rtpmaps, lrm);
+
+    /* XXX - do fmtp comparison */
+
+    if (rrm) {
+      /* Use same payload type as remote */
+      if (lrm->rm_pt != rrm->rm_pt) {
+	lrm->rm_predef = 0;
+	lrm->rm_pt = rrm->rm_pt;
+      }
+      common_codecs++;
+    }
+    else {
+      /* Determine payload type later */
+      lrm->rm_any = 1;
+    }
+  }
+  
+  if (local_codecs == common_codecs)
+    return common_codecs;
+
+  /* Select unique dynamic payload type for each payload */
+
+  memset(dynamic_pt, 0, sizeof dynamic_pt);
+
+  for (lrm = l_m->m_rtpmaps; lrm; lrm = lrm->rm_next) {
+    if (!lrm->rm_any)
+      dynamic_pt[lrm->rm_pt] = 1;
+  }
+
+  for (rrm = r_m->m_rtpmaps; rrm; rrm = rrm->rm_next) {
+    dynamic_pt[rrm->rm_pt] = 1;
+  }
+
+  for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
+    if (!lrm->rm_any) {
+      next_lrm = &lrm->rm_next;
+      continue;
+    }
+    
+    lrm->rm_any = 0;
+
+    pt = lrm->rm_pt;
+
+    if (dynamic_pt[pt]) {
+      for (pt = 96; pt < 128; pt++)
+        if (!dynamic_pt[pt])
+          break;
+      
+      if (pt == 128) {
+        for (pt = 0; pt < 128; pt++)
+          if (!sdp_rtpmap_well_known[pt] && !dynamic_pt[pt])
+            break;
+      }
+
+      if (pt == 128)  {
+        for (pt = 0; pt < 128; pt++)
+          if (!dynamic_pt[pt])
+            break;
+      }
+
+      if (pt == 128) {
+        /* Too many payload types */
+        *next_lrm = lrm->rm_next;
+        continue;
+      }
+
+      lrm->rm_pt = pt;
+      lrm->rm_predef = 0;
+    }
+
+    dynamic_pt[pt] = 1;
+  
+    next_lrm = &lrm->rm_next;
+  }
+
+  return common_codecs;
+}
+
+
+/** Sort rtpmaps in @a inout_list according to the values in @a rrm.
+ *
+ * @return Number of common codecs
+ */
+int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list, 
+			sdp_rtpmap_t const *rrm,
+			char const *auxiliary)
+{
+  sdp_rtpmap_t *sorted = NULL, **next = &sorted, **left;
+  sdp_rtpmap_t *aux = NULL, **next_aux = &aux;
+
+  int common_codecs = 0;
+
+  assert(inout_list);
+  if (!inout_list)
+    return 0;
+
+  /* If remote has only single codec, ignore list of auxiliary codecs */
+  if (rrm && !rrm->rm_next)
+    auxiliary = NULL;
+
+  /* Insertion sort from *inout_list to sorted */
+  for (; rrm && *inout_list; rrm = rrm->rm_next) {
+    for (left = inout_list; *left; left = &(*left)->rm_next) {
+      if (sdp_rtpmap_match(rrm, (*left)))
+	break;
+    }
+    if (!*left)
+      continue;
+
+    if (auxiliary && soa_sdp_is_auxiliary_codec(rrm, auxiliary)) {
+      *next_aux = *left, next_aux = &(*next_aux)->rm_next;
+    }
+    else {
+      common_codecs++;
+      *next = *left; next = &(*next)->rm_next;
+    }
+    *left = (*left)->rm_next;
+  }
+
+  /* Append common auxiliary codecs */
+  if (aux)
+    *next = aux, next = next_aux;
+
+  /* Append leftover codecs */
+  *next = *inout_list;
+
+  *inout_list = sorted;
+
+  return common_codecs;
+}
+
+
+/** Select rtpmaps in @a inout_list according to the values in @a rrm.
+ *
+ * @return Number of common codecs
+ */
+int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list, 
+			  sdp_rtpmap_t const *rrm,
+			  char const *auxiliary,
+			  int select_single)
+{
+  sdp_rtpmap_t **left;
+  sdp_rtpmap_t *aux = NULL, **next_aux = &aux;
+
+  int common_codecs = 0;
+
+  assert(inout_list);
+  if (!inout_list)
+    return 0;
+
+  for (left = inout_list; *left; ) {
+    if (auxiliary && soa_sdp_is_auxiliary_codec(*left, auxiliary))
+      /* Insert into list of auxiliary codecs */
+      *next_aux = *left, *left = (*left)->rm_next, 
+	next_aux = &(*next_aux)->rm_next;
+    else if (!(select_single && common_codecs > 0)
+	     && sdp_rtpmap_find_matching(rrm, (*left)))
+      /* Select */
+      left = &(*left)->rm_next, common_codecs++;
+    else
+      /* Remove */
+      *left = (*left)->rm_next;
+  }
+
+  *left = aux, *next_aux = NULL;
+
+  return common_codecs;
+}
+
+/** Sort and select rtpmaps within session */ 
+int soa_sdp_upgrade_rtpmaps(soa_session_t *ss,
+			    sdp_session_t *session,
+			    sdp_session_t const *remote)
+{
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+  sdp_media_t *sm;
+  sdp_media_t const *rm;
+
+  for (sm = session->sdp_media, rm = remote->sdp_media; 
+       sm && rm; 
+       sm = sm->m_next, rm = rm->m_next) {
+    if (sm->m_rejected)
+      continue;
+    if (sdp_media_uses_rtp(sm)) {
+      int common_codecs = soa_sdp_set_rtpmap_pt(sm, rm);
+
+      char const *auxiliary =
+	rm->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+      if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE || 
+	  (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
+	   rm->m_mode == sdp_recvonly)) {
+	soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary);
+      }
+
+      if (common_codecs == 0)
+	;
+      else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) {
+	soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 1);
+      }
+      else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) {
+	soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 0);
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+/** Upgrade m= lines within session */ 
+int soa_sdp_upgrade(soa_session_t *ss,
+		    su_home_t *home,
+		    sdp_session_t *session,
+		    sdp_session_t const *caps,
+		    sdp_session_t const *upgrader)
+{
+  soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+  int Ns, Nc, Nu, size, i, j;
+  sdp_media_t *m, **mm, *cm;
+  sdp_media_t **s_media, **o_media, **c_media;
+  sdp_media_t const **u_media;
+
+  Ns = sdp_media_count(session, sdp_media_any, 0, 0, 0);
+  Nc = sdp_media_count(caps, sdp_media_any, 0, 0, 0);
+  Nu = sdp_media_count(upgrader, sdp_media_any, 0, 0, 0);
+
+  if (caps == upgrader)
+    size = Ns + Nc + 1;
+  else if (Ns < Nu)
+    size = Nu + 1;
+  else
+    size = Ns + 1;
+
+  s_media = su_zalloc(home, size * (sizeof *s_media));
+  o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media));
+  c_media = su_zalloc(home, (Nc + 1) * (sizeof *c_media));
+  u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media));
+
+  cm = sdp_media_dup_all(home, caps->sdp_media, session); 
+
+  if (!s_media || !c_media || !u_media || !cm)
+    return -1;
+
+  for (i = 0, m = session->sdp_media; m && i < Ns; m = m->m_next)
+    o_media[i++] = m;
+  assert(i == Ns);
+  for (i = 0, m = cm; m && i < Nc; m = m->m_next)
+    c_media[i++] = m;
+  assert(i == Nc);
+  for (i = 0, m = upgrader->sdp_media; m && i < Nu; m = m->m_next)
+    u_media[i++] = m;
+  assert(i == Nu);
+
+  if (caps != upgrader) {
+    /* Update session according to remote */
+    for (i = 0; i < Nu; i++) {
+      int common_codecs = 0;
+
+      m = soa_sdp_matching(ss, c_media, u_media[i], &common_codecs);
+
+      if (!m || u_media[i]->m_rejected) {
+	m = soa_sdp_make_rejected_media(home, u_media[i], session, 0);
+      }
+      else if (sdp_media_uses_rtp(m)) {
+	/* Process rtpmaps */
+	char const *auxiliary =
+	  m->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+	if (!common_codecs && !ss->ss_rtp_mismatch)
+	  m = soa_sdp_make_rejected_media(home, m, session, 1);
+	soa_sdp_set_rtpmap_pt(m, u_media[i]);
+
+	if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE || 
+	    (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
+	     u_media[i]->m_mode == sdp_recvonly)) {
+	  soa_sdp_sort_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary);
+	}
+
+	if (common_codecs &&
+	    (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE ||
+	     ss->ss_rtp_select == SOA_RTP_SELECT_COMMON)) {
+	  soa_sdp_select_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary,
+				ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE);
+	}
+      }
+
+      s_media[i] = m;
+    }
+  }
+  else {
+    /* Update session according to local */
+    for (i = 0; i < Ns; i++) {
+      m = soa_sdp_matching(ss, c_media, o_media[i], NULL);
+      if (!m)
+	m = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
+      s_media[i] = m;
+    }
+    /* Here we just append new media at the end */
+    for (j = 0; c_media[j]; j++)
+      s_media[i++] = c_media[j];
+    assert(i <= size);
+  }
+
+  mm = &session->sdp_media;
+  for (i = 0; s_media[i]; i++) {
+    m = s_media[i]; *mm = m; mm = &m->m_next;
+  }
+  *mm = NULL;
+
+  return 0;
+}
+
+/** Check if @a session contains media that are rejected by @a remote. */ 
+int soa_sdp_reject_is_needed(sdp_session_t const *session,
+			     sdp_session_t const *remote)
+{
+  sdp_media_t const *sm, *rm;
+
+  if (!remote)
+    return 1;
+  if (!session)
+    return 0;
+
+  for (sm = session->sdp_media, rm = remote->sdp_media; 
+       sm && rm; sm = sm->m_next, rm = rm->m_next) {
+    if (rm->m_rejected) {
+      if (!sm->m_rejected)
+	return 1;
+    }
+    else {
+      /* Mode bits do not match */
+      if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
+	  != ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
+	return 1;
+    }
+  }
+
+  if (sm)
+    return 1;
+
+  return 0;
+}
+
+/** If m= line is rejected by remote mark m= line rejected within session */ 
+int soa_sdp_reject(su_home_t *home,
+		   sdp_session_t *session,
+		   sdp_session_t const *remote)
+{
+  sdp_media_t *sm;
+  sdp_media_t const *rm;
+
+  if (!session || !session->sdp_media || !remote)
+    return 0;
+
+  rm = remote->sdp_media;
+
+  for (sm = session->sdp_media; sm; sm = sm->m_next) {
+    if (!rm || rm->m_rejected) {
+      sm->m_rejected = 1;
+      sm->m_mode = 0;
+      sm->m_port = 0;
+      sm->m_number_of_ports = 1;
+      if (sm->m_format)
+	sm->m_format->l_next = NULL;
+      if (sm->m_rtpmaps)
+	sm->m_rtpmaps->rm_next = NULL;
+      sm->m_information = NULL;
+      if (sm->m_connections)
+	sm->m_connections->c_next = NULL;
+      sm->m_bandwidths = NULL;
+      sm->m_key = NULL;
+      sm->m_attributes = NULL;
+      sm->m_user = NULL;
+    }
+
+    if (rm)
+      rm = rm->m_next;
+  }
+
+  return 0;
+}
+
+/** Check if @a session mode should be changed. */ 
+int soa_sdp_mode_set_is_needed(sdp_session_t const *session,
+			       sdp_session_t const *remote,
+			       char const *hold)
+{
+  sdp_media_t const *sm, *rm, *rm_next;
+  int hold_all;
+  sdp_mode_t recv_mode;
+
+  SU_DEBUG_7(("soa_sdp_mode_set_is_needed(%p, %p, \"%s\"): called\n",
+	      session, remote, hold ? hold : ""));
+
+  if (!session )
+    return 0;
+
+  hold_all = str0cmp(hold, "*") == 0;
+
+  rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
+
+  for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
+    rm_next = rm ? rm->m_next : NULL;
+
+    if (sm->m_rejected)
+      continue;
+
+    if (rm) {
+      /* Mode bits do not match */
+      if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
+	  != ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
+	return 1;
+    }
+
+    recv_mode = sm->m_mode & sdp_recvonly;
+    if (recv_mode && hold &&
+	(hold_all || strcasestr(hold, sm->m_type_name)))
+      return 1;
+  }
+
+  return 0;
+}
+
+
+/** Update mode within session */ 
+int soa_sdp_mode_set(sdp_session_t *session,
+		     sdp_session_t const *remote,
+		     char const *hold)
+{
+  sdp_media_t *sm;
+  sdp_media_t const *rm, *rm_next;
+  int hold_all;
+  sdp_mode_t send_mode, recv_mode;
+
+  SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n",
+	      session, remote, hold ? hold : ""));
+
+  if (!session || !session->sdp_media)
+    return 0;
+
+  rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
+
+  hold_all = str0cmp(hold, "*") == 0;
+
+  for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
+    rm_next = rm ? rm->m_next : NULL;
+
+    if (sm->m_rejected)
+      continue;
+
+    send_mode = sdp_sendonly;
+    if (rm)
+      send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0;
+
+    recv_mode = sm->m_mode & sdp_recvonly;
+    if (recv_mode && hold && (hold_all || strcasestr(hold, sm->m_type_name)))
+      recv_mode = 0;
+
+    sm->m_mode = recv_mode | send_mode;
+  }
+
+  return 0;
+}
+
+enum offer_answer_action {
+  generate_offer,
+  generate_answer,
+  process_answer
+};
+
+/**
+ * Updates the modified copy of local SDP based
+ * on application provided local SDP and remote SDP.
+ */
+static int offer_answer_step(soa_session_t *ss,
+			     enum offer_answer_action action,
+			     char const *by)
+{
+  char c_address[64];
+  sdp_session_t *local = ss->ss_local->ssd_sdp;
+  sdp_session_t local0[1];
+
+  sdp_session_t *user = ss->ss_user->ssd_sdp;
+  unsigned user_version = ss->ss_user_version;
+
+  sdp_session_t *remote = ss->ss_remote->ssd_sdp;
+  unsigned remote_version = ss->ss_remote_version;
+
+  sdp_origin_t o[1] = {{ sizeof(o) }};
+  sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
+  sdp_time_t t[1] = {{ sizeof(t) }};
+
+  char const *phrase = "Internal Media Error";
+
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];
+
+  su_home_auto(tmphome, sizeof tmphome);
+
+  SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n", ss, by));
+
+  if (user == NULL)
+    return soa_set_status(ss, 500, "No session set by user");
+
+  if (action == generate_offer)
+    remote = NULL;
+
+  /* Pre-negotiation Step: Expand truncated remote SDP */
+  if (local && remote) switch (action) {
+  case generate_answer:
+  case process_answer:
+    if (sdp_media_count(remote, sdp_media_any, "*", 0, 0) < 
+	sdp_media_count(local, sdp_media_any, "*", 0, 0)) {
+      SU_DEBUG_5(("%s: remote %s is truncated: expanding\n",
+		  by, action == generate_answer ? "offer" : "answer"));
+      remote = soa_sdp_expand_media(tmphome, remote, local);
+    }
+  default:
+    break;
+  }
+  
+  /* Step A: Create local SDP session (based on user-supplied SDP) */
+  if (local == NULL) switch (action) {
+  case generate_offer:
+  case generate_answer:
+    SU_DEBUG_7(("soa_static(%p, %s): generating local description\n", ss, by));
+
+    local = local0;
+    *local = *user, local->sdp_media = NULL;
+
+    if (local->sdp_origin) {
+      o->o_username = local->sdp_origin->o_username;
+      /* o->o_address = local->sdp_origin->o_address; */
+    }
+    if (!o->o_address)
+      o->o_address = c0; 
+    local->sdp_origin = o;
+
+    if (soa_init_sdp_origin(ss, o, c_address) < 0) {
+      phrase = "Cannot Get IP Address for Media";
+      goto internal_error;
+    }
+
+    break;
+
+  case process_answer:
+  default:
+    goto internal_error;
+  }
+
+  /* Step B: upgrade local SDP (add m= lines to it)  */
+  switch (action) {
+  case generate_offer:
+    /* Upgrade local SDP based on user SDP */
+    if (local != local0 && ss->ss_local_user_version == user_version)
+      break;
+    if (local != local0)
+      *local0 = *local, local = local0;
+    SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by, 
+		"upgrade with local description"));
+    soa_sdp_upgrade(ss, tmphome, local, user, user);
+    break;
+  case generate_answer:
+    /* Upgrade local SDP based on remote SDP */
+    if (ss->ss_local_user_version == user_version &&
+	ss->ss_local_remote_version == remote_version)
+      break;
+    if (1) {
+      if (local != local0)
+	*local0 = *local, local = local0;
+      SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by,
+		  "upgrade with remote description"));
+      soa_sdp_upgrade(ss, tmphome, local, user, remote);
+    }
+    break;
+  case process_answer:
+  default:
+    break;
+  }
+
+
+  /* Step C: reject media */
+  switch (action) {
+  case generate_offer:
+    /* Local media is marked as rejected already in upgrade phase */
+    break;
+  case generate_answer:
+  case process_answer:
+    if (ss->ss_local_remote_version == remote_version)
+      break;
+    if (soa_sdp_reject_is_needed(local, remote)) {
+      if (local != local0) {
+	*local0 = *local, local = local0;
+#define DUP_LOCAL(local)					 \
+	do {							 \
+	  if (!local->sdp_media) break;				 \
+	  local->sdp_media =					 \
+	    sdp_media_dup_all(tmphome, local->sdp_media, local); \
+	  if (!local->sdp_media)				 \
+	    goto internal_error;				 \
+	} while (0)
+	DUP_LOCAL(local);
+      }
+      SU_DEBUG_7(("soa_static(%p, %s): marking rejected media\n", ss, by));
+      soa_sdp_reject(tmphome, local, remote);
+    }
+    break;
+  default:
+    break;
+  }
+
+  /* Step D: Set media mode bits */
+  switch (action) {
+  case generate_offer:
+  case generate_answer:
+  case process_answer:
+    if (soa_sdp_mode_set_is_needed(local, remote, ss->ss_hold)) {
+      if (local != local0) {
+	*local0 = *local, local = local0;
+	DUP_LOCAL(local);
+      }
+
+      soa_sdp_mode_set(local, remote, ss->ss_hold);
+    }
+    break;
+  default:
+    break;
+  }
+
+  /* Step E: Upgrade codecs by answer. */
+  switch (action) {
+  case process_answer:
+    /* Upgrade local SDP based on remote SDP */
+    if (ss->ss_local_remote_version == remote_version)
+      break;
+    if (1 /* We don't have good test for codecs */) {
+      SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by,
+		  "upgrade codecs with remote description"));
+      if (local != local0) {
+	*local0 = *local, local = local0; 
+	DUP_LOCAL(local);
+      }
+      soa_sdp_upgrade_rtpmaps(ss, local, remote);
+    }
+    break;
+  case generate_offer:
+  case generate_answer:
+  default:
+    break;
+  }
+
+  /* Step F: Update c= line */ 
+  switch (action) {
+  case generate_offer:
+  case generate_answer:
+    /* Upgrade local SDP based of user SDP */
+    if (ss->ss_local_user_version == user_version &&
+	local->sdp_connection)
+      break;
+
+    if (local->sdp_connection == NULL || 
+	(user->sdp_connection != NULL && 
+	 sdp_connection_cmp(local->sdp_connection, user->sdp_connection))) {
+      sdp_media_t *m;
+
+      /* Every m= line (even rejected one) must have a c= line 
+       * or there must be a c= line at session level
+       */
+      if (user->sdp_connection)
+	c = user->sdp_connection;
+      else
+	c = local->sdp_origin->o_address;
+
+      for (m = local->sdp_media; m; m = m->m_next)
+	if (m->m_connections == NULL)
+	  break;
+
+      if (m) {
+	if (local != local0) {
+	  *local0 = *local, local = local0; 
+	  DUP_LOCAL(local);
+	}
+	local->sdp_connection = c;
+      }
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  soa_description_free(ss, ss->ss_previous);
+
+  if (ss->ss_local->ssd_sdp != local &&
+      sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
+    /* We have modfied local session: update origin-line */
+    if (local->sdp_origin != o)
+      *o = *local->sdp_origin, local->sdp_origin = o;
+    o->o_version++;
+
+    /* Do sanity checks for the created SDP */
+    if (!local->sdp_subject)	/* s= is mandatory */
+      local->sdp_subject = "-";
+    if (!local->sdp_time)	/* t= is mandatory */
+      local->sdp_time = t;
+
+    if (action == generate_offer) {
+      /* Keep a copy of previous session state */
+      *ss->ss_previous = *ss->ss_local;
+      memset(ss->ss_local, 0, (sizeof *ss->ss_local));
+      ss->ss_previous_user_version = ss->ss_local_user_version;
+      ss->ss_previous_remote_version = ss->ss_local_remote_version;
+    }
+
+    SU_DEBUG_7(("soa_static(%p, %s): storing local description\n", ss, by));
+
+    /* Update the unparsed and pretty-printed descriptions  */
+    if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) {
+      goto internal_error;
+    }
+  }
+
+  /* Update version numbers */
+  switch (action) {
+  case generate_offer:
+    ss->ss_local_user_version = user_version;
+    break;
+  case generate_answer:
+    ss->ss_local_user_version = user_version;
+    ss->ss_local_remote_version = remote_version;
+    break;
+  case process_answer:
+    ss->ss_local_remote_version = remote_version;
+  default:
+    break;
+  }
+
+  su_home_deinit(tmphome);
+  return 0;
+
+ internal_error:
+  su_home_deinit(tmphome);
+  return soa_set_status(ss, 500, phrase);
+}
+
+/**
+ * Generates offer based on local SDP.
+ */
+static int soa_static_generate_offer(soa_session_t *ss,
+				     soa_callback_f *completed)
+{
+  if (!ss->ss_user->ssd_sdp)
+    return soa_set_status(ss, 500, "No session set by user");
+
+  if (offer_answer_step(ss, generate_offer, "soa_generate_offer") < 0)
+    return -1;
+
+  return soa_base_generate_offer(ss, NULL);
+}
+
+static int soa_static_generate_answer(soa_session_t *ss,
+				      soa_callback_f *completed)
+{
+  /* NOTE:
+   * - local SDP might have changed
+   * - remote SDP might have been updated 
+   */
+
+  if (offer_answer_step(ss, generate_answer, "soa_generate_answer") < 0)
+    return -1;
+
+  return soa_base_generate_answer(ss, NULL);
+}
+
+static int soa_static_process_answer(soa_session_t *ss,
+				     soa_callback_f *completed)
+{
+  /* NOTE:
+   * - both local and remote information is available
+   * - local SDP might have changed
+   * - remote SDP might have been updated 
+   */
+  if (offer_answer_step(ss, process_answer, "soa_process_answer") < 0)
+    return -1;
+
+  return soa_base_process_answer(ss, NULL);
+}
+
+/** Process rejected offer */
+static int soa_static_process_reject(soa_session_t *ss,
+				     soa_callback_f *completed)
+{
+  struct soa_description d[1];
+
+  *d = *ss->ss_local;
+  *ss->ss_local = *ss->ss_previous;
+  ss->ss_local_user_version = ss->ss_previous_user_version;
+  ss->ss_local_remote_version = ss->ss_previous_remote_version;
+
+  memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
+  soa_description_free(ss, d);
+
+  return soa_base_process_reject(ss, NULL);
+}
+
+static int soa_static_activate(soa_session_t *ss, char const *option)
+{
+  return soa_base_activate(ss, option);
+}
+
+static int soa_static_deactivate(soa_session_t *ss, char const *option)
+{
+  return soa_base_deactivate(ss, option);
+}
+
+static void soa_static_terminate(soa_session_t *ss, char const *option)
+{
+  soa_description_free(ss, ss->ss_user);
+  soa_base_terminate(ss, option);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,606 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_tag.c  Tags and tag lists for Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug  3 20:28:17 EEST 2005
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+
+#if 1
+#define TAG_NAMESPACE soa_tag_namespace
+#else
+/* Definition used by tag_dll.awk */
+#define TAG_NAMESPACE "soa"
+#endif
+
+#include <sofia-sip/soa.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sdp_tag.h>
+
+#include <string.h>
+
+char const soa_tag_namespace[] = "soa";
+
+/** Filter soa tags. */
+int soa_tag_filter(tagi_t const *f, tagi_t const *t)
+{
+  char const *ns;
+
+  if (!t || !t->t_tag)
+    return 0;
+
+  ns = t->t_tag->tt_ns; 
+  if (!ns)
+    return 0;
+
+  return ns == soa_tag_namespace || strcmp(ns, soa_tag_namespace) == 0;
+}
+
+/**@def SOATAG_ANY()
+ * 
+ * Filter tag matching any SOATAG_*() item.
+ */
+tag_typedef_t soatag_any = NSTAG_TYPEDEF(*);
+
+/**@def SOATAG_CAPS_SDP(x)
+ *  Pass parsed capability description to soa session object.
+ *
+ * @par Used with
+ *    soa_set_params() \n
+ *    soa_get_params() \n
+ *
+ * @par Parameter type
+ *    #sdp_session_t *
+ *
+ * @par Values
+ *    #sdp_session_t describing @soa capabilities
+ *
+ * Corresponding tag taking reference parameter is SOATAG_CAPS_SDP_REF()
+ */
+tag_typedef_t soatag_caps_sdp = SDPTAG_TYPEDEF(caps_sdp);
+
+/**@def SOATAG_CAPS_SDP_STR(x)
+ *  Pass capability description to @soa session object.
+ *
+ * @par Used with
+ *    soa_set_param() \n
+ *    soa_get_params() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    String containing SDP description of @soa capabilities
+ *
+ * Corresponding tag taking reference parameter is SOATAG_CAPS_SDP_STR_REF()
+ */
+tag_typedef_t soatag_caps_sdp_str = STRTAG_TYPEDEF(caps_sdp_str);
+
+/**@def SOATAG_LOCAL_SDP(x)
+ *  Get parsed local session description from soa session object.
+ *
+ * @par Used with
+ *    soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    #sdp_session_t *
+ *
+ * @par Values
+ *    pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_LOCAL_SDP_REF()
+ *
+ * @sa soa_get_local_sdp(), SOATAG_LOCAL_SDP_STR(), SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR().
+ */
+tag_typedef_t soatag_local_sdp = SDPTAG_TYPEDEF(local_sdp);
+
+/**@def SOATAG_LOCAL_SDP_STR(x)
+ * Get local session description as a string from soa session object.
+ *
+ * @par Used with
+ *    soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *  String containing SDP offer or answer.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_LOCAL_SDP_STR_REF()..
+ *
+ * @sa soa_get_local_sdp(), SOATAG_LOCAL_SDP(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR().
+ */
+tag_typedef_t soatag_local_sdp_str = STRTAG_TYPEDEF(local_sdp_str);
+
+/**@def SOATAG_REMOTE_SDP(x)
+ *  Pass parsed remote session description to soa session object.
+ *
+ * @par Used with
+ *    soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    #sdp_session_t *
+ *
+ * @par Values
+ *    pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_REMOTE_SDP_REF()
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_remote_sdp = SDPTAG_TYPEDEF(remote_sdp);
+
+/**@def SOATAG_REMOTE_SDP_STR(x)
+ *  Pass media description file name to the NUA stack.
+ *
+ * Pass name of media description file that contains media templates
+ * (normally mss.sdp) to the NUA stack.
+ *
+ * @par Used with
+ *    soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    String containing SDP description received from remote end.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_REMOTE_SDP_STR_REF()
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), SOATAG_REMOTE_SDP(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_remote_sdp_str = STRTAG_TYPEDEF(remote_sdp_str);
+
+/**@def SOATAG_USER_SDP(x)
+ *  Pass parsed user session description to soa session object.
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, consisting just sdp_session_t structures, sdp_media_t
+ * structures and sdp_rtpmap_t structures listing te supported media, used
+ * RTP port number, and RTP payload descriptions of supported codecs.
+ *
+ * When generating the offer or answer the user SDP is augmented with the
+ * required SDP lines (v=, o=, t=, c=, a=rtpmap, etc.) as required. The
+ * complete offer or answer generated by @soa is passed in
+ * SOATAG_LOCAL_SDP() (SOATAG_LOCAL_SDP_STR() contains same in text format).
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    #sdp_session_t *
+ *
+ * @par Values
+ *    pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_USER_SDP_REF()
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_user_sdp = SDPTAG_TYPEDEF(user_sdp);
+
+/**@def SOATAG_USER_SDP_STR(x)
+ * Pass unparsed user session description to soa session object.
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, listing just m= lines with the port numbers and RTP payload
+ * numbers of supported codecs, like 
+ * @code
+ *   SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8")
+ * @endcode
+ * When generating the offer or answer the user SDP is augmented with the
+ * required SDP lines (v=, o=, t=, c=, a=rtpmap, etc.) as required. The
+ * complete offer or answer generated by @soa is passed in
+ * SOATAG_LOCAL_SDP_STR() (SOATAG_LOCAL_SDP() contains session in parsed
+ * format).
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    String containing minimal SDP description.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_USER_SDP_STR_REF()
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), SOATAG_USER_SDP(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR()
+ */
+tag_typedef_t soatag_user_sdp_str = STRTAG_TYPEDEF(user_sdp_str);
+
+/**@def SOATAG_AF(x)
+ *
+ * Preferred address family for media.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    enum #soa_af {
+ *      #SOA_AF_ANY,
+ *      #SOA_AF_IP4_ONLY, #SOA_AF_IP6_ONLY,
+ *      #SOA_AF_IP4_IP6,  #SOA_AF_IP6_IP4
+ *    } 
+ *
+ * @par Values
+ *    - #SOA_AF_ANY       (0) any address family (default)
+ *    - #SOA_AF_IP4_ONLY  (1) only IP version 4
+ *    - #SOA_AF_IP6_ONLY  (2) only IP version 6
+ *    - #SOA_AF_IP4_IP6   (3) either IP version 4 or 6, version 4 preferred
+ *    - #SOA_AF_IP6_IP4   (4) either IP version 4 or 6, version 6 preferred
+ *
+ * Corresponding tag taking reference parameter is SOATAG_AF_REF()
+ *
+ * @sa SOATAG_ADDRESS()
+ */
+tag_typedef_t soatag_af = INTTAG_TYPEDEF(af);
+
+
+/**@def SOATAG_ADDRESS(x)
+ *
+ * Pass media address.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    NUL-terminated C string containing a domain name,
+ *    IPv4 address, or IPv6 address.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ADDRESS_REF()
+ *
+ * @sa SOATAG_AF()
+ */
+tag_typedef_t soatag_address = STRTAG_TYPEDEF(address);
+
+
+/**@def SOATAG_RTP_SELECT(x)
+ *
+ * When generating answer or second offer, @soa can include all the supported
+ * codecs, only one codec, or only the codecs supported by both ends in the
+ * list of payload types on the m= line.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    enum { 
+ *      #SOA_RTP_SELECT_SINGLE, #SOA_RTP_SELECT_COMMON, #SOA_RTP_SELECT_ALL
+ *    } \n
+ *    (int in range 0..2)
+ *
+ * @par Values
+ *    - #SOA_RTP_SELECT_SINGLE (0) - select the best common codec
+ *    - #SOA_RTP_SELECT_COMMON (1) - select all common codecs
+ *    - #SOA_RTP_SELECT_ALL (2) - select all local codecs
+ *
+ * The default value is 0, only one RTP codec is selected. Note, however,
+ * that if there is no common codec (no local codec is supported by remote
+ * end), all the codecs are included in the list. In that case the media
+ * line is rejected, too, unless SOATAG_RTP_MISMATCH(1) has been used.
+ *
+ * Corresponding tag taking a reference parameter is SOATAG_RTP_SELECT_REF().
+ *
+ * @sa SOATAG_RTP_MISMATCH(), SOATAG_RTP_SORT(), SOATAG_AUDIO_AUX()
+ */
+tag_typedef_t soatag_rtp_select = INTTAG_TYPEDEF(rtp_select);
+
+
+/**@def SOATAG_AUDIO_AUX(x)
+ *
+ * The named audio codecs are considered auxiliary, that is, they are
+ * considered as common codec only when they are the only codec listed on
+ * the media line.
+ * 
+ * When generating answer or second offer soa includes auxiliary audio
+ * codecs in the list of codecs even if it is selecting only one codec or
+ * common codecs.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    A string with whitespace separated list of codec names.
+ *
+ * @par Values
+ *    E.g., "telephone-event cn".
+ *
+ * By default, there are no auxiliary audio codecs.
+ *
+ * Corresponding tag taking a reference parameter is
+ * SOATAG_AUDIO_AUX_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_RTP_SORT()
+ */
+tag_typedef_t soatag_audio_aux = STRTAG_TYPEDEF(audio_aux);
+
+/**@def SOATAG_RTP_SORT(x)
+ *
+ * When selecting the common codecs, soa can either select first local codec
+ * supported by remote end, or first remote codec supported by local codecs. 
+ * The preference is indicated with ordering: the preferred codec is
+ * first and so on.
+ * 
+ * The auxiliary audio codecs (specified with SOATAG_AUDIO_AUX()) are listed
+ * after other codecs.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    enum {
+ *      #SOA_RTP_SORT_DEFAULT, #SOA_RTP_SORT_LOCAL, #SOA_RTP_SORT_REMOTE
+ *    } \n
+ *    (int in range 0..2)
+ *
+ * @par Values
+ *    - #SOA_RTP_SORT_DEFAULT (0) - select by local preference
+ *            if media is recvonly, remote preference othewise
+ *    - #SOA_RTP_SORT_LOCAL   (1) - always select by local preference
+ *    - #SOA_RTP_SORT_REMOTE  (2) - always select by remote preference
+ *
+ * The default value is #SOA_RTP_SORT_DEFAULT (0).
+ *
+ * Corresponding tag taking reference parameter is SOATAG_RTP_SORT_REF()
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_AUDIO_AUX()
+*/
+tag_typedef_t soatag_rtp_sort = INTTAG_TYPEDEF(rtp_sort);
+
+
+/**@def SOATAG_RTP_MISMATCH(x)
+ *
+ * Accept media line even if the SDP negotation code determines that there
+ * are no common codecs between local and remote media. Normally, if the soa
+ * determines there are no common codecs, the media line is rejected.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    Boolean (int)
+ *
+ * @par Values
+ *    0 - reject media if there are no common codecs \n
+ *    1 (!= 0) - accept media even if there are no common codecs \n
+ *
+ * Default value is 0.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_RTP_MISMATCH_REF()
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_AUDIO_AUX()
+ */
+tag_typedef_t soatag_rtp_mismatch = BOOLTAG_TYPEDEF(rtp_mismatch);
+
+
+/**@def SOATAG_ACTIVE_AUDIO(x)
+ * 
+ * Audio session status.
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ *    enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED, 
+ *           #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY, 
+ *           #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ *    - #SOA_ACTIVE_REJECTED  (-8)
+ *    - #SOA_ACTIVE_INACTIVE  (0)
+ *    - #SOA_ACTIVE_SENDONLY  (1)
+ *    - #SOA_ACTIVE_RECVONLY  (2)
+ *    - #SOA_ACTIVE_SENDRECV  (3)
+ *
+ *  Corresponding tag taking reference parameter is SOATAG_ACTIVE_AUDIO_REF()
+ *
+ */
+tag_typedef_t soatag_active_audio = INTTAG_TYPEDEF(active_audio);
+
+/**@def SOATAG_ACTIVE_VIDEO(x)
+ * 
+ * Video session status
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ *    enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED, 
+ *           #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY, 
+ *           #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ *    - #SOA_ACTIVE_REJECTED  (-8)
+ *    - #SOA_ACTIVE_INACTIVE  (0)
+ *    - #SOA_ACTIVE_SENDONLY  (1)
+ *    - #SOA_ACTIVE_RECVONLY  (2)
+ *    - #SOA_ACTIVE_SENDRECV  (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_VIDEO_REF()
+ */
+tag_typedef_t soatag_active_video = INTTAG_TYPEDEF(active_video);
+
+/**@def SOATAG_ACTIVE_IMAGE(x)
+ * 
+ * Active image session status
+ *
+ * @par Used with
+ *    #nua_i_active \n
+ *    #nua_i_state \n
+ *
+ * @par Parameter type
+ *    enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED, 
+ *           #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY, 
+ *           #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ *    - #SOA_ACTIVE_REJECTED  (-8)
+ *    - #SOA_ACTIVE_INACTIVE  (0)
+ *    - #SOA_ACTIVE_SENDONLY  (1)
+ *    - #SOA_ACTIVE_RECVONLY  (2)
+ *    - #SOA_ACTIVE_SENDRECV  (3)
+ *
+ * @par Parameter type
+ *    enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED, 
+ *           #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY, 
+ *           #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ *    - #SOA_ACTIVE_REJECTED  (-8)
+ *    - #SOA_ACTIVE_INACTIVE  (0)
+ *    - #SOA_ACTIVE_SENDONLY  (1)
+ *    - #SOA_ACTIVE_RECVONLY  (2)
+ *    - #SOA_ACTIVE_SENDRECV  (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_IMAGE_REF()
+ */
+tag_typedef_t soatag_active_image = INTTAG_TYPEDEF(active_image);
+
+/**@def SOATAG_ACTIVE_CHAT(x)
+ * 
+ * Active chat session status.
+ *
+ * @par Used with
+ *    #nua_i_active \n
+ *    #nua_i_state \n
+ *
+ * @par Parameter type
+ *    enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED, 
+ *           #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY, 
+ *           #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ *    - #SOA_ACTIVE_REJECTED  (-8)
+ *    - #SOA_ACTIVE_INACTIVE  (0)
+ *    - #SOA_ACTIVE_SENDONLY  (1)
+ *    - #SOA_ACTIVE_RECVONLY  (2)
+ *    - #SOA_ACTIVE_SENDRECV  (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_CHAT_REF()
+ */
+tag_typedef_t soatag_active_chat = INTTAG_TYPEDEF(active_chat);
+
+/**@def SOATAG_SRTP_ENABLE(x)
+ *  
+ * Enable SRTP
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    boolean (int)
+ *
+ * @par Values
+ *    @c !=0 enable \n
+ *    @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is 
+ * SOATAG_SRTP_ENABLE_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_enable = BOOLTAG_TYPEDEF(srtp_enable);
+
+/**@def SOATAG_SRTP_CONFIDENTIALITY(x)
+ *  
+ * Enable SRTP confidentiality negotiation.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    boolean (int)
+ *
+ * @par Values
+ *    @c != 0 enable SRTP confidentiality \n
+ *    @c 0 disable SRTP conidentiality
+ *
+ * Corresponding tag taking reference parameter is 
+ * SOATAG_SRTP_CONFIDENTIALITY_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_confidentiality = 
+  BOOLTAG_TYPEDEF(srtp_confidentiality);
+
+/**@def SOATAG_SRTP_INTEGRITY(x)
+ *  
+ * Enable SRTP integrity protection
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    boolean (int)
+ *
+ * @par Values
+ *    @c !=0 enable \n
+ *    @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is 
+ * SOATAG_SRTP_INTEGRITY_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_integrity = BOOLTAG_TYPEDEF(srtp_integrity);
+
+/**@def SOATAG_HOLD(x)
+ *
+ * Hold media stream or streams. When putting a SIP session on hold, the
+ * application can include, e.g., SOATAG_HOLD("audio") or
+ * SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
+ * as @soa parameters. When resuming the session, it can include
+ * SOATAG_HOLD(NULL). Note that last SOATAG_HOLD() in the tag list will
+ * override the SOATAG_HOLD() tags before it.
+ *
+ * @par Used with
+ *    soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ *    character string
+ *
+ * @par Values
+ *    Comma-separated media name ("audio", "video") or wildcard ("*").
+ *
+ * Corresponding tag taking reference parameter is SOATAG_HOLD_REF()
+ *
+ * @sa soa_set_params(), nua_invite(), @ref nua_event_diagram_call_hold
+ */
+tag_typedef_t soatag_hold = STRTAG_TYPEDEF(hold);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_H
+/** Defined when <sofia-sip/soa.h> has been included. */
+#define SOA_H
+/**@file sofia-sip/soa.h  SDP Offer/Answer (RFC 3264) Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Fri Jul 15 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct soa_session soa_session_t;
+
+struct sdp_session_s;
+
+#ifndef SOA_MAGIC_T
+#define SOA_MAGIC_T void
+#endif
+
+typedef SOA_MAGIC_T soa_magic_t;
+
+typedef int soa_callback_f(soa_magic_t *arg, soa_session_t *session);
+
+SOFIAPUBFUN soa_session_t *soa_create(char const *name, su_root_t *, soa_magic_t *);
+
+SOFIAPUBFUN soa_session_t *soa_clone(soa_session_t *, su_root_t *, soa_magic_t *);
+
+SOFIAPUBFUN void soa_destroy(soa_session_t *);
+
+SOFIAPUBFUN int soa_set_params(soa_session_t *ss,
+			       tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int soa_get_params(soa_session_t const *ss, 
+			       tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN tagi_t *soa_get_paramlist(soa_session_t const *ss,
+				      tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int soa_error_as_sip_response(soa_session_t *soa, 
+					  char const **return_phrase);
+
+SOFIAPUBFUN char const *soa_error_as_sip_reason(soa_session_t *soa);
+
+SOFIAPUBFUN int soa_get_warning(soa_session_t *ss, char const **return_phrase);
+
+SOFIAPUBFUN int soa_set_capability_sdp(soa_session_t *ss, 
+				       struct sdp_session_s const *sdp,
+				       char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_capability_sdp(soa_session_t const *ss,
+				       struct sdp_session_s const **return_sdp,
+				       char const **return_sdp_str,
+				       isize_t *return_len);
+
+SOFIAPUBFUN int soa_set_remote_sdp(soa_session_t *ss, 
+				   struct sdp_session_s const *sdp,
+				   char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_remote_sdp(soa_session_t const *ss,
+				   struct sdp_session_s const **return_sdp,
+				   char const **return_sdp_str,
+				   isize_t *return_len);
+
+SOFIAPUBFUN int soa_clear_remote_sdp(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_get_remote_version(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_set_user_sdp(soa_session_t *ss, 
+				 struct sdp_session_s const *sdp,
+				 char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_user_sdp(soa_session_t const *ss,
+				 struct sdp_session_s const **return_sdp,
+				 char const **return_sdp_str,
+				 isize_t *return_len);
+
+SOFIAPUBFUN int soa_get_user_version(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_get_local_sdp(soa_session_t const *ss,
+				  struct sdp_session_s const **return_sdp,
+				  char const **return_sdp_str,
+				  isize_t *return_len);
+
+SOFIAPUBFUN char const * const * soa_sip_require(soa_session_t const *ss);
+SOFIAPUBFUN char const * const * soa_sip_supported(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_remote_sip_features(soa_session_t *ss,
+					char const * const * support,
+					char const * const * required);
+
+SOFIAPUBFUN char **soa_media_features(soa_session_t *ss, int live, su_home_t *home);
+
+SOFIAPUBFUN int soa_generate_offer(soa_session_t *, int always, soa_callback_f *);
+SOFIAPUBFUN int soa_generate_answer(soa_session_t *, soa_callback_f *);
+SOFIAPUBFUN int soa_process_answer(soa_session_t *, soa_callback_f *);
+SOFIAPUBFUN int soa_process_reject(soa_session_t *, soa_callback_f *);
+
+SOFIAPUBFUN int soa_activate(soa_session_t *, char const *option);
+SOFIAPUBFUN int soa_deactivate(soa_session_t *, char const *option);
+
+SOFIAPUBFUN void soa_terminate(soa_session_t *, char const *option);
+
+SOFIAPUBFUN int soa_is_complete(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_init_offer_answer(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_is_audio_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_video_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_image_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_chat_active(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_is_remote_audio_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_video_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_image_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_chat_active(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_tag_filter(tagi_t const *f, tagi_t const *t);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_ADD_H
+#define SOA_ADD_H
+/**@file sofia-sip/soa_add.h  Register SDP Offer/Answer Interface Instances.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+struct soa_session_actions;
+
+SOFIAPUBVAR struct soa_session_actions const soa_default_actions;
+
+SOFIAPUBFUN int soa_add(char const *name, struct soa_session_actions const *handler);
+
+SOFIAPUBFUN struct soa_session_actions const *soa_find(char const *name);
+
+SOFIA_END_DECLS
+
+#endif /* SOA_ADD_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,275 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_SESSION_H
+#define SOA_SESSION_H
+/**@file sofia-sip/soa_session.h
+ *
+ * Internal API for SDP Offer/Answer Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SOA_H
+#include "sofia-sip/soa.h"
+#endif
+#ifndef SOA_TAG_H
+#include "sofia-sip/soa_tag.h"
+#endif
+#ifndef SDP_H
+#include <sofia-sip/sdp.h>
+#endif
+#ifndef SU_STRLST_H
+#include <sofia-sip/su_strlst.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct soa_session_actions
+{
+  int sizeof_soa_session_actions;
+  int sizeof_soa_session;
+  char const *soa_name;
+  int (*soa_init)(char const *name, soa_session_t *ss, soa_session_t *parent);
+  void (*soa_deinit)(soa_session_t *ss);
+  int (*soa_set_params)(soa_session_t *ss, tagi_t const *tags);
+  int (*soa_get_params)(soa_session_t const *ss, tagi_t *tags);
+  tagi_t *(*soa_get_paramlist)(soa_session_t const *ss, 
+			       tag_type_t, tag_value_t, ...);
+  char **(*soa_media_features)(soa_session_t *, int live, su_home_t *);
+  char const * const *(*soa_sip_require)(soa_session_t const *ss);
+  char const * const *(*soa_sip_supported)(soa_session_t const *ss);
+  int (*soa_remote_sip_features)(soa_session_t *ss,
+				 char const * const * support,
+				 char const * const * required);
+  int (*soa_set_capability_sdp)(soa_session_t *, sdp_session_t *,
+				char const *, isize_t);
+  int (*soa_set_remote_sdp)(soa_session_t *, int new_version,
+			    sdp_session_t *, char const *, isize_t);
+  int (*soa_set_user_sdp)(soa_session_t *, sdp_session_t *,
+			  char const *, isize_t);
+  int (*soa_generate_offer)(soa_session_t *ss, soa_callback_f *completed);
+  int (*soa_generate_answer)(soa_session_t *ss, soa_callback_f *completed);
+  int (*soa_process_answer)(soa_session_t *ss, soa_callback_f *completed);
+  int (*soa_process_reject)(soa_session_t *ss, soa_callback_f *completed);
+  int (*soa_activate_session)(soa_session_t *ss, char const *option);
+  int (*soa_deactivate_session)(soa_session_t *ss, char const *option);
+  void (*soa_terminate_session)(soa_session_t *ss, char const *option);
+};
+
+SOFIAPUBFUN soa_session_t *soa_session_ref(soa_session_t *ss);
+SOFIAPUBFUN void soa_session_unref(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_base_init(char const *name, soa_session_t *,
+			      soa_session_t *parent);
+SOFIAPUBFUN void soa_base_deinit(soa_session_t *ss);
+SOFIAPUBFUN int soa_base_set_params(soa_session_t *ss, tagi_t const *tags);
+SOFIAPUBFUN int soa_base_get_params(soa_session_t const *ss, tagi_t *tags);
+SOFIAPUBFUN tagi_t *soa_base_get_paramlist(soa_session_t const *ss,
+					   tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN char **soa_base_media_features(soa_session_t *,
+					   int live, su_home_t *);
+SOFIAPUBFUN char const * const *soa_base_sip_require(soa_session_t const *ss);
+SOFIAPUBFUN char const * const *soa_base_sip_supported(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_base_remote_sip_features(soa_session_t *ss,
+					     char const * const *support,
+					     char const * const *required);
+SOFIAPUBFUN int soa_base_set_capability_sdp(soa_session_t *ss, 
+					    sdp_session_t *sdp,
+					    char const *, isize_t);
+SOFIAPUBFUN int soa_base_set_remote_sdp(soa_session_t *ss, 
+					int new_version,
+					sdp_session_t *sdp, char const *, isize_t);
+SOFIAPUBFUN int soa_base_set_user_sdp(soa_session_t *ss,
+				      sdp_session_t *sdp, char const *, isize_t);
+
+SOFIAPUBFUN int soa_base_generate_offer(soa_session_t *ss,
+					soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_generate_answer(soa_session_t *ss,
+					 soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_process_answer(soa_session_t *ss,
+					soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_process_reject(soa_session_t *ss,
+					soa_callback_f *completed);
+
+SOFIAPUBFUN int soa_base_activate(soa_session_t *ss, char const *option);
+SOFIAPUBFUN int soa_base_deactivate(soa_session_t *ss, char const *option);
+SOFIAPUBFUN void soa_base_terminate(soa_session_t *ss, char const *option);
+
+struct soa_description 
+{
+  sdp_session_t  *ssd_sdp;	/**< Session description  */
+  char const     *ssd_unparsed;	/**< Original session description as string */
+  char const     *ssd_str;	/**< Session description as string */
+  sdp_printer_t  *ssd_printer;	/**< SDP printer object */
+};
+
+struct soa_session
+{
+  su_home_t ss_home[1];
+
+  struct soa_session_actions const *ss_actions;
+  char const *ss_name;		/**< Our name */
+
+  su_root_t *ss_root;
+  soa_magic_t *ss_magic;	/**< Application data */
+
+  soa_callback_f *ss_in_progress;/**< Operation in progress */
+
+  /** Incremented once each time session is terminated */
+  unsigned  ss_terminated;
+
+  /* XXX - this is part of public API. we should have no bitfields here */
+
+  unsigned  ss_active:1;	/**< Session has been activated */
+
+  /* Current Offer-Answer status */
+  unsigned  ss_complete:1;	/**< Completed SDP offer-answer */
+
+  unsigned  ss_unprocessed_remote:1; /**< We have received remote SDP */
+
+  unsigned  ss_offer_sent:2;	/**< We have offered SDP */
+  unsigned  ss_answer_recv:2;	/**< We have received SDP answer */
+
+  unsigned  ss_offer_recv:2;	/**< We have received an offer */
+  unsigned  ss_answer_sent:2;	/**< We have answered (reliably, if >1) */
+  unsigned  :0;			/* Pad */
+
+  unsigned  ss_oa_rounds;	/**< Number of O/A rounds completed */
+
+  struct soa_media_activity
+  {
+    int ma_audio:4; /**< Audio activity (send/recv) */
+    int ma_video:4; /**< Video activity (send/recv) */
+    int ma_image:4; /**< Image activity (send/recv) for JPIP */
+    int ma_chat:4;  /**< Chat activity (send/recv) */
+  } ss_local_activity[1], ss_remote_activity[1];
+
+  /** Capabilities as specified by application */
+  struct soa_description ss_caps[1];
+
+  /** Session description provided by user */
+  struct soa_description ss_user[1];
+  unsigned ss_user_version;  /**< Version incremented at each change */
+
+  /** Remote session description */
+  struct soa_description ss_remote[1];
+  unsigned ss_remote_version;  /**< Version incremented at each change */
+
+  /** Local session description */
+  struct soa_description ss_local[1];
+  unsigned ss_local_user_version, ss_local_remote_version;
+  char const *ss_hold_local;
+
+  /** Previous session description (return to this if offer is rejected) */
+  struct soa_description ss_previous[1];
+  unsigned ss_previous_user_version, ss_previous_remote_version;
+  char const *ss_hold_previous;
+
+  sdp_session_t *ss_rsession;	/**< Processed remote SDP */
+
+  /** SIP features required */
+  char const * const *ss_local_required;
+  /** SIP features supported */
+  char const * const *ss_local_support;
+
+  /** SIP features required by remote */
+  char const **ss_remote_required;
+  /** SIP features supported */
+  char const **ss_remote_support;
+
+  int             ss_status;	/**< Status from last media operation */
+  char const     *ss_phrase;	/**< Phrase from last media operation */
+  char           *ss_reason;	/**< Reason generated by media operation */
+  
+
+  /* Media parameters */
+  char const     *ss_address;
+  enum soa_af     ss_af;
+  char const     *ss_hold;	/**< Media on hold locally */
+
+  char const     *ss_cname;
+
+  /* XXX - this is part of public API. we should have no bitfields here */
+
+  /* Codec handling during negotiation */
+  unsigned  ss_rtp_select:2;
+  unsigned  ss_rtp_sort:2;
+  unsigned  ss_rtp_mismatch:1;
+
+  unsigned ss_srtp_enable:1,
+    ss_srtp_confidentiality:1,
+    ss_srtp_integrity:1;
+
+  unsigned :0;			/* Pad */
+
+  int             ss_wcode;	/**< Warning code from last media operation */
+  char const     *ss_warning;	/**< Warnings text from last media operation */
+};
+
+/* ====================================================================== */
+
+SOFIAPUBFUN int soa_has_received_sdp(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_set_status(soa_session_t *ss,
+			       int status, char const *phrase);
+
+SOFIAPUBFUN void soa_set_activity(soa_session_t *ss, 
+				  sdp_media_t const *m, int remote);
+
+SOFIAPUBFUN int soa_description_set(soa_session_t *ss, 
+				    struct soa_description *ssd,
+				    sdp_session_t *sdp,
+				    char const *sdp_str,
+				    isize_t sdp_len);
+
+SOFIAPUBFUN void soa_description_free(soa_session_t *, 
+				      struct soa_description *ssd);
+
+SOFIAPUBFUN int soa_description_dup(su_home_t *, 
+				    struct soa_description *ssd,
+				    struct soa_description const *ssd0);
+
+SOFIAPUBFUN int soa_init_sdp_origin(soa_session_t *ss,
+				    sdp_origin_t *o, char buf[64]);
+SOFIAPUBFUN int soa_init_sdp_connection(soa_session_t *, 
+					sdp_connection_t *, char buf[64]);
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG   soa_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+SOFIAPUBVAR su_log_t soa_log[];
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_TAG_H
+#define SOA_TAG_H
+/**@file sofia-sip/soa_tag.h  Tags for SDP Offer/Answer Application Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SDP_TAG_H
+#include <sofia-sip/sdp_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of base SOA tags (defined in base SOA module). */
+SOFIAPUBVAR tagi_t soa_tag_list[];
+
+/** Filter tag matching any soa tag. */
+#define SOATAG_ANY()         soatag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t soatag_any;
+
+/**
+ * Media states 
+ */
+enum {
+  SOA_ACTIVE_REJECTED = -8, /**< Media rejected in negotiation */
+  SOA_ACTIVE_DISABLED = -4, /**< Media not negotiated */
+  SOA_ACTIVE_INACTIVE = 0,  /**< Media is inactive: no RTP */
+  SOA_ACTIVE_SENDONLY = 1,  /**< Media is sent only */
+  SOA_ACTIVE_RECVONLY = 2,  /**< Media is received only */
+  SOA_ACTIVE_SENDRECV = SOA_ACTIVE_SENDONLY | SOA_ACTIVE_RECVONLY
+			    /**< Media is bidirectional */
+};
+
+#define SOA_ACTIVE_DISABLED SOA_ACTIVE_DISABLED
+#define SOA_ACTIVE_REJECTED SOA_ACTIVE_REJECTED
+#define SOA_ACTIVE_INACTIVE SOA_ACTIVE_INACTIVE
+#define SOA_ACTIVE_SENDONLY SOA_ACTIVE_SENDONLY
+#define SOA_ACTIVE_RECVONLY SOA_ACTIVE_RECVONLY
+#define SOA_ACTIVE_SENDRECV SOA_ACTIVE_SENDRECV
+
+/*
+ * SOA engine and media parameters set by soa_set_params(), get by
+ * soa_get_params() or soa_get_paramlist()
+ */
+
+#define SOATAG_LOCAL_SDP(x)  soatag_local_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp;
+#define SOATAG_LOCAL_SDP_REF(x) \
+  soatag_local_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_ref;
+
+#define SOATAG_LOCAL_SDP_STR(x)  soatag_local_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str;
+#define SOATAG_LOCAL_SDP_STR_REF(x) \
+  soatag_local_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str_ref;
+
+#define SOATAG_USER_SDP(x)  soatag_user_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp;
+#define SOATAG_USER_SDP_REF(x) \
+  soatag_user_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_ref;
+
+#define SOATAG_USER_SDP_STR(x)  soatag_user_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_str;
+#define SOATAG_USER_SDP_STR_REF(x) \
+  soatag_user_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_str_ref;
+
+#define SOATAG_CAPS_SDP(x)  soatag_caps_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp;
+#define SOATAG_CAPS_SDP_REF(x) \
+  soatag_caps_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_ref;
+
+#define SOATAG_CAPS_SDP_STR(x)  soatag_caps_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_str;
+#define SOATAG_CAPS_SDP_STR_REF(x) \
+  soatag_caps_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_str_ref;
+
+#define SOATAG_REMOTE_SDP(x)  soatag_remote_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp;
+#define SOATAG_REMOTE_SDP_REF(x) \
+  soatag_remote_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_ref;
+
+#define SOATAG_REMOTE_SDP_STR(x)  soatag_remote_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_str;
+#define SOATAG_REMOTE_SDP_STR_REF(x) \
+  soatag_remote_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_str_ref;
+
+#define SOATAG_LOCAL_SDP(x)  soatag_local_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp;
+#define SOATAG_LOCAL_SDP_REF(x) \
+  soatag_local_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_ref;
+
+#define SOATAG_LOCAL_SDP_STR(x)  soatag_local_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str;
+#define SOATAG_LOCAL_SDP_STR_REF(x) \
+  soatag_local_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_session_sdp_str_ref;
+
+#define SOATAG_AF(x)             soatag_af, tag_int_v((x))
+SOFIAPUBVAR tag_typedef_t soatag_af;
+
+#define SOATAG_AF_REF(x)         soatag_af_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_af_ref;
+
+/** SOATAG_AF() parameter type */
+enum soa_af {
+  SOA_AF_ANY,			/**< Use any address family. */
+  SOA_AF_IP4_ONLY,		/**< Use IP version 4 only */
+  SOA_AF_IP6_ONLY,		/**< Use IP version 6 only */
+  SOA_AF_IP4_IP6,		/**< Prefer IP4 to IP6 */
+  SOA_AF_IP6_IP4		/**< Prefer IP6 to IP4 */
+};
+
+#define SOA_AF_ANY      SOA_AF_ANY
+#define SOA_AF_IP4_ONLY SOA_AF_IP4_ONLY
+#define SOA_AF_IP6_ONLY SOA_AF_IP6_ONLY
+#define SOA_AF_IP4_IP6  SOA_AF_IP4_IP6
+#define SOA_AF_IP6_IP4  SOA_AF_IP6_IP4
+
+#define SOATAG_ADDRESS(x)  soatag_address, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_address;
+#define SOATAG_ADDRESS_REF(x) soatag_address_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_address_ref;
+
+#define SOATAG_RTP_SELECT(x)  soatag_rtp_select, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_select;
+#define SOATAG_RTP_SELECT_REF(x)  soatag_rtp_select_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_select_ref;
+
+/** Parameter type for SOATAG_RTP_SELECT() */
+enum { 
+  SOA_RTP_SELECT_SINGLE,	/**< Select the best common codec */
+  SOA_RTP_SELECT_COMMON,	/**< Select all common codecs */
+  SOA_RTP_SELECT_ALL		/**< Select all local codecs */
+ };
+
+#define SOATAG_AUDIO_AUX(x)      soatag_audio_aux, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_audio_aux;
+#define SOATAG_AUDIO_AUX_REF(x)  soatag_audio_aux_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_audio_aux_ref;
+
+#define SOATAG_RTP_SORT(x)  soatag_rtp_sort, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_sort;
+#define SOATAG_RTP_SORT_REF(x) soatag_rtp_sort_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_sort_ref;
+
+/** Parameter type for SOATAG_RTP_SORT() */
+enum {
+  SOA_RTP_SORT_DEFAULT,		/**< Select codecs by local preference
+				 *  when media is recvonly, 
+				 * remote preference othewise.
+				 */
+  SOA_RTP_SORT_LOCAL,		/**< Select codecs by local preference. */
+  SOA_RTP_SORT_REMOTE		/**< Select codecs by remote preference. */
+ };
+
+#define SOATAG_RTP_MISMATCH(x) soatag_rtp_mismatch, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_mismatch;
+#define SOATAG_RTP_MISMATCH_REF(x) soatag_rtp_mismatch_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_mismatch_ref;
+
+#define SOATAG_ACTIVE_AUDIO(x) soatag_active_audio, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_audio;
+
+#define SOATAG_ACTIVE_AUDIO_REF(x) soatag_active_audio_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_audio_ref;
+
+#define SOATAG_ACTIVE_VIDEO(x) soatag_active_video, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_video;
+
+#define SOATAG_ACTIVE_VIDEO_REF(x) soatag_active_video_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_video_ref;
+
+#define SOATAG_ACTIVE_IMAGE(x) soatag_active_image, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_image;
+
+#define SOATAG_ACTIVE_IMAGE_REF(x) soatag_active_image_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_image_ref;
+
+#define SOATAG_ACTIVE_CHAT(x) soatag_active_chat, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_chat;
+
+#define SOATAG_ACTIVE_CHAT_REF(x) soatag_active_chat_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_chat_ref;
+
+/** Enable SRTP */
+#define SOATAG_SRTP_ENABLE(x)  soatag_srtp_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_enable;
+
+#define SOATAG_SRTP_ENABLE_REF(x) soatag_srtp_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_enable_ref;
+
+#define SOATAG_SRTP_CONFIDENTIALITY(x)  soatag_srtp_confidentiality, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_confidentiality;
+#define SOATAG_SRTP_CONFIDENTIALITY_REF(x) soatag_srtp_confidentiality_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_confidentiality_ref;
+
+/** Enable SRTP integrity protection */
+#define SOATAG_SRTP_INTEGRITY(x)  soatag_srtp_integrity, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_integrity;
+
+#define SOATAG_SRTP_INTEGRITY_REF(x) \
+  soatag_srtp_integrity_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_integrity_ref;
+
+#define SOATAG_HOLD(x)           soatag_hold, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_hold;
+#define SOATAG_HOLD_REF(x)       soatag_hold_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_hold_ref;
+
+SOFIA_END_DECLS
+
+#endif /* SOA_TAG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1339 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_soa.c
+ * @brief High-level tester for Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+struct context;
+#define SOA_MAGIC_T struct context
+
+#include "sofia-sip/soa.h"
+#include "sofia-sip/soa_tag.h"
+#include "sofia-sip/soa_add.h"
+
+#include <sofia-sip/sdp.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/sip_tag.h>
+
+extern su_log_t soa_log[];
+
+char const name[] = "test_soa";
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void*)-1)
+
+struct context 
+{
+  su_home_t home[1];
+  su_root_t *root;
+
+  struct {
+    soa_session_t *a;
+    soa_session_t *b;
+  } asynch;
+
+  soa_session_t *a;
+  soa_session_t *b;
+
+  soa_session_t *completed;
+};
+
+int test_api_completed(struct context *arg, soa_session_t *session)
+{
+  return 0;
+}
+
+int test_api_errors(struct context *ctx)
+{
+  BEGIN();
+
+  char const *phrase = NULL;
+  char const *null = NULL;
+
+  TEST_1(!soa_create("default", NULL, NULL));
+  TEST_1(!soa_clone(NULL, NULL, NULL));
+  TEST_VOID(soa_destroy(NULL));
+
+  TEST_1(-1 == soa_set_params(NULL, TAG_END()));
+  TEST_1(-1 == soa_get_params(NULL, TAG_END()));
+
+  TEST_1(!soa_get_paramlist(NULL, TAG_END()));
+
+  TEST(soa_error_as_sip_response(NULL, &phrase), 500);
+  TEST_S(phrase, "Internal Server Error");
+
+  TEST_1(soa_error_as_sip_reason(NULL));
+
+  TEST_1(!soa_media_features(NULL, 0, NULL));
+
+  TEST_1(!soa_sip_require(NULL));
+  TEST_1(!soa_sip_supported(NULL));
+
+  TEST_1(-1 == soa_remote_sip_features(NULL, &null, &null));
+
+  TEST_1(soa_set_capability_sdp(NULL, NULL, NULL, -1) < 0);
+  TEST_1(soa_set_remote_sdp(NULL, NULL, NULL, -1) < 0);
+  TEST_1(soa_set_user_sdp(NULL, NULL, NULL, -1) < 0);
+
+  TEST_1(soa_get_capability_sdp(NULL, NULL, NULL, NULL) < 0);
+  TEST_1(soa_get_remote_sdp(NULL, NULL, NULL, NULL) < 0);
+  TEST_1(soa_get_user_sdp(NULL, NULL, NULL, NULL) < 0);
+  TEST_1(soa_get_local_sdp(NULL, NULL, NULL, NULL) < 0);
+
+  TEST_1(-1 == soa_generate_offer(NULL, 0, test_api_completed)); 
+
+  TEST_1(-1 == soa_generate_answer(NULL, test_api_completed)); 
+
+  TEST_1(-1 == soa_process_answer(NULL, test_api_completed)); 
+
+  TEST_1(-1 == soa_process_reject(NULL, test_api_completed));
+
+  TEST(soa_activate(NULL, "both"), -1);
+  TEST(soa_deactivate(NULL, "both"), -1);
+  TEST_VOID(soa_terminate(NULL, "both"));
+
+  TEST_1(!soa_is_complete(NULL));
+
+  TEST_1(!soa_init_offer_answer(NULL));
+
+  TEST(soa_is_audio_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_video_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_image_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_chat_active(NULL), SOA_ACTIVE_DISABLED);
+
+  TEST(soa_is_remote_audio_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_video_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_image_active(NULL), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_chat_active(NULL), SOA_ACTIVE_DISABLED);
+
+  END();
+}
+
+int test_soa_tags(struct context *ctx)
+{
+  BEGIN();
+  
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  tagi_t *t;
+
+  tagi_t const soafilter[] = {
+    { TAG_FILTER(soa_tag_filter) },
+    { TAG_NULL() }
+  };
+
+  t = tl_filtered_tlist(home, soafilter,
+			SIPTAG_FROM_STR("sip:my.domain"),
+			SOATAG_USER_SDP_STR("v=0"),
+			SOATAG_HOLD("*"),
+			TAG_END());
+  TEST_1(t);
+  TEST_P(t[0].t_tag, soatag_user_sdp_str);
+  TEST_P(t[1].t_tag, soatag_hold);
+  TEST_1(t[2].t_tag == NULL || t[2].t_tag == tag_null);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_init(struct context *ctx, char *argv[])
+{
+  BEGIN();
+
+  int n;
+
+  ctx->root = su_root_create(ctx); TEST_1(ctx->root);
+
+  ctx->asynch.a = soa_create("asynch", ctx->root, ctx); 
+  TEST_1(!ctx->asynch.a);
+
+#if 0
+  TEST_1(!soa_find("asynch"));
+  TEST_1(soa_find("default"));
+
+  n = soa_add("asynch", &soa_asynch_actions); TEST(n, 0);
+
+  TEST_1(soa_find("asynch"));
+
+  ctx->asynch.a = soa_create("asynch", ctx->root, ctx); 
+  TEST_1(ctx->asynch.a);
+
+  ctx->asynch.b = soa_create("asynch", ctx->root, ctx);
+  TEST_1(ctx->asynch.b);
+#endif
+
+  /* Create asynchronous endpoints */
+
+  ctx->a = soa_create("static", ctx->root, ctx); 
+  TEST_1(!ctx->a);
+
+  TEST_1(!soa_find("static"));
+  TEST_1(soa_find("default"));
+
+  n = soa_add("static", &soa_default_actions); TEST(n, 0);
+
+  TEST_1(soa_find("static"));
+
+  ctx->a = soa_create("static", ctx->root, ctx);
+  TEST_1(ctx->a);
+
+  ctx->b = soa_create("static", ctx->root, ctx);
+  TEST_1(ctx->b);
+
+  END();
+}
+
+int test_params(struct context *ctx)
+{
+  BEGIN();
+  int n;
+  int af;
+  char const *address;
+  char const *hold;
+  int rtp_select, rtp_sort;
+  int rtp_mismatch;
+  int srtp_enable, srtp_confidentiality, srtp_integrity;
+  soa_session_t *a = ctx->a, *b = ctx->b;
+
+  n = soa_set_params(a, TAG_END()); TEST(n, 0);
+  n = soa_set_params(b, TAG_END()); TEST(n, 0);
+
+  af = -42;
+  address = NONE;
+  hold = NONE;
+
+  rtp_select = -1, rtp_sort = -1, rtp_mismatch = -1;
+  srtp_enable = -1, srtp_confidentiality = -1, srtp_integrity = -1;
+
+  TEST(soa_get_params(a,
+		      SOATAG_AF_REF(af),
+		      SOATAG_ADDRESS_REF(address),
+		      SOATAG_HOLD_REF(hold),
+
+		      SOATAG_RTP_SELECT_REF(rtp_select),
+		      SOATAG_RTP_SORT_REF(rtp_sort),
+		      SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+		      SOATAG_SRTP_ENABLE_REF(srtp_enable),
+		      SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+		      SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+		      TAG_END()),
+       9);
+  TEST(af, SOA_AF_ANY);
+  TEST_P(address, 0);
+  TEST_P(hold, 0);
+  TEST(rtp_select, SOA_RTP_SELECT_SINGLE);
+  TEST(rtp_sort, SOA_RTP_SORT_DEFAULT);
+  TEST(rtp_mismatch, 0);
+  TEST(srtp_enable, 0);
+  TEST(srtp_confidentiality, 0);
+  TEST(srtp_integrity, 0);
+
+  TEST(soa_set_params(a,
+		      SOATAG_AF(SOA_AF_IP4_IP6),
+		      SOATAG_ADDRESS("127.0.0.1"),
+		      SOATAG_HOLD("audio"),
+
+		      SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+		      SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+		      SOATAG_RTP_MISMATCH(1),
+
+		      SOATAG_SRTP_ENABLE(1),
+		      SOATAG_SRTP_CONFIDENTIALITY(1),
+		      SOATAG_SRTP_INTEGRITY(1),
+
+		      TAG_END()),
+       9);
+  TEST(soa_get_params(a,
+		      SOATAG_AF_REF(af),
+		      SOATAG_ADDRESS_REF(address),
+		      SOATAG_HOLD_REF(hold),
+
+		      SOATAG_RTP_SELECT_REF(rtp_select),
+		      SOATAG_RTP_SORT_REF(rtp_sort),
+		      SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+		      SOATAG_SRTP_ENABLE_REF(srtp_enable),
+		      SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+		      SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+		      TAG_END()),
+       9);
+  TEST(af, SOA_AF_IP4_IP6);
+  TEST_S(address, "127.0.0.1");
+  TEST_S(hold, "audio");
+  TEST(rtp_select, SOA_RTP_SELECT_ALL);
+  TEST(rtp_sort, SOA_RTP_SORT_LOCAL);
+  TEST(rtp_mismatch, 1);
+  TEST(srtp_enable, 1);
+  TEST(srtp_confidentiality, 1);
+  TEST(srtp_integrity, 1);
+
+  /* Restore defaults */
+  TEST(soa_set_params(a,
+		      SOATAG_AF(SOA_AF_IP4_IP6),
+		      SOATAG_ADDRESS(NULL),
+		      SOATAG_HOLD(NULL),
+
+		      SOATAG_RTP_SELECT(SOA_RTP_SELECT_SINGLE),
+		      SOATAG_RTP_SORT(SOA_RTP_SORT_DEFAULT),
+		      SOATAG_RTP_MISMATCH(0),
+
+		      SOATAG_SRTP_ENABLE(0),
+		      SOATAG_SRTP_CONFIDENTIALITY(0),
+		      SOATAG_SRTP_INTEGRITY(0),
+
+		      TAG_END()),
+       9);
+
+  END();
+}
+
+int test_completed(struct context *ctx, soa_session_t *session)
+{
+  ctx->completed = session;
+  su_root_break(ctx->root);
+  return 0;
+}
+
+int test_static_offer_answer(struct context *ctx)
+{
+  BEGIN();
+  int n;
+  
+  soa_session_t *a, *b;
+
+  char const *caps = NONE, *offer = NONE, *answer = NONE;
+  isize_t capslen = -1, offerlen = -1, answerlen = -1;
+
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  char const a_caps[] = 
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 0 RTP/AVP 0 8\r\n";
+
+  char const b_caps[] = 
+    "m=audio 5004 RTP/AVP 96 8\n"
+    "m=rtpmap:96 GSM/8000\n";
+
+  TEST(soa_set_capability_sdp(ctx->a, 0, "m=audio 0 RTP/AVP 0 8", -1), 
+       1);
+  TEST(soa_set_capability_sdp(ctx->a, 0, a_caps, strlen(a_caps)), 
+       1);
+  TEST(soa_get_capability_sdp(ctx->a, NULL, &caps, &capslen), 1);
+
+  TEST_1(caps != NULL && caps != NONE);
+  TEST_1(capslen > 0);
+
+  TEST(soa_set_user_sdp(ctx->b, 0, b_caps, strlen(b_caps)), 1);
+  TEST(soa_get_capability_sdp(ctx->a, NULL, &caps, &capslen), 1);
+
+  TEST_1(a = soa_clone(ctx->a, ctx->root, ctx));
+  TEST_1(b = soa_clone(ctx->b, ctx->root, ctx));
+
+  n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 0);
+
+  n = soa_set_user_sdp(a, 0, "m=audio 5004 RTP/AVP 0 8", -1); TEST(n, 1);
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+
+  n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+
+  n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 0);
+
+  n = soa_set_params(b,
+		     SOATAG_LOCAL_SDP_STR("m=audio 5004 RTP/AVP 8"),
+		     SOATAG_AF(SOA_AF_IP4_ONLY),
+		     SOATAG_ADDRESS("1.2.3.4"),
+		     TAG_END());
+  
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(strstr(answer, "c=IN IP4 1.2.3.4"));
+
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_image_active(a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_chat_active(a), SOA_ACTIVE_DISABLED);
+
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_video_active(a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_image_active(a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_chat_active(a), SOA_ACTIVE_DISABLED);
+
+  /* 'A' will put call on hold */
+  offer = NONE;
+  TEST(soa_set_params(a, SOATAG_HOLD("*"), TAG_END()), 1);
+
+  TEST(soa_generate_offer(a, 1, test_completed), 0);
+  TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(strstr(offer, "a=sendonly"));
+  TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+  TEST(soa_generate_answer(b, test_completed), 0);
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+  TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(strstr(answer, "a=recvonly"));
+  TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+  TEST(soa_process_answer(a, test_completed), 0);
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY);
+
+  /* 'A' will release hold. */ 
+  TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1);
+
+  TEST(soa_generate_offer(a, 1, test_completed), 0);
+  TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(!strstr(offer, "a=sendonly"));
+  TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+  TEST(soa_generate_answer(b, test_completed), 0);
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+  TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(!strstr(answer, "a=recvonly"));
+  TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+  TEST(soa_process_answer(a, test_completed), 0);
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+  /* 'A' will put B on hold but this time with c=IN IP4 0.0.0.0 */
+  TEST(soa_set_params(a, SOATAG_HOLD("*"), TAG_END()), 1);
+  TEST(soa_generate_offer(a, 1, test_completed), 0);
+
+  {
+    sdp_session_t const *o_sdp;
+    sdp_session_t *sdp;
+    sdp_printer_t *p;
+    sdp_connection_t *c;
+
+    TEST(soa_get_local_sdp(a, &o_sdp, NULL, NULL), 1);
+    TEST_1(o_sdp != NULL && o_sdp != NONE);
+    TEST_1(sdp = sdp_session_dup(home, o_sdp));
+
+    /* Remove mode, change c=, encode offer */
+    if (sdp->sdp_media->m_connections)
+      c = sdp->sdp_media->m_connections;
+    else
+      c = sdp->sdp_connection;
+    TEST_1(c);
+    c->c_address = "0.0.0.0";
+    
+    TEST_1(p = sdp_print(home, sdp, NULL, 0, sdp_f_realloc));
+    TEST_1(sdp_message(p));
+    offer = sdp_message(p); offerlen = strlen(offer);
+  }
+
+  TEST(soa_set_remote_sdp(b, 0, offer, -1), 1);
+  TEST(soa_generate_answer(b, test_completed), 0);
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+  TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(strstr(answer, "a=recvonly"));
+  TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+  TEST(soa_process_answer(a, test_completed), 0);
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY);
+  TEST(soa_is_audio_active(b), SOA_ACTIVE_RECVONLY);
+  TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_RECVONLY);
+
+  /* 'A' will propose adding video. */ 
+  /* 'B' will reject. */ 
+  TEST(soa_set_params(a,
+		      SOATAG_HOLD(NULL),  /* 'A' will release hold. */ 
+		      SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8\r\n"
+					  "m=video 5006 RTP/AVP 34\r\n"),
+		      TAG_END()), 2);
+
+  TEST(soa_generate_offer(a, 1, test_completed), 0);
+  TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(!strstr(offer, "a=sendonly"));
+  TEST_1(strstr(offer, "m=video"));
+  TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+  TEST(soa_generate_answer(b, test_completed), 0);
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+  TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(!strstr(answer, "a=recvonly"));
+  TEST_1(strstr(answer, "m=video"));
+  TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+  TEST(soa_process_answer(a, test_completed), 0);
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_REJECTED);
+
+  {
+    /* Test tags */
+    sdp_session_t const *l = NULL, *u = NULL, *r = NULL;
+    sdp_media_t const *m;
+
+    TEST(soa_get_params(b, 
+			SOATAG_LOCAL_SDP_REF(l),
+			SOATAG_USER_SDP_REF(u),
+			SOATAG_REMOTE_SDP_REF(r),
+			TAG_END()), 3);
+
+    TEST_1(l); TEST_1(u); TEST_1(r);
+    TEST_1(m = l->sdp_media); TEST(m->m_type, sdp_media_audio);
+    TEST_1(!m->m_rejected);
+    TEST_1(m = m->m_next); TEST(m->m_type, sdp_media_video);
+    TEST_1(m->m_rejected);
+  }
+
+  /* 'B' will now propose adding video. */
+  /* 'A' will accept. */
+  TEST(soa_set_params(b, 
+		      SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8\r\n"
+					  "m=video 5006 RTP/AVP 34\r\n"),
+		      TAG_END()), 1);
+
+  TEST(soa_generate_offer(b, 1, test_completed), 0);
+  TEST(soa_get_local_sdp(b, NULL, &offer, &offerlen), 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(!strstr(offer, "b=sendonly"));
+  TEST_1(strstr(offer, "m=video"));
+  TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1);
+  TEST(soa_generate_answer(a, test_completed), 0);
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+  TEST(soa_get_local_sdp(a, NULL, &answer, &answerlen), 1);
+  TEST_1(answer != NULL && answer != NONE);
+  TEST_1(!strstr(answer, "b=recvonly"));
+  TEST_1(strstr(answer, "m=video"));
+  TEST(soa_set_remote_sdp(b, 0, answer, -1), 1);
+  TEST(soa_process_answer(b, test_completed), 0);
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+  
+  TEST_VOID(soa_terminate(a, NULL));
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_DISABLED);
+
+  TEST_VOID(soa_terminate(b, NULL));
+  
+  TEST_VOID(soa_destroy(a));
+  TEST_VOID(soa_destroy(b));
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_codec_selection(struct context *ctx)
+{
+  BEGIN();
+  int n;
+  
+  soa_session_t *a, *b;
+
+  char const *offer = NONE, *answer = NONE;
+  isize_t offerlen = -1, answerlen = -1;
+
+  sdp_session_t const *a_sdp, *b_sdp;
+  sdp_media_t const *m;
+  sdp_rtpmap_t const *rm;
+
+  char const a_caps[] = 
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 97\r\n"
+    "a=rtpmap:97 GSM/8000\n"
+    ;
+
+  char const b_caps[] = 
+    "m=audio 5004 RTP/AVP 96 97\n"
+    "a=rtpmap:96 G7231/8000\n"
+    "a=rtpmap:97 G729/8000\n";
+
+  TEST_1(a = soa_create("static", ctx->root, ctx));
+  TEST_1(b = soa_create("static", ctx->root, ctx));
+
+  TEST(soa_set_user_sdp(a, 0, a_caps, strlen(a_caps)), 1);
+  TEST(soa_set_user_sdp(b, 0, b_caps, strlen(b_caps)), 1);
+
+  TEST(soa_set_params(a, SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()), 1);
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 0);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_REJECTED);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_REJECTED);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G7231");
+  /* Not using payload type 97 from offer */
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 98);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(!rm->rm_next);
+
+  /* ---------------------------------------------------------------------- */
+
+  /* Re-O/A: A generates new SDP */
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  /* Re-O/A: no-one regenerates new SDP */
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 0);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  /* ---------------------------------------------------------------------- */
+
+  /* Re-O/A: accept media without common codecs */
+
+  /* Accept media without common codecs */
+  TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(1), TAG_END()));
+  TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(1), TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G7231");
+  /* Not using payload type 97 from offer */
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 98);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(!rm->rm_next);
+
+  /* ---------------------------------------------------------------------- */
+
+  /* Re-O/A: add a common codec */
+
+  /* Accept media without common codecs */
+  TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0), 
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+    "a=rtpmap:96 G729/8000\n"
+    "a=rtpmap:127 CN/8000\n"
+    ),			
+			SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
+			SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+			TAG_END()));
+  TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(0), 
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+    "a=rtpmap:96 G7231/8000\n"
+    "a=rtpmap:97 G729/8000\n"
+    "a=rtpmap:111 telephone-event/8000\n"
+    "a=fmtp:111 0-15\n"
+    ),			
+			SOATAG_AUDIO_AUX("cn telephone-event"),
+			SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+			SOATAG_RTP_SELECT(SOA_RTP_SELECT_COMMON),
+			TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, NULL, NULL); TEST(n, 1);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 3);
+  TEST_S(rm->rm_encoding, "GSM");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 0);
+  TEST_S(rm->rm_encoding, "PCMU");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 8);
+  TEST_S(rm->rm_encoding, "PCMA");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+  TEST_S(rm->rm_encoding, "CN");
+  TEST_1(!rm->rm_next);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 3);
+  TEST_S(rm->rm_encoding, "GSM");
+  /* Using payload type 96 from offer */
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+  TEST_S(rm->rm_encoding, "telephone-event");
+  TEST_1(!rm->rm_next);
+
+  /* ---------------------------------------------------------------------- */
+  /* Re-O/A: prune down to single codec. */
+
+  TEST_1(soa_set_params(a, 
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 97 96 127\r\n"
+    "a=rtpmap:96 G729/8000\n"
+    "a=rtpmap:97 GSM/8000\n"
+    "a=rtpmap:127 CN/8000\n"
+    ),			
+			SOATAG_RTP_MISMATCH(0),
+			SOATAG_RTP_SELECT(SOA_RTP_SELECT_COMMON),
+			TAG_END()));
+  TEST_1(soa_set_params(b,
+			SOATAG_RTP_MISMATCH(0),
+			SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+			SOATAG_RTP_SELECT(SOA_RTP_SELECT_SINGLE),
+			TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+  TEST_S(rm->rm_encoding, "GSM");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+  TEST_S(rm->rm_encoding, "CN");
+  TEST_1(!rm->rm_next);
+
+  /* Answering end matches payload types 
+     then sorts by local preference, 
+     then select best codec => GSM with pt 97 */
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+  TEST_S(rm->rm_encoding, "GSM");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+  TEST_S(rm->rm_encoding, "telephone-event");
+  TEST_1(!rm->rm_next);
+
+  /* ---------------------------------------------------------------------- */
+  /* Re-O/A: A generates new SDP offer with single codec only */
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+  TEST_S(rm->rm_encoding, "GSM");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+  TEST_S(rm->rm_encoding, "CN");
+  TEST_1(!rm->rm_next);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  /* Answer from B is identical to previous one */
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  /* ---------------------------------------------------------------------- */
+
+  /* Add new media - without common codecs */
+  TEST_1(soa_set_params(a,
+			SOATAG_RTP_MISMATCH(0),
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+    "a=rtpmap:96 G729/8000\n"
+    "a=rtpmap:127 CN/8000\n"
+    "m=video 5010 RTP/AVP 31\r\n"
+    "m=audio 6008 RTP/SAVP 3\n"
+    ),
+			TAG_END()));
+  TEST_1(soa_set_params(b,
+			SOATAG_RTP_MISMATCH(0),
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+    "a=rtpmap:96 G7231/8000\n"
+    "a=rtpmap:97 G729/8000\n"
+    "a=rtpmap:111 telephone-event/8000\n"
+    "a=fmtp:111 0-15\n"
+    "m=audio 6004 RTP/SAVP 96\n"
+    "a=rtpmap:96 G729/8000\n"
+    "m=video 5006 RTP/AVP 34\n"
+    ),
+			TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  /* Answer from B rejects video */
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_REJECTED);
+  TEST(soa_is_remote_video_active(a), SOA_ACTIVE_REJECTED);
+
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+  TEST_1(!m->m_next);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+  /* Rejected but tell what we support */
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+  TEST_S(rm->rm_encoding, "H263");
+  TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+  TEST_1(!m->m_next);
+
+  /* ---------------------------------------------------------------------- */
+  /* A adds H.263 to video */
+  TEST_1(soa_set_params(a,
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+    "a=rtpmap:96 G729/8000\n"
+    "a=rtpmap:127 CN/8000\n"
+    "m=video 5010 RTP/AVP 31 34\r\n"
+    "m=audio 6008 RTP/SAVP 3\n"
+    ),
+			TAG_END()));
+
+  /* B adds GSM to SRTP */
+  TEST_1(soa_set_params(b,
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+    "a=rtpmap:96 G7231/8000\n"
+    "a=rtpmap:97 G729/8000\n"
+    "a=rtpmap:111 telephone-event/8000\n"
+    "a=fmtp:111 0-15\n"
+    "m=audio 6004 RTP/SAVP 96 3\n"
+    "a=rtpmap:96 G729/8000\n"
+    "m=video 5006 RTP/AVP 34\n"
+    ),
+			TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  /* Answer from B now accepts video */
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_video_active(a), SOA_ACTIVE_SENDRECV);
+
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+  TEST_S(rm->rm_encoding, "H263");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+  TEST_S(rm->rm_encoding, "H263");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+
+  /* ---------------------------------------------------------------------- */
+  /* A drops GSM support */
+
+  TEST_1(soa_set_params(a,
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5008 RTP/AVP 0 8 96 127\r\n"
+    "a=rtpmap:96 G729/8000\n"
+    "a=rtpmap:127 CN/8000\n"
+    "m=video 5010 RTP/AVP 31 34\r\n"
+    "m=audio 6008 RTP/SAVP 3\n"
+    ),
+			TAG_END()));
+
+  /* B adds GSM to SRTP, changes IP address */
+  TEST_1(soa_set_params(b,
+			SOATAG_USER_SDP_STR(
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.3\r\n"
+    "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+    "a=rtpmap:96 G7231/8000\n"
+    "a=rtpmap:97 G729/8000\n"
+    "a=rtpmap:111 telephone-event/8000\n"
+    "a=fmtp:111 0-15\n"
+    "m=audio 6004 RTP/SAVP 96 3\n"
+    "a=rtpmap:96 G729/8000\n"
+    "m=video 5006 RTP/AVP 34\n"
+    ),
+			TAG_END()));
+
+  n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+  TEST_1(offer != NULL && offer != NONE);
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+  n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+  n = soa_generate_answer(b, test_completed); TEST(n, 0);
+  /* Answer from B now accepts video */
+  n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+  TEST_1(answer != NULL && answer != NONE);
+  /* Check that updated c= line is propagated */
+  TEST_1(b_sdp->sdp_connection);
+  TEST_S(b_sdp->sdp_connection->c_address, "127.0.0.3");
+  n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+  n = soa_process_answer(a, test_completed); TEST(n, 0);
+  n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+  TEST_1(soa_is_complete(b));
+  TEST(soa_activate(b, NULL), 0);
+
+  TEST_1(soa_is_complete(a));
+  TEST(soa_activate(a, NULL), 0);
+
+  TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_video_active(a), SOA_ACTIVE_SENDRECV);
+
+  TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+  TEST_S(rm->rm_encoding, "CN");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+  TEST_S(rm->rm_encoding, "H263");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+
+  TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+  TEST_S(rm->rm_encoding, "G729");
+  TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+  TEST_S(rm->rm_encoding, "telephone-event");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+  TEST_S(rm->rm_encoding, "H263");
+  TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+  TEST_1(!m->m_next);
+
+  /* ---------------------------------------------------------------------- */
+
+  TEST_VOID(soa_terminate(a, NULL));
+  TEST_VOID(soa_terminate(b, NULL));
+  
+  TEST_VOID(soa_destroy(a));
+  TEST_VOID(soa_destroy(b));
+
+  END();
+}
+
+
+int test_asynch_offer_answer(struct context *ctx)
+{
+  BEGIN();
+
+#if 0
+  int n;
+  
+  char const *caps = NONE, *offer = NONE, *answer = NONE;
+  isize_t capslen = -1, offerlen = -1, answerlen = -1;
+
+  char const a[] = 
+    "v=0\r\n"
+    "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+    "c=IN IP4 127.0.0.2\r\n"
+    "m=audio 5004 RTP/AVP 0 8\r\n";
+
+  char const b[] = 
+    "v=0\n"
+    "o=right 93298573265 321974 IN IP4 127.0.0.3\n"
+    "c=IN IP4 127.0.0.3\n"
+    "m=audio 5006 RTP/AVP 96\n"
+    "m=rtpmap:96 GSM/8000\n";
+
+  n = soa_set_capability_sdp(ctx->asynch.a, 0, 
+			     "m=audio 5004 RTP/AVP 0 8", -1); 
+  TEST(n, 1);
+
+  n = soa_set_capability_sdp(ctx->asynch.a, 0, a, strlen(a)); TEST(n, 1);
+  n = soa_get_capability_sdp(ctx->asynch.a, 0, &caps, &capslen); TEST(n, 1);
+
+  TEST_1(caps != NULL && caps != NONE);
+  TEST_1(capslen > 0);
+
+  n = soa_set_capability_sdp(ctx->asynch.b, 0, b, strlen(b)); TEST(n, 1);
+
+  n = soa_generate_offer(ctx->asynch.a, 1, test_completed); TEST(n, 1);
+
+  su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.a); 
+  ctx->completed = NULL;
+
+  n = soa_get_local_sdp(ctx->asynch.a, 0, &offer, &offerlen); TEST(n, 1);
+
+  n = soa_set_remote_sdp(ctx->asynch.b, 0, offer, offerlen); TEST(n, 1);
+
+  n = soa_generate_answer(ctx->asynch.b, test_completed); TEST(n, 1);
+
+  su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.b); 
+  ctx->completed = NULL;
+
+  TEST_1(soa_is_complete(ctx->asynch.b));
+  TEST(soa_activate(ctx->asynch.b, NULL), 0);
+
+  n = soa_get_local_sdp(ctx->asynch.b, 0, &answer, &answerlen); TEST(n, 1);
+
+  n = soa_set_remote_sdp(ctx->asynch.a, 0, answer, answerlen); TEST(n, 1);
+
+  n = soa_process_answer(ctx->asynch.a, test_completed); TEST(n, 1);
+
+  su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.a); 
+  ctx->completed = NULL;
+
+  TEST_1(soa_is_complete(ctx->asynch.a));
+  TEST(soa_activate(ctx->asynch.a, NULL), 0);
+
+  TEST(soa_is_audio_active(ctx->asynch.a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_video_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_image_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_chat_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+  TEST(soa_is_remote_audio_active(ctx->asynch.a), SOA_ACTIVE_SENDRECV);
+  TEST(soa_is_remote_video_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_image_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_chat_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+  TEST(soa_deactivate(ctx->asynch.a, NULL), 0);
+  TEST(soa_deactivate(ctx->asynch.b, NULL), 0);
+
+  TEST_VOID(soa_terminate(ctx->asynch.a, NULL));
+
+  TEST(soa_is_audio_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+  TEST(soa_is_remote_audio_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+  TEST_VOID(soa_terminate(ctx->asynch.b, NULL));
+
+#endif
+  
+  END();
+}
+
+int test_deinit(struct context *ctx)
+{
+  BEGIN();
+  END();
+}
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v|-q] [-l level] [-p outbound-proxy-uri]\n", 
+	  name);
+  exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0, quit_on_single_failure = 0;
+  int i, o_attach = 0, o_alarm = 1;
+
+  struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-q") == 0)
+      tstflags &= ~tst_verbatim;
+    else if (strcmp(argv[i], "-1") == 0)
+      quit_on_single_failure = 1;
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      int level = 3;
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage();
+      
+      su_log_set_level(soa_log, level);
+    }
+    else if (strcmp(argv[i], "--attach") == 0) {
+      o_attach = 1;
+    }
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (argv[i][0] != '-') {
+      break;
+    }
+    else
+      usage();
+  }
+
+  if (o_attach) {
+    char line[10];
+    printf("%s: pid %u\n", name, getpid());
+    printf("<Press RETURN to continue>\n");
+    fgets(line, sizeof line, stdin);
+  }
+#if HAVE_ALARM
+  else if (o_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  su_init();
+
+  if (!(TSTFLAGS & tst_verbatim)) {
+    su_log_soft_set_level(soa_log, 0);
+  }
+
+#define SINGLE_FAILURE_CHECK()						\
+  do { fflush(stdout);							\
+    if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+  } while(0)
+
+  retval |= test_api_errors(ctx); SINGLE_FAILURE_CHECK();
+  retval |= test_soa_tags(ctx); SINGLE_FAILURE_CHECK();
+  retval |= test_init(ctx, argv + i); SINGLE_FAILURE_CHECK();
+  if (retval == 0) {
+    retval |= test_params(ctx); SINGLE_FAILURE_CHECK();
+    retval |= test_static_offer_answer(ctx); SINGLE_FAILURE_CHECK();
+    retval |= test_codec_selection(ctx); SINGLE_FAILURE_CHECK();
+
+    retval |= test_asynch_offer_answer(ctx); SINGLE_FAILURE_CHECK();
+  }
+  retval |= test_deinit(ctx); SINGLE_FAILURE_CHECK();
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+
+built-sources: $(BUILT_SOURCES)
+
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+# rules for building tag files
+
+TAG_AWK=$(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+if ENABLE_COVERAGE
+coverage:
+	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+endif
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$TTL 86400
+@	IN	SOA	localhost.	root.localhost (
+			1 ; serial
+			28800 ; refresh
+			7200 ; retry
+			604800 ; expire	
+			86400 ; ttk
+			)
+
+
+@	IN	NS	localhost.
+
+1	IN	PTR	localhost.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+$ORIGIN 188.2.194.in-addr.arpa.
+$TTL     60
+@ 	 IN SOA ns root (
+	     2002042901 ; SERIAL
+	     7200       ; REFRESH
+	     600        ; RETRY
+	     36000000   ; EXPIRE
+	     120        ; MINIMUM
+	     )
+	       	
+	    NS	 ns.example.com.
+
+133	    PTR  sip00.example.com.
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$ORIGIN 0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int.
+$TTL     60
+@ 	 IN SOA ns root (
+	     2002042901 ; SERIAL
+	     7200       ; REFRESH
+	     600        ; RETRY
+	     36000000   ; EXPIRE
+	     120        ; MINIMUM
+	     )
+	       	
+	    NS	 ns.example.com.
+
+c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0 PTR  sip01.example.com.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$ORIGIN 0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa.
+$TTL     60
+@ 	 IN SOA ns root (
+	     2002042901 ; SERIAL
+	     7200       ; REFRESH
+	     600        ; RETRY
+	     36000000   ; EXPIRE
+	     120        ; MINIMUM
+	     )
+	       	
+	    NS	 ns.example.com.
+
+c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0 PTR  sip01.example.com.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+2006-05-03  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sres.c: Added win32 registry name server discovery. Based on a
+	patch from Dimitri E. Prado.
+
+	* sres.c: Decreased update interval to 180secs (SRES_UPDATE_INTERVAL_SECS).
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+PROJECT_NAME         = "sresolv"
+OUTPUT_DIRECTORY     = ../docs/html/sresolv
+
+INPUT 		     =  sofia-sip sofia-resolv sresolv.docs .
+
+ at INCLUDE 	     = ../docs/Doxyfile.conf
+
+ALIASES             += CFILE="@internal @file" IFILE="@internal @file"
+
+TAGFILES            += ../docs/su.doxytags=../su
+GENERATE_TAGFILE     = ../docs/sresolv.doxytags
+
+PREDEFINED          += SRES_CONTEXT_T="struct sres_context_s"
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,64 @@
+#
+# Makefile.am for sresolv module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsresolv.la
+
+check_PROGRAMS = 	test_sresolv
+
+TESTS = 		run_test_sresolv
+
+TESTS_ENVIRONMENT =	$(SHELL)
+
+CLEANFILES =		resolv.conf error.conf named.conf.tmp \
+			.test_sresolv.api.conf.?????? \
+			named.run
+
+LDADD = 		../url/liburl.la ../bnf/libbnf.la \
+			libsresolv.la \
+			../su/libsu.la
+
+test_sresolv_LDFLAGS =	-static
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/sresolv.h \
+			sofia-resolv/sres.h \
+			sofia-resolv/sres_config.h \
+			sofia-resolv/sres_async.h \
+			sofia-resolv/sres_cache.h \
+			sofia-resolv/sres_record.h
+
+libsresolv_la_SOURCES =	sres.c sres_cache.c sres_blocking.c sresolv.c
+
+COVERAGE_INPUT = 	$(libsresolv_la_SOURCES) $(include_sofia_HEADERS)
+
+# ----------------------------------------------------------------------
+# Distribution
+
+EXTRA_DIST =		Doxyfile sresolv.docs
+
+dist_noinst_DATA = run_test_sresolv \
+	root.zone rndc.conf \
+	127.zone 194.2.188 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 example.com \
+	3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,713 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sresolv module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsresolv_la_SOURCES) test_sresolv.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = test_sresolv$(EXEEXT)
+DIST_COMMON = $(dist_noinst_DATA) $(nobase_include_sofia_HEADERS) \
+	$(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sresolv
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsresolv_la_LIBADD =
+am_libsresolv_la_OBJECTS = sres.lo sres_cache.lo sres_blocking.lo \
+	sresolv.lo
+libsresolv_la_OBJECTS = $(am_libsresolv_la_OBJECTS)
+test_sresolv_SOURCES = test_sresolv.c
+test_sresolv_OBJECTS = test_sresolv.$(OBJEXT)
+test_sresolv_LDADD = $(LDADD)
+test_sresolv_DEPENDENCIES = ../url/liburl.la ../bnf/libbnf.la \
+	libsresolv.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsresolv_la_SOURCES) test_sresolv.c
+DIST_SOURCES = $(libsresolv_la_SOURCES) test_sresolv.c
+DATA = $(dist_noinst_DATA)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = $(SHELL)
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsresolv.la
+TESTS = run_test_sresolv
+CLEANFILES = resolv.conf error.conf named.conf.tmp \
+			.test_sresolv.api.conf.?????? \
+			named.run
+
+LDADD = ../url/liburl.la ../bnf/libbnf.la \
+			libsresolv.la \
+			../su/libsu.la
+
+test_sresolv_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+			sofia-sip/sresolv.h \
+			sofia-resolv/sres.h \
+			sofia-resolv/sres_config.h \
+			sofia-resolv/sres_async.h \
+			sofia-resolv/sres_cache.h \
+			sofia-resolv/sres_record.h
+
+libsresolv_la_SOURCES = sres.c sres_cache.c sres_blocking.c sresolv.c
+COVERAGE_INPUT = $(libsresolv_la_SOURCES) $(include_sofia_HEADERS)
+
+# ----------------------------------------------------------------------
+# Distribution
+EXTRA_DIST = Doxyfile sresolv.docs
+dist_noinst_DATA = run_test_sresolv \
+	root.zone rndc.conf \
+	127.zone 194.2.188 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 example.com \
+	3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/sresolv/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/sresolv/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsresolv.la: $(libsresolv_la_OBJECTS) $(libsresolv_la_DEPENDENCIES) 
+	$(LINK)  $(libsresolv_la_LDFLAGS) $(libsresolv_la_OBJECTS) $(libsresolv_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_sresolv$(EXEEXT): $(test_sresolv_OBJECTS) $(test_sresolv_DEPENDENCIES) 
+	@rm -f test_sresolv$(EXEEXT)
+	$(LINK) $(test_sresolv_LDFLAGS) $(test_sresolv_OBJECTS) $(test_sresolv_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres_blocking.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres_cache.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sresolv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sresolv.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-resolv $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+;
+; Zone file for example.com
+;
+$TTL     60
+@ 	IN SOA ns root (
+	    2002042901 ; SERIAL
+	    7200       ; REFRESH
+	    600        ; RETRY
+	    36000000   ; EXPIRE
+	    60         ; MINIMUM
+	    )
+	NS	ns.example.com.
+	;;  order pref flags service           regexp  replacement
+        NAPTR 20 50 "s" "SIPS+D2T" "" _sips._tcp
+        NAPTR 80 25 "s" "SIP+D2T" "" _sip._tcp
+        NAPTR 40 15 "s" "SIP+D2U" "" _sip._udp
+        NAPTR 50 15 "u" "TEST+D2U" "/(tst:([^@]+@))?example.com$/\\1operator.com/i" .
+	MX 10 mgw00
+	MX 10 mgw01
+	MX 10 mgw02
+	MX 100 smtp.example.net.
+   	TXT foobar
+
+ns	A	127.0.0.2
+	AAAA	::2
+	A6	0 ::2
+
+oldns	A	194.2.188.133
+	A6	0 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+
+_sip._udp	SRV 1 100 5060 sip00
+		SRV 1 100 5060 sip01
+		SRV 1 50 5060 sip02
+_sips._tcp	SRV 3 100 5061 sip00
+		SRV 5 10 5060 sip01
+		SRV 4 50 5050 sip02
+_sip._tcp	SRV 2 100 5060 sip00
+		SRV 2 100 5060 sip01
+		SRV 2 50 5060 sip02
+
+_sips._udp	SRV 3 100 5061 sip00
+		SRV 4 50 5051 sip02
+		SRV 5 10 5061 sip01
+
+sip	CNAME	sip00
+
+subnet  A6	0 3ff0:0::
+labnet	A6	23 0:12:3012:: subnet
+sublab	A6	48 0:0:0:c006:: labnet
+mynet	A6	56 0:0:0:c006:: sublab
+a6	A6	64 ::0a08:20ff:fe7d:e7ac mynet
+alias6  A6      128 a6
+full	A6	0 3ff0:12:3012:c006:0a08:20ff:fe7d:e7ac
+
+sip00	A	194.2.188.133
+	AAAA	3ff0:0010:3012:c000:02c0:95ff:fee2:4b78 
+
+sip01	A	194.2.188.134
+	AAAA	3ff0:0012:3012:c006:0a08:20ff:fe7d:e7ac
+
+sip02	A	194.2.188.135
+	AAAA	3ffe:1200:3012:c006:0206:5bff:fe55:462f
+
+sip03	A	194.2.188.136
+	AAAA	3ffe:1200:3012:c000:0206:5bff:fe55:4630
+
+mgw00	A	194.2.188.130
+	AAAA	3ffe:1200:3012:c000:02c0:95ff:fee2:4b78
+
+mgw01	A	194.2.188.131
+	AAAA	3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac
+
+mgw02	A	194.2.188.132
+	AAAA	3ffe:1200:3012:c000:0206:5bff:fe55:462f
+
+a	A	194.2.188.137
+aaaa	AAAA	3ffe:1200:3012:c000:0206:5bff:fe55:462f
+
+$ORIGIN iptel
+@	A	194.2.188.133
+	AAAA	3ffe:1200:3012:c000:200:5eff:fe00:106
+	NAPTR 50 50 "s" "SIPS+D2T" "" _sips._tcp.iptel
+        NAPTR 90 50 "s" "SIP+D2T"  "" _sip._tcp.iptel
+        NAPTR 80 50 "s" "SIP+D2U"  "" _sip._udp.iptel
+
+_sip._udp  SRV 0 100 5060 iptel
+_sip._tcp  SRV 1 100 5060 iptel
+_sips._tcp SRV 1 100 5061 iptel

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,33 @@
+options {
+	pid-file "/tmp/named.pid";
+};
+
+zone "example.com" in {
+        type master;
+        file "example.com";
+};
+
+zone "." in {
+        type master;
+        file "root.zone";
+};
+
+zone "188.2.194.in-addr.arpa" in {
+        type master;
+	file "194.2.188";
+};
+
+zone "0.0.127.in-addr.arpa" in {
+        type master;
+	file "127.zone";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int" in {
+        type master;
+	file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa" in {
+        type master;
+	file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa";
+};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,5 @@
+foo bar foobar
+nameserver 137.0.0.1
+nameserver 182.21.40.170
+#nameserver 127.0.0.1
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,321 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file resolve_sip.c Use sresolv library to resolve a SIP or SIPS domain.
+ *
+ * This is an example program for @b sresolv library. 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @par Created: Tue Jul 16 18:50:14 2002 ppessi
+ *
+ *
+ */
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Typesafe */
+#define SRES_CONTEXT_T struct context
+
+#include "sofia-sip/sresolv.h"
+
+char const name[] = "sip_resolve";
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <poll.h>
+
+enum progress {
+  querying_naptr,
+  querying_srv,
+  querying_cname,
+  querying_a6,
+  querying_aaaa,
+  querying_a
+};
+
+/* Application context */
+struct context
+{
+  sres_resolver_t     *sres;
+  int                  sr_exitcode;
+  int                  sr_ready;
+
+  char const          *sr_canon;
+  int                  sr_sips;
+  char const          *sr_tport;
+
+  sres_query_t        *sr_query;
+  unsigned short       sr_port;
+
+  int                  sr_n_sockets;
+  sres_socket_t       *sr_sockets;
+  struct pollfd       *sr_pollfds;
+
+#if 0
+  char const          *sr_domain;
+
+  enum progress        sr_progress;
+  sres_naptr_record_t *sr_naptr;
+  sres_srv_record_t   *sr_srv;
+  sres_cname_record_t *sr_cname;
+  sres_aaaa_record_t  *sr_aaaa;
+  sres_a6_record_t    *sr_a6;
+  sres_a_record_t     *sr_a;
+#endif
+};
+
+static int query_srv(struct context *sr, char const *domain);
+static int query_a(struct context *sr, char const *domain);
+
+/* Process NAPTR records */
+static 
+void answer_to_naptr_query(sres_context_t *sr, 
+			   sres_query_t *q, 
+			   sres_record_t *answers[])
+{
+  int i;
+
+  sr->sr_query = NULL;
+
+  /* Sort NAPTR records by the order. */
+  sres_sort_answers(sr->sres, answers);  
+
+  for (i = 0; answers && answers[i]; i++) {
+    sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+    if (na->na_record->r_status)
+      /* There was an error */
+      continue;
+
+    printf("naptr: %s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
+	   na->na_record->r_name, na->na_record->r_ttl, 
+	   na->na_order, na->na_prefer, 
+	   na->na_flags, na->na_services,
+	   na->na_regexp, na->na_replace);
+
+    switch (na->na_flags[0]) {
+    case 's': /* srv */
+      if (strncasecmp("SIP+", na->na_services, 4))
+	/* Something else but SIP */
+	break;
+      query_srv(sr, na->na_replace);
+      sres_free_answers(sr->sres, answers);
+      return;
+
+    case 'a':
+      if (strncasecmp("SIP+", na->na_services, 4))
+	/* Something else but SIP */
+	break;
+      query_a(sr, na->na_replace);
+      sres_free_answers(sr->sres, answers);
+      return;
+    }
+  }
+
+  query_a(sr, /* sr->sr_uri->url_host */ sr->sr_canon);
+
+  sres_free_answers(sr->sres, answers);
+}
+
+static
+int query_naptr(struct context *sr, char const *domain)
+{
+  sres_record_t **answers;
+
+  answers = sres_cached_answers(sr->sres, sres_type_naptr, domain);
+
+  if (answers) {
+    answer_to_naptr_query(sr, NULL, answers);
+    return 0;
+  }
+  else {
+    sr->sr_query = sres_query_make(sr->sres, answer_to_naptr_query, sr,
+				   sr->sr_sockets[0], sres_type_naptr, domain);
+    return sr->sr_query ? 0 : -1;
+  }
+}
+
+/* Process SRV records */
+static 
+void answer_to_srv_query(sres_context_t *sr, sres_query_t *q, 
+			 sres_record_t *answers[])
+{
+  int i;
+
+  sr->sr_query = NULL;
+
+  sres_sort_answers(sr->sres, answers);  /* Sort SRV records by the priority. */
+
+  for (i = 0; answers && answers[i]; i++) {
+    sres_srv_record_t const *srv = answers[i]->sr_srv;
+    if (srv->srv_record->r_status)
+      /* There was an error */
+      continue;
+    sr->sr_port = srv->srv_port;
+    query_a(sr, srv->srv_target);
+    return;
+  }
+
+  query_a(sr, /* sr->sr_uri->url_host */ sr->sr_canon);
+
+  sres_free_answers(sr->sres, answers);
+}
+
+static
+int query_srv(struct context *sr, char const *domain)
+{
+  sres_record_t **answers;
+
+  answers = sres_cached_answers(sr->sres, sres_type_srv, domain);
+
+  if (answers) {
+    answer_to_srv_query(sr, NULL, answers);
+    return 0;
+  }
+  else {
+    sr->sr_query = sres_query_make(sr->sres, answer_to_srv_query, sr,
+				   sr->sr_sockets[0], sres_type_srv, domain);
+    return sr->sr_query ? 0 : -1;
+  }
+}
+
+/* Process A records */
+static 
+void answer_to_a_query(sres_context_t *sr, sres_query_t *q, 
+		       sres_record_t *answers[])
+{
+  int i;
+
+  sr->sr_query = NULL;
+
+  for (i = 0; answers && answers[i]; i++) {
+    char addr[64];
+    sres_a_record_t const *a = answers[i]->sr_a;
+
+    if (a->a_record->r_status)
+      continue;			      /* There was an error */
+
+    inet_ntop(AF_INET, &a->a_addr, addr, sizeof(addr));
+    printf("%s@%s:%u\n", sr->sr_tport, addr, sr->sr_port);
+    sr->sr_exitcode = 0;
+  }
+
+  sres_free_answers(sr->sres, answers);
+
+  sr->sr_ready = 1;
+}
+
+static
+int query_a(struct context *sr, char const *domain)
+{
+  sres_record_t **answers;
+
+  answers = sres_cached_answers(sr->sres, sres_type_a, domain);
+
+  if (answers) {
+    answer_to_a_query(sr, NULL, answers);
+    return 0;
+  }
+  else {
+    sr->sr_query = sres_query_make(sr->sres, answer_to_a_query, sr,
+				   sr->sr_sockets[0], sres_type_a, domain);
+    return sr->sr_query ? 0 : -1;
+  }
+}
+
+void usage(void)
+{
+  fprintf(stderr, "usage: resolve_sip [-s] [@dnsserver] domain\n");
+  exit(1);
+}
+
+int prepare_run(struct context *sr)
+{
+  sr->sr_n_sockets = 1;
+  sr->sr_sockets = calloc(1, sizeof(*sr->sr_sockets));
+  sr->sr_pollfds = calloc(1, sizeof(*sr->sr_pollfds));
+  
+  if (!sr->sr_sockets || !sr->sr_pollfds ||
+      (sres_resolver_sockets(sr->sres, sr->sr_sockets, 1) == -1))
+    return 0;
+  
+  sr->sr_pollfds[0].fd = sr->sr_sockets[0];
+  sr->sr_pollfds[0].events = POLLIN | POLLERR;
+
+  return 1;
+}
+
+void run(struct context *sr)
+{
+  int i, n, events;
+
+  n = sr->sr_n_sockets;
+
+  while (!sr->sr_ready) {
+    events = poll(sr->sr_pollfds, n, 500);
+
+    if (events) 
+      for (i = 0; i < n; i++) {
+	if (sr->sr_pollfds[i].revents)
+	  sres_resolver_receive(sr->sres, sr->sr_pollfds[i].fd);
+      }
+
+    /* No harm is done (except wasted CPU) if timer is called more often */
+    sres_resolver_timer(sr->sres, sr->sr_sockets[0]); 
+  }
+}
+
+int main(int argc, char *argv[])
+{
+  struct context sr[1] = {{ 0 }};
+  char const *dnsserver = NULL;
+
+  sr->sr_exitcode = 1;
+  sr->sr_tport = "*";
+
+  if (argv[1] && strcmp(argv[1], "-s") == 0)
+    sr->sr_sips = 1, argv++;
+
+  if (argv[1] && argv[1][0] == '@')
+    dnsserver = argv++[1] + 1;
+
+  if (argv[1] == NULL)
+    usage();
+
+  sr->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
+
+  if (sr->sres) 
+    if (prepare_run(sr)) 
+      if (query_naptr(sr, sr->sr_canon = argv[1]) == 0)
+	run(sr);
+
+  sres_resolver_unref(sr->sres), sr->sres = NULL;
+
+  return sr->sr_exitcode;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3077 @@
+Network Working Group                                     P. Mockapetris
+Request for Comments: 1034                                           ISI
+Obsoletes: RFCs 882, 883, 973                              November 1987
+
+
+                 DOMAIN NAMES - CONCEPTS AND FACILITIES
+
+
+
+1. STATUS OF THIS MEMO
+
+This RFC is an introduction to the Domain Name System (DNS), and omits
+many details which can be found in a companion RFC, "Domain Names -
+Implementation and Specification" [RFC-1035].  That RFC assumes that the
+reader is familiar with the concepts discussed in this memo.
+
+A subset of DNS functions and data types constitute an official
+protocol.  The official protocol includes standard queries and their
+responses and most of the Internet class data formats (e.g., host
+addresses).
+
+However, the domain system is intentionally extensible.  Researchers are
+continuously proposing, implementing and experimenting with new data
+types, query types, classes, functions, etc.  Thus while the components
+of the official protocol are expected to stay essentially unchanged and
+operate as a production service, experimental behavior should always be
+expected in extensions beyond the official protocol.  Experimental or
+obsolete features are clearly marked in these RFCs, and such information
+should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical.  Distribution of this memo is unlimited.
+
+2. INTRODUCTION
+
+This RFC introduces domain style names, their use for Internet mail and
+host address support, and the protocols and servers used to implement
+domain name facilities.
+
+2.1. The history of domain names
+
+The impetus for the development of the domain system was growth in the
+Internet:
+
+   - Host name to address mappings were maintained by the Network
+     Information Center (NIC) in a single file (HOSTS.TXT) which
+     was FTPed by all hosts [RFC-952, RFC-953].  The total network
+
+
+
+Mockapetris                                                     [Page 1]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+     bandwidth consumed in distributing a new version by this
+     scheme is proportional to the square of the number of hosts in
+     the network, and even when multiple levels of FTP are used,
+     the outgoing FTP load on the NIC host is considerable.
+     Explosive growth in the number of hosts didn't bode well for
+     the future.
+
+   - The network population was also changing in character.  The
+     timeshared hosts that made up the original ARPANET were being
+     replaced with local networks of workstations.  Local
+     organizations were administering their own names and
+     addresses, but had to wait for the NIC to change HOSTS.TXT to
+     make changes visible to the Internet at large.  Organizations
+     also wanted some local structure on the name space.
+
+   - The applications on the Internet were getting more
+     sophisticated and creating a need for general purpose name
+     service.
+
+
+The result was several ideas about name spaces and their management
+[IEN-116, RFC-799, RFC-819, RFC-830].  The proposals varied, but a
+common thread was the idea of a hierarchical name space, with the
+hierarchy roughly corresponding to organizational structure, and names
+using "."  as the character to mark the boundary between hierarchy
+levels.  A design using a distributed database and generalized resources
+was described in [RFC-882, RFC-883].  Based on experience with several
+implementations, the system evolved into the scheme described in this
+memo.
+
+The terms "domain" or "domain name" are used in many contexts beyond the
+DNS described here.  Very often, the term domain name is used to refer
+to a name with structure indicated by dots, but no relation to the DNS.
+This is particularly true in mail addressing [Quarterman 86].
+
+2.2. DNS design goals
+
+The design goals of the DNS influence its structure.  They are:
+
+   - The primary goal is a consistent name space which will be used
+     for referring to resources.  In order to avoid the problems
+     caused by ad hoc encodings, names should not be required to
+     contain network identifiers, addresses, routes, or similar
+     information as part of the name.
+
+   - The sheer size of the database and frequency of updates
+     suggest that it must be maintained in a distributed manner,
+     with local caching to improve performance.  Approaches that
+
+
+
+Mockapetris                                                     [Page 2]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+     attempt to collect a consistent copy of the entire database
+     will become more and more expensive and difficult, and hence
+     should be avoided.  The same principle holds for the structure
+     of the name space, and in particular mechanisms for creating
+     and deleting names; these should also be distributed.
+
+   - Where there tradeoffs between the cost of acquiring data, the
+     speed of updates, and the accuracy of caches, the source of
+     the data should control the tradeoff.
+
+   - The costs of implementing such a facility dictate that it be
+     generally useful, and not restricted to a single application.
+     We should be able to use names to retrieve host addresses,
+     mailbox data, and other as yet undetermined information.  All
+     data associated with a name is tagged with a type, and queries
+     can be limited to a single type.
+
+   - Because we want the name space to be useful in dissimilar
+     networks and applications, we provide the ability to use the
+     same name space with different protocol families or
+     management.  For example, host address formats differ between
+     protocols, though all protocols have the notion of address.
+     The DNS tags all data with a class as well as the type, so
+     that we can allow parallel use of different formats for data
+     of type address.
+
+   - We want name server transactions to be independent of the
+     communications system that carries them.  Some systems may
+     wish to use datagrams for queries and responses, and only
+     establish virtual circuits for transactions that need the
+     reliability (e.g., database updates, long transactions); other
+     systems will use virtual circuits exclusively.
+
+   - The system should be useful across a wide spectrum of host
+     capabilities.  Both personal computers and large timeshared
+     hosts should be able to use the system, though perhaps in
+     different ways.
+
+2.3. Assumptions about usage
+
+The organization of the domain system derives from some assumptions
+about the needs and usage patterns of its user community and is designed
+to avoid many of the the complicated problems found in general purpose
+database systems.
+
+The assumptions are:
+
+   - The size of the total database will initially be proportional
+
+
+
+Mockapetris                                                     [Page 3]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+     to the number of hosts using the system, but will eventually
+     grow to be proportional to the number of users on those hosts
+     as mailboxes and other information are added to the domain
+     system.
+
+   - Most of the data in the system will change very slowly (e.g.,
+     mailbox bindings, host addresses), but that the system should
+     be able to deal with subsets that change more rapidly (on the
+     order of seconds or minutes).
+
+   - The administrative boundaries used to distribute
+     responsibility for the database will usually correspond to
+     organizations that have one or more hosts.  Each organization
+     that has responsibility for a particular set of domains will
+     provide redundant name servers, either on the organization's
+     own hosts or other hosts that the organization arranges to
+     use.
+
+   - Clients of the domain system should be able to identify
+     trusted name servers they prefer to use before accepting
+     referrals to name servers outside of this "trusted" set.
+
+   - Access to information is more critical than instantaneous
+     updates or guarantees of consistency.  Hence the update
+     process allows updates to percolate out through the users of
+     the domain system rather than guaranteeing that all copies are
+     simultaneously updated.  When updates are unavailable due to
+     network or host failure, the usual course is to believe old
+     information while continuing efforts to update it.  The
+     general model is that copies are distributed with timeouts for
+     refreshing.  The distributor sets the timeout value and the
+     recipient of the distribution is responsible for performing
+     the refresh.  In special situations, very short intervals can
+     be specified, or the owner can prohibit copies.
+
+   - In any system that has a distributed database, a particular
+     name server may be presented with a query that can only be
+     answered by some other server.  The two general approaches to
+     dealing with this problem are "recursive", in which the first
+     server pursues the query for the client at another server, and
+     "iterative", in which the server refers the client to another
+     server and lets the client pursue the query.  Both approaches
+     have advantages and disadvantages, but the iterative approach
+     is preferred for the datagram style of access.  The domain
+     system requires implementation of the iterative approach, but
+     allows the recursive approach as an option.
+
+
+
+
+
+Mockapetris                                                     [Page 4]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+The domain system assumes that all data originates in master files
+scattered through the hosts that use the domain system.  These master
+files are updated by local system administrators.  Master files are text
+files that are read by a local name server, and hence become available
+through the name servers to users of the domain system.  The user
+programs access name servers through standard programs called resolvers.
+
+The standard format of master files allows them to be exchanged between
+hosts (via FTP, mail, or some other mechanism); this facility is useful
+when an organization wants a domain, but doesn't want to support a name
+server.  The organization can maintain the master files locally using a
+text editor, transfer them to a foreign host which runs a name server,
+and then arrange with the system administrator of the name server to get
+the files loaded.
+
+Each host's name servers and resolvers are configured by a local system
+administrator [RFC-1033].  For a name server, this configuration data
+includes the identity of local master files and instructions on which
+non-local master files are to be loaded from foreign servers.  The name
+server uses the master files or copies to load its zones.  For
+resolvers, the configuration data identifies the name servers which
+should be the primary sources of information.
+
+The domain system defines procedures for accessing the data and for
+referrals to other name servers.  The domain system also defines
+procedures for caching retrieved data and for periodic refreshing of
+data defined by the system administrator.
+
+The system administrators provide:
+
+   - The definition of zone boundaries.
+
+   - Master files of data.
+
+   - Updates to master files.
+
+   - Statements of the refresh policies desired.
+
+The domain system provides:
+
+   - Standard formats for resource data.
+
+   - Standard methods for querying the database.
+
+   - Standard methods for name servers to refresh local data from
+     foreign name servers.
+
+
+
+
+
+Mockapetris                                                     [Page 5]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+2.4. Elements of the DNS
+
+The DNS has three major components:
+
+   - The DOMAIN NAME SPACE and RESOURCE RECORDS, which are
+     specifications for a tree structured name space and data
+     associated with the names.  Conceptually, each node and leaf
+     of the domain name space tree names a set of information, and
+     query operations are attempts to extract specific types of
+     information from a particular set.  A query names the domain
+     name of interest and describes the type of resource
+     information that is desired.  For example, the Internet
+     uses some of its domain names to identify hosts; queries for
+     address resources return Internet host addresses.
+
+   - NAME SERVERS are server programs which hold information about
+     the domain tree's structure and set information.  A name
+     server may cache structure or set information about any part
+     of the domain tree, but in general a particular name server
+     has complete information about a subset of the domain space,
+     and pointers to other name servers that can be used to lead to
+     information from any part of the domain tree.  Name servers
+     know the parts of the domain tree for which they have complete
+     information; a name server is said to be an AUTHORITY for
+     these parts of the name space.  Authoritative information is
+     organized into units called ZONEs, and these zones can be
+     automatically distributed to the name servers which provide
+     redundant service for the data in a zone.
+
+   - RESOLVERS are programs that extract information from name
+     servers in response to client requests.  Resolvers must be
+     able to access at least one name server and use that name
+     server's information to answer a query directly, or pursue the
+     query using referrals to other name servers.  A resolver will
+     typically be a system routine that is directly accessible to
+     user programs; hence no protocol is necessary between the
+     resolver and the user program.
+
+These three components roughly correspond to the three layers or views
+of the domain system:
+
+   - From the user's point of view, the domain system is accessed
+     through a simple procedure or OS call to a local resolver.
+     The domain space consists of a single tree and the user can
+     request information from any section of the tree.
+
+   - From the resolver's point of view, the domain system is
+     composed of an unknown number of name servers.  Each name
+
+
+
+Mockapetris                                                     [Page 6]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+     server has one or more pieces of the whole domain tree's data,
+     but the resolver views each of these databases as essentially
+     static.
+
+   - From a name server's point of view, the domain system consists
+     of separate sets of local information called zones.  The name
+     server has local copies of some of the zones.  The name server
+     must periodically refresh its zones from master copies in
+     local files or foreign name servers.  The name server must
+     concurrently process queries that arrive from resolvers.
+
+In the interests of performance, implementations may couple these
+functions.  For example, a resolver on the same machine as a name server
+might share a database consisting of the the zones managed by the name
+server and the cache managed by the resolver.
+
+3. DOMAIN NAME SPACE and RESOURCE RECORDS
+
+3.1. Name space specifications and terminology
+
+The domain name space is a tree structure.  Each node and leaf on the
+tree corresponds to a resource set (which may be empty).  The domain
+system makes no distinctions between the uses of the interior nodes and
+leaves, and this memo uses the term "node" to refer to both.
+
+Each node has a label, which is zero to 63 octets in length.  Brother
+nodes may not have the same label, although the same label can be used
+for nodes which are not brothers.  One label is reserved, and that is
+the null (i.e., zero length) label used for the root.
+
+The domain name of a node is the list of the labels on the path from the
+node to the root of the tree.  By convention, the labels that compose a
+domain name are printed or read left to right, from the most specific
+(lowest, farthest from the root) to the least specific (highest, closest
+to the root).
+
+Internally, programs that manipulate domain names should represent them
+as sequences of labels, where each label is a length octet followed by
+an octet string.  Because all domain names end at the root, which has a
+null string for a label, these internal representations can use a length
+byte of zero to terminate a domain name.
+
+By convention, domain names can be stored with arbitrary case, but
+domain name comparisons for all present domain functions are done in a
+case-insensitive manner, assuming an ASCII character set, and a high
+order zero bit.  This means that you are free to create a node with
+label "A" or a node with label "a", but not both as brothers; you could
+refer to either using "a" or "A".  When you receive a domain name or
+
+
+
+Mockapetris                                                     [Page 7]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+label, you should preserve its case.  The rationale for this choice is
+that we may someday need to add full binary domain names for new
+services; existing services would not be changed.
+
+When a user needs to type a domain name, the length of each label is
+omitted and the labels are separated by dots (".").  Since a complete
+domain name ends with the root label, this leads to a printed form which
+ends in a dot.  We use this property to distinguish between:
+
+   - a character string which represents a complete domain name
+     (often called "absolute").  For example, "poneria.ISI.EDU."
+
+   - a character string that represents the starting labels of a
+     domain name which is incomplete, and should be completed by
+     local software using knowledge of the local domain (often
+     called "relative").  For example, "poneria" used in the
+     ISI.EDU domain.
+
+Relative names are either taken relative to a well known origin, or to a
+list of domains used as a search list.  Relative names appear mostly at
+the user interface, where their interpretation varies from
+implementation to implementation, and in master files, where they are
+relative to a single origin domain name.  The most common interpretation
+uses the root "." as either the single origin or as one of the members
+of the search list, so a multi-label relative name is often one where
+the trailing dot has been omitted to save typing.
+
+To simplify implementations, the total number of octets that represent a
+domain name (i.e., the sum of all label octets and label lengths) is
+limited to 255.
+
+A domain is identified by a domain name, and consists of that part of
+the domain name space that is at or below the domain name which
+specifies the domain.  A domain is a subdomain of another domain if it
+is contained within that domain.  This relationship can be tested by
+seeing if the subdomain's name ends with the containing domain's name.
+For example, A.B.C.D is a subdomain of B.C.D, C.D, D, and " ".
+
+3.2. Administrative guidelines on use
+
+As a matter of policy, the DNS technical specifications do not mandate a
+particular tree structure or rules for selecting labels; its goal is to
+be as general as possible, so that it can be used to build arbitrary
+applications.  In particular, the system was designed so that the name
+space did not have to be organized along the lines of network
+boundaries, name servers, etc.  The rationale for this is not that the
+name space should have no implied semantics, but rather that the choice
+of implied semantics should be left open to be used for the problem at
+
+
+
+Mockapetris                                                     [Page 8]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+hand, and that different parts of the tree can have different implied
+semantics.  For example, the IN-ADDR.ARPA domain is organized and
+distributed by network and host address because its role is to translate
+from network or host numbers to names; NetBIOS domains [RFC-1001, RFC-
+1002] are flat because that is appropriate for that application.
+
+However, there are some guidelines that apply to the "normal" parts of
+the name space used for hosts, mailboxes, etc., that will make the name
+space more uniform, provide for growth, and minimize problems as
+software is converted from the older host table.  The political
+decisions about the top levels of the tree originated in RFC-920.
+Current policy for the top levels is discussed in [RFC-1032].  MILNET
+conversion issues are covered in [RFC-1031].
+
+Lower domains which will eventually be broken into multiple zones should
+provide branching at the top of the domain so that the eventual
+decomposition can be done without renaming.  Node labels which use
+special characters, leading digits, etc., are likely to break older
+software which depends on more restrictive choices.
+
+3.3. Technical guidelines on use
+
+Before the DNS can be used to hold naming information for some kind of
+object, two needs must be met:
+
+   - A convention for mapping between object names and domain
+     names.  This describes how information about an object is
+     accessed.
+
+   - RR types and data formats for describing the object.
+
+These rules can be quite simple or fairly complex.  Very often, the
+designer must take into account existing formats and plan for upward
+compatibility for existing usage.  Multiple mappings or levels of
+mapping may be required.
+
+For hosts, the mapping depends on the existing syntax for host names
+which is a subset of the usual text representation for domain names,
+together with RR formats for describing host addresses, etc.  Because we
+need a reliable inverse mapping from address to host name, a special
+mapping for addresses into the IN-ADDR.ARPA domain is also defined.
+
+For mailboxes, the mapping is slightly more complex.  The usual mail
+address <local-part>@<mail-domain> is mapped into a domain name by
+converting <local-part> into a single label (regardles of dots it
+contains), converting <mail-domain> into a domain name using the usual
+text format for domain names (dots denote label breaks), and
+concatenating the two to form a single domain name.  Thus the mailbox
+
+
+
+Mockapetris                                                     [Page 9]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+HOSTMASTER at SRI-NIC.ARPA is represented as a domain name by
+HOSTMASTER.SRI-NIC.ARPA.  An appreciation for the reasons behind this
+design also must take into account the scheme for mail exchanges [RFC-
+974].
+
+The typical user is not concerned with defining these rules, but should
+understand that they usually are the result of numerous compromises
+between desires for upward compatibility with old usage, interactions
+between different object definitions, and the inevitable urge to add new
+features when defining the rules.  The way the DNS is used to support
+some object is often more crucial than the restrictions inherent in the
+DNS.
+
+3.4. Example name space
+
+The following figure shows a part of the current domain name space, and
+is used in many examples in this RFC.  Note that the tree is a very
+small subset of the actual name space.
+
+                                   |
+                                   |
+             +---------------------+------------------+
+             |                     |                  |
+            MIL                   EDU                ARPA
+             |                     |                  |
+             |                     |                  |
+       +-----+-----+               |     +------+-----+-----+
+       |     |     |               |     |      |           |
+      BRL  NOSC  DARPA             |  IN-ADDR  SRI-NIC     ACC
+                                   |
+       +--------+------------------+---------------+--------+
+       |        |                  |               |        |
+      UCI      MIT                 |              UDEL     YALE
+                |                 ISI
+                |                  |
+            +---+---+              |
+            |       |              |
+           LCS  ACHILLES  +--+-----+-----+--------+
+            |             |  |     |     |        |
+            XX            A  C   VAXA  VENERA Mockapetris
+
+In this example, the root domain has three immediate subdomains: MIL,
+EDU, and ARPA.  The LCS.MIT.EDU domain has one immediate subdomain named
+XX.LCS.MIT.EDU.  All of the leaves are also domains.
+
+3.5. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+
+
+
+Mockapetris                                                    [Page 10]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+for constructing domain names.  The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822.  When creating a new host name,
+the old rules for HOSTS.TXT should be followed.  This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case.  That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names.  They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen.  There are also some
+restrictions on the length.  Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU  XX.LCS.MIT.EDU  SRI-NIC.ARPA
+
+3.6. Resource Records
+
+A domain name identifies a node.  Each node has a set of resource
+
+
+
+Mockapetris                                                    [Page 11]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+information, which may be empty.  The set of resource information
+associated with a particular name is composed of separate resource
+records (RRs).  The order of RRs in a set is not significant, and need
+not be preserved by name servers, resolvers, or other parts of the DNS.
+
+When we talk about a specific RR, we assume it has the following:
+
+owner           which is the domain name where the RR is found.
+
+type            which is an encoded 16 bit value that specifies the type
+                of the resource in this resource record.  Types refer to
+                abstract resources.
+
+                This memo uses the following types:
+
+                A               a host address
+
+                CNAME           identifies the canonical name of an
+                                alias
+
+                HINFO           identifies the CPU and OS used by a host
+
+                MX              identifies a mail exchange for the
+                                domain.  See [RFC-974 for details.
+
+                NS
+                the authoritative name server for the domain
+
+                PTR
+                a pointer to another part of the domain name space
+
+                SOA
+                identifies the start of a zone of authority]
+
+class           which is an encoded 16 bit value which identifies a
+                protocol family or instance of a protocol.
+
+                This memo uses the following classes:
+
+                IN              the Internet system
+
+                CH              the Chaos system
+
+TTL             which is the time to live of the RR.  This field is a 32
+                bit integer in units of seconds, an is primarily used by
+                resolvers when they cache RRs.  The TTL describes how
+                long a RR can be cached before it should be discarded.
+
+
+
+
+Mockapetris                                                    [Page 12]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+RDATA           which is the type and sometimes class dependent data
+                which describes the resource:
+
+                A               For the IN class, a 32 bit IP address
+
+                                For the CH class, a domain name followed
+                                by a 16 bit octal Chaos address.
+
+                CNAME           a domain name.
+
+                MX              a 16 bit preference value (lower is
+                                better) followed by a host name willing
+                                to act as a mail exchange for the owner
+                                domain.
+
+                NS              a host name.
+
+                PTR             a domain name.
+
+                SOA             several fields.
+
+The owner name is often implicit, rather than forming an integral part
+of the RR.  For example, many name servers internally form tree or hash
+structures for the name space, and chain RRs off nodes.  The remaining
+RR parts are the fixed header (type, class, TTL) which is consistent for
+all RRs, and a variable part (RDATA) that fits the needs of the resource
+being described.
+
+The meaning of the TTL field is a time limit on how long an RR can be
+kept in a cache.  This limit does not apply to authoritative data in
+zones; it is also timed out, but by the refreshing policies for the
+zone.  The TTL is assigned by the administrator for the zone where the
+data originates.  While short TTLs can be used to minimize caching, and
+a zero TTL prohibits caching, the realities of Internet performance
+suggest that these times should be on the order of days for the typical
+host.  If a change can be anticipated, the TTL can be reduced prior to
+the change to minimize inconsistency during the change, and then
+increased back to its former value following the change.
+
+The data in the RDATA section of RRs is carried as a combination of
+binary strings and domain names.  The domain names are frequently used
+as "pointers" to other data in the DNS.
+
+3.6.1. Textual expression of RRs
+
+RRs are represented in binary form in the packets of the DNS protocol,
+and are usually represented in highly encoded form when stored in a name
+server or resolver.  In this memo, we adopt a style similar to that used
+
+
+
+Mockapetris                                                    [Page 13]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+in master files in order to show the contents of RRs.  In this format,
+most RRs are shown on a single line, although continuation lines are
+possible using parentheses.
+
+The start of the line gives the owner of the RR.  If a line begins with
+a blank, then the owner is assumed to be the same as that of the
+previous RR.  Blank lines are often included for readability.
+
+Following the owner, we list the TTL, type, and class of the RR.  Class
+and type use the mnemonics defined above, and TTL is an integer before
+the type field.  In order to avoid ambiguity in parsing, type and class
+mnemonics are disjoint, TTLs are integers, and the type mnemonic is
+always last. The IN class and TTL values are often omitted from examples
+in the interests of clarity.
+
+The resource data or RDATA section of the RR are given using knowledge
+of the typical representation for the data.
+
+For example, we might show the RRs carried in a message as:
+
+    ISI.EDU.        MX      10 VENERA.ISI.EDU.
+                    MX      10 VAXA.ISI.EDU.
+    VENERA.ISI.EDU. A       128.9.0.32
+                    A       10.1.0.52
+    VAXA.ISI.EDU.   A       10.2.0.27
+                    A       128.9.0.33
+
+The MX RRs have an RDATA section which consists of a 16 bit number
+followed by a domain name.  The address RRs use a standard IP address
+format to contain a 32 bit internet address.
+
+This example shows six RRs, with two RRs at each of three domain names.
+
+Similarly we might see:
+
+    XX.LCS.MIT.EDU. IN      A       10.0.0.44
+                    CH      A       MIT.EDU. 2420
+
+This example shows two addresses for XX.LCS.MIT.EDU, each of a different
+class.
+
+3.6.2. Aliases and canonical names
+
+In existing systems, hosts and other resources often have several names
+that identify the same resource.  For example, the names C.ISI.EDU and
+USC-ISIC.ARPA both identify the same host.  Similarly, in the case of
+mailboxes, many organizations provide many names that actually go to the
+same mailbox; for example Mockapetris at C.ISI.EDU, Mockapetris at B.ISI.EDU,
+
+
+
+Mockapetris                                                    [Page 14]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+and PVM at ISI.EDU all go to the same mailbox (although the mechanism
+behind this is somewhat complicated).
+
+Most of these systems have a notion that one of the equivalent set of
+names is the canonical or primary name and all others are aliases.
+
+The domain system provides such a feature using the canonical name
+(CNAME) RR.  A CNAME RR identifies its owner name as an alias, and
+specifies the corresponding canonical name in the RDATA section of the
+RR.  If a CNAME RR is present at a node, no other data should be
+present; this ensures that the data for a canonical name and its aliases
+cannot be different.  This rule also insures that a cached CNAME can be
+used without checking with an authoritative server for other RR types.
+
+CNAME RRs cause special action in DNS software.  When a name server
+fails to find a desired RR in the resource set associated with the
+domain name, it checks to see if the resource set consists of a CNAME
+record with a matching class.  If so, the name server includes the CNAME
+record in the response and restarts the query at the domain name
+specified in the data field of the CNAME record.  The one exception to
+this rule is that queries which match the CNAME type are not restarted.
+
+For example, suppose a name server was processing a query with for USC-
+ISIC.ARPA, asking for type A information, and had the following resource
+records:
+
+    USC-ISIC.ARPA   IN      CNAME   C.ISI.EDU
+
+    C.ISI.EDU       IN      A       10.0.0.52
+
+Both of these RRs would be returned in the response to the type A query,
+while a type CNAME or * query should return just the CNAME.
+
+Domain names in RRs which point at another name should always point at
+the primary name and not the alias.  This avoids extra indirections in
+accessing information.  For example, the address to name RR for the
+above host should be:
+
+    52.0.0.10.IN-ADDR.ARPA  IN      PTR     C.ISI.EDU
+
+rather than pointing at USC-ISIC.ARPA.  Of course, by the robustness
+principle, domain software should not fail when presented with CNAME
+chains or loops; CNAME chains should be followed and CNAME loops
+signalled as an error.
+
+3.7. Queries
+
+Queries are messages which may be sent to a name server to provoke a
+
+
+
+Mockapetris                                                    [Page 15]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+response.  In the Internet, queries are carried in UDP datagrams or over
+TCP connections.  The response by the name server either answers the
+question posed in the query, refers the requester to another set of name
+servers, or signals some error condition.
+
+In general, the user does not generate queries directly, but instead
+makes a request to a resolver which in turn sends one or more queries to
+name servers and deals with the error conditions and referrals that may
+result.  Of course, the possible questions which can be asked in a query
+does shape the kind of service a resolver can provide.
+
+DNS queries and responses are carried in a standard message format.  The
+message format has a header containing a number of fixed fields which
+are always present, and four sections which carry query parameters and
+RRs.
+
+The most important field in the header is a four bit field called an
+opcode which separates different queries.  Of the possible 16 values,
+one (standard query) is part of the official protocol, two (inverse
+query and status query) are options, one (completion) is obsolete, and
+the rest are unassigned.
+
+The four sections are:
+
+Question        Carries the query name and other query parameters.
+
+Answer          Carries RRs which directly answer the query.
+
+Authority       Carries RRs which describe other authoritative servers.
+                May optionally carry the SOA RR for the authoritative
+                data in the answer section.
+
+Additional      Carries RRs which may be helpful in using the RRs in the
+                other sections.
+
+Note that the content, but not the format, of these sections varies with
+header opcode.
+
+3.7.1. Standard queries
+
+A standard query specifies a target domain name (QNAME), query type
+(QTYPE), and query class (QCLASS) and asks for RRs which match.  This
+type of query makes up such a vast majority of DNS queries that we use
+the term "query" to mean standard query unless otherwise specified.  The
+QTYPE and QCLASS fields are each 16 bits long, and are a superset of
+defined types and classes.
+
+
+
+
+
+Mockapetris                                                    [Page 16]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+The QTYPE field may contain:
+
+<any type>      matches just that type. (e.g., A, PTR).
+
+AXFR            special zone transfer QTYPE.
+
+MAILB           matches all mail box related RRs (e.g. MB and MG).
+
+*               matches all RR types.
+
+The QCLASS field may contain:
+
+<any class>     matches just that class (e.g., IN, CH).
+
+*               matches aLL RR classes.
+
+Using the query domain name, QTYPE, and QCLASS, the name server looks
+for matching RRs.  In addition to relevant records, the name server may
+return RRs that point toward a name server that has the desired
+information or RRs that are expected to be useful in interpreting the
+relevant RRs.  For example, a name server that doesn't have the
+requested information may know a name server that does; a name server
+that returns a domain name in a relevant RR may also return the RR that
+binds that domain name to an address.
+
+For example, a mailer tying to send mail to Mockapetris at ISI.EDU might
+ask the resolver for mail information about ISI.EDU, resulting in a
+query for QNAME=ISI.EDU, QTYPE=MX, QCLASS=IN.  The response's answer
+section would be:
+
+    ISI.EDU.        MX      10 VENERA.ISI.EDU.
+                    MX      10 VAXA.ISI.EDU.
+
+while the additional section might be:
+
+    VAXA.ISI.EDU.   A       10.2.0.27
+                    A       128.9.0.33
+    VENERA.ISI.EDU. A       10.1.0.52
+                    A       128.9.0.32
+
+Because the server assumes that if the requester wants mail exchange
+information, it will probably want the addresses of the mail exchanges
+soon afterward.
+
+Note that the QCLASS=* construct requires special interpretation
+regarding authority.  Since a particular name server may not know all of
+the classes available in the domain system, it can never know if it is
+authoritative for all classes.  Hence responses to QCLASS=* queries can
+
+
+
+Mockapetris                                                    [Page 17]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+never be authoritative.
+
+3.7.2. Inverse queries (Optional)
+
+Name servers may also support inverse queries that map a particular
+resource to a domain name or domain names that have that resource.  For
+example, while a standard query might map a domain name to a SOA RR, the
+corresponding inverse query might map the SOA RR back to the domain
+name.
+
+Implementation of this service is optional in a name server, but all
+name servers must at least be able to understand an inverse query
+message and return a not-implemented error response.
+
+The domain system cannot guarantee the completeness or uniqueness of
+inverse queries because the domain system is organized by domain name
+rather than by host address or any other resource type.  Inverse queries
+are primarily useful for debugging and database maintenance activities.
+
+Inverse queries may not return the proper TTL, and do not indicate cases
+where the identified RR is one of a set (for example, one address for a
+host having multiple addresses).  Therefore, the RRs returned in inverse
+queries should never be cached.
+
+Inverse queries are NOT an acceptable method for mapping host addresses
+to host names; use the IN-ADDR.ARPA domain instead.
+
+A detailed discussion of inverse queries is contained in [RFC-1035].
+
+3.8. Status queries (Experimental)
+
+To be defined.
+
+3.9. Completion queries (Obsolete)
+
+The optional completion services described in RFCs 882 and 883 have been
+deleted.  Redesigned services may become available in the future, or the
+opcodes may be reclaimed for other use.
+
+4. NAME SERVERS
+
+4.1. Introduction
+
+Name servers are the repositories of information that make up the domain
+database.  The database is divided up into sections called zones, which
+are distributed among the name servers.  While name servers can have
+several optional functions and sources of data, the essential task of a
+name server is to answer queries using data in its zones.  By design,
+
+
+
+Mockapetris                                                    [Page 18]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+name servers can answer queries in a simple manner; the response can
+always be generated using only local data, and either contains the
+answer to the question or a referral to other name servers "closer" to
+the desired information.
+
+A given zone will be available from several name servers to insure its
+availability in spite of host or communication link failure.  By
+administrative fiat, we require every zone to be available on at least
+two servers, and many zones have more redundancy than that.
+
+A given name server will typically support one or more zones, but this
+gives it authoritative information about only a small section of the
+domain tree.  It may also have some cached non-authoritative data about
+other parts of the tree.  The name server marks its responses to queries
+so that the requester can tell whether the response comes from
+authoritative data or not.
+
+4.2. How the database is divided into zones
+
+The domain database is partitioned in two ways: by class, and by "cuts"
+made in the name space between nodes.
+
+The class partition is simple.  The database for any class is organized,
+delegated, and maintained separately from all other classes.  Since, by
+convention, the name spaces are the same for all classes, the separate
+classes can be thought of as an array of parallel namespace trees.  Note
+that the data attached to nodes will be different for these different
+parallel classes.  The most common reasons for creating a new class are
+the necessity for a new data format for existing types or a desire for a
+separately managed version of the existing name space.
+
+Within a class, "cuts" in the name space can be made between any two
+adjacent nodes.  After all cuts are made, each group of connected name
+space is a separate zone.  The zone is said to be authoritative for all
+names in the connected region.  Note that the "cuts" in the name space
+may be in different places for different classes, the name servers may
+be different, etc.
+
+These rules mean that every zone has at least one node, and hence domain
+name, for which it is authoritative, and all of the nodes in a
+particular zone are connected.  Given, the tree structure, every zone
+has a highest node which is closer to the root than any other node in
+the zone.  The name of this node is often used to identify the zone.
+
+It would be possible, though not particularly useful, to partition the
+name space so that each domain name was in a separate zone or so that
+all nodes were in a single zone.  Instead, the database is partitioned
+at points where a particular organization wants to take over control of
+
+
+
+Mockapetris                                                    [Page 19]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+a subtree.  Once an organization controls its own zone it can
+unilaterally change the data in the zone, grow new tree sections
+connected to the zone, delete existing nodes, or delegate new subzones
+under its zone.
+
+If the organization has substructure, it may want to make further
+internal partitions to achieve nested delegations of name space control.
+In some cases, such divisions are made purely to make database
+maintenance more convenient.
+
+4.2.1. Technical considerations
+
+The data that describes a zone has four major parts:
+
+   - Authoritative data for all nodes within the zone.
+
+   - Data that defines the top node of the zone (can be thought of
+     as part of the authoritative data).
+
+   - Data that describes delegated subzones, i.e., cuts around the
+     bottom of the zone.
+
+   - Data that allows access to name servers for subzones
+     (sometimes called "glue" data).
+
+All of this data is expressed in the form of RRs, so a zone can be
+completely described in terms of a set of RRs.  Whole zones can be
+transferred between name servers by transferring the RRs, either carried
+in a series of messages or by FTPing a master file which is a textual
+representation.
+
+The authoritative data for a zone is simply all of the RRs attached to
+all of the nodes from the top node of the zone down to leaf nodes or
+nodes above cuts around the bottom edge of the zone.
+
+Though logically part of the authoritative data, the RRs that describe
+the top node of the zone are especially important to the zone's
+management.  These RRs are of two types: name server RRs that list, one
+per RR, all of the servers for the zone, and a single SOA RR that
+describes zone management parameters.
+
+The RRs that describe cuts around the bottom of the zone are NS RRs that
+name the servers for the subzones.  Since the cuts are between nodes,
+these RRs are NOT part of the authoritative data of the zone, and should
+be exactly the same as the corresponding RRs in the top node of the
+subzone.  Since name servers are always associated with zone boundaries,
+NS RRs are only found at nodes which are the top node of some zone.  In
+the data that makes up a zone, NS RRs are found at the top node of the
+
+
+
+Mockapetris                                                    [Page 20]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+zone (and are authoritative) and at cuts around the bottom of the zone
+(where they are not authoritative), but never in between.
+
+One of the goals of the zone structure is that any zone have all the
+data required to set up communications with the name servers for any
+subzones.  That is, parent zones have all the information needed to
+access servers for their children zones.  The NS RRs that name the
+servers for subzones are often not enough for this task since they name
+the servers, but do not give their addresses.  In particular, if the
+name of the name server is itself in the subzone, we could be faced with
+the situation where the NS RRs tell us that in order to learn a name
+server's address, we should contact the server using the address we wish
+to learn.  To fix this problem, a zone contains "glue" RRs which are not
+part of the authoritative data, and are address RRs for the servers.
+These RRs are only necessary if the name server's name is "below" the
+cut, and are only used as part of a referral response.
+
+4.2.2. Administrative considerations
+
+When some organization wants to control its own domain, the first step
+is to identify the proper parent zone, and get the parent zone's owners
+to agree to the delegation of control.  While there are no particular
+technical constraints dealing with where in the tree this can be done,
+there are some administrative groupings discussed in [RFC-1032] which
+deal with top level organization, and middle level zones are free to
+create their own rules.  For example, one university might choose to use
+a single zone, while another might choose to organize by subzones
+dedicated to individual departments or schools.  [RFC-1033] catalogs
+available DNS software an discusses administration procedures.
+
+Once the proper name for the new subzone is selected, the new owners
+should be required to demonstrate redundant name server support.  Note
+that there is no requirement that the servers for a zone reside in a
+host which has a name in that domain.  In many cases, a zone will be
+more accessible to the internet at large if its servers are widely
+distributed rather than being within the physical facilities controlled
+by the same organization that manages the zone.  For example, in the
+current DNS, one of the name servers for the United Kingdom, or UK
+domain, is found in the US.  This allows US hosts to get UK data without
+using limited transatlantic bandwidth.
+
+As the last installation step, the delegation NS RRs and glue RRs
+necessary to make the delegation effective should be added to the parent
+zone.  The administrators of both zones should insure that the NS and
+glue RRs which mark both sides of the cut are consistent and remain so.
+
+4.3. Name server internals
+
+
+
+
+Mockapetris                                                    [Page 21]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+4.3.1. Queries and responses
+
+The principal activity of name servers is to answer standard queries.
+Both the query and its response are carried in a standard message format
+which is described in [RFC-1035].  The query contains a QTYPE, QCLASS,
+and QNAME, which describe the types and classes of desired information
+and the name of interest.
+
+The way that the name server answers the query depends upon whether it
+is operating in recursive mode or not:
+
+   - The simplest mode for the server is non-recursive, since it
+     can answer queries using only local information: the response
+     contains an error, the answer, or a referral to some other
+     server "closer" to the answer.  All name servers must
+     implement non-recursive queries.
+
+   - The simplest mode for the client is recursive, since in this
+     mode the name server acts in the role of a resolver and
+     returns either an error or the answer, but never referrals.
+     This service is optional in a name server, and the name server
+     may also choose to restrict the clients which can use
+     recursive mode.
+
+Recursive service is helpful in several situations:
+
+   - a relatively simple requester that lacks the ability to use
+     anything other than a direct answer to the question.
+
+   - a request that needs to cross protocol or other boundaries and
+     can be sent to a server which can act as intermediary.
+
+   - a network where we want to concentrate the cache rather than
+     having a separate cache for each client.
+
+Non-recursive service is appropriate if the requester is capable of
+pursuing referrals and interested in information which will aid future
+requests.
+
+The use of recursive mode is limited to cases where both the client and
+the name server agree to its use.  The agreement is negotiated through
+the use of two bits in query and response messages:
+
+   - The recursion available, or RA bit, is set or cleared by a
+     name server in all responses.  The bit is true if the name
+     server is willing to provide recursive service for the client,
+     regardless of whether the client requested recursive service.
+     That is, RA signals availability rather than use.
+
+
+
+Mockapetris                                                    [Page 22]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+   - Queries contain a bit called recursion desired or RD.  This
+     bit specifies specifies whether the requester wants recursive
+     service for this query.  Clients may request recursive service
+     from any name server, though they should depend upon receiving
+     it only from servers which have previously sent an RA, or
+     servers which have agreed to provide service through private
+     agreement or some other means outside of the DNS protocol.
+
+The recursive mode occurs when a query with RD set arrives at a server
+which is willing to provide recursive service; the client can verify
+that recursive mode was used by checking that both RA and RD are set in
+the reply.  Note that the name server should never perform recursive
+service unless asked via RD, since this interferes with trouble shooting
+of name servers and their databases.
+
+If recursive service is requested and available, the recursive response
+to a query will be one of the following:
+
+   - The answer to the query, possibly preface by one or more CNAME
+     RRs that specify aliases encountered on the way to an answer.
+
+   - A name error indicating that the name does not exist.  This
+     may include CNAME RRs that indicate that the original query
+     name was an alias for a name which does not exist.
+
+   - A temporary error indication.
+
+If recursive service is not requested or is not available, the non-
+recursive response will be one of the following:
+
+   - An authoritative name error indicating that the name does not
+     exist.
+
+   - A temporary error indication.
+
+   - Some combination of:
+
+     RRs that answer the question, together with an indication
+     whether the data comes from a zone or is cached.
+
+     A referral to name servers which have zones which are closer
+     ancestors to the name than the server sending the reply.
+
+   - RRs that the name server thinks will prove useful to the
+     requester.
+
+
+
+
+
+
+Mockapetris                                                    [Page 23]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+4.3.2. Algorithm
+
+The actual algorithm used by the name server will depend on the local OS
+and data structures used to store RRs.  The following algorithm assumes
+that the RRs are organized in several tree structures, one for each
+zone, and another for the cache:
+
+   1. Set or clear the value of recursion available in the response
+      depending on whether the name server is willing to provide
+      recursive service.  If recursive service is available and
+      requested via the RD bit in the query, go to step 5,
+      otherwise step 2.
+
+   2. Search the available zones for the zone which is the nearest
+      ancestor to QNAME.  If such a zone is found, go to step 3,
+      otherwise step 4.
+
+   3. Start matching down, label by label, in the zone.  The
+      matching process can terminate several ways:
+
+         a. If the whole of QNAME is matched, we have found the
+            node.
+
+            If the data at the node is a CNAME, and QTYPE doesn't
+            match CNAME, copy the CNAME RR into the answer section
+            of the response, change QNAME to the canonical name in
+            the CNAME RR, and go back to step 1.
+
+            Otherwise, copy all RRs which match QTYPE into the
+            answer section and go to step 6.
+
+         b. If a match would take us out of the authoritative data,
+            we have a referral.  This happens when we encounter a
+            node with NS RRs marking cuts along the bottom of a
+            zone.
+
+            Copy the NS RRs for the subzone into the authority
+            section of the reply.  Put whatever addresses are
+            available into the additional section, using glue RRs
+            if the addresses are not available from authoritative
+            data or the cache.  Go to step 4.
+
+         c. If at some label, a match is impossible (i.e., the
+            corresponding label does not exist), look to see if a
+            the "*" label exists.
+
+            If the "*" label does not exist, check whether the name
+            we are looking for is the original QNAME in the query
+
+
+
+Mockapetris                                                    [Page 24]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+            or a name we have followed due to a CNAME.  If the name
+            is original, set an authoritative name error in the
+            response and exit.  Otherwise just exit.
+
+            If the "*" label does exist, match RRs at that node
+            against QTYPE.  If any match, copy them into the answer
+            section, but set the owner of the RR to be QNAME, and
+            not the node with the "*" label.  Go to step 6.
+
+   4. Start matching down in the cache.  If QNAME is found in the
+      cache, copy all RRs attached to it that match QTYPE into the
+      answer section.  If there was no delegation from
+      authoritative data, look for the best one from the cache, and
+      put it in the authority section.  Go to step 6.
+
+   5. Using the local resolver or a copy of its algorithm (see
+      resolver section of this memo) to answer the query.  Store
+      the results, including any intermediate CNAMEs, in the answer
+      section of the response.
+
+   6. Using local data only, attempt to add other RRs which may be
+      useful to the additional section of the query.  Exit.
+
+4.3.3. Wildcards
+
+In the previous algorithm, special treatment was given to RRs with owner
+names starting with the label "*".  Such RRs are called wildcards.
+Wildcard RRs can be thought of as instructions for synthesizing RRs.
+When the appropriate conditions are met, the name server creates RRs
+with an owner name equal to the query name and contents taken from the
+wildcard RRs.
+
+This facility is most often used to create a zone which will be used to
+forward mail from the Internet to some other mail system.  The general
+idea is that any name in that zone which is presented to server in a
+query will be assumed to exist, with certain properties, unless explicit
+evidence exists to the contrary.  Note that the use of the term zone
+here, instead of domain, is intentional; such defaults do not propagate
+across zone boundaries, although a subzone may choose to achieve that
+appearance by setting up similar defaults.
+
+The contents of the wildcard RRs follows the usual rules and formats for
+RRs.  The wildcards in the zone have an owner name that controls the
+query names they will match.  The owner name of the wildcard RRs is of
+the form "*.<anydomain>", where <anydomain> is any domain name.
+<anydomain> should not contain other * labels, and should be in the
+authoritative data of the zone.  The wildcards potentially apply to
+descendants of <anydomain>, but not to <anydomain> itself.  Another way
+
+
+
+Mockapetris                                                    [Page 25]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+to look at this is that the "*" label always matches at least one whole
+label and sometimes more, but always whole labels.
+
+Wildcard RRs do not apply:
+
+   - When the query is in another zone.  That is, delegation cancels
+     the wildcard defaults.
+
+   - When the query name or a name between the wildcard domain and
+     the query name is know to exist.  For example, if a wildcard
+     RR has an owner name of "*.X", and the zone also contains RRs
+     attached to B.X, the wildcards would apply to queries for name
+     Z.X (presuming there is no explicit information for Z.X), but
+     not to B.X, A.B.X, or X.
+
+A * label appearing in a query name has no special effect, but can be
+used to test for wildcards in an authoritative zone; such a query is the
+only way to get a response containing RRs with an owner name with * in
+it.  The result of such a query should not be cached.
+
+Note that the contents of the wildcard RRs are not modified when used to
+synthesize RRs.
+
+To illustrate the use of wildcard RRs, suppose a large company with a
+large, non-IP/TCP, network wanted to create a mail gateway.  If the
+company was called X.COM, and IP/TCP capable gateway machine was called
+A.X.COM, the following RRs might be entered into the COM zone:
+
+    X.COM           MX      10      A.X.COM
+
+    *.X.COM         MX      10      A.X.COM
+
+    A.X.COM         A       1.2.3.4
+    A.X.COM         MX      10      A.X.COM
+
+    *.A.X.COM       MX      10      A.X.COM
+
+This would cause any MX query for any domain name ending in X.COM to
+return an MX RR pointing at A.X.COM.  Two wildcard RRs are required
+since the effect of the wildcard at *.X.COM is inhibited in the A.X.COM
+subtree by the explicit data for A.X.COM.  Note also that the explicit
+MX data at X.COM and A.X.COM is required, and that none of the RRs above
+would match a query name of XX.COM.
+
+4.3.4. Negative response caching (Optional)
+
+The DNS provides an optional service which allows name servers to
+distribute, and resolvers to cache, negative results with TTLs.  For
+
+
+
+Mockapetris                                                    [Page 26]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+example, a name server can distribute a TTL along with a name error
+indication, and a resolver receiving such information is allowed to
+assume that the name does not exist during the TTL period without
+consulting authoritative data.  Similarly, a resolver can make a query
+with a QTYPE which matches multiple types, and cache the fact that some
+of the types are not present.
+
+This feature can be particularly important in a system which implements
+naming shorthands that use search lists beacuse a popular shorthand,
+which happens to require a suffix toward the end of the search list,
+will generate multiple name errors whenever it is used.
+
+The method is that a name server may add an SOA RR to the additional
+section of a response when that response is authoritative.  The SOA must
+be that of the zone which was the source of the authoritative data in
+the answer section, or name error if applicable.  The MINIMUM field of
+the SOA controls the length of time that the negative result may be
+cached.
+
+Note that in some circumstances, the answer section may contain multiple
+owner names.  In this case, the SOA mechanism should only be used for
+the data which matches QNAME, which is the only authoritative data in
+this section.
+
+Name servers and resolvers should never attempt to add SOAs to the
+additional section of a non-authoritative response, or attempt to infer
+results which are not directly stated in an authoritative response.
+There are several reasons for this, including: cached information isn't
+usually enough to match up RRs and their zone names, SOA RRs may be
+cached due to direct SOA queries, and name servers are not required to
+output the SOAs in the authority section.
+
+This feature is optional, although a refined version is expected to
+become part of the standard protocol in the future.  Name servers are
+not required to add the SOA RRs in all authoritative responses, nor are
+resolvers required to cache negative results.  Both are recommended.
+All resolvers and recursive name servers are required to at least be
+able to ignore the SOA RR when it is present in a response.
+
+Some experiments have also been proposed which will use this feature.
+The idea is that if cached data is known to come from a particular zone,
+and if an authoritative copy of the zone's SOA is obtained, and if the
+zone's SERIAL has not changed since the data was cached, then the TTL of
+the cached data can be reset to the zone MINIMUM value if it is smaller.
+This usage is mentioned for planning purposes only, and is not
+recommended as yet.
+
+
+
+
+
+Mockapetris                                                    [Page 27]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+4.3.5. Zone maintenance and transfers
+
+Part of the job of a zone administrator is to maintain the zones at all
+of the name servers which are authoritative for the zone.  When the
+inevitable changes are made, they must be distributed to all of the name
+servers.  While this distribution can be accomplished using FTP or some
+other ad hoc procedure, the preferred method is the zone transfer part
+of the DNS protocol.
+
+The general model of automatic zone transfer or refreshing is that one
+of the name servers is the master or primary for the zone.  Changes are
+coordinated at the primary, typically by editing a master file for the
+zone.  After editing, the administrator signals the master server to
+load the new zone.  The other non-master or secondary servers for the
+zone periodically check for changes (at a selectable interval) and
+obtain new zone copies when changes have been made.
+
+To detect changes, secondaries just check the SERIAL field of the SOA
+for the zone.  In addition to whatever other changes are made, the
+SERIAL field in the SOA of the zone is always advanced whenever any
+change is made to the zone.  The advancing can be a simple increment, or
+could be based on the write date and time of the master file, etc.  The
+purpose is to make it possible to determine which of two copies of a
+zone is more recent by comparing serial numbers.  Serial number advances
+and comparisons use sequence space arithmetic, so there is a theoretic
+limit on how fast a zone can be updated, basically that old copies must
+die out before the serial number covers half of its 32 bit range.  In
+practice, the only concern is that the compare operation deals properly
+with comparisons around the boundary between the most positive and most
+negative 32 bit numbers.
+
+The periodic polling of the secondary servers is controlled by
+parameters in the SOA RR for the zone, which set the minimum acceptable
+polling intervals.  The parameters are called REFRESH, RETRY, and
+EXPIRE.  Whenever a new zone is loaded in a secondary, the secondary
+waits REFRESH seconds before checking with the primary for a new serial.
+If this check cannot be completed, new checks are started every RETRY
+seconds.  The check is a simple query to the primary for the SOA RR of
+the zone.  If the serial field in the secondary's zone copy is equal to
+the serial returned by the primary, then no changes have occurred, and
+the REFRESH interval wait is restarted.  If the secondary finds it
+impossible to perform a serial check for the EXPIRE interval, it must
+assume that its copy of the zone is obsolete an discard it.
+
+When the poll shows that the zone has changed, then the secondary server
+must request a zone transfer via an AXFR request for the zone.  The AXFR
+may cause an error, such as refused, but normally is answered by a
+sequence of response messages.  The first and last messages must contain
+
+
+
+Mockapetris                                                    [Page 28]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+the data for the top authoritative node of the zone.  Intermediate
+messages carry all of the other RRs from the zone, including both
+authoritative and non-authoritative RRs.  The stream of messages allows
+the secondary to construct a copy of the zone.  Because accuracy is
+essential, TCP or some other reliable protocol must be used for AXFR
+requests.
+
+Each secondary server is required to perform the following operations
+against the master, but may also optionally perform these operations
+against other secondary servers.  This strategy can improve the transfer
+process when the primary is unavailable due to host downtime or network
+problems, or when a secondary server has better network access to an
+"intermediate" secondary than to the primary.
+
+5. RESOLVERS
+
+5.1. Introduction
+
+Resolvers are programs that interface user programs to domain name
+servers.  In the simplest case, a resolver receives a request from a
+user program (e.g., mail programs, TELNET, FTP) in the form of a
+subroutine call, system call etc., and returns the desired information
+in a form compatible with the local host's data formats.
+
+The resolver is located on the same machine as the program that requests
+the resolver's services, but it may need to consult name servers on
+other hosts.  Because a resolver may need to consult several name
+servers, or may have the requested information in a local cache, the
+amount of time that a resolver will take to complete can vary quite a
+bit, from milliseconds to several seconds.
+
+A very important goal of the resolver is to eliminate network delay and
+name server load from most requests by answering them from its cache of
+prior results.  It follows that caches which are shared by multiple
+processes, users, machines, etc., are more efficient than non-shared
+caches.
+
+5.2. Client-resolver interface
+
+5.2.1. Typical functions
+
+The client interface to the resolver is influenced by the local host's
+conventions, but the typical resolver-client interface has three
+functions:
+
+   1. Host name to host address translation.
+
+      This function is often defined to mimic a previous HOSTS.TXT
+
+
+
+Mockapetris                                                    [Page 29]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+      based function.  Given a character string, the caller wants
+      one or more 32 bit IP addresses.  Under the DNS, it
+      translates into a request for type A RRs.  Since the DNS does
+      not preserve the order of RRs, this function may choose to
+      sort the returned addresses or select the "best" address if
+      the service returns only one choice to the client.  Note that
+      a multiple address return is recommended, but a single
+      address may be the only way to emulate prior HOSTS.TXT
+      services.
+
+   2. Host address to host name translation
+
+      This function will often follow the form of previous
+      functions.  Given a 32 bit IP address, the caller wants a
+      character string.  The octets of the IP address are reversed,
+      used as name components, and suffixed with "IN-ADDR.ARPA".  A
+      type PTR query is used to get the RR with the primary name of
+      the host.  For example, a request for the host name
+      corresponding to IP address 1.2.3.4 looks for PTR RRs for
+      domain name "4.3.2.1.IN-ADDR.ARPA".
+
+   3. General lookup function
+
+      This function retrieves arbitrary information from the DNS,
+      and has no counterpart in previous systems.  The caller
+      supplies a QNAME, QTYPE, and QCLASS, and wants all of the
+      matching RRs.  This function will often use the DNS format
+      for all RR data instead of the local host's, and returns all
+      RR content (e.g., TTL) instead of a processed form with local
+      quoting conventions.
+
+When the resolver performs the indicated function, it usually has one of
+the following results to pass back to the client:
+
+   - One or more RRs giving the requested data.
+
+     In this case the resolver returns the answer in the
+     appropriate format.
+
+   - A name error (NE).
+
+     This happens when the referenced name does not exist.  For
+     example, a user may have mistyped a host name.
+
+   - A data not found error.
+
+     This happens when the referenced name exists, but data of the
+     appropriate type does not.  For example, a host address
+
+
+
+Mockapetris                                                    [Page 30]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+     function applied to a mailbox name would return this error
+     since the name exists, but no address RR is present.
+
+It is important to note that the functions for translating between host
+names and addresses may combine the "name error" and "data not found"
+error conditions into a single type of error return, but the general
+function should not.  One reason for this is that applications may ask
+first for one type of information about a name followed by a second
+request to the same name for some other type of information; if the two
+errors are combined, then useless queries may slow the application.
+
+5.2.2. Aliases
+
+While attempting to resolve a particular request, the resolver may find
+that the name in question is an alias.  For example, the resolver might
+find that the name given for host name to address translation is an
+alias when it finds the CNAME RR.  If possible, the alias condition
+should be signalled back from the resolver to the client.
+
+In most cases a resolver simply restarts the query at the new name when
+it encounters a CNAME.  However, when performing the general function,
+the resolver should not pursue aliases when the CNAME RR matches the
+query type.  This allows queries which ask whether an alias is present.
+For example, if the query type is CNAME, the user is interested in the
+CNAME RR itself, and not the RRs at the name it points to.
+
+Several special conditions can occur with aliases.  Multiple levels of
+aliases should be avoided due to their lack of efficiency, but should
+not be signalled as an error.  Alias loops and aliases which point to
+non-existent names should be caught and an error condition passed back
+to the client.
+
+5.2.3. Temporary failures
+
+In a less than perfect world, all resolvers will occasionally be unable
+to resolve a particular request.  This condition can be caused by a
+resolver which becomes separated from the rest of the network due to a
+link failure or gateway problem, or less often by coincident failure or
+unavailability of all servers for a particular domain.
+
+It is essential that this sort of condition should not be signalled as a
+name or data not present error to applications.  This sort of behavior
+is annoying to humans, and can wreak havoc when mail systems use the
+DNS.
+
+While in some cases it is possible to deal with such a temporary problem
+by blocking the request indefinitely, this is usually not a good choice,
+particularly when the client is a server process that could move on to
+
+
+
+Mockapetris                                                    [Page 31]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+other tasks.  The recommended solution is to always have temporary
+failure as one of the possible results of a resolver function, even
+though this may make emulation of existing HOSTS.TXT functions more
+difficult.
+
+5.3. Resolver internals
+
+Every resolver implementation uses slightly different algorithms, and
+typically spends much more logic dealing with errors of various sorts
+than typical occurances.  This section outlines a recommended basic
+strategy for resolver operation, but leaves details to [RFC-1035].
+
+5.3.1. Stub resolvers
+
+One option for implementing a resolver is to move the resolution
+function out of the local machine and into a name server which supports
+recursive queries.  This can provide an easy method of providing domain
+service in a PC which lacks the resources to perform the resolver
+function, or can centralize the cache for a whole local network or
+organization.
+
+All that the remaining stub needs is a list of name server addresses
+that will perform the recursive requests.  This type of resolver
+presumably needs the information in a configuration file, since it
+probably lacks the sophistication to locate it in the domain database.
+The user also needs to verify that the listed servers will perform the
+recursive service; a name server is free to refuse to perform recursive
+services for any or all clients.  The user should consult the local
+system administrator to find name servers willing to perform the
+service.
+
+This type of service suffers from some drawbacks.  Since the recursive
+requests may take an arbitrary amount of time to perform, the stub may
+have difficulty optimizing retransmission intervals to deal with both
+lost UDP packets and dead servers; the name server can be easily
+overloaded by too zealous a stub if it interprets retransmissions as new
+requests.  Use of TCP may be an answer, but TCP may well place burdens
+on the host's capabilities which are similar to those of a real
+resolver.
+
+5.3.2. Resources
+
+In addition to its own resources, the resolver may also have shared
+access to zones maintained by a local name server.  This gives the
+resolver the advantage of more rapid access, but the resolver must be
+careful to never let cached information override zone data.  In this
+discussion the term "local information" is meant to mean the union of
+the cache and such shared zones, with the understanding that
+
+
+
+Mockapetris                                                    [Page 32]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+authoritative data is always used in preference to cached data when both
+are present.
+
+The following resolver algorithm assumes that all functions have been
+converted to a general lookup function, and uses the following data
+structures to represent the state of a request in progress in the
+resolver:
+
+SNAME           the domain name we are searching for.
+
+STYPE           the QTYPE of the search request.
+
+SCLASS          the QCLASS of the search request.
+
+SLIST           a structure which describes the name servers and the
+                zone which the resolver is currently trying to query.
+                This structure keeps track of the resolver's current
+                best guess about which name servers hold the desired
+                information; it is updated when arriving information
+                changes the guess.  This structure includes the
+                equivalent of a zone name, the known name servers for
+                the zone, the known addresses for the name servers, and
+                history information which can be used to suggest which
+                server is likely to be the best one to try next.  The
+                zone name equivalent is a match count of the number of
+                labels from the root down which SNAME has in common with
+                the zone being queried; this is used as a measure of how
+                "close" the resolver is to SNAME.
+
+SBELT           a "safety belt" structure of the same form as SLIST,
+                which is initialized from a configuration file, and
+                lists servers which should be used when the resolver
+                doesn't have any local information to guide name server
+                selection.  The match count will be -1 to indicate that
+                no labels are known to match.
+
+CACHE           A structure which stores the results from previous
+                responses.  Since resolvers are responsible for
+                discarding old RRs whose TTL has expired, most
+                implementations convert the interval specified in
+                arriving RRs to some sort of absolute time when the RR
+                is stored in the cache.  Instead of counting the TTLs
+                down individually, the resolver just ignores or discards
+                old RRs when it runs across them in the course of a
+                search, or discards them during periodic sweeps to
+                reclaim the memory consumed by old RRs.
+
+
+
+
+
+Mockapetris                                                    [Page 33]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+5.3.3. Algorithm
+
+The top level algorithm has four steps:
+
+   1. See if the answer is in local information, and if so return
+      it to the client.
+
+   2. Find the best servers to ask.
+
+   3. Send them queries until one returns a response.
+
+   4. Analyze the response, either:
+
+         a. if the response answers the question or contains a name
+            error, cache the data as well as returning it back to
+            the client.
+
+         b. if the response contains a better delegation to other
+            servers, cache the delegation information, and go to
+            step 2.
+
+         c. if the response shows a CNAME and that is not the
+            answer itself, cache the CNAME, change the SNAME to the
+            canonical name in the CNAME RR and go to step 1.
+
+         d. if the response shows a servers failure or other
+            bizarre contents, delete the server from the SLIST and
+            go back to step 3.
+
+Step 1 searches the cache for the desired data. If the data is in the
+cache, it is assumed to be good enough for normal use.  Some resolvers
+have an option at the user interface which will force the resolver to
+ignore the cached data and consult with an authoritative server.  This
+is not recommended as the default.  If the resolver has direct access to
+a name server's zones, it should check to see if the desired data is
+present in authoritative form, and if so, use the authoritative data in
+preference to cached data.
+
+Step 2 looks for a name server to ask for the required data.  The
+general strategy is to look for locally-available name server RRs,
+starting at SNAME, then the parent domain name of SNAME, the
+grandparent, and so on toward the root.  Thus if SNAME were
+Mockapetris.ISI.EDU, this step would look for NS RRs for
+Mockapetris.ISI.EDU, then ISI.EDU, then EDU, and then . (the root).
+These NS RRs list the names of hosts for a zone at or above SNAME.  Copy
+the names into SLIST.  Set up their addresses using local data.  It may
+be the case that the addresses are not available.  The resolver has many
+choices here; the best is to start parallel resolver processes looking
+
+
+
+Mockapetris                                                    [Page 34]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+for the addresses while continuing onward with the addresses which are
+available.  Obviously, the design choices and options are complicated
+and a function of the local host's capabilities.  The recommended
+priorities for the resolver designer are:
+
+   1. Bound the amount of work (packets sent, parallel processes
+      started) so that a request can't get into an infinite loop or
+      start off a chain reaction of requests or queries with other
+      implementations EVEN IF SOMEONE HAS INCORRECTLY CONFIGURED
+      SOME DATA.
+
+   2. Get back an answer if at all possible.
+
+   3. Avoid unnecessary transmissions.
+
+   4. Get the answer as quickly as possible.
+
+If the search for NS RRs fails, then the resolver initializes SLIST from
+the safety belt SBELT.  The basic idea is that when the resolver has no
+idea what servers to ask, it should use information from a configuration
+file that lists several servers which are expected to be helpful.
+Although there are special situations, the usual choice is two of the
+root servers and two of the servers for the host's domain.  The reason
+for two of each is for redundancy.  The root servers will provide
+eventual access to all of the domain space.  The two local servers will
+allow the resolver to continue to resolve local names if the local
+network becomes isolated from the internet due to gateway or link
+failure.
+
+In addition to the names and addresses of the servers, the SLIST data
+structure can be sorted to use the best servers first, and to insure
+that all addresses of all servers are used in a round-robin manner.  The
+sorting can be a simple function of preferring addresses on the local
+network over others, or may involve statistics from past events, such as
+previous response times and batting averages.
+
+Step 3 sends out queries until a response is received.  The strategy is
+to cycle around all of the addresses for all of the servers with a
+timeout between each transmission.  In practice it is important to use
+all addresses of a multihomed host, and too aggressive a retransmission
+policy actually slows response when used by multiple resolvers
+contending for the same name server and even occasionally for a single
+resolver.  SLIST typically contains data values to control the timeouts
+and keep track of previous transmissions.
+
+Step 4 involves analyzing responses.  The resolver should be highly
+paranoid in its parsing of responses.  It should also check that the
+response matches the query it sent using the ID field in the response.
+
+
+
+Mockapetris                                                    [Page 35]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+The ideal answer is one from a server authoritative for the query which
+either gives the required data or a name error.  The data is passed back
+to the user and entered in the cache for future use if its TTL is
+greater than zero.
+
+If the response shows a delegation, the resolver should check to see
+that the delegation is "closer" to the answer than the servers in SLIST
+are.  This can be done by comparing the match count in SLIST with that
+computed from SNAME and the NS RRs in the delegation.  If not, the reply
+is bogus and should be ignored.  If the delegation is valid the NS
+delegation RRs and any address RRs for the servers should be cached.
+The name servers are entered in the SLIST, and the search is restarted.
+
+If the response contains a CNAME, the search is restarted at the CNAME
+unless the response has the data for the canonical name or if the CNAME
+is the answer itself.
+
+Details and implementation hints can be found in [RFC-1035].
+
+6. A SCENARIO
+
+In our sample domain space, suppose we wanted separate administrative
+control for the root, MIL, EDU, MIT.EDU and ISI.EDU zones.  We might
+allocate name servers as follows:
+
+
+                                   |(C.ISI.EDU,SRI-NIC.ARPA
+                                   | A.ISI.EDU)
+             +---------------------+------------------+
+             |                     |                  |
+            MIL                   EDU                ARPA
+             |(SRI-NIC.ARPA,       |(SRI-NIC.ARPA,    |
+             | A.ISI.EDU           | C.ISI.EDU)       |
+       +-----+-----+               |     +------+-----+-----+
+       |     |     |               |     |      |           |
+      BRL  NOSC  DARPA             |  IN-ADDR  SRI-NIC     ACC
+                                   |
+       +--------+------------------+---------------+--------+
+       |        |                  |               |        |
+      UCI      MIT                 |              UDEL     YALE
+                |(XX.LCS.MIT.EDU, ISI
+                |ACHILLES.MIT.EDU) |(VAXA.ISI.EDU,VENERA.ISI.EDU,
+            +---+---+              | A.ISI.EDU)
+            |       |              |
+           LCS   ACHILLES +--+-----+-----+--------+
+            |             |  |     |     |        |
+            XX            A  C   VAXA  VENERA Mockapetris
+
+
+
+
+Mockapetris                                                    [Page 36]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+In this example, the authoritative name server is shown in parentheses
+at the point in the domain tree at which is assumes control.
+
+Thus the root name servers are on C.ISI.EDU, SRI-NIC.ARPA, and
+A.ISI.EDU.  The MIL domain is served by SRI-NIC.ARPA and A.ISI.EDU.  The
+EDU domain is served by SRI-NIC.ARPA. and C.ISI.EDU.  Note that servers
+may have zones which are contiguous or disjoint.  In this scenario,
+C.ISI.EDU has contiguous zones at the root and EDU domains.  A.ISI.EDU
+has contiguous zones at the root and MIL domains, but also has a non-
+contiguous zone at ISI.EDU.
+
+6.1. C.ISI.EDU name server
+
+C.ISI.EDU is a name server for the root, MIL, and EDU domains of the IN
+class, and would have zones for these domains.  The zone data for the
+root domain might be:
+
+    .       IN      SOA     SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+                            870611          ;serial
+                            1800            ;refresh every 30 min
+                            300             ;retry every 5 min
+                            604800          ;expire after a week
+                            86400)          ;minimum of a day
+                    NS      A.ISI.EDU.
+                    NS      C.ISI.EDU.
+                    NS      SRI-NIC.ARPA.
+
+    MIL.    86400   NS      SRI-NIC.ARPA.
+            86400   NS      A.ISI.EDU.
+
+    EDU.    86400   NS      SRI-NIC.ARPA.
+            86400   NS      C.ISI.EDU.
+
+    SRI-NIC.ARPA.   A       26.0.0.73
+                    A       10.0.0.51
+                    MX      0 SRI-NIC.ARPA.
+                    HINFO   DEC-2060 TOPS20
+
+    ACC.ARPA.       A       26.6.0.65
+                    HINFO   PDP-11/70 UNIX
+                    MX      10 ACC.ARPA.
+
+    USC-ISIC.ARPA.  CNAME   C.ISI.EDU.
+
+    73.0.0.26.IN-ADDR.ARPA.  PTR    SRI-NIC.ARPA.
+    65.0.6.26.IN-ADDR.ARPA.  PTR    ACC.ARPA.
+    51.0.0.10.IN-ADDR.ARPA.  PTR    SRI-NIC.ARPA.
+    52.0.0.10.IN-ADDR.ARPA.  PTR    C.ISI.EDU.
+
+
+
+Mockapetris                                                    [Page 37]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+    103.0.3.26.IN-ADDR.ARPA. PTR    A.ISI.EDU.
+
+    A.ISI.EDU. 86400 A      26.3.0.103
+    C.ISI.EDU. 86400 A      10.0.0.52
+
+This data is represented as it would be in a master file.  Most RRs are
+single line entries; the sole exception here is the SOA RR, which uses
+"(" to start a multi-line RR and ")" to show the end of a multi-line RR.
+Since the class of all RRs in a zone must be the same, only the first RR
+in a zone need specify the class.  When a name server loads a zone, it
+forces the TTL of all authoritative RRs to be at least the MINIMUM field
+of the SOA, here 86400 seconds, or one day.  The NS RRs marking
+delegation of the MIL and EDU domains, together with the glue RRs for
+the servers host addresses, are not part of the authoritative data in
+the zone, and hence have explicit TTLs.
+
+Four RRs are attached to the root node: the SOA which describes the root
+zone and the 3 NS RRs which list the name servers for the root.  The
+data in the SOA RR describes the management of the zone.  The zone data
+is maintained on host SRI-NIC.ARPA, and the responsible party for the
+zone is HOSTMASTER at SRI-NIC.ARPA.  A key item in the SOA is the 86400
+second minimum TTL, which means that all authoritative data in the zone
+has at least that TTL, although higher values may be explicitly
+specified.
+
+The NS RRs for the MIL and EDU domains mark the boundary between the
+root zone and the MIL and EDU zones.  Note that in this example, the
+lower zones happen to be supported by name servers which also support
+the root zone.
+
+The master file for the EDU zone might be stated relative to the origin
+EDU.  The zone data for the EDU domain might be:
+
+    EDU.  IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+                            870729 ;serial
+                            1800 ;refresh every 30 minutes
+                            300 ;retry every 5 minutes
+                            604800 ;expire after a week
+                            86400 ;minimum of a day
+                            )
+                    NS SRI-NIC.ARPA.
+                    NS C.ISI.EDU.
+
+    UCI 172800 NS ICS.UCI
+                    172800 NS ROME.UCI
+    ICS.UCI 172800 A 192.5.19.1
+    ROME.UCI 172800 A 192.5.19.31
+
+
+
+
+Mockapetris                                                    [Page 38]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+    ISI 172800 NS VAXA.ISI
+                    172800 NS A.ISI
+                    172800 NS VENERA.ISI.EDU.
+    VAXA.ISI 172800 A 10.2.0.27
+                    172800 A 128.9.0.33
+    VENERA.ISI.EDU. 172800 A 10.1.0.52
+                    172800 A 128.9.0.32
+    A.ISI 172800 A 26.3.0.103
+
+    UDEL.EDU.  172800 NS LOUIE.UDEL.EDU.
+                    172800 NS UMN-REI-UC.ARPA.
+    LOUIE.UDEL.EDU. 172800 A 10.0.0.96
+                    172800 A 192.5.39.3
+
+    YALE.EDU.  172800 NS YALE.ARPA.
+    YALE.EDU.  172800 NS YALE-BULLDOG.ARPA.
+
+    MIT.EDU.  43200 NS XX.LCS.MIT.EDU.
+                      43200 NS ACHILLES.MIT.EDU.
+    XX.LCS.MIT.EDU.  43200 A 10.0.0.44
+    ACHILLES.MIT.EDU. 43200 A 18.72.0.8
+
+Note the use of relative names here.  The owner name for the ISI.EDU. is
+stated using a relative name, as are two of the name server RR contents.
+Relative and absolute domain names may be freely intermixed in a master
+
+6.2. Example standard queries
+
+The following queries and responses illustrate name server behavior.
+Unless otherwise noted, the queries do not have recursion desired (RD)
+in the header.  Note that the answers to non-recursive queries do depend
+on the server being asked, but do not depend on the identity of the
+requester.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 39]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+6.2.1. QNAME=SRI-NIC.ARPA, QTYPE=A
+
+The query would look like:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY                                     |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A           |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+The response from C.ISI.EDU would be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A           |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 86400 IN A 26.0.0.73                |
+               |               86400 IN A 10.0.0.51                |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+The header of the response looks like the header of the query, except
+that the RESPONSE bit is set, indicating that this message is a
+response, not a query, and the Authoritative Answer (AA) bit is set
+indicating that the address RRs in the answer section are from
+authoritative data.  The question section of the response matches the
+question section of the query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 40]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+If the same query was sent to some other server which was not
+authoritative for SRI-NIC.ARPA, the response might be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY,RESPONSE                            |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A           |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 1777 IN A 10.0.0.51                 |
+               |               1777 IN A 26.0.0.73                 |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+This response is different from the previous one in two ways: the header
+does not have AA set, and the TTLs are different.  The inference is that
+the data did not come from a zone, but from a cache.  The difference
+between the authoritative TTL and the TTL here is due to aging of the
+data in a cache.  The difference in ordering of the RRs in the answer
+section is not significant.
+
+6.2.2. QNAME=SRI-NIC.ARPA, QTYPE=*
+
+A query similar to the previous one, but using a QTYPE of *, would
+receive the following response from C.ISI.EDU:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 86400 IN  A     26.0.0.73           |
+               |                         A     10.0.0.51           |
+               |                         MX    0 SRI-NIC.ARPA.     |
+               |                         HINFO DEC-2060 TOPS20     |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 41]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+If a similar query was directed to two name servers which are not
+authoritative for SRI-NIC.ARPA, the responses might be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE                           |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 12345 IN     A       26.0.0.73      |
+               |                            A       10.0.0.51      |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+and
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE                           |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=*           |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 1290 IN HINFO  DEC-2060 TOPS20      |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+Neither of these answers have AA set, so neither response comes from
+authoritative data.  The different contents and different TTLs suggest
+that the two servers cached data at different times, and that the first
+server cached the response to a QTYPE=A query and the second cached the
+response to a HINFO query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 42]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+6.2.3. QNAME=SRI-NIC.ARPA, QTYPE=MX
+
+This type of query might be result from a mailer trying to look up
+routing information for the mail destination HOSTMASTER at SRI-NIC.ARPA.
+The response from C.ISI.EDU would be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=MX          |
+               +---------------------------------------------------+
+    Answer     | SRI-NIC.ARPA. 86400 IN     MX      0 SRI-NIC.ARPA.|
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | SRI-NIC.ARPA. 86400 IN     A       26.0.0.73      |
+               |                            A       10.0.0.51      |
+               +---------------------------------------------------+
+
+This response contains the MX RR in the answer section of the response.
+The additional section contains the address RRs because the name server
+at C.ISI.EDU guesses that the requester will need the addresses in order
+to properly use the information carried by the MX.
+
+6.2.4. QNAME=SRI-NIC.ARPA, QTYPE=NS
+
+C.ISI.EDU would reply to this query with:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=NS          |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+The only difference between the response and the query is the AA and
+RESPONSE bits in the header.  The interpretation of this response is
+that the server is authoritative for the name, and the name exists, but
+no RRs of type NS are present there.
+
+6.2.5. QNAME=SIR-NIC.ARPA, QTYPE=A
+
+If a user mistyped a host name, we might see this type of query.
+
+
+
+Mockapetris                                                    [Page 43]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+C.ISI.EDU would answer it with:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA, RCODE=NE             |
+               +---------------------------------------------------+
+    Question   | QNAME=SIR-NIC.ARPA., QCLASS=IN, QTYPE=A           |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | . SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA.      |
+               |       870611 1800 300 604800 86400                |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+This response states that the name does not exist.  This condition is
+signalled in the response code (RCODE) section of the header.
+
+The SOA RR in the authority section is the optional negative caching
+information which allows the resolver using this response to assume that
+the name will not exist for the SOA MINIMUM (86400) seconds.
+
+6.2.6. QNAME=BRL.MIL, QTYPE=A
+
+If this query is sent to C.ISI.EDU, the reply would be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE                           |
+               +---------------------------------------------------+
+    Question   | QNAME=BRL.MIL, QCLASS=IN, QTYPE=A                 |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | MIL.             86400 IN NS       SRI-NIC.ARPA.  |
+               |                  86400    NS       A.ISI.EDU.     |
+               +---------------------------------------------------+
+    Additional | A.ISI.EDU.                A        26.3.0.103     |
+               | SRI-NIC.ARPA.             A        26.0.0.73      |
+               |                           A        10.0.0.51      |
+               +---------------------------------------------------+
+
+This response has an empty answer section, but is not authoritative, so
+it is a referral.  The name server on C.ISI.EDU, realizing that it is
+not authoritative for the MIL domain, has referred the requester to
+servers on A.ISI.EDU and SRI-NIC.ARPA, which it knows are authoritative
+for the MIL domain.
+
+
+
+
+
+Mockapetris                                                    [Page 44]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+6.2.7. QNAME=USC-ISIC.ARPA, QTYPE=A
+
+The response to this query from A.ISI.EDU would be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A          |
+               +---------------------------------------------------+
+    Answer     | USC-ISIC.ARPA. 86400 IN CNAME      C.ISI.EDU.     |
+               | C.ISI.EDU.     86400 IN A          10.0.0.52      |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+Note that the AA bit in the header guarantees that the data matching
+QNAME is authoritative, but does not say anything about whether the data
+for C.ISI.EDU is authoritative.  This complete reply is possible because
+A.ISI.EDU happens to be authoritative for both the ARPA domain where
+USC-ISIC.ARPA is found and the ISI.EDU domain where C.ISI.EDU data is
+found.
+
+If the same query was sent to C.ISI.EDU, its response might be the same
+as shown above if it had its own address in its cache, but might also
+be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 45]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A          |
+               +---------------------------------------------------+
+    Answer     | USC-ISIC.ARPA.   86400 IN CNAME   C.ISI.EDU.      |
+               +---------------------------------------------------+
+    Authority  | ISI.EDU.        172800 IN NS      VAXA.ISI.EDU.   |
+               |                           NS      A.ISI.EDU.      |
+               |                           NS      VENERA.ISI.EDU. |
+               +---------------------------------------------------+
+    Additional | VAXA.ISI.EDU.   172800    A       10.2.0.27       |
+               |                 172800    A       128.9.0.33      |
+               | VENERA.ISI.EDU. 172800    A       10.1.0.52       |
+               |                 172800    A       128.9.0.32      |
+               | A.ISI.EDU.      172800    A       26.3.0.103      |
+               +---------------------------------------------------+
+
+This reply contains an authoritative reply for the alias USC-ISIC.ARPA,
+plus a referral to the name servers for ISI.EDU.  This sort of reply
+isn't very likely given that the query is for the host name of the name
+server being asked, but would be common for other aliases.
+
+6.2.8. QNAME=USC-ISIC.ARPA, QTYPE=CNAME
+
+If this query is sent to either A.ISI.EDU or C.ISI.EDU, the reply would
+be:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A          |
+               +---------------------------------------------------+
+    Answer     | USC-ISIC.ARPA. 86400 IN CNAME      C.ISI.EDU.     |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+Because QTYPE=CNAME, the CNAME RR itself answers the query, and the name
+server doesn't attempt to look up anything for C.ISI.EDU.  (Except
+possibly for the additional section.)
+
+6.3. Example resolution
+
+The following examples illustrate the operations a resolver must perform
+for its client.  We assume that the resolver is starting without a
+
+
+
+Mockapetris                                                    [Page 46]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+cache, as might be the case after system boot.  We further assume that
+the system is not one of the hosts in the data and that the host is
+located somewhere on net 26, and that its safety belt (SBELT) data
+structure has the following information:
+
+    Match count = -1
+    SRI-NIC.ARPA.   26.0.0.73       10.0.0.51
+    A.ISI.EDU.      26.3.0.103
+
+This information specifies servers to try, their addresses, and a match
+count of -1, which says that the servers aren't very close to the
+target.  Note that the -1 isn't supposed to be an accurate closeness
+measure, just a value so that later stages of the algorithm will work.
+
+The following examples illustrate the use of a cache, so each example
+assumes that previous requests have completed.
+
+6.3.1. Resolve MX for ISI.EDU.
+
+Suppose the first request to the resolver comes from the local mailer,
+which has mail for PVM at ISI.EDU.  The mailer might then ask for type MX
+RRs for the domain name ISI.EDU.
+
+The resolver would look in its cache for MX RRs at ISI.EDU, but the
+empty cache wouldn't be helpful.  The resolver would recognize that it
+needed to query foreign servers and try to determine the best servers to
+query.  This search would look for NS RRs for the domains ISI.EDU, EDU,
+and the root.  These searches of the cache would also fail.  As a last
+resort, the resolver would use the information from the SBELT, copying
+it into its SLIST structure.
+
+At this point the resolver would need to pick one of the three available
+addresses to try.  Given that the resolver is on net 26, it should
+choose either 26.0.0.73 or 26.3.0.103 as its first choice.  It would
+then send off a query of the form:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 47]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY                                     |
+               +---------------------------------------------------+
+    Question   | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX               |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+The resolver would then wait for a response to its query or a timeout.
+If the timeout occurs, it would try different servers, then different
+addresses of the same servers, lastly retrying addresses already tried.
+It might eventually receive a reply from SRI-NIC.ARPA:
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE                           |
+               +---------------------------------------------------+
+    Question   | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX               |
+               +---------------------------------------------------+
+    Answer     | <empty>                                           |
+               +---------------------------------------------------+
+    Authority  | ISI.EDU.        172800 IN NS       VAXA.ISI.EDU.  |
+               |                           NS       A.ISI.EDU.     |
+               |                           NS       VENERA.ISI.EDU.|
+               +---------------------------------------------------+
+    Additional | VAXA.ISI.EDU.   172800    A        10.2.0.27      |
+               |                 172800    A        128.9.0.33     |
+               | VENERA.ISI.EDU. 172800    A        10.1.0.52      |
+               |                 172800    A        128.9.0.32     |
+               | A.ISI.EDU.      172800    A        26.3.0.103     |
+               +---------------------------------------------------+
+
+The resolver would notice that the information in the response gave a
+closer delegation to ISI.EDU than its existing SLIST (since it matches
+three labels).  The resolver would then cache the information in this
+response and use it to set up a new SLIST:
+
+    Match count = 3
+    A.ISI.EDU.      26.3.0.103
+    VAXA.ISI.EDU.   10.2.0.27       128.9.0.33
+    VENERA.ISI.EDU. 10.1.0.52       128.9.0.32
+
+A.ISI.EDU appears on this list as well as the previous one, but that is
+purely coincidental.  The resolver would again start transmitting and
+waiting for responses.  Eventually it would get an answer:
+
+
+
+Mockapetris                                                    [Page 48]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX               |
+               +---------------------------------------------------+
+    Answer     | ISI.EDU.                MX 10 VENERA.ISI.EDU.     |
+               |                         MX 20 VAXA.ISI.EDU.       |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | VAXA.ISI.EDU.   172800  A  10.2.0.27              |
+               |                 172800  A  128.9.0.33             |
+               | VENERA.ISI.EDU. 172800  A  10.1.0.52              |
+               |                 172800  A  128.9.0.32             |
+               +---------------------------------------------------+
+
+The resolver would add this information to its cache, and return the MX
+RRs to its client.
+
+6.3.2. Get the host name for address 26.6.0.65
+
+The resolver would translate this into a request for PTR RRs for
+65.0.6.26.IN-ADDR.ARPA.  This information is not in the cache, so the
+resolver would look for foreign servers to ask.  No servers would match,
+so it would use SBELT again.  (Note that the servers for the ISI.EDU
+domain are in the cache, but ISI.EDU is not an ancestor of
+65.0.6.26.IN-ADDR.ARPA, so the SBELT is used.)
+
+Since this request is within the authoritative data of both servers in
+SBELT, eventually one would return:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 49]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+               +---------------------------------------------------+
+    Header     | OPCODE=SQUERY, RESPONSE, AA                       |
+               +---------------------------------------------------+
+    Question   | QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR |
+               +---------------------------------------------------+
+    Answer     | 65.0.6.26.IN-ADDR.ARPA.    PTR     ACC.ARPA.      |
+               +---------------------------------------------------+
+    Authority  | <empty>                                           |
+               +---------------------------------------------------+
+    Additional | <empty>                                           |
+               +---------------------------------------------------+
+
+6.3.3. Get the host address of poneria.ISI.EDU
+
+This request would translate into a type A request for poneria.ISI.EDU.
+The resolver would not find any cached data for this name, but would
+find the NS RRs in the cache for ISI.EDU when it looks for foreign
+servers to ask.  Using this data, it would construct a SLIST of the
+form:
+
+    Match count = 3
+
+    A.ISI.EDU.      26.3.0.103
+    VAXA.ISI.EDU.   10.2.0.27       128.9.0.33
+    VENERA.ISI.EDU. 10.1.0.52
+
+A.ISI.EDU is listed first on the assumption that the resolver orders its
+choices by preference, and A.ISI.EDU is on the same network.
+
+One of these servers would answer the query.
+
+7. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87]       Dyer, S., and F. Hsu, "Hesiod", Project Athena
+                Technical Plan - Name Service, April 1987, version 1.9.
+
+                Describes the fundamentals of the Hesiod name service.
+
+[IEN-116]       J. Postel, "Internet Name Server", IEN-116,
+                USC/Information Sciences Institute, August 1979.
+
+                A name service obsoleted by the Domain Name System, but
+                still in use.
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 50]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+[Quarterman 86] Quarterman, J., and J. Hoskins, "Notable Computer
+                Networks",Communications of the ACM, October 1986,
+                volume 29, number 10.
+
+[RFC-742]       K. Harrenstien, "NAME/FINGER", RFC-742, Network
+                Information Center, SRI International, December 1977.
+
+[RFC-768]       J. Postel, "User Datagram Protocol", RFC-768,
+                USC/Information Sciences Institute, August 1980.
+
+[RFC-793]       J. Postel, "Transmission Control Protocol", RFC-793,
+                USC/Information Sciences Institute, September 1981.
+
+[RFC-799]       D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+                September 1981.
+
+                Suggests introduction of a hierarchy in place of a flat
+                name space for the Internet.
+
+[RFC-805]       J. Postel, "Computer Mail Meeting Notes", RFC-805,
+                USC/Information Sciences Institute, February 1982.
+
+[RFC-810]       E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+                Internet Host Table Specification", RFC-810, Network
+                Information Center, SRI International, March 1982.
+
+                Obsolete.  See RFC-952.
+
+[RFC-811]       K. Harrenstien, V. White, and E. Feinler, "Hostnames
+                Server", RFC-811, Network Information Center, SRI
+                International, March 1982.
+
+                Obsolete.  See RFC-953.
+
+[RFC-812]       K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+                Network Information Center, SRI International, March
+                1982.
+
+[RFC-819]       Z. Su, and J. Postel, "The Domain Naming Convention for
+                Internet User Applications", RFC-819, Network
+                Information Center, SRI International, August 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-821]       J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+                USC/Information Sciences Institute, August 1980.
+
+
+
+
+Mockapetris                                                    [Page 51]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+[RFC-830]       Z. Su, "A Distributed System for Internet Name Service",
+                RFC-830, Network Information Center, SRI International,
+                October 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-882]       P. Mockapetris, "Domain names - Concepts and
+                Facilities," RFC-882, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-883]       P. Mockapetris, "Domain names - Implementation and
+                Specification," RFC-883, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-920]       J. Postel and J. Reynolds, "Domain Requirements",
+                RFC-920, USC/Information Sciences Institute
+                October 1984.
+
+                Explains the naming scheme for top level domains.
+
+[RFC-952]       K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+                Table Specification", RFC-952, SRI, October 1985.
+
+                Specifies the format of HOSTS.TXT, the host/address
+                table replaced by the DNS.
+
+[RFC-953]       K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+                RFC-953, SRI, October 1985.
+
+                This RFC contains the official specification of the
+                hostname server protocol, which is obsoleted by the DNS.
+                This TCP based protocol accesses information stored in
+                the RFC-952 format, and is used to obtain copies of the
+                host table.
+
+[RFC-973]       P. Mockapetris, "Domain System Changes and
+                Observations", RFC-973, USC/Information Sciences
+                Institute, January 1986.
+
+                Describes changes to RFC-882 and RFC-883 and reasons for
+                them.  Now obsolete.
+
+
+
+
+
+Mockapetris                                                    [Page 52]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+[RFC-974]       C. Partridge, "Mail routing and the domain system",
+                RFC-974, CSNET CIC BBN Labs, January 1986.
+
+                Describes the transition from HOSTS.TXT based mail
+                addressing to the more powerful MX system used with the
+                domain system.
+
+[RFC-1001]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Concepts and Methods",
+                RFC-1001, March 1987.
+
+                This RFC and RFC-1002 are a preliminary design for
+                NETBIOS on top of TCP/IP which proposes to base NetBIOS
+                name service on top of the DNS.
+
+[RFC-1002]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Detailed
+                Specifications", RFC-1002, March 1987.
+
+[RFC-1010]      J. Reynolds and J. Postel, "Assigned Numbers", RFC-1010,
+                USC/Information Sciences Institute, May 1987
+
+                Contains socket numbers and mnemonics for host names,
+                operating systems, etc.
+
+[RFC-1031]      W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+                November 1987.
+
+                Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032]      M. K. Stahl, "Establishing a Domain - Guidelines for
+                Administrators", RFC-1032, November 1987.
+
+                Describes the registration policies used by the NIC to
+                administer the top level domains and delegate subzones.
+
+[RFC-1033]      M. K. Lottor, "Domain Administrators Operations Guide",
+                RFC-1033, November 1987.
+
+                A cookbook for domain administrators.
+
+[Solomon 82]    M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+                Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+                Describes a name service for CSNET which is independent
+                from the DNS and DNS use in the CSNET.
+
+
+
+
+
+Mockapetris                                                    [Page 53]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+Index
+
+          A   12
+          Absolute names   8
+          Aliases   14, 31
+          Authority   6
+          AXFR   17
+
+          Case of characters   7
+          CH   12
+          CNAME   12, 13, 31
+          Completion queries   18
+
+          Domain name   6, 7
+
+          Glue RRs   20
+
+          HINFO   12
+
+          IN   12
+          Inverse queries   16
+          Iterative   4
+
+          Label   7
+
+          Mailbox names   9
+          MX   12
+
+          Name error   27, 36
+          Name servers   5, 17
+          NE   30
+          Negative caching   44
+          NS   12
+
+          Opcode   16
+
+          PTR   12
+
+          QCLASS   16
+          QTYPE   16
+
+          RDATA   13
+          Recursive   4
+          Recursive service   22
+          Relative names   7
+          Resolvers   6
+          RR   12
+
+
+
+
+Mockapetris                                                    [Page 54]
+
+RFC 1034             Domain Concepts and Facilities        November 1987
+
+
+          Safety belt   33
+          Sections   16
+          SOA   12
+          Standard queries   22
+
+          Status queries   18
+          Stub resolvers   32
+
+          TTL   12, 13
+
+          Wildcards   25
+
+          Zone transfers   28
+          Zones   19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 55]
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3077 @@
+Network Working Group                                     P. Mockapetris
+Request for Comments: 1035                                           ISI
+                                                           November 1987
+Obsoletes: RFCs 882, 883, 973
+
+            DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental.  Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol.  The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses).  Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical.  Distribution of this memo is unlimited.
+
+                           Table of Contents
+
+  1. STATUS OF THIS MEMO                                              1
+  2. INTRODUCTION                                                     3
+      2.1. Overview                                                   3
+      2.2. Common configurations                                      4
+      2.3. Conventions                                                7
+          2.3.1. Preferred name syntax                                7
+          2.3.2. Data Transmission Order                              8
+          2.3.3. Character Case                                       9
+          2.3.4. Size limits                                         10
+  3. DOMAIN NAME SPACE AND RR DEFINITIONS                            10
+      3.1. Name space definitions                                    10
+      3.2. RR definitions                                            11
+          3.2.1. Format                                              11
+          3.2.2. TYPE values                                         12
+          3.2.3. QTYPE values                                        12
+          3.2.4. CLASS values                                        13
+
+
+
+Mockapetris                                                     [Page 1]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+          3.2.5. QCLASS values                                       13
+      3.3. Standard RRs                                              13
+          3.3.1. CNAME RDATA format                                  14
+          3.3.2. HINFO RDATA format                                  14
+          3.3.3. MB RDATA format (EXPERIMENTAL)                      14
+          3.3.4. MD RDATA format (Obsolete)                          15
+          3.3.5. MF RDATA format (Obsolete)                          15
+          3.3.6. MG RDATA format (EXPERIMENTAL)                      16
+          3.3.7. MINFO RDATA format (EXPERIMENTAL)                   16
+          3.3.8. MR RDATA format (EXPERIMENTAL)                      17
+          3.3.9. MX RDATA format                                     17
+          3.3.10. NULL RDATA format (EXPERIMENTAL)                   17
+          3.3.11. NS RDATA format                                    18
+          3.3.12. PTR RDATA format                                   18
+          3.3.13. SOA RDATA format                                   19
+          3.3.14. TXT RDATA format                                   20
+      3.4. ARPA Internet specific RRs                                20
+          3.4.1. A RDATA format                                      20
+          3.4.2. WKS RDATA format                                    21
+      3.5. IN-ADDR.ARPA domain                                       22
+      3.6. Defining new types, classes, and special namespaces       24
+  4. MESSAGES                                                        25
+      4.1. Format                                                    25
+          4.1.1. Header section format                               26
+          4.1.2. Question section format                             28
+          4.1.3. Resource record format                              29
+          4.1.4. Message compression                                 30
+      4.2. Transport                                                 32
+          4.2.1. UDP usage                                           32
+          4.2.2. TCP usage                                           32
+  5. MASTER FILES                                                    33
+      5.1. Format                                                    33
+      5.2. Use of master files to define zones                       35
+      5.3. Master file example                                       36
+  6. NAME SERVER IMPLEMENTATION                                      37
+      6.1. Architecture                                              37
+          6.1.1. Control                                             37
+          6.1.2. Database                                            37
+          6.1.3. Time                                                39
+      6.2. Standard query processing                                 39
+      6.3. Zone refresh and reload processing                        39
+      6.4. Inverse queries (Optional)                                40
+          6.4.1. The contents of inverse queries and responses       40
+          6.4.2. Inverse query and response example                  41
+          6.4.3. Inverse query processing                            42
+
+
+
+
+
+
+Mockapetris                                                     [Page 2]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+      6.5. Completion queries and responses                          42
+  7. RESOLVER IMPLEMENTATION                                         43
+      7.1. Transforming a user request into a query                  43
+      7.2. Sending the queries                                       44
+      7.3. Processing responses                                      46
+      7.4. Using the cache                                           47
+  8. MAIL SUPPORT                                                    47
+      8.1. Mail exchange binding                                     48
+      8.2. Mailbox binding (Experimental)                            48
+  9. REFERENCES and BIBLIOGRAPHY                                     50
+  Index                                                              54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name.  Thus a user might ask for the host address or
+mail information associated with a particular domain name.  To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name.  To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers.  Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers.  The
+resolver starts with knowledge of at least one name server.  When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server.  Using these
+referrals, resolvers learn the identities and contents of other name
+servers.  Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data.  The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space.  This data is called
+authoritative.  A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris                                                     [Page 3]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+from master files stored locally or in another name server.  The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed.  Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions.  The simplest, and
+perhaps most typical, configuration is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+    +---------+               +----------+         |  +--------+
+    |         | user queries  |          |queries  |  |        |
+    |  User   |-------------->|          |---------|->|Foreign |
+    | Program |               | Resolver |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    |         | user responses|          |responses|  |        |
+    +---------+               +----------+         |  +--------+
+                                |     A            |
+                cache additions |     | references |
+                                V     |            |
+                              +----------+         |
+                              |  cache   |         |
+                              +----------+         |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system.  User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system.  Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time.  The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris                                                     [Page 4]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host.  A simple configuration might be:
+
+                 Local Host                        |  Foreign
+                                                   |
+      +---------+                                  |
+     /         /|                                  |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server.  Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS.  This configuration is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+      +---------+                                  |
+     /         /|                                  |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+                                A     |maintenance |  +--------+
+                                |     +------------|->|        |
+                                |      queries     |  |Foreign |
+                                |                  |  |  Name  |
+                                +------------------|--| Server |
+                             maintenance responses |  +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed.  The messages sent for
+
+
+
+Mockapetris                                                     [Page 5]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+    +---------+               +----------+         |  +--------+
+    |         | user queries  |          |queries  |  |        |
+    |  User   |-------------->|          |---------|->|Foreign |
+    | Program |               | Resolver |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    |         | user responses|          |responses|  |        |
+    +---------+               +----------+         |  +--------+
+                                |     A            |
+                cache additions |     | references |
+                                V     |            |
+                              +----------+         |
+                              |  Shared  |         |
+                              | database |         |
+                              +----------+         |
+                                A     |            |
+      +---------+     refreshes |     | references |
+     /         /|               |     V            |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+                                A     |maintenance |  +--------+
+                                |     +------------|->|        |
+                                |      queries     |  |Foreign |
+                                |                  |  |  Name  |
+                                +------------------|--| Server |
+                             maintenance responses |  +--------+
+
+The shared database holds domain space data for the local name server
+and resolver.  The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests.  The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris                                                     [Page 6]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities.  Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required.  This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio.  In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+                   Local Hosts                     |  Foreign
+                                                   |
+    +---------+                                    |
+    |         | responses                          |
+    | Stub    |<--------------------+              |
+    | Resolver|                     |              |
+    |         |----------------+    |              |
+    +---------+ recursive      |    |              |
+                queries        |    |              |
+                               V    |              |
+    +---------+ recursive     +----------+         |  +--------+
+    |         | queries       |          |queries  |  |        |
+    | Stub    |-------------->| Recursive|---------|->|Foreign |
+    | Resolver|               | Server   |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    +---------+ responses     |          |responses|  |        |
+                              +----------+         |  +--------+
+                              |  Central |         |
+                              |   cache  |         |
+                              +----------+         |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues.  While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names.  The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris                                                     [Page 7]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822.  When creating a new host name,
+the old rules for HOSTS.TXT should be followed.  This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case.  That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names.  They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen.  There are also some
+restrictions on the length.  Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level.  Whenever a diagram shows a
+
+
+
+Mockapetris                                                     [Page 8]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English.  For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+     0                   1
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       1       |       2       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       3       |       4       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       5       |       6       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit.  That is, the bit
+labeled 0 is the most significant bit.  For example, the following
+diagram represents the value 170 (decimal).
+
+     0 1 2 3 4 5 6 7
+    +-+-+-+-+-+-+-+-+
+    |1 0 1 0 1 0 1 0|
+    +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit.  When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner.  At present, this rule is in
+force throughout the domain system without exception.  However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible.  In certain circumstances this cannot be
+done.  For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved.  The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris                                                     [Page 9]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Loss of case sensitive data must be minimized.  Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X.  In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive.  The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits.  They are
+listed below.  Some could be easily changed, others are more
+fundamental.
+
+labels          63 octets or less
+
+names           255 octets or less
+
+TTL             positive values of a signed 32 bit number.
+
+UDP messages    512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets.  Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero.  The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions.  Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity.  Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris                                                    [Page 10]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                                               /
+    /                      NAME                     /
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     CLASS                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TTL                      |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                   RDLENGTH                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+    /                     RDATA                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME            an owner name, i.e., the name of the node to which this
+                resource record pertains.
+
+TYPE            two octets containing one of the RR TYPE codes.
+
+CLASS           two octets containing one of the RR CLASS codes.
+
+TTL             a 32 bit signed integer that specifies the time interval
+                that the resource record may be cached before the source
+                of the information should again be consulted.  Zero
+                values are interpreted to mean that the RR can only be
+                used for the transaction in progress, and should not be
+                cached.  For example, SOA records are always distributed
+                with a zero TTL to prohibit caching.  Zero values can
+                also be used for extremely volatile data.
+
+RDLENGTH        an unsigned 16 bit integer that specifies the length in
+                octets of the RDATA field.
+
+
+
+Mockapetris                                                    [Page 11]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+RDATA           a variable length string of octets that describes the
+                resource.  The format of this information varies
+                according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records.  Note that these types are a
+subset of QTYPEs.
+
+TYPE            value and meaning
+
+A               1 a host address
+
+NS              2 an authoritative name server
+
+MD              3 a mail destination (Obsolete - use MX)
+
+MF              4 a mail forwarder (Obsolete - use MX)
+
+CNAME           5 the canonical name for an alias
+
+SOA             6 marks the start of a zone of authority
+
+MB              7 a mailbox domain name (EXPERIMENTAL)
+
+MG              8 a mail group member (EXPERIMENTAL)
+
+MR              9 a mail rename domain name (EXPERIMENTAL)
+
+NULL            10 a null RR (EXPERIMENTAL)
+
+WKS             11 a well known service description
+
+PTR             12 a domain name pointer
+
+HINFO           13 host information
+
+MINFO           14 mailbox or mail list information
+
+MX              15 mail exchange
+
+TXT             16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query.  QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs.  In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris                                                    [Page 12]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+AXFR            252 A request for a transfer of an entire zone
+
+MAILB           253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA           254 A request for mail agent RRs (Obsolete - see MX)
+
+*               255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records.  The following CLASS mnemonics
+and values are defined:
+
+IN              1 the Internet
+
+CS              2 the CSNET class (Obsolete - used only for examples in
+                some obsolete RFCs)
+
+CH              3 the CHAOS class
+
+HS              4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query.  QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS.  In
+addition to CLASS values, the following QCLASSes are defined:
+
+*               255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes.  In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length.  <character-string> is a single
+length octet followed by that number of characters.  <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 13]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.1. CNAME RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     CNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME           A <domain-name> which specifies the canonical or primary
+                name for the owner.  The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases.  See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                      CPU                      /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                       OS                      /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU             A <character-string> which specifies the CPU type.
+
+OS              A <character-string> which specifies the operating
+                system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host.  The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has the
+                specified mailbox.
+
+
+
+Mockapetris                                                    [Page 14]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has a mail
+                agent for the domain which should be able to deliver
+                mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete.  See the definition of MX and [RFC-974] for details of
+the new scheme.  The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has a mail
+                agent for the domain which will accept mail for
+                forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete.  See the definition of MX and [RFC-974] for details ofw
+the new scheme.  The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 15]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MGMNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME         A <domain-name> which specifies a mailbox which is a
+                member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                    RMAILBX                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                    EMAILBX                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX         A <domain-name> which specifies a mailbox which is
+                responsible for the mailing list or mailbox.  If this
+                domain name names the root, the owner of the MINFO RR is
+                responsible for itself.  Note that many existing mailing
+                lists use a mailbox X-request for the RMAILBX field of
+                mailing list X, e.g., Msgroup-request for Msgroup.  This
+                field provides a more general mechanism.
+
+
+EMAILBX         A <domain-name> which specifies a mailbox which is to
+                receive error messages related to the mailing list or
+                mailbox specified by the owner of the MINFO RR (similar
+                to the ERRORS-TO: field which has been proposed).  If
+                this domain name names the root, errors should be
+                returned to the sender of the message.
+
+MINFO records cause no additional section processing.  Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 16]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   NEWNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME         A <domain-name> which specifies a mailbox which is the
+                proper rename of the specified mailbox.
+
+MR records cause no additional section processing.  The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                  PREFERENCE                   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   EXCHANGE                    /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE      A 16 bit integer which specifies the preference given to
+                this RR among others at the same owner.  Lower values
+                are preferred.
+
+EXCHANGE        A <domain-name> which specifies a host willing to act as
+                a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE.  The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                  <anything>                   /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris                                                    [Page 17]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+NULL records cause no additional section processing.  NULL RRs are not
+allowed in master files.  NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   NSDNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME         A <domain-name> which specifies a host which should be
+                authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class.  Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint.  For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   PTRDNAME                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME        A <domain-name> which points to some location in the
+                domain name space.
+
+PTR records cause no additional section processing.  These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases.  See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 18]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.13. SOA RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     MNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     RNAME                     /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    SERIAL                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    REFRESH                    |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     RETRY                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    EXPIRE                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    MINIMUM                    |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME           The <domain-name> of the name server that was the
+                original or primary source of data for this zone.
+
+RNAME           A <domain-name> which specifies the mailbox of the
+                person responsible for this zone.
+
+SERIAL          The unsigned 32 bit version number of the original copy
+                of the zone.  Zone transfers preserve this value.  This
+                value wraps and should be compared using sequence space
+                arithmetic.
+
+REFRESH         A 32 bit time interval before the zone should be
+                refreshed.
+
+RETRY           A 32 bit time interval that should elapse before a
+                failed refresh should be retried.
+
+EXPIRE          A 32 bit time value that specifies the upper limit on
+                the time interval that can elapse before the zone is no
+                longer authoritative.
+
+
+
+
+
+Mockapetris                                                    [Page 19]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+MINIMUM         The unsigned 32 bit minimum TTL field that should be
+                exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations.  However, MINIMUM is used in all query operations that
+retrieve RRs from a zone.  Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA.  Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone.  Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer.  The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   TXT-DATA                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA        One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text.  The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ADDRESS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS         A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris                                                    [Page 20]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+A records cause no additional section processing.  The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any imbedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ADDRESS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |       PROTOCOL        |                       |
+    +--+--+--+--+--+--+--+--+                       |
+    |                                               |
+    /                   <BIT MAP>                   /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS         An 32 bit Internet address
+
+PROTOCOL        An 8 bit IP protocol number
+
+<BIT MAP>       A variable length bit map.  The bit map must be a
+                multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address.  The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol.  The first bit corresponds to port 0,
+the second to port 1, etc.  If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero.  The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP).  If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP.  If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris                                                    [Page 21]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping.  Other classes may employ a similar
+strategy in other domains.  The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix.  Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified.  Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA.  The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space.  For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET.  Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets.  Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network.  Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it.  Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris                                                    [Page 22]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU.  Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+    18.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+    26.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    22.0.2.10.IN-ADDR.ARPA.    PTR MILNET-GW.ISI.EDU.
+    103.0.0.26.IN-ADDR.ARPA.   PTR MILNET-GW.ISI.EDU.
+    77.0.0.10.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
+    4.0.10.18.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
+    103.0.3.26.IN-ADDR.ARPA.   PTR A.ISI.EDU.
+    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA.  It
+would receive two RRs in response:
+
+    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+   - Since the IN-ADDR.ARPA special domain and the normal domain
+     for a particular host or gateway will be in different zones,
+     the possibility exists that that the data may be inconsistent.
+
+   - Gateways will often have two names in separate domains, only
+     one of which can be primary.
+
+   - Systems that use the domain database to initialize their
+     routing tables must start with enough gateway information to
+     guarantee that they can access the appropriate name server.
+
+   - The gateway data only reflects the existence of a gateway in a
+     manner equivalent to the current HOSTS.TXT file.  It doesn't
+     replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris                                                    [Page 23]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo.  New definitions should be expected.  This section
+makes some recommendations to designers considering additions to the
+existing facilities.  The mailing list NAMEDROPPERS at SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object.  Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information.  New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR.  This is less efficient for most applications, but does keep
+RRs shorter.  The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency.  Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address.  This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used.  This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF).  The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both).  The redesigned
+
+
+
+Mockapetris                                                    [Page 24]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs.  However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message.  The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+    +---------------------+
+    |        Header       |
+    +---------------------+
+    |       Question      | the question for the name server
+    +---------------------+
+    |        Answer       | RRs answering the question
+    +---------------------+
+    |      Authority      | RRs pointing toward an authority
+    +---------------------+
+    |      Additional     | RRs holding additional information
+    +---------------------+
+
+The header section is always present.  The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries.  The question section contains fields that describe a
+question to a name server.  These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME).  The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs).  The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 25]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      ID                       |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    QDCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ANCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    NSCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ARCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID              A 16 bit identifier assigned by the program that
+                generates any kind of query.  This identifier is copied
+                the corresponding reply and can be used by the requester
+                to match up replies to outstanding queries.
+
+QR              A one bit field that specifies whether this message is a
+                query (0), or a response (1).
+
+OPCODE          A four bit field that specifies kind of query in this
+                message.  This value is set by the originator of a query
+                and copied into the response.  The values are:
+
+                0               a standard query (QUERY)
+
+                1               an inverse query (IQUERY)
+
+                2               a server status request (STATUS)
+
+                3-15            reserved for future use
+
+AA              Authoritative Answer - this bit is valid in responses,
+                and specifies that the responding name server is an
+                authority for the domain name in question section.
+
+                Note that the contents of the answer section may have
+                multiple owner names because of aliases.  The AA bit
+
+
+
+Mockapetris                                                    [Page 26]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                corresponds to the name which matches the query name, or
+                the first owner name in the answer section.
+
+TC              TrunCation - specifies that this message was truncated
+                due to length greater than that permitted on the
+                transmission channel.
+
+RD              Recursion Desired - this bit may be set in a query and
+                is copied into the response.  If RD is set, it directs
+                the name server to pursue the query recursively.
+                Recursive query support is optional.
+
+RA              Recursion Available - this be is set or cleared in a
+                response, and denotes whether recursive query support is
+                available in the name server.
+
+Z               Reserved for future use.  Must be zero in all queries
+                and responses.
+
+RCODE           Response code - this 4 bit field is set as part of
+                responses.  The values have the following
+                interpretation:
+
+                0               No error condition
+
+                1               Format error - The name server was
+                                unable to interpret the query.
+
+                2               Server failure - The name server was
+                                unable to process this query due to a
+                                problem with the name server.
+
+                3               Name Error - Meaningful only for
+                                responses from an authoritative name
+                                server, this code signifies that the
+                                domain name referenced in the query does
+                                not exist.
+
+                4               Not Implemented - The name server does
+                                not support the requested kind of query.
+
+                5               Refused - The name server refuses to
+                                perform the specified operation for
+                                policy reasons.  For example, a name
+                                server may not wish to provide the
+                                information to the particular requester,
+                                or a name server may not wish to perform
+                                a particular operation (e.g., zone
+
+
+
+Mockapetris                                                    [Page 27]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                                transfer) for particular data.
+
+                6-15            Reserved for future use.
+
+QDCOUNT         an unsigned 16 bit integer specifying the number of
+                entries in the question section.
+
+ANCOUNT         an unsigned 16 bit integer specifying the number of
+                resource records in the answer section.
+
+NSCOUNT         an unsigned 16 bit integer specifying the number of name
+                server resource records in the authority records
+                section.
+
+ARCOUNT         an unsigned 16 bit integer specifying the number of
+                resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked.  The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                     QNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     QTYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     QCLASS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME           a domain name represented as a sequence of labels, where
+                each label consists of a length octet followed by that
+                number of octets.  The domain name terminates with the
+                zero length octet for the null label of the root.  Note
+                that this field may be an odd number of octets; no
+                padding is used.
+
+QTYPE           a two octet code which specifies the type of the query.
+                The values for this field include all codes valid for a
+                TYPE field, together with some more general codes which
+                can match more than one type of RR.
+
+
+
+Mockapetris                                                    [Page 28]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+QCLASS          a two octet code that specifies the class of the query.
+                For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                                               /
+    /                      NAME                     /
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     CLASS                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TTL                      |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                   RDLENGTH                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+    /                     RDATA                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME            a domain name to which this resource record pertains.
+
+TYPE            two octets containing one of the RR type codes.  This
+                field specifies the meaning of the data in the RDATA
+                field.
+
+CLASS           two octets which specify the class of the data in the
+                RDATA field.
+
+TTL             a 32 bit unsigned integer that specifies the time
+                interval (in seconds) that the resource record may be
+                cached before it should be discarded.  Zero values are
+                interpreted to mean that the RR can only be used for the
+                transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris                                                    [Page 29]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+RDLENGTH        an unsigned 16 bit integer that specifies the length in
+                octets of the RDATA field.
+
+RDATA           a variable length string of octets that describes the
+                resource.  The format of this information varies
+                according to the TYPE and CLASS of the resource record.
+                For example, the if the TYPE is A and the CLASS is IN,
+                the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message.  In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurance
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    | 1  1|                OFFSET                   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones.  This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less.  (The 10 and 01 combinations
+are reserved for future use.)  The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header).  A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+   - a sequence of labels ending in a zero octet
+
+   - a pointer
+
+   - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurances of a domain name where the
+format is not class specific.  If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris                                                    [Page 30]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root.  Ignoring the other fields of the
+message, these domain names might be represented as:
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    20 |           1           |           F           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    22 |           3           |           I           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    24 |           S           |           I           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    26 |           4           |           A           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    28 |           R           |           P           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    30 |           A           |           0           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    40 |           3           |           F           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    42 |           O           |           O           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    44 | 1  1|                20                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    64 | 1  1|                26                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    92 |           0           |                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20.  The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA.  The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20.  The root domain name is
+
+
+
+Mockapetris                                                    [Page 31]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit.  While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance.  Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers).  Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet.  Queries sent using UDP may be
+lost, and hence a retransmission strategy is required.  Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+   - The client should try other servers and server addresses
+     before repeating a query to a specific address of a server.
+
+   - The retransmission interval should be based on prior
+     statistics if possible.  Too aggressive retransmission can
+     easily slow responses for the community at large.  Depending
+     on how well connected the client is to its expected servers,
+     the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal).  The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris                                                    [Page 32]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+length, excluding the two byte length field.  This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+   - The server should not block other activities waiting for TCP
+     data.
+
+   - The server should support multiple connections.
+
+   - The server should assume that the client will initiate
+     connection closing, and should delay closing its end of the
+     connection until all outstanding client requests have been
+     satisfied.
+
+   - If the server needs to close a dormant connection to reclaim
+     resources, it should wait until the connection has been idle
+     for a period on the order of two minutes.  In particular, the
+     server should allow the SOA and AXFR request sequence (which
+     begins a refresh operation) to be made on a single connection.
+     Since the server would be unable to answer queries anyway, a
+     unilateral close or reset may be used instead of a graceful
+     close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form.  Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents.  Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries.  Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text.  Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry.  The end of
+any line in the master file can end with a comment.  The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+    <blank>[<comment>]
+
+
+
+
+Mockapetris                                                    [Page 33]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+    $ORIGIN <domain-name> [<comment>]
+
+    $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+    <domain-name><rr> [<comment>]
+
+    <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE.  $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name.  $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file.  $INCLUDE may also
+have a comment.  Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs.  If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner.  If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+    [<TTL>] [<class>] <type> <RDATA>
+
+    [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class.  Class and type use the
+standard mnemonics, TTL is a decimal integer.  Omitted class and TTL
+values are default to the last explicitly stated values.  Since type and
+class mnemonics are disjoint, the parse is unique.  (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots.  Quoting conventions allow arbitrary characters to be
+stored in domain names.  Domain names that end in a dot are called
+absolute, and are taken as complete.  Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine.  A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris                                                    [Page 34]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ".  Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded.  In particular:
+
+                of the root.
+
+@               A free standing @ is used to denote the current origin.
+
+\X              where X is any character other than a digit (0-9), is
+                used to quote that character so that its special meaning
+                does not apply.  For example, "\." can be used to place
+                a dot character in a label.
+
+\DDD            where each D is a digit is the octet corresponding to
+                the decimal number described by DDD.  The resulting
+                octet is assumed to be text and is not checked for
+                special meaning.
+
+( )             Parentheses are used to group data that crosses a line
+                boundary.  In effect, line terminations are not
+                recognized within parentheses.
+
+;               Semicolon is used to start a comment; the remainder of
+                the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file.  The
+rationale for this is that a single error can have widespread
+consequences.  For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+   1. All RRs in the file should have the same class.
+
+   2. Exactly one SOA RR should be present at the top of the zone.
+
+   3. If delegations are present and glue information is required,
+      it should be present.
+
+
+
+Mockapetris                                                    [Page 35]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   4. Information present outside of the authoritative nodes in the
+      zone should be glue information, rather than the result of an
+      origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@   IN  SOA     VENERA      Action\.domains (
+                                 20     ; SERIAL
+                                 7200   ; REFRESH
+                                 600    ; RETRY
+                                 3600000; EXPIRE
+                                 60)    ; MINIMUM
+
+        NS      A.ISI.EDU.
+        NS      VENERA
+        NS      VAXA
+        MX      10      VENERA
+        MX      20      VAXA
+
+A       A       26.3.0.103
+
+VENERA  A       10.1.0.52
+        A       128.9.0.32
+
+VAXA    A       10.2.0.27
+        A       128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+    MOE     MB      A.ISI.EDU.
+    LARRY   MB      A.ISI.EDU.
+    CURLEY  MB      A.ISI.EDU.
+    STOOGES MG      MOE
+            MG      LARRY
+            MG      CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains at E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 36]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver.  This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program.  It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities.  Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates.  A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+   - A "catalog" data structure which lists the zones available to
+     this server, and a "pointer" to the zone data structure.  The
+     main purpose of this structure is to find the nearest ancestor
+     zone, if any, for arriving standard queries.
+
+   - Separate data structures for each of the zones held by the
+     name server.
+
+   - A data structure for cached data. (or perhaps separate caches
+     for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs.  In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris                                                    [Page 37]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case.  The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded.  In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+   - The catalog structure can be an almost static structure that
+     need change only when the system administrator changes the
+     zones supported by the server.  This structure can also be
+     used to store parameters used to control refreshing
+     activities.
+
+   - The individual data structures for zones allow a zone to be
+     replaced simply by changing a pointer in the catalog.  Zone
+     refresh operations can build a new structure and, when
+     complete, splice it into the database via a simple pointer
+     replacement.  It is very important that when a zone is
+     refreshed, queries should not use old and new data
+     simultaneously.
+
+   - With the proper search procedures, authoritative data in zones
+     will always "hide", and hence take precedence over, cached
+     data.
+
+   - Errors in zone definitions that cause overlapping zones, etc.,
+     may cause erroneous responses to queries, but problem
+     determination is simplified, and the contents of one "bad"
+     zone can't corrupt another.
+
+   - Since the cache is most frequently updated, it is most
+     vulnerable to corruption during system restarts.  It can also
+     become full of expired RR data.  In either case, it can easily
+     be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host.  State
+information which a name server should save across system crashes
+
+
+
+Mockapetris                                                    [Page 38]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds.  Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways:  as
+a relative increment and as an absolute time.  One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other.  The RRs in zones use relative times; the refresh timers and
+cache data use absolute times.  Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query.  When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram.  Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone.  This floor function should be done when
+the data is copied into a response.  This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter.  In this case, the name server
+
+
+
+Mockapetris                                                    [Page 39]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible.  In any case, it should never send part of one version and
+part of another.  If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS.  Name servers are not
+required to support any form of inverse queries.  If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header.  While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses          Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name.  For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section.  The owner name of the
+query RR and its TTL are not significant.  The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS.  Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete.  Thus inverse queries are primarily useful for database
+management and debugging activities.  Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries.  Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix".  However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+   1. zero, one, or multiple domain names for the specified
+      resource as QNAMEs in the question section
+
+
+
+Mockapetris                                                    [Page 40]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   2. an error code indicating that the name server doesn't support
+      inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries.  One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear.  For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example          The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+                         +-----------------------------------------+
+           Header        |          OPCODE=IQUERY, ID=997          |
+                         +-----------------------------------------+
+          Question       |                 <empty>                 |
+                         +-----------------------------------------+
+           Answer        |        <anyname> A IN 10.1.0.52         |
+                         +-----------------------------------------+
+          Authority      |                 <empty>                 |
+                         +-----------------------------------------+
+         Additional      |                 <empty>                 |
+                         +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52.  Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored).  A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message.  The TTL of the RR is not significant.  The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 41]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                         +-----------------------------------------+
+           Header        |         OPCODE=RESPONSE, ID=997         |
+                         +-----------------------------------------+
+          Question       |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+                         +-----------------------------------------+
+           Answer        |  VENERA.ISI.EDU  A IN 10.1.0.52         |
+                         +-----------------------------------------+
+          Authority      |                 <empty>                 |
+                         +-----------------------------------------+
+         Additional      |                 <empty>                 |
+                         +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query.  Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique.  If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases.  An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone.  When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted.  Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 42]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034].  This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler.  The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source.  If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information.  This state block will
+typically contain:
+
+   - A timestamp indicating the time the request began.
+     The timestamp is used to decide whether RRs in the database
+     can be used or are out of date.  This timestamp uses the
+     absolute time format previously discussed for RR storage in
+     zones and caches.  Note that when an RRs TTL indicates a
+     relative time, the RR must be timely, since it is part of a
+     zone.  When the RR has an absolute time, it is part of a
+     cache, and the TTL of the RR is compared against the timestamp
+     for the start of the request.
+
+     Note that using the timestamp is superior to using a current
+     time, since it allows RRs with TTLs of zero to be entered in
+     the cache in the usual manner, but still used by the current
+     request, even after intervals of many seconds due to system
+     load, query retransmission timeouts, etc.
+
+   - Some sort of parameters to limit the amount of work which will
+     be performed for this request.
+
+     The amount of work which a resolver will do in response to a
+     client request must be limited to guard against errors in the
+     database, such as circular CNAME references, and operational
+     problems, such as network partition which prevents the
+
+
+
+Mockapetris                                                    [Page 43]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+     resolver from accessing the name servers it needs.  While
+     local limits on the number of times a resolver will retransmit
+     a particular query to a particular name server address are
+     essential, the resolver should have a global per-request
+     counter to limit work on a single request.  The counter should
+     be set to some initial value and decremented whenever the
+     resolver performs any action (retransmission timeout,
+     retransmission, etc.)  If the counter passes zero, the request
+     is terminated with a temporary error.
+
+     Note that if the resolver structure allows one request to
+     start others in parallel, such as when the need to access a
+     name server for one request causes a parallel resolve for the
+     name server's addresses, the spawned request should be started
+     with a lower counter.  This prevents circular references in
+     the database from starting a chain reaction of resolver
+     activity.
+
+   - The SLIST data structure discussed in [RFC-1034].
+
+     This structure keeps track of the state of a request if it
+     must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information.  The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information.  In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated.  Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions.  The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive.  The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris                                                    [Page 44]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about.  To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate.  The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST.  This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request).  Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address.  Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses.  Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses.  Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried.  The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+   - The resolver may encounter a situation where no addresses are
+     available for any of the name servers named in SLIST, and
+     where the servers in the list are precisely those which would
+     normally be used to look up their own addresses.  This
+     situation typically occurs when the glue address RRs have a
+     smaller TTL than the NS RRs marking delegation, or when the
+     resolver caches the result of a NS search.  The resolver
+     should detect this condition and restart the search at the
+     next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris                                                    [Page 45]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   - If a resolver gets a server error or other bizarre response
+     from a name server, it should remove it from SLIST, and may
+     wish to schedule an immediate transmission to the next
+     candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response.  This procedure should include:
+
+   - Check the header for reasonableness.  Discard datagrams which
+     are queries when responses are expected.
+
+   - Parse the sections of the message, and insure that all RRs are
+     correctly formatted.
+
+   - As an optional step, check the TTLs of arriving data looking
+     for RRs with excessively long TTLs.  If a RR has an
+     excessively long TTL, say greater than 1 week, either discard
+     the whole response, or limit all TTLs in the response to 1
+     week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired.  This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort.  This step has several fine points:
+
+   - Some name servers send their responses from different
+     addresses than the one used to receive the query.  That is, a
+     resolver cannot rely that a response will come from the same
+     address which it sent the corresponding query to.  This name
+     server bug is typically encountered in UNIX systems.
+
+   - If the resolver retransmits a particular request to a name
+     server it should be able to use a response from any of the
+     transmissions.  However, if it is using the response to sample
+     the round trip time to access the name server, it must be able
+     to determine which transmission matches the response (and keep
+     transmission times for each outgoing message), or only
+     calculate round trip times based on initial transmissions.
+
+   - A name server will occasionally not have a current copy of a
+     zone which it should have according to some NS RRs.  The
+     resolver should simply remove the name server from the current
+     SLIST, and continue.
+
+
+
+
+Mockapetris                                                    [Page 46]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+   - When several RRs of the same type are available for a
+     particular owner name, the resolver should either cache them
+     all or none at all.  When a response is truncated, and a
+     resolver doesn't know whether it has a complete set, it should
+     not cache a possibly partial set of RRs.
+
+   - Cached data should never be used in preference to
+     authoritative data, so if caching would cause this to happen
+     the data should not be cached.
+
+   - The results of an inverse query should not be cached.
+
+   - The results of standard queries where the QNAME contains "*"
+     labels if the data might be used to construct wildcards.  The
+     reason is that the cache does not necessarily contain existing
+     RRs or zone boundary information which is necessary to
+     restrict the application of the wildcard RRs.
+
+   - RR data in responses of dubious reliability.  When a resolver
+     receives unsolicited responses or RR data other than that
+     requested, it should discard it without caching it.  The basic
+     implication is that all sanity checks on a packet should be
+     performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs.  Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined.  If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information.  The first method is called mail exchange binding
+and the other method is mailbox binding.  The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet.  Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris                                                    [Page 47]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>".  While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name.  The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox.  Thus the mailbox HOSTMASTER at SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA.  If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded.  For
+example, the mailbox Action.domains at ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent.  The <local-part>
+is not even consulted.  [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function.  However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU.  If a mailer had a message for Mockapetris at ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU.  The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name.  The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris                                                    [Page 48]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   1. The query can return a name error indicating that the mailbox
+      does not exist as a domain name.
+
+      In the long term, this would indicate that the specified
+      mailbox doesn't exist.  However, until the use of mailbox
+      binding is universal, this error condition should be
+      interpreted to mean that the organization identified by the
+      global part does not support mailbox binding.  The
+      appropriate procedure is to revert to exchange binding at
+      this point.
+
+   2. The query can return a Mail Rename (MR) RR.
+
+      The MR RR carries new mailbox specification in its RDATA
+      field.  The mailer should replace the old mailbox with the
+      new one and retry the operation.
+
+   3. The query can return a MB RR.
+
+      The MB RR carries a domain name for a host in its RDATA
+      field.  The mailer should deliver the message to that host
+      via whatever protocol is applicable, e.g., b,SMTP.
+
+   4. The query can return one or more Mail Group (MG) RRs.
+
+      This condition means that the mailbox was actually a mailing
+      list or mail group, rather than a single mailbox.  Each MG RR
+      has a RDATA field that identifies a mailbox that is a member
+      of the group.  The mailer should deliver a copy of the
+      message to each member.
+
+   5. The query can return a MB RR as well as one or more MG RRs.
+
+      This condition means the the mailbox was actually a mailing
+      list.  The mailer can either deliver the message to the host
+      specified by the MB RR, which will in turn do the delivery to
+      all members, or the mailer can use the MG RRs to do the
+      expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR.  This RR is usually associated with a mail group, but is
+legal with a MB.  The MINFO RR identifies two mailboxes.  One of these
+identifies a responsible person for the original mailbox name.  This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures.  This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris                                                    [Page 49]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87]       S. Dyer, F. Hsu, "Hesiod", Project Athena
+                Technical Plan - Name Service, April 1987, version 1.9.
+
+                Describes the fundamentals of the Hesiod name service.
+
+[IEN-116]       J. Postel, "Internet Name Server", IEN-116,
+                USC/Information Sciences Institute, August 1979.
+
+                A name service obsoleted by the Domain Name System, but
+                still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+                Communications of the ACM, October 1986, volume 29, number
+                10.
+
+[RFC-742]       K. Harrenstien, "NAME/FINGER", RFC-742, Network
+                Information Center, SRI International, December 1977.
+
+[RFC-768]       J. Postel, "User Datagram Protocol", RFC-768,
+                USC/Information Sciences Institute, August 1980.
+
+[RFC-793]       J. Postel, "Transmission Control Protocol", RFC-793,
+                USC/Information Sciences Institute, September 1981.
+
+[RFC-799]       D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+                September 1981.
+
+                Suggests introduction of a hierarchy in place of a flat
+                name space for the Internet.
+
+[RFC-805]       J. Postel, "Computer Mail Meeting Notes", RFC-805,
+                USC/Information Sciences Institute, February 1982.
+
+[RFC-810]       E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+                Internet Host Table Specification", RFC-810, Network
+                Information Center, SRI International, March 1982.
+
+                Obsolete.  See RFC-952.
+
+[RFC-811]       K. Harrenstien, V. White, and E. Feinler, "Hostnames
+                Server", RFC-811, Network Information Center, SRI
+                International, March 1982.
+
+
+
+
+Mockapetris                                                    [Page 50]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                Obsolete.  See RFC-953.
+
+[RFC-812]       K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+                Network Information Center, SRI International, March
+                1982.
+
+[RFC-819]       Z. Su, and J. Postel, "The Domain Naming Convention for
+                Internet User Applications", RFC-819, Network
+                Information Center, SRI International, August 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-821]       J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+                USC/Information Sciences Institute, August 1980.
+
+[RFC-830]       Z. Su, "A Distributed System for Internet Name Service",
+                RFC-830, Network Information Center, SRI International,
+                October 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-882]       P. Mockapetris, "Domain names - Concepts and
+                Facilities," RFC-882, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-883]       P. Mockapetris, "Domain names - Implementation and
+                Specification," RFC-883, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-920]       J. Postel and J. Reynolds, "Domain Requirements",
+                RFC-920, USC/Information Sciences Institute,
+                October 1984.
+
+                Explains the naming scheme for top level domains.
+
+[RFC-952]       K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+                Table Specification", RFC-952, SRI, October 1985.
+
+                Specifies the format of HOSTS.TXT, the host/address
+                table replaced by the DNS.
+
+
+
+
+
+Mockapetris                                                    [Page 51]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+[RFC-953]       K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+                RFC-953, SRI, October 1985.
+
+                This RFC contains the official specification of the
+                hostname server protocol, which is obsoleted by the DNS.
+                This TCP based protocol accesses information stored in
+                the RFC-952 format, and is used to obtain copies of the
+                host table.
+
+[RFC-973]       P. Mockapetris, "Domain System Changes and
+                Observations", RFC-973, USC/Information Sciences
+                Institute, January 1986.
+
+                Describes changes to RFC-882 and RFC-883 and reasons for
+                them.
+
+[RFC-974]       C. Partridge, "Mail routing and the domain system",
+                RFC-974, CSNET CIC BBN Labs, January 1986.
+
+                Describes the transition from HOSTS.TXT based mail
+                addressing to the more powerful MX system used with the
+                domain system.
+
+[RFC-1001]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Concepts and Methods",
+                RFC-1001, March 1987.
+
+                This RFC and RFC-1002 are a preliminary design for
+                NETBIOS on top of TCP/IP which proposes to base NetBIOS
+                name service on top of the DNS.
+
+[RFC-1002]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Detailed
+                Specifications", RFC-1002, March 1987.
+
+[RFC-1010]      J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+                USC/Information Sciences Institute, May 1987.
+
+                Contains socket numbers and mnemonics for host names,
+                operating systems, etc.
+
+[RFC-1031]      W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+                November 1987.
+
+                Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032]      M. Stahl, "Establishing a Domain - Guidelines for
+                Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris                                                    [Page 52]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                Describes the registration policies used by the NIC to
+                administer the top level domains and delegate subzones.
+
+[RFC-1033]      M. Lottor, "Domain Administrators Operations Guide",
+                RFC-1033, November 1987.
+
+                A cookbook for domain administrators.
+
+[Solomon 82]    M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+                Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+                Describes a name service for CSNET which is independent
+                from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 53]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Index
+
+          *   13
+
+          ;   33, 35
+
+          <character-string>   35
+          <domain-name>   34
+
+          @   35
+
+          \   35
+
+          A   12
+
+          Byte order   8
+
+          CH   13
+          Character case   9
+          CLASS   11
+          CNAME   12
+          Completion   42
+          CS   13
+
+          Hesiod   13
+          HINFO   12
+          HS   13
+
+          IN   13
+          IN-ADDR.ARPA domain   22
+          Inverse queries   40
+
+          Mailbox names   47
+          MB   12
+          MD   12
+          MF   12
+          MG   12
+          MINFO   12
+          MINIMUM   20
+          MR   12
+          MX   12
+
+          NS   12
+          NULL   12
+
+          Port numbers   32
+          Primary server   5
+          PTR   12, 18
+
+
+
+Mockapetris                                                    [Page 54]
+
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+          QCLASS   13
+          QTYPE   12
+
+          RDATA   12
+          RDLENGTH  11
+
+          Secondary server   5
+          SOA   12
+          Stub resolvers   7
+
+          TCP   32
+          TXT   12
+          TYPE   11
+
+          UDP   32
+
+          WKS   12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 55]
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group                                            P. Vixie
+Request for Comments: 2671                                            ISC
+Category: Standards Track                                     August 1999
+
+
+                  Extension Mechanisms for DNS (EDNS0)
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+Abstract
+
+   The Domain Name System's wire protocol includes a number of fixed
+   fields whose range has been or soon will be exhausted and does not
+   allow clients to advertise their capabilities to servers.  This
+   document describes backward compatible mechanisms for allowing the
+   protocol to grow.
+
+1 - Rationale and Scope
+
+1.1. DNS (see [RFC1035]) specifies a Message Format and within such
+     messages there are standard formats for encoding options, errors,
+     and name compression.  The maximum allowable size of a DNS Message
+     is fixed.  Many of DNS's protocol limits are too small for uses
+     which are or which are desired to become common.  There is no way
+     for implementations to advertise their capabilities.
+
+1.2. Existing clients will not know how to interpret the protocol
+     extensions detailed here.  In practice, these clients will be
+     upgraded when they have need of a new feature, and only new
+     features will make use of the extensions.  We must however take
+     account of client behaviour in the face of extra fields, and design
+     a fallback scheme for interoperability with these clients.
+
+
+
+
+
+
+
+
+
+Vixie                       Standards Track                     [Page 1]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+2 - Affected Protocol Elements
+
+2.1. The DNS Message Header's (see [RFC1035 4.1.1]) second full 16-bit
+     word is divided into a 4-bit OPCODE, a 4-bit RCODE, and a number of
+     1-bit flags.  The original reserved Z bits have been allocated to
+     various purposes, and most of the RCODE values are now in use.
+     More flags and more possible RCODEs are needed.
+
+2.2. The first two bits of a wire format domain label are used to denote
+     the type of the label.  [RFC1035 4.1.4] allocates two of the four
+     possible types and reserves the other two.  Proposals for use of
+     the remaining types far outnumber those available.  More label
+     types are needed.
+
+2.3. DNS Messages are limited to 512 octets in size when sent over UDP.
+     While the minimum maximum reassembly buffer size still allows a
+     limit of 512 octets of UDP payload, most of the hosts now connected
+     to the Internet are able to reassemble larger datagrams.  Some
+     mechanism must be created to allow requestors to advertise larger
+     buffer sizes to responders.
+
+3 - Extended Label Types
+
+3.1. The "0 1" label type will now indicate an extended label type,
+     whose value is encoded in the lower six bits of the first octet of
+     a label.  All subsequently developed label types should be encoded
+     using an extended label type.
+
+3.2. The "1 1 1 1 1 1" extended label type will be reserved for future
+     expansion of the extended label type code space.
+
+4 - OPT pseudo-RR
+
+4.1. One OPT pseudo-RR can be added to the additional data section of
+     either a request or a response.  An OPT is called a pseudo-RR
+     because it pertains to a particular transport level message and not
+     to any actual DNS data.  OPT RRs shall never be cached, forwarded,
+     or stored in or loaded from master files.  The quantity of OPT
+     pseudo-RRs per message shall be either zero or one, but not
+     greater.
+
+4.2. An OPT RR has a fixed part and a variable set of options expressed
+     as {attribute, value} pairs.  The fixed part holds some DNS meta
+     data and also a small collection of new protocol elements which we
+     expect to be so popular that it would be a waste of wire space to
+     encode them as {attribute, value} pairs.
+
+
+
+
+
+Vixie                       Standards Track                     [Page 2]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+4.3. The fixed part of an OPT RR is structured as follows:
+
+     Field Name   Field Type     Description
+     ------------------------------------------------------
+     NAME         domain name    empty (root domain)
+     TYPE         u_int16_t      OPT
+     CLASS        u_int16_t      sender's UDP payload size
+     TTL          u_int32_t      extended RCODE and flags
+     RDLEN        u_int16_t      describes RDATA
+     RDATA        octet stream   {attribute,value} pairs
+
+4.4. The variable part of an OPT RR is encoded in its RDATA and is
+     structured as zero or more of the following:
+
+                +0 (MSB)                            +1 (LSB)
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  0: |                          OPTION-CODE                          |
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  2: |                         OPTION-LENGTH                         |
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  4: |                                                               |
+     /                          OPTION-DATA                          /
+     /                                                               /
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+
+   OPTION-CODE    (Assigned by IANA.)
+
+   OPTION-LENGTH  Size (in octets) of OPTION-DATA.
+
+   OPTION-DATA    Varies per OPTION-CODE.
+
+4.5. The sender's UDP payload size (which OPT stores in the RR CLASS
+     field) is the number of octets of the largest UDP payload that can
+     be reassembled and delivered in the sender's network stack.  Note
+     that path MTU, with or without fragmentation, may be smaller than
+     this.
+
+4.5.1. Note that a 512-octet UDP payload requires a 576-octet IP
+       reassembly buffer.  Choosing 1280 on an Ethernet connected
+       requestor would be reasonable.  The consequence of choosing too
+       large a value may be an ICMP message from an intermediate
+       gateway, or even a silent drop of the response message.
+
+4.5.2. Both requestors and responders are advised to take account of the
+       path's discovered MTU (if already known) when considering message
+       sizes.
+
+
+
+
+
+Vixie                       Standards Track                     [Page 3]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+4.5.3. The requestor's maximum payload size can change over time, and
+       should therefore not be cached for use beyond the transaction in
+       which it is advertised.
+
+4.5.4. The responder's maximum payload size can change over time, but
+       can be reasonably expected to remain constant between two
+       sequential transactions; for example, a meaningless QUERY to
+       discover a responder's maximum UDP payload size, followed
+       immediately by an UPDATE which takes advantage of this size.
+       (This is considered preferrable to the outright use of TCP for
+       oversized requests, if there is any reason to suspect that the
+       responder implements EDNS, and if a request will not fit in the
+       default 512 payload size limit.)
+
+4.5.5. Due to transaction overhead, it is unwise to advertise an
+       architectural limit as a maximum UDP payload size.  Just because
+       your stack can reassemble 64KB datagrams, don't assume that you
+       want to spend more than about 4KB of state memory per ongoing
+       transaction.
+
+4.6. The extended RCODE and flags (which OPT stores in the RR TTL field)
+     are structured as follows:
+
+                 +0 (MSB)                            +1 (LSB)
+      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+   0: |         EXTENDED-RCODE        |            VERSION            |
+      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+   2: |                               Z                               |
+      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+
+   EXTENDED-RCODE  Forms upper 8 bits of extended 12-bit RCODE.  Note
+                   that EXTENDED-RCODE value "0" indicates that an
+                   unextended RCODE is in use (values "0" through "15").
+
+   VERSION         Indicates the implementation level of whoever sets
+                   it.  Full conformance with this specification is
+                   indicated by version "0."  Requestors are encouraged
+                   to set this to the lowest implemented level capable
+                   of expressing a transaction, to minimize the
+                   responder and network load of discovering the
+                   greatest common implementation level between
+                   requestor and responder.  A requestor's version
+                   numbering strategy should ideally be a run time
+                   configuration option.
+
+                   If a responder does not implement the VERSION level
+                   of the request, then it answers with RCODE=BADVERS.
+                   All responses will be limited in format to the
+
+
+
+Vixie                       Standards Track                     [Page 4]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+                   VERSION level of the request, but the VERSION of each
+                   response will be the highest implementation level of
+                   the responder.  In this way a requestor will learn
+                   the implementation level of a responder as a side
+                   effect of every response, including error responses,
+                   including RCODE=BADVERS.
+
+   Z               Set to zero by senders and ignored by receivers,
+                   unless modified in a subsequent specification.
+
+5 - Transport Considerations
+
+5.1. The presence of an OPT pseudo-RR in a request should be taken as an
+     indication that the requestor fully implements the given version of
+     EDNS, and can correctly understand any response that conforms to
+     that feature's specification.
+
+5.2. Lack of use of these features in a request must be taken as an
+     indication that the requestor does not implement any part of this
+     specification and that the responder may make no use of any
+     protocol extension described here in its response.
+
+5.3. Responders who do not understand these protocol extensions are
+     expected to send a response with RCODE NOTIMPL, FORMERR, or
+     SERVFAIL.  Therefore use of extensions should be "probed" such that
+     a responder who isn't known to support them be allowed a retry with
+     no extensions if it responds with such an RCODE.  If a responder's
+     capability level is cached by a requestor, a new probe should be
+     sent periodically to test for changes to responder capability.
+
+6 - Security Considerations
+
+     Requestor-side specification of the maximum buffer size may open a
+     new DNS denial of service attack if responders can be made to send
+     messages which are too large for intermediate gateways to forward,
+     thus leading to potential ICMP storms between gateways and
+     responders.
+
+7 - IANA Considerations
+
+     The IANA has assigned RR type code 41 for OPT.
+
+     It is the recommendation of this document and its working group
+     that IANA create a registry for EDNS Extended Label Types, for EDNS
+     Option Codes, and for EDNS Version Numbers.
+
+     This document assigns label type 0b01xxxxxx as "EDNS Extended Label
+     Type."  We request that IANA record this assignment.
+
+
+
+Vixie                       Standards Track                     [Page 5]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+     This document assigns extended label type 0bxx111111 as "Reserved
+     for future extended label types."  We request that IANA record this
+     assignment.
+
+     This document assigns option code 65535 to "Reserved for future
+     expansion."
+
+     This document expands the RCODE space from 4 bits to 12 bits.  This
+     will allow IANA to assign more than the 16 distinct RCODE values
+     allowed in [RFC1035].
+
+     This document assigns EDNS Extended RCODE "16" to "BADVERS".
+
+     IESG approval should be required to create new entries in the EDNS
+     Extended Label Type or EDNS Version Number registries, while any
+     published RFC (including Informational, Experimental, or BCP)
+     should be grounds for allocation of an EDNS Option Code.
+
+8 - Acknowledgements
+
+     Paul Mockapetris, Mark Andrews, Robert Elz, Don Lewis, Bob Halley,
+     Donald Eastlake, Rob Austein, Matt Crawford, Randy Bush, and Thomas
+     Narten were each instrumental in creating and refining this
+     specification.
+
+9 - References
+
+    [RFC1035]  Mockapetris, P., "Domain Names - Implementation and
+               Specification", STD 13, RFC 1035, November 1987.
+
+10 - Author's Address
+
+   Paul Vixie
+   Internet Software Consortium
+   950 Charter Street
+   Redwood City, CA 94063
+
+   Phone: +1 650 779 7001
+   EMail: vixie at isc.org
+
+
+
+
+
+
+
+
+
+
+
+
+Vixie                       Standards Track                     [Page 6]
+
+RFC 2671          Extension Mechanisms for DNS (EDNS0)       August 1999
+
+
+11 - Full Copyright Statement
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Vixie                       Standards Track                     [Page 7]
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Sample rndc configuration file.
+ */
+
+options {
+        default-server  localhost;
+        default-key     "rndckey";
+};
+
+server localhost {
+        key     "rndckey";
+};
+
+key "rndckey" {
+        algorithm       hmac-md5;
+        secret "ckyTJVIxigdpaEAjOMGNWgIPlYoKInXXqzsKikjSsiVJAWTkWONHwQlARsjY";
+};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+; Root zone for testing
+. 3600000  IN  SOA ns root (
+	    2002042901 ; SERIAL
+	    7200       ; REFRESH
+	    600        ; RETRY
+	    36000000   ; EXPIRE
+	    60         ; MINIMUM
+	    )
+		NS	ns.example.com
+ns.example.com	A	127.0.0.2
+		AAAA	::2
+		A6	0 ::2
+
+	
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,180 @@
+#! /bin/bash
+#
+# Run sresolv_test using our own name server
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author(s): Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+s=${0%/*}
+
+test x$s = x$0 && s=`pwd`
+
+PATH=/usr/sbin:/usr/local/sbin:/sbin:$PATH
+
+# Test for support for IPv6 on Linux. This probably fails on everything else.
+ipv6='sysctl net.ipv6.conf.default.mtu >& /dev/null'
+# Bind not working with IPv6 on RHEL 4:
+# client.c:1325: unexpected error: failed to get request's destination: failure
+#ipv6=false
+
+port=`expr $$ % \( 65536 - 1024 \) + 1024`
+
+# Try to find a free port
+if netstat --ip >/dev/null 2>&1 ; then
+    while netstat --ip -n -a | fgrep -q ":$port "
+    do
+	port=$(($port + 1))
+	if [$port = 65536] ; then
+	    port=1024
+	fi
+    done
+fi
+
+# No named, no fun
+type -p named >/dev/null || exit 77
+
+if eval $ipv6
+then
+    # Figure out nice IPv6 address for us
+    ns=$(ip addr ls | awk '
+    /^[0-9]:/ { up = ($3 ~ /UP/) && ($3 !~ /LOOPBACK/); }
+    /inet6 fe80::/ { next; } # no link-local 
+    up && $1 ~ /inet6/ { sub(/\/.*$/, "", $2); print $2; exit 0; }')
+
+    # Nothing found, use localnode ::1
+    if test -z "$ns"; then ns=::1 ; fi
+
+    listen6="listen-on-v6 port $port { any; };"
+else
+    ns="127.0.0.1"
+    listen4="listen-on port $port { 127.0.0.1; };"
+fi
+
+#
+# Set up configuration. First, nice tmpdir
+#
+t=${TMPDIR:-/tmp}/sofia-sip-sresolv-$USER-$$
+
+mkdir $t || exit 77
+
+# Main resolv.conf (with primary nameserver not answering)
+cat > $t/resolv.conf <<EOF
+# Zeroconf subnet, reserved range - no-one should answer this
+#nameserver 169.254.0.2
+#...but bind9 listens to it if using IPv6 ... and chokes on it.
+
+# 00:10:c6:e3:da:7f belongs to a Nokia WLAN card tucked safely in my closet
+nameserver fe80::10:c6ff:fee3:da7f
+
+# This is bind we set up
+nameserver $ns
+
+domain example.com
+
+# This is our addition
+port $port
+EOF
+
+# Resolv.conf with bad namserver addresses
+cat > $t/error.conf <<EOF
+nameserver 0.0.0.2
+nameserver 1.1.1.1.1
+search example.com
+port $port
+EOF
+
+cat > $t/named.conf <<EOF
+options {
+	directory "$(cd $s; pwd)";
+	pid-file "$t/named.pid";
+	notify no;
+	$listen4
+	$listen6
+};
+
+zone "example.com" in {
+        type master;
+        file "example.com";
+};
+
+zone "." in {
+        type master;
+        file "root.zone";
+};
+
+zone "188.2.194.in-addr.arpa" in {
+        type master;
+	file "194.2.188";
+};
+
+zone "0.0.127.in-addr.arpa" in {
+        type master;
+	file "127.zone";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int" in {
+        type master;
+	file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa" in {
+        type master;
+	file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa";
+};
+
+EOF
+
+named -f -d 999 -c $t/named.conf &
+
+echo $0: started named pid $!
+for i in 1 2 3 4 5; do
+    test -r $t/named.pid && break
+    sleep 1; 
+done
+
+test -r $t/named.pid || { 
+    echo $0: cannot start named >&2 ; 
+    if fgrep -q -i -e SELINUX=enforcing /etc/selinux/config 2>&/dev/null ; then
+	echo $0: perhaps you have to disable SELinux protection for named 
+    fi
+    exit 77
+}
+
+function kill_named
+{
+    kill `cat $t/named.pid`
+    rm $t/named.conf $t/resolv.conf $t/error.conf $t/named.pid
+    rmdir $t
+}
+trap kill_named EXIT
+
+# export SOFIA_DEBUG=9
+
+$VALGRIND ./test_sresolv "$@" - $t/resolv.conf $t/error.conf || exit 1
+
+exit 0

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,267 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_H
+/** Defined when <sofia-resolv/sres.h> has been included. */
+#define SOFIA_RESOLV_SRES_H
+/**
+ * @file sofia-resolv/sres.h Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>,
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>.
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres.h>
+ * @endcode
+ *
+ */
+
+#include <stdarg.h>
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+  /** Resolver timer interval in milliseconds. */
+  SRES_RETRANSMIT_INTERVAL = 500,
+#define SRES_RETRANSMIT_INTERVAL  (SRES_RETRANSMIT_INTERVAL)
+
+  /** Initial retry interval in seconds. */
+  SRES_RETRY_INTERVAL = 1,
+#define SRES_RETRY_INTERVAL  (SRES_RETRY_INTERVAL)
+
+  /** Maximum number of retries sent. */
+  SRES_MAX_RETRY_COUNT = 6,
+#define SRES_MAX_RETRY_COUNT (SRES_MAX_RETRY_COUNT)
+
+  /** Maximum number of search domains. */
+  SRES_MAX_SEARCH = 6,
+#define SRES_MAX_SEARCH (SRES_MAX_SEARCH)
+
+  /** Maximum number of nameservers. */
+  SRES_MAX_NAMESERVERS = 6,
+#define SRES_MAX_NAMESERVERS (SRES_MAX_NAMESERVERS)
+
+  /** Maximum length of domain name. */
+  SRES_MAXDNAME = 1025,
+#define SRES_MAXDNAME (SRES_MAXDNAME)
+
+  /** Maximum length of sortlist */
+  SRES_MAX_SORTLIST = 10
+#define SRES_MAX_SORTLIST (SRES_MAX_SORTLIST)
+};
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record sres_record_t;
+#endif
+
+#ifndef SRES_CACHE_T
+#define SRES_CACHE_T
+/** Opaque type of DNS cache object. */
+typedef struct sres_cache sres_cache_t;
+#endif
+
+/** Opaque type of DNS resolver object. */
+typedef struct sres_resolver_s sres_resolver_t;
+
+#ifndef SRES_CONTEXT_T 
+#define SRES_CONTEXT_T struct sres_context_s
+#endif
+/** Application-defined type for sres_query_t context. */
+typedef SRES_CONTEXT_T sres_context_t;
+
+/** Opaque type of DNS query object. */
+typedef struct sres_query_s         sres_query_t;
+
+struct sockaddr;
+
+/** New resolver object. */
+SRESPUBFUN sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
+
+/** Copy a resolver. */
+SRESPUBFUN sres_resolver_t *sres_resolver_copy(sres_resolver_t *);
+
+/** New resolver object. */
+SRESPUBFUN
+sres_resolver_t *
+sres_resolver_new_with_cache(char const *conf_file_path,
+			     sres_cache_t *cache,
+			     char const *options, ...);
+
+/** New resolver object. */
+SRESPUBFUN 
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+				sres_cache_t *cache,
+				char const *options, va_list va);
+
+/** Increase reference count on a resolver object. */
+SRESPUBFUN sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
+
+/** Decrease the reference count on a resolver object.  */
+SRESPUBFUN void sres_resolver_unref(sres_resolver_t *res);
+
+/** Re-read resolv.conf if needed */
+SRESPUBFUN int sres_resolver_update(sres_resolver_t *res, int always);
+
+/** Set userdata pointer. */
+SRESPUBFUN
+void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
+
+/** Get userdata pointer. */
+SRESPUBFUN
+void *sres_resolver_get_userdata(sres_resolver_t const *res);
+
+/** Prototype for callback function.
+ *
+ * This kind of function is called when a query is completed. The called
+ * function is responsible for freeing the list of answers and it must
+ * (eventually) call sres_free_answers().
+ */
+typedef void sres_answer_f(sres_context_t *context, 
+			   sres_query_t *query,
+			   sres_record_t **answers);
+
+/** Make a DNS query. */
+SRESPUBFUN 
+sres_query_t *sres_query(sres_resolver_t *res,
+                         sres_answer_f *callback,
+                         sres_context_t *context,
+                         uint16_t type,
+                         char const *domain);
+
+/** Search DNS. */
+SRESPUBFUN 
+sres_query_t *sres_search(sres_resolver_t *res,
+			  sres_answer_f *callback,
+			  sres_context_t *context,
+			  uint16_t type,
+			  char const *name);
+
+/** Make a reverse DNS query. */
+SRESPUBFUN 
+sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
+                                  sres_answer_f *callback,
+                                  sres_context_t *context,
+                                  uint16_t type,
+				  struct sockaddr const *addr);
+
+/** Make a DNS query with socket. @deprecated */
+SRESPUBFUN 
+sres_query_t *sres_query_make(sres_resolver_t *res,
+			      sres_answer_f *callback,
+			      sres_context_t *context,
+			      int dummy,
+			      uint16_t type,
+			      char const *domain);
+
+/** Make a reverse DNS query with socket. @deprecated */
+SRESPUBFUN 
+sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res,
+				       sres_answer_f *callback,
+				       sres_context_t *context,
+				       int dummy,
+				       uint16_t type,
+				       struct sockaddr const *addr);
+
+/** Rebind a DNS query. */
+SRESPUBFUN 
+void sres_query_bind(sres_query_t *q,
+                     sres_answer_f *callback,
+                     sres_context_t *context);
+
+/**Get a list of matching (type/domain) records from cache. */
+SRESPUBFUN 
+sres_record_t **sres_cached_answers(sres_resolver_t *res,
+				    uint16_t type,
+				    char const *domain);
+
+/**Search for a list of matching (type/name) records from cache. */
+SRESPUBFUN 
+sres_record_t **sres_search_cached_answers(sres_resolver_t *res,
+					   uint16_t type,
+					   char const *name);
+
+/**Get a list of matching (type/domain) records from cache. */
+SRESPUBFUN 
+sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
+                                             uint16_t type,
+					     struct sockaddr const *addr);
+
+/** Send a query, wait for answer, return results. */
+SRESPUBFUN 
+int sres_blocking_query(sres_resolver_t *res,
+			uint16_t type,
+			char const *domain,
+			int ignore_cache,
+			sres_record_t ***return_records);
+
+/** Search DNS, return results. */
+SRESPUBFUN 
+int sres_blocking_search(sres_resolver_t *res,
+			 uint16_t type,
+			 char const *name,
+			 int ignore_cache,
+			 sres_record_t ***return_records);
+
+/** Send a a reverse DNS query, wait for answer, return results. */
+SRESPUBFUN 
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+				 uint16_t type,
+				 struct sockaddr const *addr,
+				 int ignore_cache,
+				 sres_record_t ***return_records);
+
+/** Return true (and set resolver in blocking mode) if resolver can block. */
+SRESPUBFUN int sres_is_blocking(sres_resolver_t *res);
+
+/** Sort the list of records */
+SRESPUBFUN int sres_sort_answers(sres_resolver_t *, sres_record_t **answers);
+
+/** Filter and sort the list of records */
+SRESPUBFUN
+int sres_filter_answers(sres_resolver_t *res, 
+			sres_record_t **answers, 
+			uint16_t type);
+
+/** Free the list records. */
+SRESPUBFUN void sres_free_answers(sres_resolver_t *, sres_record_t **answers);
+
+/** Free and zero one record. */
+SRESPUBFUN void sres_free_answer(sres_resolver_t *res, sres_record_t *answer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_ASYNC_H
+/** Defined when <sofia-resolv/sres_async.h> has been included. */
+#define SOFIA_RESOLV_SRES_ASYNC_H
+
+/**
+ * @file sofia-resolv/sres_async.h 
+ *
+ * Asynchronous interface for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres.h>
+ * #include <sofia-resolv/sres_async.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SRES_ASYNC_T 
+#define SRES_ASYNC_T struct sres_async_s
+#endif
+/** Application-defined type for context used by asynchronous operation. */
+typedef SRES_ASYNC_T sres_async_t;
+
+/** Prototype for update function.
+ *
+ * This kind of function is called when the nameserver configuration has
+ * been updated. 
+ *
+ * If the old_socket is not -1, it indicates that old_socket will be closed
+ * and it should be removed from poll() or select() set.
+ *
+ * If the new_socket is not -1, it indicates that resolver has created new
+ * socket that should be added to the poll() or select() set.
+ *
+ * @sa sres_resolver_set_async(), sres_resolver_get_async()
+ */
+typedef int sres_update_f(sres_async_t *async,
+			  sres_socket_t new_socket,
+			  sres_socket_t old_socket);
+
+/** Set asynchronous operation data. */
+SRESPUBFUN
+sres_async_t *sres_resolver_set_async(sres_resolver_t *res, 
+				      sres_update_f *update,
+				      sres_async_t *async,
+				      int update_all);
+
+/** Get async operation data. */
+SRESPUBFUN
+sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
+				      sres_update_f *update);
+
+/** Create sockets for resolver. */
+SRESPUBFUN int sres_resolver_sockets(sres_resolver_t *, 
+				     sres_socket_t *sockets,
+				     int n);
+
+/** Resolver timer function. */
+SRESPUBFUN void sres_resolver_timer(sres_resolver_t *, int dummy);
+
+/** Prototype for scheduler function.
+ *
+ * This function is called when a timer callback is to be scheduled.
+ *
+ * @param async asynchronous object (registered with sres_resolver_set_async())
+ * @param interval interval in milliseconds
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+ typedef int sres_schedule_f(sres_async_t *async, unsigned long interval);
+
+/** Register resolver timer callback. */
+SRESPUBFUN int sres_resolver_set_timer_cb(sres_resolver_t *res,
+					  sres_schedule_f *callback,
+					  sres_async_t *async);
+
+/** Receive DNS response from socket. */
+SRESPUBFUN int sres_resolver_receive(sres_resolver_t *, int socket);
+
+/** Receive error message from socket. */
+SRESPUBFUN int sres_resolver_error(sres_resolver_t *, int socket);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_ASYNC_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_CACHE_H
+/** Defined when <sofia-resolv/sres_cache.h> has been included. */
+#define SOFIA_RESOLV_SRES_CACHE_H
+/**
+ * @file sofia-resolv/sres_cache.h Sofia DNS Resolver Cache.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres_cache.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SRES_CACHE_T
+#define SRES_CACHE_T
+/** Opaque type of DNS cache object. */
+typedef struct sres_cache sres_cache_t;
+#endif
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record sres_record_t;
+#endif
+
+enum {
+  /** Cache cleanup interval in seconds. */
+  SRES_CACHE_TIMER_INTERVAL = 30,
+#define SRES_CACHE_TIMER_INTERVAL (SRES_CACHE_TIMER_INTERVAL)
+};
+
+/** Create a resolver cache object. */
+SRESPUBFUN sres_cache_t *sres_cache_new(int n);
+
+/** Increase reference count on a resolver cache object. */
+SRESPUBFUN sres_cache_t *sres_cache_ref(sres_cache_t *);
+
+/** Decrease the reference count on a resolver cache object. */
+SRESPUBFUN void sres_cache_unref(sres_cache_t *);
+
+/** Get a list of matching records from cache. */
+SRESPUBFUN int sres_cache_get(sres_cache_t *cache,
+			      uint16_t type,
+			      char const *domain,
+			      sres_record_t ***return_cached);
+
+/** Free answers not matching with type */
+SRESPUBFUN int sres_cache_filter(sres_cache_t *cache,
+				 sres_record_t **answers, 
+				 uint16_t type);
+
+/** Free the list records. */
+SRESPUBFUN void sres_cache_free_answers(sres_cache_t *, sres_record_t **);
+
+/** Free and zero one record. */
+SRESPUBFUN void sres_cache_free_one(sres_cache_t *, sres_record_t *answer);
+
+/** Allocate a cache record */
+SRESPUBFUN
+sres_record_t *sres_cache_alloc_record(sres_cache_t *cache,
+				       sres_record_t const *template,
+				       size_t extra);
+
+/** Free a record that has not been stored. */
+SRESPUBFUN void sres_cache_free_record(sres_cache_t *cache, void *rr);
+
+/** Store a record to cache */
+SRESPUBFUN void sres_cache_store(sres_cache_t *, sres_record_t *, time_t now);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CACHED_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_CONFIG_H
+/** Defined when <sofia-resolv/sres_config.h> has been included. */
+#define SOFIA_RESOLV_SRES_CONFIG_H
+
+/**
+ * @file sofia-resolv/sres_config.h 
+ *
+ * Configuration for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Macros required by Win32 linkage */
+
+/** SRESPUBFUN declares an exported function */
+#define SRESPUBFUN
+
+#if defined(_WIN32) && !defined(LIBSRES_STATIC) && \
+  (defined(_MSC_VER) || defined(__BORLANDC__) ||  \
+   defined(__CYGWIN__) || defined(__MINGW32__))
+  /* Windows platform with MS/Borland/Cygwin/MinGW32 compiler */
+  #undef SRESPUBFUN
+  #if defined(IN_LIBSOFIA_SRES)
+    #define SRESPUBFUN __declspec(dllexport)
+  #else
+    #define SRESPUBFUN __declspec(dllimport)
+  #endif
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/* Types required by Win32/64 */
+
+#if defined(_WIN32)
+typedef SOCKET sres_socket_t;
+#else
+/** Socket descriptor. @since New in @VERSION_1_12_2. */
+typedef int sres_socket_t;
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CONFIG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,259 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_RECORD_H
+/** Defined when <sofia-resolv/sres_record.h> has been included. */
+#define SOFIA_RESOLV_SRES_RECORD_H
+/**
+ * @file sofia-resolv/sres_record.h Sofia DNS Resolver Records.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres_record.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+/** Common part of all DNS records. */
+typedef struct sres_common
+{
+  int               r_refcount;	/**< Number of references to this record */
+  char             *r_name;	/**< Domain name */
+  uint16_t          r_status;	/**< Status of query (nonzero upon an error) */
+  uint16_t          r_size;	/**< Size of this record */
+  uint16_t          r_type;	/**< Record type (A, CNAME, A6, etc) */
+  uint16_t          r_class;	/**< Record class (IN) */
+  uint32_t          r_ttl;	/**< Time-to-live */
+  uint16_t          r_rdlen;	/**< Length of record data */
+  uint16_t          r_parsed;	/**< Nonzero if parsed */
+} sres_common_t;
+
+/** Possible values for r_status (RCODE) in #sres_common */
+enum sres_status {
+  SRES_OK = 0,			/**< No error condition. */
+  SRES_FORMAT_ERR = 1,		/**< Server could not interpret query. */
+  SRES_SERVER_ERR = 2,		/**< Server error. */
+  SRES_NAME_ERR = 3,		/**< No domain name. */
+  SRES_UNIMPL_ERR = 4,		/**< Not implemented. */
+  SRES_AUTH_ERR = 5,		/**< Refused */
+
+  /* Errors generated by sresolv */
+  SRES_TIMEOUT_ERR = 32,	/**< Timeout occurred */
+  SRES_RECORD_ERR = 33	        /**< Name has no given record type */
+};
+
+/** Start of a zone of authority record (@RFC1035). */
+typedef struct sres_soa_record
+{
+  sres_common_t  soa_record[1];	/**< Common part of DNS records. */
+  char          *soa_mname;	/**< Primary name server */
+  char          *soa_rname;	/**< Person responsible for domain */
+  uint32_t       soa_serial;	/**< Version number */
+  uint32_t       soa_refresh;	/**< Refresh intercal */
+  uint32_t       soa_retry;	/**< Interval between refres retries */
+  uint32_t       soa_expire;	/**< Upper limit on zone expiration time  */
+  uint32_t       soa_minimum;	/**< Minimum TTL for any record in zone */
+} sres_soa_record_t;
+
+/** Generic DNS record. */
+typedef struct sres_generic
+{
+  sres_common_t  g_record[1];	/**< Common part of DNS records. */
+  uint8_t        g_data[128];	/**< Record data */
+} sres_generic_t;
+
+/** Address record (@RFC1035). */
+typedef struct sres_a_record
+{
+  sres_common_t  a_record[1];	/**< Common part of DNS records. */
+  struct in_addr a_addr;	/**< IP4 address */
+} sres_a_record_t;
+
+/** IPv6 address used by sresolv library. 
+ *
+ * @sa #sres_aaaa_record, #sres_a6_record
+ */
+typedef struct
+{
+  uint8_t u6_addr[16];		/**< Array of 16 octets. */
+} sres_in6_t;
+
+/** Aggregated address record for IPv6 (@RFC2874, deprecated). */
+typedef struct sres_a6_record
+{
+  sres_common_t  a6_record[1];	/**< Common part of DNS records. */
+  uint8_t        a6_prelen;	/**< Prefix length */
+  uint8_t        a6_pad[3];	/**<  */
+  sres_in6_t     a6_suffix;	/**< Address suffix */
+  char          *a6_prename;	/**< Prefix name */
+} sres_a6_record_t;
+
+/** Address record for IPv6 (@RFC1886). */
+typedef struct sres_aaaa_record
+{
+  sres_common_t aaaa_record[1];	/**< Common part of DNS records. */
+  sres_in6_t    aaaa_addr;	/**< IP6 address */
+} sres_aaaa_record_t;
+
+/** Canonic name record (@RFC1035). */
+typedef struct sres_cname_record
+{
+  sres_common_t  cn_record[1];	/**< Common part of DNS records. */
+  char          *cn_cname;	/**<  */
+} sres_cname_record_t;
+
+/** Pointer record (@RFC1035). */
+typedef struct sres_ptr_record
+{
+  sres_common_t  ptr_record[1];	/**< Common part of DNS records. */
+  char          *ptr_domain;	/**< Domain */
+} sres_ptr_record_t;
+
+/** Service location record (@RFC2782). */
+typedef struct sres_srv_record
+{
+  sres_common_t  srv_record[1];	/**< Common part of DNS records. */
+  uint16_t       srv_priority;	/**< Priority */
+  uint16_t       srv_weight;	/**< Weight */
+  uint16_t       srv_port;	/**< Service port on the target host. */
+  uint16_t       srv_pad;
+  char          *srv_target;	/**< Domain name of the target host. */
+} sres_srv_record_t;
+
+/** Naming authority pointer record (@RFC2915). */
+typedef struct sres_naptr_record
+{
+  sres_common_t  na_record[1];	/**< Common part of DNS records. */
+  uint16_t       na_order;	/**< Processing order for NAPTR records. */
+  uint16_t       na_prefer;	/**< Preference */
+  char          *na_flags;	/**< Flags for interpretation and rewriting */
+  char          *na_services;	/**< Services available. */
+  char          *na_regexp;	/**< Substitution expression. */
+  char          *na_replace;	/**< Replacement. */
+} sres_naptr_record_t;
+
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record           sres_record_t;
+#endif
+
+/** Union of different DNS records */
+union sres_record
+{
+  sres_common_t       sr_record[1];	/**< Common part of all DNS records */
+  sres_generic_t      sr_generic[1];	/**< Generic (unparsed) DNS record */
+  sres_soa_record_t   sr_soa[1];	/**< SOA (start-of-authority) record */
+  sres_a_record_t     sr_a[1];		/**< A (address) record */
+  sres_cname_record_t sr_cname[1];	/**< CNAME (canonic name) record */
+  sres_ptr_record_t   sr_ptr[1];	/**< PTR (pointer) record */
+  sres_a6_record_t    sr_a6[1];		/**< A6 (IP6 address) record */
+  sres_aaaa_record_t  sr_aaaa[1];	/**< AAAA (IP6 address) record */
+  sres_srv_record_t   sr_srv[1];	/**< SRV record */
+  sres_naptr_record_t sr_naptr[1];	/**< NAPTR record */
+};
+
+/** Protocol family classes. */
+enum sres_class {
+  sres_class_in = 1,		        /**< Internet (@b IN) */
+  sres_class_any = 255		        /**< Any class */
+};
+
+/** Query types. */
+enum sres_qtypes {
+  sres_type_a = 1,	    /**< IPv4 address (#sres_a_record). */
+  sres_type_ns = 2,	    /**< Authoritative server. */
+  sres_type_mf = 4,	    /**< Mail forwarder. */
+  sres_type_cname = 5,	    /**< Canonical name (#sres_cname_record). */
+  sres_type_soa = 6,	    /**< Start of authority zone (#sres_soa_record). */
+  sres_type_mb = 7,	    /**< Mailbox domain name. */
+  sres_type_mg = 8,	    /**< Mail group member. */
+  sres_type_mr = 9,	    /**< Mail rename name. */
+  sres_type_null = 10,	    /**< Null resource record. */
+  sres_type_wks = 11,	    /**< Well known service. */
+  sres_type_ptr = 12,	    /**< Domain name pointer (#sres_ptr_record). */
+  sres_type_hinfo = 13,	    /**< Host information. */
+  sres_type_minfo = 14,	    /**< Mailbox information. */
+  sres_type_mx = 15,	    /**< Mail routing information. */
+  sres_type_txt = 16,	    /**< Text strings. */
+  sres_type_rp = 17,	    /**< Responsible person. */
+  sres_type_afsdb = 18,	    /**< AFS cell database. */
+  sres_type_x25 = 19,	    /**< X_25 calling address. */
+  sres_type_isdn = 20,	    /**< ISDN calling address. */
+  sres_type_rt = 21,	    /**< Router. */
+  sres_type_nsap = 22,	    /**< NSAP address. */
+  sres_type_nsap_ptr = 23,  /**< Reverse NSAP lookup. */
+  sres_type_sig = 24,	    /**< Security signature. */
+  sres_type_key = 25,	    /**< Security key. */
+  sres_type_px = 26,	    /**< X.400 mail mapping. */
+  sres_type_gpos = 27,	    /**< ICBM record. */
+  sres_type_aaaa = 28,	    /**< IPv6 Address (#sres_aaaa_record). */
+  sres_type_loc = 29,	    /**< Location Information. */
+  sres_type_nxt = 30,	    /**< Next domain. */
+  sres_type_eid = 31,	    /**< Endpoint identifier. */
+  sres_type_nimloc = 32,    /**< Nimrod Locator. */
+  sres_type_srv = 33,	    /**< Server Selection (@RFC2782, 
+			         #sres_srv_record). */
+  sres_type_atma = 34,	    /**< ATM Address */
+  sres_type_naptr = 35,	    /**< Naming Authority PoinTeR (@RFC2915, 
+                                 #sres_naptr_record) */
+  sres_type_kx = 36,	    /**< Key Exchange */
+  sres_type_cert = 37,	    /**< Certification record */
+  sres_type_a6 = 38,	    /**< IPv6 address (deprecates AAAA) */
+  sres_type_dname = 39,	    /**< Non-terminal DNAME (for IPv6) */
+  sres_type_sink = 40,	    /**< Kitchen sink (experimental) */
+  sres_type_opt = 41,	    /**< EDNS 0 option (@RFC2671) */
+
+  sres_qtype_tsig = 250,    /**< Transaction signature. */
+  sres_qtype_ixfr = 251,    /**< Incremental zone transfer. */
+  sres_qtype_axfr = 252,    /**< Transfer zone of authority. */
+  sres_qtype_mailb = 253,   /**< Transfer mailbox records. */
+  sres_qtype_maila = 254,   /**< Transfer mail agent records. */
+  sres_qtype_any = 255	    /**< Wildcard match. */
+};
+
+/** Convert type to its name. */
+SRESPUBFUN char const *sres_record_type(int type, char buffer[8]);
+
+/** Compare two records. */
+SRESPUBFUN int sres_record_compare(sres_record_t const *,
+				   sres_record_t const *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CACHE_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SRESOLV_H 
+/** Defined when <sofia-sip/sresolv.h> has been included. */
+#define SRESOLV_H
+
+/**
+ * @file sofia-sip/sresolv.h Easy API for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>,
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>.
+ *
+ */
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag.h>
+
+#include <sofia-resolv/sres.h>
+#include <sofia-resolv/sres_record.h>
+#include <sofia-resolv/sres_async.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Sofia-specific reactor interface for asynchronous operation */
+
+/** Filter tag matching any sresolv tag. */
+#define SRESOLVTAG_ANY()         srestag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t srestag_any;
+
+SOFIAPUBVAR tag_typedef_t srestag_resolv_conf;
+/** Path of resolv.conf file. */
+#define SRESTAG_RESOLV_CONF(x) srestag_resolv_conf, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t srestag_resolv_conf_ref;
+#define SRESTAG_RESOLV_CONF_REF(x) srestag_resolv_conf_ref, tag_str_vr(&(x))
+
+SOFIAPUBVAR tag_typedef_t srestag_cache;
+/** Pointer to existing #sres_cache_t object. */
+#define SRESTAG_CACHE(x) srestag_cache, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t srestag_cache_ref;
+#define SRESTAG_CACHE_REF(x) srestag_cache_ref, tag_ptr_vr(&(x), (x))
+
+/** Create a resolver object using @a root reactor. */
+SOFIAPUBFUN sres_resolver_t *sres_resolver_create(su_root_t *root, 
+						  char const *resolv_conf,
+				                  tag_type_t, tag_value_t,
+						  ...);
+/** Destroy a resolver object. */
+SOFIAPUBFUN int sres_resolver_destroy(sres_resolver_t *res);
+
+/* Return socket used by root. @deprecated */
+SOFIAPUBFUN su_socket_t sres_resolver_root_socket(sres_resolver_t *res);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4060 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ * Copyright (C) 2006 Dimitri E. Prado.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres.c
+ * @brief Sofia DNS Resolver implementation.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com> 
+ *         (work on the win32 nameserver discovery) 
+ * @author Dimitri E. Prado 
+ *         (initial version of win32 nameserver discovery)
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef _int8 int8_t;
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#ifndef IPPROTO_IPV6		/* socklen_t is used with @RFC2133 API */
+typedef int socklen_t;
+#endif
+#endif
+
+#include <time.h>
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_cache.h"
+#include "sofia-resolv/sres_record.h"
+#include "sofia-resolv/sres_async.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_errno.h>
+
+#include "sofia-sip/htable.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <limits.h>
+
+#include <assert.h>
+
+#if HAVE_WINSOCK2_H
+/* Posix send() */
+static inline 
+ssize_t sres_send(sres_socket_t s, void *b, size_t length, int flags)
+{
+  if (length > INT_MAX)
+    length = INT_MAX;
+  return (ssize_t)send(s, b, (int)length, flags);
+}
+
+/* Posix recvfrom() */
+static inline 
+ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags,
+		      struct sockaddr *from, socklen_t *fromlen)
+{
+  int retval, ilen;
+
+  if (fromlen)
+    ilen = *fromlen;
+
+  if (length > INT_MAX)
+    length = INT_MAX;
+
+  retval = recvfrom(s, buffer, (int)length, flags, 
+		    (void *)from, fromlen ? &ilen : NULL);
+
+  if (fromlen)
+    *fromlen = ilen;
+
+  return (ssize_t)retval;
+}
+
+static inline
+int sres_close(sres_socket_t s)
+{
+  return closesocket(s);
+}
+
+#if !defined(IPPROTO_IPV6)
+#if HAVE_SIN6
+#include <tpipv6.h>
+#else
+#if !defined(__MINGW32__)
+struct sockaddr_storage {
+    short ss_family;
+    char ss_pad[126];
+};
+#endif
+#endif
+#endif
+#else
+
+#define sres_send(s,b,len,flags) send((s),(b),(len),(flags))
+#define sres_recvfrom(s,b,len,flags,a,alen) \
+  recvfrom((s),(b),(len),(flags),(a),(alen))
+#define sres_close(s) close((s))
+#define SOCKET_ERROR   (-1)
+#define INVALID_SOCKET ((sres_socket_t)-1)
+#endif
+
+
+#if !HAVE_INET_PTON
+int inet_pton(int af, char const *src, void *dst);
+#endif
+#if !HAVE_INET_NTOP
+const char *inet_ntop(int af, void const *src, char *dst, size_t size);
+#endif
+
+#if defined(va_copy)
+#elif defined(__va_copy)
+#define va_copy(dst, src) __va_copy((dst), (src))
+#else
+#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
+#endif
+
+/**
+ * How often to recheck nameserver information (seconds).
+ */
+#ifndef _WIN32
+#define SRES_UPDATE_INTERVAL_SECS        5
+#else
+#define SRES_UPDATE_INTERVAL_SECS        180
+#endif
+void sres_cache_clean(sres_cache_t *cache, time_t now);
+
+typedef struct sres_message    sres_message_t;
+typedef struct sres_config     sres_config_t;
+typedef struct sres_server     sres_server_t;
+typedef struct sres_nameserver sres_nameserver_t;
+
+/** Default path to resolv.conf */
+static char const sres_conf_file_path[] = "/etc/resolv.conf";
+
+/** EDNS0 support. @internal */
+enum edns { 
+  edns_not_tried = -1,
+  edns_not_supported = 0,
+  edns0_configured = 1,
+  edns0_supported = 2,
+};
+
+struct sres_server {
+  sres_socket_t           dns_socket;
+
+  char                    dns_name[48];     /**< Server name */
+  struct sockaddr_storage dns_addr[1];  /**< Server node address */
+  ssize_t                 dns_addrlen;  /**< Size of address */
+
+  enum edns               dns_edns;	/**< Server supports edns. */
+
+  /** ICMP/temporary error received, zero when successful. */
+  time_t                  dns_icmp;
+  /** Persisten error, zero when successful. */
+  time_t                  dns_error;
+};
+
+HTABLE_DECLARE_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);
+
+struct sres_resolver_s {
+  su_home_t           res_home[1];
+
+  void               *res_userdata;
+  sres_cache_t       *res_cache;
+
+  time_t              res_now;
+  sres_qtable_t       res_queries[1];   /**< Table of active queries */
+
+  char const         *res_cnffile;      /**< Configuration file name */
+  char const        **res_options;      /**< Option strings */
+
+  sres_config_t const *res_config;
+  time_t              res_checked;
+
+  unsigned long       res_updated;
+  sres_update_f      *res_updcb;
+  sres_async_t       *res_async;
+  sres_schedule_f    *res_schedulecb;
+  short               res_update_all;
+
+  uint16_t            res_id;
+  short               res_i_server;  /**< Current server to try 
+					(when doing round-robin) */
+  short               res_n_servers; /**< Number of servers */
+  sres_server_t     **res_servers;
+};
+
+/* Parsed configuration. @internal */
+struct sres_config {
+  su_home_t c_home[1];
+
+  time_t c_modified;
+  char const *c_filename;
+
+  /* domain and search */
+  char const *c_search[SRES_MAX_SEARCH + 1];
+
+  /* nameserver */
+  struct sres_nameserver {
+    struct sockaddr_storage ns_addr[1];
+    ssize_t ns_addrlen;
+  } *c_nameservers[SRES_MAX_NAMESERVERS + 1];
+
+  /* sortlist */
+  struct sres_sortlist {
+    struct sockaddr_storage addr[1];
+    ssize_t addrlen;
+    char const *name;
+  } *c_sortlist[SRES_MAX_SORTLIST + 1];
+
+  uint16_t    c_port;	     /**< Server port to use */
+
+  /* options */
+  struct sres_options {
+    uint16_t timeout;
+    uint16_t attempts;
+    uint16_t ndots;
+    enum edns edns;
+    unsigned debug:1;
+    unsigned rotate:1;
+    unsigned check_names:1;
+    unsigned inet6:1;
+    unsigned ip6int:1;
+    unsigned ip6bytestring:1;
+  } c_opt;
+};
+
+struct sres_query_s {
+  unsigned        q_hash;
+  sres_resolver_t*q_res;
+  sres_answer_f  *q_callback;
+  sres_context_t *q_context;
+  char           *q_name;
+  time_t          q_timestamp;
+  uint16_t        q_type;
+  uint16_t        q_class;
+  uint16_t        q_id;			/**< If nonzero, not answered */
+  uint16_t        q_retry_count;
+  uint8_t         q_n_servers;
+  uint8_t         q_i_server;
+  int8_t          q_edns;
+  uint8_t         q_n_subs;
+  sres_query_t   *q_subqueries[1 + SRES_MAX_SEARCH];
+  sres_record_t **q_subanswers[1 + SRES_MAX_SEARCH];
+};
+
+
+struct sres_message {
+  uint16_t m_offset;
+  uint16_t m_size;
+  char const *m_error;
+  union {
+    struct {
+      /* Header defined in RFC 1035 section 4.1.1 (page 26) */
+      uint16_t mh_id;		/* Query ID */
+      uint16_t mh_flags;	/* Flags */
+      uint16_t mh_qdcount;	/* Question record count */
+      uint16_t mh_ancount;	/* Answer record count */
+      uint16_t mh_nscount;	/* Authority records count */
+      uint16_t mh_arcount;	/* Additional records count */
+    } mp_header;
+    uint8_t mp_data[1500 - 40];	/**< IPv6 datagram */
+  } m_packet;
+#define m_id      m_packet.mp_header.mh_id
+#define m_flags   m_packet.mp_header.mh_flags
+#define m_qdcount m_packet.mp_header.mh_qdcount
+#define m_ancount m_packet.mp_header.mh_ancount
+#define m_nscount m_packet.mp_header.mh_nscount
+#define m_arcount m_packet.mp_header.mh_arcount 
+#define m_data    m_packet.mp_data
+};
+
+#define sr_refcount sr_record->r_refcount
+#define sr_name     sr_record->r_name
+#define sr_status   sr_record->r_status
+#define sr_size     sr_record->r_size
+#define sr_type     sr_record->r_type
+#define sr_class    sr_record->r_class
+#define sr_ttl      sr_record->r_ttl
+#define sr_rdlen    sr_record->r_rdlen
+#define sr_parsed   sr_record->r_parsed
+#define sr_rdata    sr_generic->g_data
+
+enum {
+  SRES_HDR_QR = (1 << 15),
+  SRES_HDR_QUERY = (0 << 11),
+  SRES_HDR_IQUERY = (1 << 11),
+  SRES_HDR_STATUS = (2 << 11),
+  SRES_HDR_OPCODE = (15 << 11),	/* mask */
+  SRES_HDR_AA = (1 << 10),
+  SRES_HDR_TC = (1 << 9),
+  SRES_HDR_RD = (1 << 8),
+  SRES_HDR_RA = (1 << 7),
+  SRES_HDR_RCODE = (15 << 0)	/* mask of return code */
+};
+
+HTABLE_PROTOS_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);
+
+#define CHOME(cache) ((su_home_t *)(cache))
+
+/** Get address from sockaddr storage. */
+#if HAVE_SIN6
+#define SS_ADDR(ss) \
+  ((ss)->ss_family == AF_INET ? \
+   (void *)&((struct sockaddr_in *)ss)->sin_addr : \
+  ((ss)->ss_family == AF_INET6 ? \
+   (void *)&((struct sockaddr_in6 *)ss)->sin6_addr : \
+   (void *)&((struct sockaddr *)ss)->sa_data))
+#else
+#define SS_ADDR(ss) \
+  ((ss)->ss_family == AF_INET ? \
+   (void *)&((struct sockaddr_in *)ss)->sin_addr : \
+   (void *)&((struct sockaddr *)ss)->sa_data)
+#endif
+
+static int sres_config_changed_servers(sres_config_t const *new_c, 
+				       sres_config_t const *old_c);
+static sres_server_t **sres_servers_new(sres_resolver_t *res,
+					sres_config_t const *c);
+
+/** Generate new 16-bit identifier for DNS query. */
+static uint16_t
+sres_new_id(sres_resolver_t *res)
+{
+  return res->res_id ? res->res_id++ : (res->res_id = 2, 1);
+}
+
+/** Return true if we have a search list or a local domain name. */
+static int 
+sres_has_search_domain(sres_resolver_t *res) 
+{
+  return res->res_config->c_search[0] != NULL;
+}
+
+static void sres_resolver_destructor(void *);
+
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+				sres_cache_t *cache,
+				char const *options, 
+				va_list va);
+static
+sres_resolver_t *
+sres_resolver_new_internal(sres_cache_t *cache,
+			   sres_config_t const *config,
+			   char const *conf_file_path,
+			   char const **options);
+
+static void sres_servers_close(sres_resolver_t *res,
+			       sres_server_t **servers);
+
+static int sres_servers_count(sres_server_t * const *servers);
+
+static sres_socket_t sres_server_socket(sres_resolver_t *res,
+					sres_server_t *dns);
+
+static sres_query_t * sres_query_alloc(sres_resolver_t *res,
+				       sres_answer_f *callback,
+				       sres_context_t *context,
+				       uint16_t type,
+				       char const * domain);
+
+static void sres_free_query(sres_resolver_t *res, sres_query_t *q);
+
+static 
+int sres_sockaddr2string(sres_resolver_t *, 
+			 char name[], size_t namelen, 
+			 struct sockaddr const *);
+
+static 
+sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
+				      char const **options);
+
+static
+sres_server_t *sres_next_server(sres_resolver_t *res, 
+				uint8_t *in_out_i,
+				int timeout);
+
+static
+int sres_send_dns_query(sres_resolver_t *res, sres_query_t *q);
+
+static 
+void sres_answer_subquery(sres_context_t *context, 
+			  sres_query_t *query,
+			  sres_record_t **answers);
+
+static
+sres_record_t **
+sres_combine_results(sres_resolver_t *res,
+		     sres_record_t **search_results[SRES_MAX_SEARCH + 1]);
+
+static
+void sres_query_report_error(sres_query_t *q,
+			     sres_record_t **answers);
+
+static void
+sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout);
+
+static 
+sres_server_t *sres_server_by_socket(sres_resolver_t const *ts,
+				     sres_socket_t socket);
+
+static
+int sres_resolver_report_error(sres_resolver_t *res, 
+			       sres_socket_t socket,
+			       int errcode,
+			       struct sockaddr_storage *remote,
+			       socklen_t remotelen, 
+			       char const *info);
+
+static
+void sres_log_response(sres_resolver_t const *res, 
+		       sres_message_t const *m,
+		       struct sockaddr_storage const *from,
+		       sres_query_t const *query,
+		       sres_record_t * const *reply);
+
+static int sres_decode_msg(sres_resolver_t *res, 
+			   sres_message_t *m,
+			   sres_query_t **,
+			   sres_record_t ***aanswers);
+
+static char const *sres_toplevel(char buf[], size_t bsize, char const *domain);
+
+static sres_record_t *sres_create_record(sres_resolver_t *, sres_message_t *m);
+
+static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
+				       sres_soa_record_t *,
+				       sres_message_t *m);
+static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
+				     sres_a_record_t *,
+				     sres_message_t *m);
+static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
+				      sres_a6_record_t *,
+				      sres_message_t *m);
+static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
+					sres_aaaa_record_t *,
+					sres_message_t *m);
+static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
+					 sres_cname_record_t *,
+					 sres_message_t *m);
+static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
+				       sres_ptr_record_t *,
+				       sres_message_t *m);
+static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
+				       sres_srv_record_t *,
+				       sres_message_t *m);
+static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
+					 sres_naptr_record_t *,
+					 sres_message_t *m);
+static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
+					   sres_common_t *r,
+					   sres_message_t *m);
+
+static sres_record_t *sres_create_error_rr(sres_cache_t *cache,
+                                           sres_query_t const *q,
+                                           uint16_t errcode);
+
+static void m_put_uint16(sres_message_t *m, uint16_t h);
+static void m_put_uint32(sres_message_t *m, uint32_t w);
+
+static uint16_t m_put_domain(sres_message_t *m, 
+                             char const *domain, 
+                             uint16_t top, 
+                             char const *topdomain);
+
+static uint32_t m_get_uint32(sres_message_t *m);
+static uint16_t m_get_uint16(sres_message_t *m);
+static uint8_t m_get_uint8(sres_message_t *m);
+
+static int m_get_string(char *d, int n, sres_message_t *m, uint16_t offset);
+static int m_get_domain(char *d, int n, sres_message_t *m, uint16_t offset);
+
+/* ---------------------------------------------------------------------- */
+
+#define SU_LOG sresolv_log
+
+#include <sofia-sip/su_debug.h>
+
+#ifdef _WIN32
+#include <winreg.h>
+#endif
+
+/**@var SRESOLV_DEBUG
+ *
+ * Environment variable determining the debug log level for @b sresolv
+ * module.
+ *
+ * The SRESOLV_DEBUG environment variable is used to determine the debug
+ * logging level for @b sresolv module. The default level is 3.
+ * 
+ * @sa <su_debug.h>, sresolv_log, SOFIA_DEBUG
+ */
+extern char const SRESOLV_DEBUG[];
+
+/**Debug log for @b sresolv module. 
+ * 
+ * The sresolv_log is the log object used by @b sresolv module. The level of
+ * #sresolv_log is set using #SRESOLV_DEBUG environment variable.
+ */
+su_log_t sresolv_log[] = { SU_LOG_INIT("sresolv", "SRESOLV_DEBUG", 3) };
+
+/** Internal errors */
+enum {
+  SRES_EDNS0_ERR = 255		/**< Server did not support EDNS. */
+};
+
+/* ---------------------------------------------------------------------- */
+
+/**Create a resolver.
+ *
+ * Allocate and initialize a new sres resolver object. The resolver object
+ * contains the parsed resolv.conf file, a cache object containing past
+ * answers from DNS, and a list of active queries. The default resolv.conf
+ * file can be overriden by giving the name of the configuration file as @a
+ * conf_file_path.
+ *
+ * @param conf_file_path name of the resolv.conf configuration file 
+ *
+ * @return A pointer to a newly created sres resolver object, or NULL upon
+ * an error.
+ */
+sres_resolver_t *
+sres_resolver_new(char const *conf_file_path)
+{
+  return sres_resolver_new_internal(NULL, NULL, conf_file_path, NULL);
+}
+
+/** Copy a resolver.
+ *
+ * Make a copy of resolver sharing the configuration and cache with old
+ * resolver.
+ */
+sres_resolver_t *sres_resolver_copy(sres_resolver_t *res)
+{
+  char const *cnffile;
+  sres_config_t *config;
+  sres_cache_t *cache;
+  char const **options;
+
+  if (!res)
+    return NULL;
+
+  cnffile = res->res_cnffile;
+  config = su_home_ref(res->res_config->c_home);
+  cache = res->res_cache;
+  options = res->res_options;
+
+  return sres_resolver_new_internal(cache, config, cnffile, options);
+}
+
+/**New resolver object.
+ *
+ * Allocate and initialize a new sres resolver object. The resolver object
+ * contains the parsed resolv.conf file, a cache object containing past
+ * answers from DNS, and a list of active queries. The default resolv.conf
+ * file can be overriden by giving the name of the configuration file as @a
+ * conf_file_path.
+ *
+ * It is also possible to override the values in the resolv.conf and
+ * RES_OPTIONS by giving the directives in the NULL-terminated list.
+ *
+ * @param conf_file_path name of the resolv.conf configuration file 
+ * @param cache          optional pointer to a resolver cache (may be NULL)
+ * @param option, ...    list of resolv.conf options directives 
+ *                       (overriding options in conf_file)
+ *
+ * @par Environment Variables
+ * - LOCALDOMAIN overrides @c domain or @c search directives
+ * - #RES_OPTIONS overrides values of @a options in resolv.conf
+ * - #SRES_OPTIONS overrides values of @a options in resolv.conf, #RES_OPTIONS,
+ *   and @a options, ... list given as argument for this function
+ *
+ * @return A pointer to a newly created sres resolver object, or NULL upon
+ * an error.
+ */
+sres_resolver_t *
+sres_resolver_new_with_cache(char const *conf_file_path,
+			     sres_cache_t *cache,
+			     char const *option, ...)
+{
+  sres_resolver_t *retval;
+  va_list va;
+  va_start(va, option);
+  retval = sres_resolver_new_with_cache_va(conf_file_path, cache, option, va);
+  va_end(va);
+  return retval;
+}
+
+/**Create a resolver.
+ *
+ * Allocate and initialize a new sres resolver object. 
+ *
+ * This is a stdarg version of sres_resolver_new_with_cache().
+ */
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+				sres_cache_t *cache,
+				char const *option,
+				va_list va)
+{
+  va_list va0;
+  size_t i;
+  char const *o, *oarray[16], **olist = oarray;
+  sres_resolver_t *res;
+
+  va_copy(va0, va);
+  
+  for (i = 0, o = option; o; o = va_arg(va0, char const *)) {
+    if (i < 16)
+      olist[i] = o;
+    i++;
+  }
+
+  if (i >= 16) {
+    olist = malloc((i + 1) * sizeof *olist);
+    if (!olist)
+      return NULL;
+    for (i = 0, o = option; o; o = va_arg(va, char const *)) {
+      olist[i++] = o;
+      i++;
+    }
+  }
+  olist[i] = NULL;
+  res = sres_resolver_new_internal(cache, NULL, conf_file_path, olist);
+  if (olist != oarray)
+    free(olist);
+
+  return res;
+}
+
+sres_resolver_t *
+sres_resolver_new_internal(sres_cache_t *cache,
+			   sres_config_t const *config,
+			   char const *conf_file_path,
+			   char const **options)
+{
+  sres_resolver_t *res;
+  size_t i, n, len;
+  char **array, *o, *end;
+ 
+  for (n = 0, len = 0; options && options[n]; n++)
+    len += strlen(options[n]) + 1;
+
+  res = su_home_new(sizeof(*res) + (n + 1) * (sizeof *options) + len);
+
+  if (res == NULL)
+    return NULL;
+
+  array = (void *)(res + 1);
+  o = (void *)(array + n + 1);
+  end = o + len;
+
+  for (i = 0; options && options[i]; i++)
+    o = memccpy(array[i] = o, options[i], '\0', len - (end - o));
+  assert(o == end);
+
+  su_home_destructor(res->res_home, sres_resolver_destructor);
+
+  while (res->res_id == 0) {
+#if HAVE_DEV_URANDOM
+    int fd;
+    if ((fd = open("/dev/urandom", O_RDONLY, 0)) != -1) {
+      size_t len = read(fd, &res->res_id, (sizeof res->res_id)); (void)len;
+      close(fd);
+    }
+    else
+#endif
+    res->res_id = time(NULL);
+  }
+
+  time(&res->res_now);
+
+  if (cache)
+    res->res_cache = sres_cache_ref(cache);
+  else
+    res->res_cache = sres_cache_new(0);
+
+  res->res_config = config;
+
+  if (conf_file_path && conf_file_path != sres_conf_file_path)
+    res->res_cnffile = su_strdup(res->res_home, conf_file_path);
+  else
+    res->res_cnffile = conf_file_path = sres_conf_file_path;
+
+  if (!res->res_cache || !res->res_cnffile) {
+    perror("sres: malloc");
+  }
+  else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {
+    perror("sres: res_qtable_resize");
+  }
+  else if (sres_resolver_update(res, config == NULL) < 0) {
+    perror("sres: sres_resolver_update");
+  }
+  else {
+    return res;
+  }
+
+  sres_resolver_unref(res);
+
+  return NULL;
+}
+
+/** Increase reference count on a resolver object. */
+sres_resolver_t *
+sres_resolver_ref(sres_resolver_t *res)
+{
+  return su_home_ref(res->res_home);
+}
+		     
+/** Decrease the reference count on a resolver object.  */
+void
+sres_resolver_unref(sres_resolver_t *res)
+{
+  su_home_unref(res->res_home);
+}
+
+/** Set userdata pointer.
+ *
+ * @return New userdata pointer.
+ * 
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ */
+void *
+sres_resolver_set_userdata(sres_resolver_t *res, 
+			   void *userdata)
+{
+  void *old;
+
+  if (!res)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  old = res->res_userdata, res->res_userdata = userdata;
+
+  return old;
+}
+
+/**Get userdata pointer.
+ *
+ * @return Userdata pointer.
+ * 
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ */
+void *
+sres_resolver_get_userdata(sres_resolver_t const *res)
+{
+  if (res == NULL)
+    return su_seterrno(EFAULT), (void *)NULL;
+  else
+    return res->res_userdata;
+}
+
+/** Set async object.
+ *
+ * @return Set async object.
+ * 
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ * @ERROR EALREADY different async callback already set
+ */
+sres_async_t *
+sres_resolver_set_async(sres_resolver_t *res,
+			sres_update_f *callback,
+			sres_async_t *async, 
+			int update_all)
+{
+  if (!res)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  if (res->res_updcb && res->res_updcb != callback)
+    return su_seterrno(EALREADY), (void *)NULL;
+    
+  res->res_async = async;
+  res->res_updcb = callback;
+  res->res_update_all = callback && update_all != 0;
+
+  return async;
+}
+
+/** Get async object */
+sres_async_t *
+sres_resolver_get_async(sres_resolver_t const *res,
+			sres_update_f *callback)
+{
+  if (res == NULL)
+    return su_seterrno(EFAULT), (void *)NULL;
+  else if (callback == NULL)
+    return res->res_async ? (sres_async_t *)-1 : 0;
+  else if (res->res_updcb != callback)
+    return NULL;
+  else
+    return res->res_async;
+}
+
+/** Register resolver timer callback. */
+int sres_resolver_set_timer_cb(sres_resolver_t *res,
+			       sres_schedule_f *callback,
+			       sres_async_t *async)
+{
+  if (res == NULL)
+    return su_seterrno(EFAULT);
+  if (res->res_async != async)
+    return su_seterrno(EALREADY);
+
+  res->res_schedulecb = callback;
+  return 0;
+}
+
+/**Send a DNS query.
+ *
+ * Sends a DNS query with specified @a type and @a domain to the DNS server.
+ * When an answer is received, the @a callback function is called with
+ * @a context and returned records as arguments.
+ *
+ * The sres resolver takes care of retransmitting the query if a root object
+ * is associate with the resolver or if sres_resolver_timer() is called in
+ * regular intervals. It generates an error record with nonzero status if no
+ * response is received.
+ *
+ * @param res pointer to resolver
+ * @param callback function called when query is answered or times out
+ * @param context pointer given as an extra argument to @a callback function
+ * @param type record type to query (see #sres_qtypes)
+ * @param domain name to query
+ *
+ * Query types also indicate the record type of the result.
+ * Any record can be queried with #sres_qtype_any.
+ * Well-known query types understood and decoded by @b sres include
+ * #sres_type_a, 
+ * #sres_type_aaaa,
+ * #sres_type_cname,
+ * #sres_type_ptr 
+ * #sres_type_soa, 
+ * #sres_type_aaaa, 
+ * #sres_type_srv, and
+ * #sres_type_naptr.
+ *
+ * Deprecated query type #sres_type_a6 is also decoded.
+ *
+ * @note The domain name is @b not concatenated with the domains from seach
+ * path or with the local domain. Use sres_search() in order to try domains
+ * in search path.
+ *
+ * @sa sres_search(), sres_blocking_query(), sres_cached_answers(),
+ * sres_query_sockaddr()
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_query_t *
+sres_query(sres_resolver_t *res,
+	   sres_answer_f *callback,
+	   sres_context_t *context,
+	   uint16_t type,
+	   char const *domain)
+{
+  sres_query_t *query = NULL;
+  size_t dlen;
+  
+  char b[8];
+  SU_DEBUG_9(("sres_query(%p, %p, %p, %s, \"%s\") called\n",
+	      res, callback, context, sres_record_type(type, b), domain));
+
+  if (res == NULL || domain == NULL)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  dlen = strlen(domain);
+  if (dlen > SRES_MAXDNAME ||
+      (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {
+    su_seterrno(ENAMETOOLONG);
+    return NULL;
+  }
+
+  /* Reread resolv.conf if needed */
+  sres_resolver_update(res, 0);
+
+  if (res->res_n_servers == 0)
+    return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL;
+
+  query = sres_query_alloc(res, callback, context, type, domain);
+
+  if (query && sres_send_dns_query(res, query) != 0)
+    sres_free_query(res, query), query = NULL;
+
+  return query;
+}
+
+/**Search DNS.
+ *
+ * Sends DNS queries with specified @a type and @a name to the DNS server. 
+ * If the @a name does not contain enought dots, the search domains are
+ * appended to the name and resulting domain name are also queried. When
+ * answer to all the search domains is received, the @a callback function
+ * is called with @a context and combined records from answers as arguments.
+ * 
+ * The sres resolver takes care of retransmitting the queries if a root
+ * object is associate with the resolver or if sres_resolver_timer() is
+ * called in regular intervals. It generates an error record with nonzero
+ * status if no response is received.
+ *
+ * @param res pointer to resolver object
+ * @param callback pointer to completion function
+ * @param context argument given to the completion function
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param name host or domain name to search from DNS
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_query(), sres_blocking_search(), sres_search_cached_answers().
+ */
+sres_query_t *
+sres_search(sres_resolver_t *res,
+	    sres_answer_f *callback,
+	    sres_context_t *context,
+	    uint16_t type,
+	    char const *name)
+{
+  char const *domain = name;
+  sres_query_t *query = NULL;
+  size_t dlen;
+  unsigned dots; char const *dot;
+  char b[8];
+
+  SU_DEBUG_9(("sres_search(%p, %p, %p, %s, \"%s\") called\n",
+	      res, callback, context, sres_record_type(type, b), domain));
+
+  if (res == NULL || domain == NULL)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  dlen = strlen(domain);
+  if (dlen > SRES_MAXDNAME ||
+      (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {
+    su_seterrno(ENAMETOOLONG);
+    return NULL;
+  }
+
+  sres_resolver_update(res, 0);
+
+  if (res->res_n_servers == 0)
+    return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL;
+
+  if (sres_has_search_domain(res))
+    for (dots = 0, dot = strchr(domain, '.');
+	 dots < res->res_config->c_opt.ndots && dot; 
+	 dots++, dot = strchr(dot + 1, '.'))
+      ;
+  else
+    dots = 0;
+
+  query = sres_query_alloc(res, callback, context, type, domain);
+
+  if (query) {
+    /* Create sub-query for each search domain */
+    if (dots < res->res_config->c_opt.ndots) {
+      sres_query_t *sub;
+      int i, subs;
+      size_t len;
+      char const *const *domains = res->res_config->c_search;
+      char search[SRES_MAXDNAME + 1];
+
+      memcpy(search, domain, dlen);
+      search[dlen++] = '.';
+      search[dlen] = '\0';
+
+      for (i = 0, subs = 0; i <= SRES_MAX_SEARCH; i++) {
+	if (domains[i]) {
+	  len = strlen(domains[i]);
+	  
+	  if (dlen + len + 1 > SRES_MAXDNAME)
+	    continue;
+
+	  memcpy(search + dlen, domains[i], len);
+	  search[dlen + len] = '.';
+	  search[dlen + len + 1] = '\0';
+	  sub = sres_query_alloc(res, sres_answer_subquery, (void *)query,
+				 type, search);
+
+	  if (sres_send_dns_query(res, sub) == 0) {
+	    query->q_subqueries[i] = sub;
+	  }
+	  else {
+	    sres_free_query(res, sub), sub = NULL;
+	  }
+	  subs += sub != NULL;
+	}
+      }
+
+      query->q_n_subs = subs;
+    }
+
+    if (sres_send_dns_query(res, query) != 0) {
+      if (!query->q_n_subs)
+	sres_free_query(res, query), query = NULL;
+      else
+	query->q_id = 0;
+    }
+  }
+
+  return query;
+}
+
+/** Make a reverse DNS query.
+ *
+ * Send a query to DNS server with specified @a type and domain name formed
+ * from the socket address @a addr. The sres resolver takes care of
+ * retransmitting the query if a root object is associate with the resolver or
+ * if sres_resolver_timer() is called in regular intervals. It generates an
+ * error record with nonzero status if no response is received.
+ *
+ * @param res pointer to resolver
+ * @param callback function called when query is answered or times out
+ * @param context pointer given as an extra argument to @a callback function
+ * @param type record type to query (or sres_qtype_any for any record)
+ * @param addr socket address structure
+ * 
+ * The @a type should be #sres_type_ptr. The @a addr should contain either
+ * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
+ *
+ * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
+ * variable, or an "options" entry in resolv.conf file contains an option
+ * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
+ * instead of the standard ".ip6.arpa" suffix.
+ *
+ * @ERRORS
+ * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_query(), sres_blocking_query_sockaddr(),
+ * sres_cached_answers_sockaddr()
+ *
+ */
+sres_query_t *
+sres_query_sockaddr(sres_resolver_t *res,
+		    sres_answer_f *callback,
+		    sres_context_t *context,
+		    uint16_t type,
+		    struct sockaddr const *addr)
+{
+  char name[80]; 
+
+  if (!res || !addr)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  if (!sres_sockaddr2string(res, name, sizeof(name), addr))
+    return NULL;
+
+  return sres_query(res, callback, context, type, name);
+}
+
+
+/** Make a DNS query.
+ *
+ * @deprecated Use sres_query() instead.
+ */
+sres_query_t *
+sres_query_make(sres_resolver_t *res,
+		sres_answer_f *callback,
+		sres_context_t *context,
+		int dummy,
+		uint16_t type,
+		char const *domain)
+{
+  return sres_query(res, callback, context, type, domain);
+}
+
+/** Make a reverse DNS query.
+ *
+ * @deprecated Use sres_query_sockaddr() instead.
+ */
+sres_query_t *
+sres_query_make_sockaddr(sres_resolver_t *res,
+			 sres_answer_f *callback,
+			 sres_context_t *context,
+			 int dummy,
+			 uint16_t type,
+			 struct sockaddr const *addr)
+{
+  char name[80]; 
+
+  if (!res || !addr)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  if (!sres_sockaddr2string(res, name, sizeof(name), addr))
+    return NULL;
+
+  return sres_query_make(res, callback, context, dummy, type, name);
+}
+
+
+/** Bind a query with another callback and context pointer.
+ *
+ * @param query pointer to a query object to bind
+ * @param callback pointer to new callback function (may be NULL)
+ * @param context pointer to callback context (may be NULL)
+*/
+void sres_query_bind(sres_query_t *query,
+                     sres_answer_f *callback,
+                     sres_context_t *context)
+{
+  if (query) {
+    query->q_callback = callback;
+    query->q_context = context;
+  }
+}
+
+/**Get a list of matching (type/domain) records from cache.
+ *
+ * @return
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_record_t **
+sres_cached_answers(sres_resolver_t *res,
+		    uint16_t type,
+		    char const *domain)
+{
+  sres_record_t **result;
+  char rooted_domain[SRES_MAXDNAME];
+
+  if (!res)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
+
+  if (!domain)
+    return NULL;
+  
+  if (!sres_cache_get(res->res_cache, type, domain, &result))
+    return su_seterrno(ENOENT), (void *)NULL;
+
+  return result;
+}
+
+/**Search for a list of matching (type/name) records from cache.
+ *
+ * @return
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR ENAMETOOLONG @a name or resulting domain is longer than SRES_MAXDNAME
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_search(), sres_cached_answers()
+ */
+sres_record_t **
+sres_search_cached_answers(sres_resolver_t *res,
+			   uint16_t type,
+			   char const *name)
+{
+  char const *domain = name;
+  sres_record_t **search_results[SRES_MAX_SEARCH + 1] = { NULL };
+  char rooted_domain[SRES_MAXDNAME];
+  unsigned dots; char const *dot;
+  size_t found = 0;
+  int i;
+
+  SU_DEBUG_9(("sres_search_cached_answers(%p, %s, \"%s\") called\n",
+	      res, sres_record_type(type, rooted_domain), domain));
+
+  if (!res || !name)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  if (sres_has_search_domain(res))
+    for (dots = 0, dot = strchr(domain, '.');
+	 dots < res->res_config->c_opt.ndots && dot; 
+	 dots++, dot = strchr(dot + 1, '.'))
+      ;
+  else
+    dots = 0;
+
+  domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
+
+  if (!domain)
+    return NULL;
+
+  if (sres_cache_get(res->res_cache, type, domain, &search_results[0]))
+    found = 1;
+
+  if (dots < res->res_config->c_opt.ndots) {
+    char const *const *domains = res->res_config->c_search;
+    size_t dlen = strlen(domain);
+
+    for (i = 0; domains[i] && i < SRES_MAX_SEARCH; i++) {
+      size_t len = strlen(domains[i]);
+      if (dlen + len + 1 >= SRES_MAXDNAME)
+	continue;
+      if (domain != rooted_domain)
+	domain = memcpy(rooted_domain, domain, dlen);
+      memcpy(rooted_domain + dlen, domains[i], len);
+      strcpy(rooted_domain + dlen + len, ".");
+      if (sres_cache_get(res->res_cache, type, domain, search_results + i + 1))
+	found++;
+    }
+  }
+
+  if (found == 0)
+    return su_seterrno(ENOENT), (void *)NULL;
+
+  if (found == 1) {
+    for (i = 0; i <= SRES_MAX_SEARCH; i++)
+      if (search_results[i])
+	return search_results[i];
+  }
+
+  return sres_combine_results(res, search_results);
+}
+
+/**Get a list of matching (type/domain) reverse records from cache.
+ *
+ * @param res pointer to resolver
+ * @param type record type to query (or sres_qtype_any for any record)
+ * @param addr socket address structure
+ * 
+ * The @a type should be #sres_type_ptr. The @a addr should contain either
+ * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
+ *
+ * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
+ * variable or an "options" entry in resolv.conf file contains an option
+ * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
+ * instead of default ".ip6.arpa".
+ *
+ * @retval 
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_record_t **
+sres_cached_answers_sockaddr(sres_resolver_t *res,
+			     uint16_t type,
+			     struct sockaddr const *addr)
+{
+  sres_record_t **result;
+  char name[80];
+
+  if (!res || !addr)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  if (!sres_sockaddr2string(res, name, sizeof name, addr))
+    return NULL;
+
+  if (!sres_cache_get(res->res_cache, type, name, &result))
+    su_seterrno(ENOENT), (void *)NULL;
+
+  return result;
+}
+
+/** Sort answers. */
+int
+sres_sort_answers(sres_resolver_t *res, sres_record_t **answers)
+{
+  int i, j;
+
+  if (res == NULL || answers == NULL)
+    return su_seterrno(EFAULT);
+
+  if (answers[0] == NULL || answers[1] == NULL)
+    return 0;
+
+  /* Simple insertion sorting */
+  /*
+   * We do not use qsort because we want later extend this to sort 
+   * local A records first etc.
+   */
+  for (i = 1; answers[i]; i++) {
+    for (j = 0; j < i; j++) {
+      if (sres_record_compare(answers[i], answers[j]) < 0)
+	break;
+    }
+    if (j < i) {
+      sres_record_t *r = answers[i];
+      for (; j < i; i--) {
+	answers[i] = answers[i - 1];
+      }
+      answers[j] = r;
+    }
+  }
+
+  return 0;
+}
+
+/** Sort and filter query results */
+int
+sres_filter_answers(sres_resolver_t *res, 
+		    sres_record_t **answers, 
+		    uint16_t type)
+{		    
+  int i, n;
+
+  for (n = 0, i = 0; answers && answers[i]; i++) {
+    if (answers[i]->sr_record->r_status ||
+	answers[i]->sr_record->r_class != sres_class_in ||
+	(type != 0 && answers[i]->sr_record->r_type != type)) {
+      sres_free_answer(res, answers[i]);
+      continue;
+    }
+    answers[n++] = answers[i];
+  }
+  answers[n] = NULL;
+
+  sres_sort_answers(res, answers);
+
+  return n;
+}
+
+
+/** Free and zero one record. */
+void sres_free_answer(sres_resolver_t *res, sres_record_t *answer)
+{
+  if (res && answer)
+    sres_cache_free_one(res->res_cache, answer);
+}
+
+/** Free and zero an array of records.
+ * 
+ * The array of records can be returned by sres_cached_answers() or 
+ * given by callback function.
+ */
+void 
+sres_free_answers(sres_resolver_t *res,
+		  sres_record_t **answers)
+{
+  if (res && answers)
+    sres_cache_free_answers(res->res_cache, answers);
+}
+
+/** Convert type to its name. */
+char const *sres_record_type(int type, char buffer[8])
+{
+  switch (type) {
+  case sres_type_a: return "A";
+  case sres_type_ns: return "NS";
+  case sres_type_mf: return "MF";
+  case sres_type_cname: return "CNAME";
+  case sres_type_soa: return "SOA";
+  case sres_type_mb: return "MB";
+  case sres_type_mg: return "MG";
+  case sres_type_mr: return "MR";
+  case sres_type_null: return "NULL";
+  case sres_type_wks: return "WKS";
+  case sres_type_ptr: return "PTR";
+  case sres_type_hinfo: return "HINFO";
+  case sres_type_minfo: return "MINFO";
+  case sres_type_mx: return "MX";
+  case sres_type_txt: return "TXT";
+  case sres_type_rp: return "RP";
+  case sres_type_afsdb: return "AFSDB";
+  case sres_type_x25: return "X25";
+  case sres_type_isdn: return "ISDN";
+  case sres_type_rt: return "RT";
+  case sres_type_nsap: return "NSAP";
+  case sres_type_nsap_ptr: return "NSAP_PTR";
+  case sres_type_sig: return "SIG";
+  case sres_type_key: return "KEY";
+  case sres_type_px: return "PX";
+  case sres_type_gpos: return "GPOS";
+  case sres_type_aaaa: return "AAAA";
+  case sres_type_loc: return "LOC";
+  case sres_type_nxt: return "NXT";
+  case sres_type_eid: return "EID";
+  case sres_type_nimloc: return "NIMLOC";
+  case sres_type_srv: return "SRV";
+  case sres_type_atma: return "ATMA";
+  case sres_type_naptr: return "NAPTR";
+  case sres_type_kx: return "KX";
+  case sres_type_cert: return "CERT";
+  case sres_type_a6: return "A6";
+  case sres_type_dname: return "DNAME";
+  case sres_type_sink: return "SINK";
+  case sres_type_opt: return "OPT";
+
+  case sres_qtype_tsig: return "TSIG";
+  case sres_qtype_ixfr: return "IXFR";
+  case sres_qtype_axfr: return "AXFR";
+  case sres_qtype_mailb: return "MAILB";
+  case sres_qtype_maila: return "MAILA";
+  case sres_qtype_any: return "ANY";
+    
+  default:
+    sprintf(buffer, "%u?", type & 65535);
+    return buffer;
+  }
+}
+
+/** Convert class to its name. */
+char const *sres_record_class(int rclass, char buffer[8])
+{
+  switch (rclass) {
+  case 1: return "IN";
+  case 2: return "2?";
+  case 3: return "CHAOS";
+  case 4: return "HS";
+  case 254: return "NONE";
+  case 255: return "ANY";
+
+  default:
+    sprintf(buffer, "%u?", rclass & 65535);
+    return buffer;
+  }
+}
+
+/** Compare two records. */
+int 
+sres_record_compare(sres_record_t const *aa, sres_record_t const *bb)
+{
+  int D;
+  sres_common_t const *a = aa->sr_record, *b = bb->sr_record;
+
+  D = a->r_status - b->r_status; if (D) return D;
+  D = a->r_class - b->r_class; if (D) return D;
+  D = a->r_type - b->r_type; if (D) return D;
+
+  if (a->r_status)
+    return 0;
+  
+  switch (a->r_type) {
+  case sres_type_soa: 
+    {
+      sres_soa_record_t const *A = aa->sr_soa, *B = bb->sr_soa;
+      D = A->soa_serial - B->soa_serial; if (D) return D;
+      D = strcasecmp(A->soa_mname, B->soa_mname); if (D) return D;
+      D = strcasecmp(A->soa_rname, B->soa_rname); if (D) return D;
+      D = A->soa_refresh - B->soa_refresh; if (D) return D;
+      D = A->soa_retry - B->soa_retry; if (D) return D;
+      D = A->soa_expire - B->soa_expire; if (D) return D;
+      D = A->soa_minimum - B->soa_minimum; if (D) return D;
+      return 0;
+    }
+  case sres_type_a:
+    {
+      sres_a_record_t const *A = aa->sr_a, *B = bb->sr_a;
+      return memcmp(&A->a_addr, &B->a_addr, sizeof A->a_addr);
+    }
+  case sres_type_a6:
+    {
+      sres_a6_record_t const *A = aa->sr_a6, *B = bb->sr_a6;
+      D = A->a6_prelen - B->a6_prelen; if (D) return D;
+      D = !A->a6_prename - !B->a6_prename; 
+      if (D == 0 && A->a6_prename && B->a6_prename)
+	D = strcasecmp(A->a6_prename, B->a6_prename); if (D) return D;
+      return memcmp(&A->a6_suffix, &B->a6_suffix, sizeof A->a6_suffix);
+    }
+  case sres_type_aaaa:
+    {
+      sres_aaaa_record_t const *A = aa->sr_aaaa, *B = bb->sr_aaaa;
+      return memcmp(&A->aaaa_addr, &B->aaaa_addr, sizeof A->aaaa_addr);      
+    }
+  case sres_type_cname:
+    {
+      sres_cname_record_t const *A = aa->sr_cname, *B = bb->sr_cname;
+      return strcmp(A->cn_cname, B->cn_cname);
+    }
+  case sres_type_ptr:
+    {
+      sres_ptr_record_t const *A = aa->sr_ptr, *B = bb->sr_ptr;
+      return strcmp(A->ptr_domain, B->ptr_domain);
+    }
+  case sres_type_srv:
+    {
+      sres_srv_record_t const *A = aa->sr_srv, *B = bb->sr_srv;
+      D = A->srv_priority - B->srv_priority; if (D) return D;
+      /* Record with larger weight first */
+      D = B->srv_weight - A->srv_weight; if (D) return D;
+      D = strcmp(A->srv_target, B->srv_target); if (D) return D;
+      return A->srv_port - B->srv_port;
+    }
+  case sres_type_naptr:
+    {
+      sres_naptr_record_t const *A = aa->sr_naptr, *B = bb->sr_naptr;
+      D = A->na_order - B->na_order; if (D) return D;
+      D = A->na_prefer - B->na_prefer; if (D) return D;
+      D = strcmp(A->na_flags, B->na_flags); if (D) return D;
+      D = strcmp(A->na_services, B->na_services); if (D) return D;
+      D = strcmp(A->na_regexp, B->na_regexp); if (D) return D;
+      return strcmp(A->na_replace, B->na_replace); 
+    }
+  default:
+    return 0;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Private functions */
+
+/** Destruct */
+static 
+void 
+sres_resolver_destructor(void *arg)
+{
+  sres_resolver_t *res = arg;
+
+  assert(res);
+  sres_cache_unref(res->res_cache); 
+  res->res_cache = NULL;
+
+  sres_servers_close(res, res->res_servers);
+
+  if (res->res_config)
+    su_home_unref((su_home_t *)res->res_config->c_home);
+
+  if (res->res_updcb)
+    res->res_updcb(res->res_async, INVALID_SOCKET, INVALID_SOCKET);
+}
+
+/*
+ * 3571 is a prime => 
+ * we hash successive id values to different parts of hash tables
+ */
+#define Q_PRIME 3571
+#define SRES_QUERY_HASH(q) ((q)->q_hash)
+
+HTABLE_BODIES_WITH(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH,
+		   unsigned, size_t);
+
+/** Allocate a query structure */
+static
+sres_query_t *
+sres_query_alloc(sres_resolver_t *res,
+		 sres_answer_f *callback,
+		 sres_context_t *context,
+		 uint16_t type,
+		 char const *domain)
+{
+  sres_query_t *query;
+  size_t dlen = strlen(domain);
+
+  if (sres_qtable_is_full(res->res_queries))
+    if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0)
+      return NULL;
+
+  query = su_alloc(res->res_home, sizeof(*query) + dlen + 1);
+
+  if (query) {
+    memset(query, 0, sizeof *query);
+    query->q_res = res;
+    query->q_callback = callback;
+    query->q_context = context;
+    query->q_type = type;
+    query->q_class = sres_class_in;
+    query->q_timestamp = res->res_now;
+    query->q_name = strcpy((char *)(query + 1), domain);
+
+    query->q_id = sres_new_id(res); assert(query->q_id);
+    query->q_i_server = res->res_i_server;
+    query->q_n_servers = res->res_n_servers;
+    query->q_hash = query->q_id * Q_PRIME /* + query->q_i_server */;
+    
+    sres_qtable_append(res->res_queries, query);
+
+    if (res->res_schedulecb && res->res_queries->qt_used == 1)
+      res->res_schedulecb(res->res_async, 2 * SRES_RETRANSMIT_INTERVAL); 
+  }
+
+  return query;
+}
+
+static inline
+void 
+sres_remove_query(sres_resolver_t *res, sres_query_t *q, int all)
+{
+  int i;
+
+  if (q->q_hash) {
+    sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
+
+    if (all)
+      for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+	if (q->q_subqueries[i] && q->q_subqueries[i]->q_hash) {
+	  sres_qtable_remove(res->res_queries, q->q_subqueries[i]);
+	  q->q_subqueries[i]->q_hash = 0;
+	}
+      }
+  }
+}
+
+/** Remove a query from hash table and free it. */
+static
+void sres_free_query(sres_resolver_t *res, sres_query_t *q)
+{
+  int i;
+
+  if (q == NULL)
+    return;
+
+  if (q->q_hash)
+    sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
+
+  for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+    sres_query_t *sq;
+
+    sq = q->q_subqueries[i];
+    q->q_subqueries[i] = NULL;
+    if (sq)
+      sres_free_query(res, sq);
+    if (q->q_subanswers[i])
+      sres_cache_free_answers(res->res_cache, q->q_subanswers[i]);
+    q->q_subanswers[i] = NULL;
+  }
+ 
+  su_free(res->res_home, q);
+}
+
+static
+sres_record_t **
+sres_combine_results(sres_resolver_t *res,
+		     sres_record_t **search_results[SRES_MAX_SEARCH + 1])
+{
+  sres_record_t **combined_result;
+  int i, j, found;
+
+  /* Combine the results into a single list. */
+  for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++)
+    if (search_results[i])
+      for (j = 0; search_results[i][j]; j++)
+	found++;
+
+  combined_result = su_alloc((su_home_t *)res->res_cache, 
+			     (found + 1) * (sizeof combined_result[0]));
+  if (combined_result) {
+    for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++)
+      if (search_results[i])
+	for (j = 0; search_results[i][j]; j++) {
+	  combined_result[found++] = search_results[i][j];
+	  search_results[i][j] = NULL;
+	}
+
+    combined_result[found] = NULL;
+    sres_sort_answers(res, combined_result);
+  }
+
+  for (i = 0; i <= SRES_MAX_SEARCH; i++)
+    if (search_results[i])
+      sres_free_answers(res, search_results[i]), search_results[i] = NULL;
+
+  return combined_result;
+}
+
+static
+int
+sres_sockaddr2string(sres_resolver_t *res,
+		     char name[],
+		     size_t namelen,
+		     struct sockaddr const *addr)
+{
+  name[0] = '\0';
+
+  if (addr->sa_family == AF_INET) {
+    struct sockaddr_in const *sin = (struct sockaddr_in *)addr;
+    uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
+    return snprintf(name, namelen, "%u.%u.%u.%u.in-addr.arpa.",
+		    in_addr[3], in_addr[2], in_addr[1], in_addr[0]);
+  }
+#if HAVE_SIN6
+  else if (addr->sa_family == AF_INET6) {
+    struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)addr;
+    size_t addrsize = sizeof(sin6->sin6_addr.s6_addr);
+    char *postfix;
+    size_t required;
+    size_t i;
+
+    if (res->res_config->c_opt.ip6int)
+      postfix = "ip6.int.";
+    else
+      postfix = "ip6.arpa.";
+
+    required = addrsize * 4 + strlen(postfix);
+
+    if (namelen <= required)
+      return (int)required;
+
+    for (i = 0; i < addrsize; i++) {
+      uint8_t byte = sin6->sin6_addr.s6_addr[addrsize - i - 1];
+      uint8_t hex;
+
+      hex = byte & 0xf;
+      name[4 * i] = hex > 9 ? hex + 'a' - 10 : hex + '0';
+      name[4 * i + 1] = '.';
+      hex = (byte >> 4) & 0xf;
+      name[4 * i + 2] = hex > 9 ? hex + 'a' - 10 : hex + '0';
+      name[4 * i + 3] = '.';
+    }
+    
+    strcpy(name + 4 * i, postfix);
+
+    return (int)required;
+  }
+#endif /* HAVE_SIN6 */
+  else {
+    su_seterrno(EAFNOSUPPORT);
+    SU_DEBUG_3(("%s: %s\n", "sres_sockaddr2string", 
+                su_strerror(EAFNOSUPPORT)));
+    return 0;
+  }
+}
+
+/** Make a domain name a top level domain name.
+ *
+ * The function sres_toplevel() returns a copies string @a domain and 
+ * terminates it with a dot if it is not already terminated. 
+ */
+static
+char const *
+sres_toplevel(char buf[], size_t blen, char const *domain)
+{
+  size_t len;
+  int already;
+
+  if (!domain)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  len = strlen(domain);
+
+  if (len >= blen)
+    return su_seterrno(ENAMETOOLONG), (void *)NULL;
+
+  already = len > 0 && domain[len - 1] == '.';
+
+  if (already)
+    return domain;
+
+  if (len + 1 >= blen)
+    return su_seterrno(ENAMETOOLONG), (void *)NULL;
+
+  strcpy(buf, domain);
+  buf[len] = '.'; buf[len + 1] = '\0';
+
+  return buf;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int sres_update_config(sres_resolver_t *res, int always, time_t now);
+static int sres_parse_config(sres_config_t *, FILE *);
+static int sres_parse_options(sres_config_t *c, char const *value);
+static int sres_parse_nameserver(sres_config_t *c, char const *server);
+static time_t sres_config_timestamp(sres_config_t const *c);
+
+/** Update configuration
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int sres_resolver_update(sres_resolver_t *res, int always)
+{
+  sres_server_t **servers, **old_servers;
+  int updated;
+
+  updated = sres_update_config(res, always, time(&res->res_now));
+  if (updated < 0)
+    return -1;
+
+  if (!res->res_servers || always || updated) {
+    servers = sres_servers_new(res, res->res_config);
+    old_servers = res->res_servers;
+
+    res->res_i_server = 0;
+    res->res_n_servers = sres_servers_count(servers);
+    res->res_servers = servers;
+
+    sres_servers_close(res, old_servers);
+    su_free(res->res_home, old_servers);
+
+    if (!servers)
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Update config file.
+ *
+ * @retval 1 if DNS server list is different from old one.
+ * @retval 0 when otherwise successful
+ * @retval -1 upon an error
+ */
+static 
+int sres_update_config(sres_resolver_t *res, int always, time_t now)
+{
+  sres_config_t *c = NULL;
+  sres_config_t const *previous;
+  int retval;
+
+  previous = res->res_config;
+
+  if (!always && previous && now < res->res_checked)
+    return 0;
+  /* Try avoid checking for changes too often. */
+  res->res_checked = now + SRES_UPDATE_INTERVAL_SECS; 
+  
+  if (!always && previous && 
+      sres_config_timestamp(previous) == previous->c_modified)
+    return 0;
+
+  c = sres_parse_resolv_conf(res, res->res_options);
+  if (!c)
+    return -1;
+
+  res->res_config = c;
+
+  retval = sres_config_changed_servers(c, previous);
+
+  su_home_unref((su_home_t *)previous->c_home);
+
+  return retval;
+}
+
+#if _WIN32
+
+/** Number of octets to read from a registry key at a time */
+#define QUERY_DATALEN         1024
+#define MAX_DATALEN           65535
+
+/**
+ * Parses name servers listed in registry key 'key+lpValueName'. The
+ * key is expected to contain a whitespace separate list of
+ * name server IP addresses.
+ *
+ * @return number of server addresses added
+ */ 
+static int sres_parse_win32_reg_parse_dnsserver(sres_config_t *c, HKEY key, LPCTSTR lpValueName)
+{
+  su_home_t *home = c->c_home;
+  su_strlst_t *reg_dns_list;
+  BYTE *name_servers = su_alloc(home, QUERY_DATALEN);
+  DWORD name_servers_length = QUERY_DATALEN;
+  int ret, servers_added = 0;
+
+  /* get name servers and ... */
+  while((ret = RegQueryValueEx(key, 
+			       lpValueName, 
+			       NULL, NULL, 
+			       name_servers, 
+			       &name_servers_length)) == ERROR_MORE_DATA) {
+    name_servers_length += QUERY_DATALEN;
+
+    /* sanity check, upper limit for memallocs */
+    if (name_servers_length > MAX_DATALEN) break;
+
+    name_servers = su_realloc(home, name_servers, name_servers_length);
+  }
+
+  /* if reading the key was succesful, continue */
+  if (ret == ERROR_SUCCESS) {
+    if (name_servers[0]){
+      int i;
+
+      /* add to list */
+      reg_dns_list = su_strlst_split(home, (char *)name_servers, " ");
+	    
+      for(i = 0 ; i < su_strlst_len(reg_dns_list); i++) {
+	const char *item = su_strlst_item(reg_dns_list, i);
+	SU_DEBUG_3(("Adding nameserver: %s (key=%s)\n", item, (char*)lpValueName));
+	sres_parse_nameserver(c, item);
+	++servers_added;
+      }
+	    
+      su_strlst_destroy(reg_dns_list);
+
+    }
+  }
+
+  su_free(home, name_servers);
+
+  return servers_added;
+}
+
+/**
+ * Discover system nameservers from Windows registry.
+ *
+ * Refs:
+ *  - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regqueryvalueex.asp
+ *  - http://support.microsoft.com/default.aspx?scid=kb;en-us;120642
+ *  - http://support.microsoft.com/kb/314053/EN-US/
+ *  - IP Helper API (possibly better way than current registry-based impl.)
+ *    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iphlp/iphlp/ip_helper_start_page.asp
+ */
+static int sres_parse_win32_reg(sres_config_t *c)
+{
+  int ret = -1;
+
+#define MAX_KEY_LEN           255
+#define MAX_VALUE_NAME_LEN    16383
+
+  su_home_t *home = c->c_home;
+  HKEY key_handle;  
+#if 0
+  HKEY interface_key_handle;  
+  FILETIME ftime;
+  int index, i;
+#endif
+  int found = 0;
+  char *interface_guid = su_alloc(home, MAX_VALUE_NAME_LEN);
+
+#if 0
+#if __MINGW32__
+  DWORD guid_size = QUERY_DATALEN;
+#else
+  int guid_size = MAX_VALUE_NAME_LEN;
+#endif
+
+  /* step: find interface specific nameservers 
+   * - this is currently disabled 2006/Jun (the current check might insert
+   *   multiple unnecessary nameservers to the search list) 
+   */
+  /* open the 'Interfaces' registry Key */
+  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
+		   "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 
+		   0, KEY_READ, &key_handle)) {
+    SU_DEBUG_2(("RegOpenKeyEx failed\n"));
+  } else {
+    index = 0;
+    /* for each interface listed ... */
+    while (RegEnumKeyEx(key_handle, index,
+			interface_guid, &guid_size,
+			NULL,NULL,0,&ftime) == ERROR_SUCCESS){
+      if (RegOpenKeyEx(key_handle, interface_guid,
+		       0, KEY_READ, 
+		       &interface_key_handle) == ERROR_SUCCESS) {
+
+	/* note: 'NameServer' is preferred over 'DhcpNameServer' */
+	found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "NameServer");
+	if (found == 0) 
+	  found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "DhcpNameServer");
+
+	RegCloseKey(interface_key_handle);
+      } else{
+	SU_DEBUG_2(("interface RegOpenKeyEx failed\n"));
+      }
+      index++;
+      guid_size = 64;
+    }
+    RegCloseKey(key_handle);
+  }
+#endif /* #if 0: interface-specific nameservers */
+
+  /* step: if no interface-specific nameservers are found, 
+   *       check for system-wide nameservers */
+  if (found == 0) {
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
+		     "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 
+		     0, KEY_READ, &key_handle)) {
+      SU_DEBUG_2(("RegOpenKeyEx failed (2)\n"));
+    } else {
+      found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "NameServer");
+      if (found == 0) 
+	found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "DhcpNameServer");
+      RegCloseKey(key_handle);
+    }
+  }
+
+  SU_DEBUG_3(("Total of %d name servers found from win32 registry.\n", found));
+
+  /* return success if servers found */
+  if (found) ret = 0;
+
+  su_free(home, interface_guid);
+
+  return ret;
+}
+
+#endif /* _WIN32 */
+
+/** Parse /etc/resolv.conf file.
+ *
+ * @retval #sres_config_t structure when successful 
+ * @retval NULL upon an error
+ *
+ * @todo The resolv.conf directives @b sortlist and most of the options 
+ *       are currently ignored.
+ */
+static 
+sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
+				      char const **options)
+{
+  sres_config_t *c = su_home_new(sizeof *c);
+
+  if (c) {
+    FILE *f;
+    int i;
+    
+    f = fopen(c->c_filename = res->res_cnffile, "r");
+
+    sres_parse_config(c, f);
+
+    if (f)
+      fclose(f);
+
+#if _WIN32    
+    /* note: no 127.0.0.1 on win32 systems */
+    /* on win32, query the registry for nameservers */
+    if (sres_parse_win32_reg(c) == 0) 
+      /* success */;
+    else
+      /* now what? */;
+#else
+    /* Use local nameserver by default */
+    if (c->c_nameservers[0] == NULL)
+      sres_parse_nameserver(c, "127.0.0.1");
+#endif
+      
+    for (i = 0; c->c_nameservers[i] && i < SRES_MAX_NAMESERVERS; i++) {
+      struct sockaddr_in *sin = (void *)c->c_nameservers[i]->ns_addr;
+      sin->sin_port = htons(c->c_port);
+    }
+
+    sres_parse_options(c, getenv("RES_OPTIONS"));
+    
+    if (options)
+      for (i = 0; options[i]; i++)
+	sres_parse_options(c, options[i]);
+
+    sres_parse_options(c, getenv("SRES_OPTIONS"));
+
+    su_home_threadsafe(c->c_home);
+  }
+
+  return c;
+}
+
+/** Parse config file. 
+ *
+ * @return Number of search domains, if successful.
+ * @retval -1 upon an error (never happens).
+ */
+static
+int sres_parse_config(sres_config_t *c, FILE *f)
+{
+  su_home_t *home = c->c_home;
+  int line;
+  char const *localdomain;
+  char *search = NULL, *domain = NULL;
+  char buf[1025];
+  int i = 0;
+
+  localdomain = getenv("LOCALDOMAIN");
+
+  /* Default values */
+  c->c_opt.ndots = 1;
+  c->c_opt.check_names = 1;
+  c->c_opt.timeout = SRES_RETRY_INTERVAL;
+  c->c_opt.attempts = SRES_MAX_RETRY_COUNT;
+  c->c_port = 53;
+
+  if (f != NULL) {  
+    for (line = 1; fgets(buf, sizeof(buf), f); line++) {
+      size_t len;
+      char *value, *b;
+
+      /* Skip whitespace at the beginning ...*/
+      b = buf + strspn(buf, " \t");
+
+      /* ... and at the end of line */
+      for (len = strlen(b); len > 0 && strchr(" \t\r\n", b[len - 1]); len--)
+	;
+
+      if (len == 0 || b[0] == '#') 	/* Empty line or comment */
+	continue;
+
+      b[len] = '\0';
+
+      len = strcspn(b, " \t");
+      value = b + len; value += strspn(value, " \t");
+
+#define MATCH(token) (len == strlen(token) && strncasecmp(token, b, len) == 0)
+
+      if (MATCH("nameserver")) {
+	if (sres_parse_nameserver(c, value) < 0)
+	  return -1;
+      }
+      else if (MATCH("domain")) {
+	if (localdomain)	/* LOCALDOMAIN overrides */
+	  continue;
+	if (search)
+	  su_free(home, search), search = NULL;
+	if (domain)
+	  su_free(home, domain), domain = NULL;
+	domain = su_strdup(home, value);
+	if (!domain)
+	  return -1;
+      }
+      else if (MATCH("search")) {
+	if (localdomain)	/* LOCALDOMAIN overrides */
+	  continue;
+	if (search) su_free(home, search), search = NULL;
+	if (domain) su_free(home, domain), domain = NULL;
+	search = su_strdup(home, value);
+	if (!search)
+	  return -1;
+      }
+      else if (MATCH("port")) {
+	unsigned long port = strtoul(value, NULL, 10);
+	if (port < 65536)
+	  c->c_port = port;
+      }
+      else if (MATCH("options")) {
+	sres_parse_options(c, value);
+      }
+    }
+  }
+
+  if (f)
+    c->c_modified = sres_config_timestamp(c);
+
+  if (localdomain)
+    c->c_search[0] = localdomain;
+  else if (domain)
+    c->c_search[0] = domain;
+  else if (search) {
+    for (i = 0; search[0] && i < SRES_MAX_SEARCH; i++) {
+      c->c_search[i] = search;
+      search += strcspn(search, " \t");
+      if (*search) {
+	*search++ = '\0';
+	search += strspn(search, " \t");
+      }
+    }
+  }
+
+  return i;
+}
+
+/**Environment variable containing options for Sofia resolver. The options
+ * recognized by Sofia resolver are as follows:
+ * - debug           turn on debugging (no effect)
+ * - ndots:<i>n</i>  when searching, try first to query name as absolute
+ *                   domain if it contains at least <i>n</i> dots
+ * - timeout:<i>secs</i> timeout in seconds
+ * - attempts:<i>n</i> fail after <i>n</i> retries
+ * - rotate          use round robin selection of nameservers
+ * - no-check-names  do not check names for invalid characters
+ * - inet6           (no effect) 
+ * - ip6-dotint      IPv6 addresses are resolved using suffix ".ip6.int"
+ *                   instead of the standard ".ip6.arpa" suffix
+ * - ip6-bytestring  (no effect)
+ * The following option is a Sofia-specific extension:
+ * - no-edns0        do not try to use EDNS0 extension (@RFC2671)
+ *
+ * The same options can be listed in @b options directive in resolv.conf, or
+ * in #RES_OPTIONS environment variable. Note that options given in
+ * #SRES_OPTIONS override those specified in #RES_OPTIONS which in turn
+ * override options specified in the @b options directive of resolve.conf.
+ *
+ * The meaning of an option can be reversed with prefix "no-".
+ *
+ * @sa Manual page for resolv.conf, #RES_OPTIONS.
+ */
+extern char const SRES_OPTIONS[];
+
+/**Environment variable containing resolver options. This environment
+ * variable is also used by standard BIND resolver.
+ *
+ * @sa Manual page for resolv.conf, #SRES_OPTIONS.
+ */
+extern char const RES_OPTIONS[];
+
+
+/* Parse options line or #SRES_OPTIONS or #RES_OPTIONS environment variable. */
+static int 
+sres_parse_options(sres_config_t *c, char const *value)
+{
+  if (!value)
+    return -1;
+
+  while (value[0]) {
+    char const *b;
+    size_t len, extra = 0;
+    unsigned long n = 0;
+
+    b = value; len = strcspn(value, " \t:");
+    value += len;
+
+    if (value[0] == ':') {
+      len++;
+      n = strtoul(++value, NULL, 10);
+      value += extra = strcspn(value, " \t");
+    }
+
+    if (*value)
+      value += strspn(value, " \t");
+
+    if (n > 65536) {
+      SU_DEBUG_3(("sres: %s: invalid %*.s\n", c->c_filename,
+		  (int)(len + extra), b));
+      continue;
+    }
+
+    /* Documented by BIND9 resolv.conf */
+    if (MATCH("no-debug")) c->c_opt.debug = 0;
+    else if (MATCH("debug")) c->c_opt.debug = 1;
+    else if (MATCH("ndots:")) c->c_opt.ndots = n;
+    else if (MATCH("timeout:")) c->c_opt.timeout = n;
+    else if (MATCH("attempts:")) c->c_opt.attempts = n;
+    else if (MATCH("no-rotate")) c->c_opt.rotate = 0;
+    else if (MATCH("rotate")) c->c_opt.rotate = 1;
+    else if (MATCH("no-check-names")) c->c_opt.check_names = 0;
+    else if (MATCH("check-names")) c->c_opt.check_names = 1;
+    else if (MATCH("no-inet6")) c->c_opt.ip6int = 0;
+    else if (MATCH("inet6")) c->c_opt.inet6 = 1;
+    else if (MATCH("no-ip6-dotint")) c->c_opt.ip6int = 0;
+    else if (MATCH("ip6-dotint")) c->c_opt.ip6int = 1;
+    else if (MATCH("no-ip6-bytestring")) c->c_opt.ip6bytestring = 0;
+    else if (MATCH("ip6-bytestring")) c->c_opt.ip6bytestring = 1;
+    /* Sofia-specific extensions: */
+    else if (MATCH("no-edns0")) c->c_opt.edns = edns_not_supported;
+    else if (MATCH("edns0")) c->c_opt.edns = edns0_configured;
+    else {
+      SU_DEBUG_3(("sres: %s: unknown option %*.s\n",
+		  c->c_filename, (int)(len + extra), b));
+    }
+  }
+
+  return 0;
+}
+
+static
+int sres_parse_nameserver(sres_config_t *c, char const *server)
+{
+  sres_nameserver_t *ns;
+  struct sockaddr *sa;
+  int err, i;
+
+  for (i = 0; i < SRES_MAX_NAMESERVERS; i++)
+    if (c->c_nameservers[i] == NULL)
+      break;
+
+  if (i >= SRES_MAX_NAMESERVERS)
+    return 0 /* Silently discard extra nameservers */;
+
+  ns = su_zalloc(c->c_home, (sizeof *ns) + strlen(server) + 1);
+  if (!ns)
+    return -1;
+
+  sa = (void *)ns->ns_addr;
+
+#if HAVE_SIN6
+  if (strchr(server, ':')) {
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+    memset(sa, 0, ns->ns_addrlen = sizeof *sin6);
+    err = inet_pton(sa->sa_family = AF_INET6, server, &sin6->sin6_addr);
+  } 
+  else 
+#endif
+    {
+      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+      memset(sa, 0, ns->ns_addrlen = sizeof *sin);
+      err = inet_pton(sa->sa_family = AF_INET, server, &sin->sin_addr);
+    }
+
+  if (err <= 0) {
+    SU_DEBUG_3(("sres: nameserver %s: invalid address\n", server));
+    su_free(c->c_home, ns);
+    return 0;
+  }
+
+#if HAVE_SA_LEN
+  sa->sa_len = ns->ns_addrlen;
+#endif
+
+  c->c_nameservers[i] = ns;
+
+  return 1;
+}
+
+/** Get current timestamp of resolv.conf file */
+static
+time_t sres_config_timestamp(sres_config_t const *c)
+{
+#ifndef _WIN32
+  struct stat st;
+
+  if (stat(c->c_filename, &st) == 0)
+    return st.st_mtime;
+
+  /** @return If the resolv.conf file does not exists, return old timestamp. */
+  return c->c_modified;
+#else
+  /** On WIN32, return always different timestamp */
+  return c->c_modified + SRES_UPDATE_INTERVAL_SECS;
+#endif
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/** Check if the new configuration has different servers than the old */
+static 
+int sres_config_changed_servers(sres_config_t const *new_c, 
+				sres_config_t const *old_c)
+{
+  int i;
+  sres_nameserver_t const *new_ns, *old_ns;
+
+  if (old_c == NULL)
+    return 1;
+
+  for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+    new_ns = new_c->c_nameservers[i];
+    old_ns = old_c->c_nameservers[i];
+
+    if (!new_ns != !old_ns)
+      return 1;
+    if (!new_ns)
+      return 0;
+    if (new_ns->ns_addrlen != old_ns->ns_addrlen)
+      return 1;
+    if (memcmp(new_ns->ns_addr, old_ns->ns_addr, new_ns->ns_addrlen))
+      return 1;
+  }
+
+  return 0;
+}
+
+/** Allocate new servers structure */
+static
+sres_server_t **sres_servers_new(sres_resolver_t *res,
+				 sres_config_t const *c)
+{
+  sres_server_t **servers, *dns;
+  sres_nameserver_t *ns;
+  int N, i;
+  size_t size;
+
+  for (N = 0; c->c_nameservers[N] && N < SRES_MAX_NAMESERVERS; N++)
+    ;
+
+  size = (N + 1) * (sizeof *servers) + N * (sizeof **servers);
+
+  servers = su_zalloc(res->res_home, size); if (!servers) return servers;
+  dns = (void *)(servers + N + 1);
+  for (i = 0; i < N; i++) {
+    dns->dns_socket = INVALID_SOCKET;
+    ns = c->c_nameservers[i];
+    memcpy(dns->dns_addr, ns->ns_addr, dns->dns_addrlen = ns->ns_addrlen);
+    inet_ntop(dns->dns_addr->ss_family, SS_ADDR(dns->dns_addr), 
+	      dns->dns_name, sizeof dns->dns_name);
+    dns->dns_edns = c->c_opt.edns;
+    servers[i] = dns++;
+  }
+
+  return servers;
+}
+
+static
+void sres_servers_close(sres_resolver_t *res,
+			sres_server_t **servers)
+{
+  int i;
+
+  if (res == NULL || servers == NULL)
+    return;
+
+  for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+    if (!servers[i])
+      break;
+
+    if (servers[i]->dns_socket != -1) {
+      if (res->res_updcb)
+	res->res_updcb(res->res_async, INVALID_SOCKET, servers[i]->dns_socket);
+      sres_close(servers[i]->dns_socket);
+    }
+  }
+}
+
+static
+int sres_servers_count(sres_server_t *const *servers)
+{
+  int i;
+
+  if (!servers)
+    return 0;
+
+  for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+    if (!servers[i])
+      break;
+  }  
+
+  return i;
+}
+
+static
+sres_socket_t sres_server_socket(sres_resolver_t *res, sres_server_t *dns)
+{
+  int family = dns->dns_addr->ss_family;
+  sres_socket_t s;
+
+  if (dns->dns_socket != -1)
+    return dns->dns_socket;
+
+  s = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+  if (s == -1) {
+    SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "socket",
+		su_strerror(su_errno())));
+    dns->dns_error = time(NULL);
+    return s;
+  }
+
+#if HAVE_IP_RECVERR
+  if (family == AF_INET || family == AF_INET6) {
+    int const one = 1;
+    if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) {
+      if (family == AF_INET)
+	SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno())));
+    }
+  }
+#endif
+#if HAVE_IPV6_RECVERR
+  if (family == AF_INET6) {
+    int const one = 1;
+    if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)
+      SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())));
+  }
+#endif
+
+  if (connect(s, (void *)dns->dns_addr, dns->dns_addrlen) < 0) {
+    char ipaddr[64];
+    char const *lb = "", *rb = "";
+
+    if (family == AF_INET) {
+      void *addr = &((struct sockaddr_in *)dns->dns_addr)->sin_addr;
+      inet_ntop(family, addr, ipaddr, sizeof ipaddr);
+    }
+#if HAVE_SIN6
+    else if (family == AF_INET6) {
+      void *addr = &((struct sockaddr_in6 *)dns->dns_addr)->sin6_addr;
+      inet_ntop(family, addr, ipaddr, sizeof ipaddr);
+      lb = "[", rb = "]";
+    }
+#endif
+    else
+      snprintf(ipaddr, sizeof ipaddr, "<af=%u>", family);
+
+    SU_DEBUG_1(("%s: %s: %s: %s%s%s:%u\n", "sres_server_socket", "connect",
+		su_strerror(su_errno()), lb, ipaddr, rb,
+		ntohs(((struct sockaddr_in *)dns->dns_addr)->sin_port)));
+    sres_close(s);
+    dns->dns_error = time(NULL);
+    return INVALID_SOCKET;
+  }
+  
+  if (res->res_updcb) {
+    if (res->res_updcb(res->res_async, s, INVALID_SOCKET) < 0) {
+      SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "update callback",
+		  su_strerror(su_errno())));
+      sres_close(s);
+      dns->dns_error = time(NULL);
+      return INVALID_SOCKET;
+    }
+  }
+
+  dns->dns_socket = s;
+  
+  return s;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Send a query packet */
+static 
+int 
+sres_send_dns_query(sres_resolver_t *res, 
+		    sres_query_t *q)
+{                        
+  sres_message_t m[1];
+  uint8_t i, i0, N = res->res_n_servers;
+  sres_socket_t s;
+  int transient, error = 0;
+  ssize_t size, no_edns_size, edns_size;
+  uint16_t id = q->q_id;
+  uint16_t type = q->q_type;
+  char const *domain = q->q_name;
+  time_t now = res->res_now;
+  sres_server_t **servers = res->res_servers, *dns;
+  char b[8];
+
+  if (now == 0) time(&now);
+
+  SU_DEBUG_9(("sres_send_dns_query(%p, %p) called\n", res, q));
+
+  if (domain == NULL)
+    return -1;
+  if (servers == NULL)
+    return -1;
+  if (N == 0) 
+    return -1;
+
+  memset(m, 0, offsetof(sres_message_t, m_data[sizeof m->m_packet.mp_header]));
+
+  /* Create a DNS message */
+  size = sizeof(m->m_packet.mp_header);
+  m->m_size = (uint16_t)sizeof(m->m_data);
+  m->m_offset = (uint16_t)size;
+  
+  m->m_id = id;
+  m->m_flags = htons(SRES_HDR_QUERY | SRES_HDR_RD);
+  
+  /* Query record */
+  m->m_qdcount = htons(1);
+  m_put_domain(m, domain, 0, NULL);
+  m_put_uint16(m, type);
+  m_put_uint16(m, sres_class_in);
+  
+  no_edns_size = m->m_offset;
+
+  /* EDNS0 record (optional) */
+  m_put_domain(m, ".", 0, NULL);
+  m_put_uint16(m, sres_type_opt);
+  m_put_uint16(m, sizeof(m->m_packet)); /* Class: our UDP payload size */
+  m_put_uint32(m, 0);		/* TTL: extended RCODE & flags */
+  m_put_uint16(m, 0);
+  
+  edns_size = m->m_offset;
+
+  if (m->m_error) {
+    SU_DEBUG_3(("%s(): encoding: %s\n", "sres_send_dns_query", m->m_error));
+    su_seterrno(EIO);
+    return -1;
+  }
+
+  transient = 0;
+
+  i0 = q->q_i_server; if (i0 > N) i0 = 0; /* Number of DNS servers reduced */
+
+  if (res->res_config->c_opt.rotate || 
+      servers[i0]->dns_error || servers[i0]->dns_icmp)
+    dns = sres_next_server(res, &q->q_i_server, 0), i = q->q_i_server;
+  else 
+    dns = servers[i0], i = i0;
+
+  for (; dns; dns = sres_next_server(res, &i, 0)) {
+    /* If server supports EDNS, include EDNS0 record */
+    q->q_edns = dns->dns_edns;
+    /* 0 (no EDNS) or 1 (EDNS supported) additional data records */
+    m->m_arcount = htons(q->q_edns != 0); 
+    /* Size with or without EDNS record */
+    size = q->q_edns ? edns_size : no_edns_size; 
+
+    s = sres_server_socket(res, dns);
+
+    /* Send the DNS message via the UDP socket */
+    if (s != INVALID_SOCKET && sres_send(s, m->m_data, size, 0) == size)
+      break;
+
+    error = su_errno();
+    dns->dns_icmp = now;
+    /* EINVAL is returned if destination address is bad */
+    if (transient++ < 3 && error != EINVAL && s != -1)
+      continue;
+    transient = 0;
+
+    dns->dns_error = now;	/* Mark as a bad destination */
+  }
+
+  if (!dns) {
+    /* All servers have reported errors */
+    SU_DEBUG_5(("%s(): sendto: %s\n", "sres_send_dns_query",
+		su_strerror(error)));
+    return su_seterrno(error);
+  }
+
+  q->q_i_server = i;
+
+  SU_DEBUG_5(("%s(%p, %p) id=%u %s %s (to [%s]:%u)\n", 
+	      "sres_send_dns_query",
+	      res, q, id, sres_record_type(type, b), domain, 
+	      dns->dns_name, 
+	      htons(((struct sockaddr_in *)dns->dns_addr)->sin_port)));
+
+  return 0;
+}
+
+
+/** Select next server */
+static
+sres_server_t *sres_next_server(sres_resolver_t *res, 
+				uint8_t *in_out_i,
+				int timeout)
+{
+  int i, j, N;
+  sres_server_t **servers;
+
+  assert(res && in_out_i);
+
+  N = res->res_n_servers;
+  servers = res->res_servers;
+  i = *in_out_i;
+
+  assert(res->res_servers && res->res_servers[i]);
+  
+  /* Retry using another server? */
+  for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
+    if (servers[j]->dns_icmp == 0) {
+      return *in_out_i = j, servers[j];
+    }
+  }
+
+  for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
+    if (servers[j]->dns_error == 0) {
+      return *in_out_i = j, servers[j];
+    }
+  }
+
+  if (timeout)
+    return servers[i];
+  
+  return NULL;
+}
+
+/**
+ * Callback function for subqueries
+ */
+static
+void sres_answer_subquery(sres_context_t *context, 
+			  sres_query_t *query,
+			  sres_record_t **answers)
+{
+  sres_resolver_t *res;
+  sres_query_t *top = (sres_query_t *)context;
+  int i;
+  assert(top); assert(top->q_n_subs > 0); assert(query);
+
+  res = query->q_res;
+
+  for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+    if (top->q_subqueries[i] == query)
+      break;
+  }
+  assert(i <= SRES_MAX_SEARCH);
+  if (i > SRES_MAX_SEARCH || top->q_n_subs == 0) {
+    sres_free_answers(res, answers);
+    return;
+  }
+
+  if (answers) {
+    int j, k;
+    for (j = 0, k = 0; answers[j]; j++) {
+      if (answers[j]->sr_status)
+	sres_free_answer(query->q_res, answers[j]);
+      else
+	answers[k++] = answers[j];
+    }
+    answers[k] = NULL;
+    if (!answers[0])
+      sres_free_answers(query->q_res, answers), answers = NULL;
+  }
+
+  top->q_subqueries[i] = NULL;
+  top->q_subanswers[i] = answers;
+  top->q_n_subs--;
+
+  if (answers && top->q_callback) {
+    sres_answer_f *callback = top->q_callback;
+
+    top->q_callback = NULL;
+    sres_remove_query(top->q_res, top, 1);
+    callback(top->q_context, top, answers);
+  }
+  else if (top->q_n_subs == 0 && top->q_id == 0) {
+    sres_query_report_error(top, NULL);
+  };
+}
+
+/** Report sres error */
+static void
+sres_query_report_error(sres_query_t *q,
+			sres_record_t **answers)
+{
+  int i;
+
+  if (q->q_callback) {
+    for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+      if (q->q_subqueries[i])	/* a pending query... */
+	return;
+
+      if (q->q_subanswers[i]) {
+	answers = q->q_subanswers[i];
+	q->q_subanswers[i] = NULL;
+	break;
+      }
+    }
+
+    SU_DEBUG_5(("sres(q=%p): reporting errors for %u %s\n",
+		q, q->q_type, q->q_name));
+ 
+    sres_remove_query(q->q_res, q, 1);
+    (q->q_callback)(q->q_context, q, answers);
+  }
+
+  sres_free_query(q->q_res, q);
+}
+
+/** Resolver timer function.
+ *
+ * The function sresolver_timer() should be called in regular intervals. We
+ * recommend calling it in 500 ms intervals.
+ *
+ * @param res pointer to resolver object
+ * @param dummy argument for compatibility 
+ */
+void sres_resolver_timer(sres_resolver_t *res, int dummy)
+{
+  size_t i;
+  sres_query_t *q;
+  time_t now, retry_time;
+
+  if (res == NULL)
+    return;
+
+  now = time(&res->res_now);
+
+  if (res->res_queries->qt_used) {
+    SU_DEBUG_9(("sres_resolver_timer() called at %lu\n", (long) now));
+
+    /** Every time it is called it goes through all query structures, and
+     * retransmits all the query messages, which have not been answered yet.
+     */
+    for (i = 0; i < res->res_queries->qt_size; i++) {
+      q = res->res_queries->qt_table[i];
+      
+      if (!q)
+	continue;
+      
+      /* Exponential backoff */
+      retry_time = q->q_timestamp + ((time_t)1 << q->q_retry_count);
+      
+      if (now < retry_time)
+	continue;
+      
+      sres_resend_dns_query(res, q, 1);
+
+      if (q != res->res_queries->qt_table[i])
+	i--;
+    }
+
+    if (res->res_schedulecb && res->res_queries->qt_used)
+      res->res_schedulecb(res->res_async, SRES_RETRANSMIT_INTERVAL); 
+  }
+
+  sres_cache_clean(res->res_cache, res->res_now);
+}
+
+/** Resend DNS query, report error if cannot resend any more. */
+static void
+sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout)
+{
+  uint8_t i, N;
+  sres_server_t *dns;
+
+  SU_DEBUG_9(("sres_resend_dns_query(%p, %p, %u) called\n",
+	      res, q, timeout));
+  
+  N = res->res_n_servers;
+
+  if (N > 0 && q->q_retry_count < SRES_MAX_RETRY_COUNT) {
+    i = q->q_i_server;
+    dns = sres_next_server(res, &i, timeout);
+
+    if (dns) {
+      res->res_i_server = q->q_i_server = i;
+
+      if (q->q_retry_count > res->res_n_servers + 1 &&
+	  dns->dns_edns == edns_not_tried)
+	q->q_edns = edns_not_supported;
+      
+      sres_send_dns_query(res, q);
+
+      if (timeout)
+	q->q_retry_count++;
+      
+      return;
+    }
+  }
+
+  /* report timeout/network error */
+  q->q_id = 0;
+
+  if (q->q_n_subs)
+    return;			/* let subqueries also timeout */
+
+  sres_query_report_error(q, NULL);
+}
+
+
+/** Get a server by socket */
+static 
+sres_server_t *
+sres_server_by_socket(sres_resolver_t const *res, sres_socket_t socket)
+{
+  int i;
+
+  if (socket == -1)
+    return NULL;
+
+  for (i = 0; i < res->res_n_servers; i++) {
+    if (socket == res->res_servers[i]->dns_socket)
+      return res->res_servers[i];
+  }
+
+  return NULL;
+}
+
+static
+void
+sres_canonize_sockaddr(struct sockaddr_storage *from, socklen_t *fromlen)
+{
+#if HAVE_SIN6
+  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)from;
+
+  size_t sin6_addrsize =
+    offsetof(struct sockaddr_in6, sin6_addr) +
+    (sizeof sin6->sin6_addr);
+
+  if (from->ss_family == AF_INET6) {
+    struct in6_addr const *ip6 = &sin6->sin6_addr;
+  
+    if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
+      /* Convert to a IPv4 address */
+      struct sockaddr_in *sin = (struct sockaddr_in *)from;
+      memcpy(&sin->sin_addr, ip6->s6_addr + 12, sizeof sin->sin_addr);
+      sin->sin_family = AF_INET;
+      *fromlen = sizeof (*sin);
+#if HAVE_SA_LEN
+      sin->sin_len = sizeof (*sin);
+#endif
+    }
+    else if (sin6_addrsize < *fromlen) {
+      /* Zero extra sin6 members like sin6_flowinfo or sin6_scope_id */
+      memset((char *)from + sin6_addrsize, 0, *fromlen - sin6_addrsize);
+    }
+  }
+#endif
+
+  if (from->ss_family == AF_INET) {
+    struct sockaddr_in *sin = (struct sockaddr_in *)from;
+    memset(sin->sin_zero, 0, sizeof (sin->sin_zero));
+  }
+}
+
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <sys/uio.h>
+#endif
+
+static
+int sres_no_update(sres_async_t *async,
+		   sres_socket_t new_socket,
+		   sres_socket_t old_socket)
+{
+  return 0;
+}
+
+/** Create connected sockets for resolver.
+ */
+int sres_resolver_sockets(sres_resolver_t *res,
+			  sres_socket_t *return_sockets, 
+			  int n)
+{
+  sres_socket_t s = INVALID_SOCKET;
+  int i, retval;
+
+  if (!sres_resolver_set_async(res, sres_no_update,
+			       (sres_async_t *)-1, 1))
+    return -1;
+
+  retval = res->res_n_servers; assert(retval <= SRES_MAX_NAMESERVERS);
+
+  if (!return_sockets || n == 0)
+    return retval;
+
+  for (i = 0; i < retval && i < n;) {
+    sres_server_t *dns = res->res_servers[i];
+
+    s = sres_server_socket(res, dns);
+
+    return_sockets[i++] = s;
+  }
+
+  return retval;
+}
+
+#if 0
+/** Get a server by socket address */
+static
+sres_server_t *
+sres_server_by_sockaddr(sres_resolver_t const *res, 
+			void const *from, socklen_t fromlen)
+{
+  int i;
+
+  for (i = 0; i < res->res_n_servers; i++) {
+    sres_server_t *dns = res->res_servers[i];
+    if (dns->dns_addrlen == fromlen && 
+	memcmp(dns->dns_addr, from, fromlen) == 0)
+      return dns;
+  }
+  
+  return NULL;
+}
+#endif
+
+/** Receive error message from socket. */
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+int sres_resolver_error(sres_resolver_t *res, int socket)
+{
+  int errcode = 0;
+  struct cmsghdr *c;
+  struct sock_extended_err *ee;
+  struct sockaddr_storage *from;
+  char control[512];
+  char errmsg[64 + 768];
+  struct iovec iov[1];
+  struct msghdr msg[1] = {{ 0 }};
+  struct sockaddr_storage name[1] = {{ 0 }};
+  int n;
+  char info[128] = "";
+
+  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));
+
+  msg->msg_name = name, msg->msg_namelen = sizeof(name);
+  msg->msg_iov = iov, msg->msg_iovlen = 1;
+  iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
+  msg->msg_control = control, msg->msg_controllen = sizeof(control);
+
+  n = recvmsg(socket, msg, MSG_ERRQUEUE);
+
+  if (n < 0) {
+    int error = su_errno();
+    if (error != EAGAIN && error != EWOULDBLOCK)
+      SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(error)));
+    return n;
+  }
+
+  if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {
+    SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));
+    return su_seterrno(EIO);
+  }
+
+  if (msg->msg_flags & MSG_CTRUNC) {
+    SU_DEBUG_1(("%s: extended error was truncated\n", __func__));
+    return su_seterrno(EIO);
+  }
+
+  if (msg->msg_flags & MSG_TRUNC) {
+    /* ICMP message may contain original message... */
+    SU_DEBUG_5(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));
+  }
+
+  /* Go through the ancillary data */
+  for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
+    if (0
+#if HAVE_IP_RECVERR
+	|| (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR)
+#endif
+#if HAVE_IPV6_RECVERR
+	|| (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR)
+#endif
+	) {
+      char const *origin;
+
+      ee = (struct sock_extended_err *)CMSG_DATA(c);
+      from = (void *)SO_EE_OFFENDER(ee);
+      info[0] = '\0';
+
+      switch (ee->ee_origin) {
+      case SO_EE_ORIGIN_LOCAL:
+	strcpy(info, origin = "local");
+	break;
+      case SO_EE_ORIGIN_ICMP:
+	snprintf(info, sizeof(info), "%s type=%u code=%u", 
+		 origin = "icmp", ee->ee_type, ee->ee_code);
+	break;
+      case SO_EE_ORIGIN_ICMP6:
+	snprintf(info, sizeof(info), "%s type=%u code=%u", 
+		 origin = "icmp6", ee->ee_type, ee->ee_code);
+	break;
+      case SO_EE_ORIGIN_NONE:
+	strcpy(info, origin = "none");
+	break;
+      default:
+	strcpy(info, origin = "unknown");
+	break;
+      }
+
+      if (ee->ee_info)
+	snprintf(info + strlen(info), sizeof(info) - strlen(info), 
+		 " info=%08x", ee->ee_info);
+      errcode = ee->ee_errno;
+
+      if (from->ss_family != AF_UNSPEC) {
+	socklen_t fromlen = ((char *)c + c->cmsg_len) - (char *)from;
+
+	sres_canonize_sockaddr(from, &fromlen);
+
+	snprintf(info + strlen(info), sizeof(info) - strlen(info), 
+		 " reported by ");
+	inet_ntop(from->ss_family, SS_ADDR(from), 
+		  info + strlen(info), sizeof(info) - strlen(info));
+      }
+
+      if (msg->msg_namelen <= 0)
+	break;
+
+      {
+	int error;
+	socklen_t errorlen = sizeof error;
+	/* Get error, if any */
+	getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errorlen);
+      }
+      
+      if (sres_resolver_report_error(res, socket, errcode, 
+				     msg->msg_name, msg->msg_namelen,
+				     info))
+	return errcode;
+      break;
+    }
+  }
+
+  if (errcode)
+    sres_resolver_report_error(res, socket, errcode, NULL, 0, info);
+
+  return errcode;
+}
+
+#else
+int sres_resolver_error(sres_resolver_t *res, int socket)
+{
+  int errcode = 0;
+  socklen_t errorlen = sizeof(errcode);
+
+  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));
+
+  getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&errcode, &errorlen);
+
+  return sres_resolver_report_error(res, socket, errcode, NULL, 0, "");
+}
+#endif
+
+
+/** Report error */
+static
+int 
+sres_resolver_report_error(sres_resolver_t *res,
+			   sres_socket_t socket,
+			   int errcode,
+			   struct sockaddr_storage *remote,
+			   socklen_t remotelen, 
+			   char const *info)
+{
+  char buf[80];
+
+  buf[0] = '\0';
+
+  if (remote) {
+    sres_canonize_sockaddr(remote, &remotelen);
+
+    if (remote->ss_family == AF_INET) {
+      struct sockaddr_in const *sin = (struct sockaddr_in *)remote;
+      uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
+      inet_ntop(AF_INET, in_addr, buf, sizeof(buf));
+    } 
+#if HAVE_SIN6
+    else if (remote->ss_family == AF_INET6) {
+      struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)remote;
+      uint8_t const *in_addr = (uint8_t*)&sin6->sin6_addr;
+      inet_ntop(AF_INET6, in_addr, buf, sizeof(buf));
+    }
+#endif
+  }
+
+  SU_DEBUG_5(("sres: network error %u (%s)%s%s%s%s\n", 
+	      errcode, su_strerror(errcode),
+	      buf[0] ? " from " : "", buf, 
+	      info ? " by " : "",
+	      info ? info : ""));
+
+  if (res->res_queries->qt_used) {
+    /* Report error to queries */
+    sres_server_t *dns;
+    sres_query_t *q;
+    size_t i;
+
+    dns = sres_server_by_socket(res, socket);
+
+    if (dns) {
+      time(&res->res_now);
+      dns->dns_icmp = res->res_now;
+
+      for (i = 0; i < res->res_queries->qt_size; i++) {
+	q = res->res_queries->qt_table[i];
+      
+	if (!q || dns != res->res_servers[q->q_i_server])
+	  continue;
+
+	/* Resend query/report error to application */
+	sres_resend_dns_query(res, q, 1);
+
+	if (q != res->res_queries->qt_table[i])
+	  i--;
+      }
+    }
+  }
+  
+  return 1;
+}
+
+
+/** Receive a response packet from socket. */
+int 
+sres_resolver_receive(sres_resolver_t *res, int socket)
+{
+  ssize_t num_bytes;
+  int error;
+  sres_message_t m[1];
+
+  sres_query_t *query = NULL;
+  sres_record_t **reply;
+  sres_server_t *dns;
+
+  struct sockaddr_storage from[1];
+  socklen_t fromlen = sizeof from;
+
+  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_receive", res, socket));
+
+  memset(m, 0, offsetof(sres_message_t, m_data)); 
+  
+  num_bytes = sres_recvfrom(socket, m->m_data, sizeof (m->m_data), 0,
+			    (void *)from, &fromlen);
+
+  if (num_bytes <= 0) {
+    SU_DEBUG_5(("%s: %s\n", "sres_resolver_receive", su_strerror(su_errno())));
+    return 0;
+  }
+
+  if (num_bytes > 65535)
+    num_bytes = 65535;
+
+  dns = sres_server_by_socket(res, socket);
+  if (!dns)
+    return 0;
+
+  m->m_size = (uint16_t)num_bytes;
+
+  /* Decode the received message and get the matching query object */
+  error = sres_decode_msg(res, m, &query, &reply);
+
+  sres_log_response(res, m, from, query, reply);
+
+  if (query == NULL)
+    ;
+  else if (error == SRES_EDNS0_ERR) {
+    dns->dns_edns = edns_not_supported;
+    assert(query->q_id);
+    sres_remove_query(res, query, 0);
+    query->q_id = sres_new_id(res);
+    query->q_hash = query->q_id * Q_PRIME;
+    sres_qtable_append(res->res_queries, query);
+    sres_send_dns_query(res, query);
+    query->q_retry_count++;
+  } 
+  else if (!error && reply) {
+    /* Remove the query from the pending list and notify the listener */
+    sres_remove_query(res, query, 1);
+    if (query->q_callback != NULL)
+      (query->q_callback)(query->q_context, query, reply); 
+    sres_free_query(res, query);
+  }
+  else {
+    sres_query_report_error(query, reply);
+  }
+
+  return 1;
+}
+
+static
+void sres_log_response(sres_resolver_t const *res, 
+		       sres_message_t const *m,
+		       struct sockaddr_storage const *from,
+		       sres_query_t const *query,
+		       sres_record_t * const *reply)
+{
+  if (SU_LOG->log_level >= 5) {
+#ifndef ADDRSIZE
+#define ADDRSIZE 48
+#endif
+    char host[ADDRSIZE] = "*";
+
+    if (from == NULL)
+      ;
+    else if (from->ss_family == AF_INET) {
+      struct sockaddr_in const *sin = (void *)from;
+      inet_ntop(AF_INET, &sin->sin_addr, host, sizeof host);
+    } 
+#if HAVE_SIN6
+    else if (from->ss_family == AF_INET6) {
+      struct sockaddr_in6 const *sin6 = (void *)from;
+      inet_ntop(AF_INET6, &sin6->sin6_addr, host, sizeof host);
+    }
+#endif
+
+    SU_DEBUG_5(("sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n", 
+		res, query, m->m_id, 
+		host, ntohs(((struct sockaddr_in *)from)->sin_port)));
+  }
+}
+
+/** Decode DNS message.
+ *
+ *
+ * @retval 0 if successful
+ * @retval >0 if message indicated error
+ * @retval -1 if decoding error
+ */
+static
+int
+sres_decode_msg(sres_resolver_t *res, 
+		sres_message_t *m,
+		sres_query_t **qq,
+		sres_record_t ***return_answers)
+{
+  sres_record_t *rr = NULL, **answers = NULL, *error = NULL;
+  sres_query_t *query = NULL, **hq;
+  su_home_t *chome = CHOME(res->res_cache);
+  hash_value_t hash;
+  int err;
+  unsigned i, total, errorcount = 0;
+
+  assert(res && m && return_answers);
+
+  time(&res->res_now);
+
+  *qq = NULL;
+  *return_answers = NULL;
+
+  m->m_offset = sizeof(m->m_packet.mp_header);
+
+  if (m->m_size < m->m_offset) {
+    SU_DEBUG_5(("sres_decode_msg: truncated message\n"));
+    return -1;
+  }
+
+  m->m_flags   = ntohs(m->m_flags);
+  m->m_qdcount = ntohs(m->m_qdcount);
+  m->m_ancount = ntohs(m->m_ancount); 
+  m->m_nscount = ntohs(m->m_nscount); 
+  m->m_arcount = ntohs(m->m_arcount); 
+
+  hash = Q_PRIME * m->m_id;
+
+  /* Search for query with this ID */
+  for (hq = sres_qtable_hash(res->res_queries, hash);
+       *hq;
+       hq = sres_qtable_next(res->res_queries, hq))
+    if (hash == (*hq)->q_hash)
+      break;
+
+  *qq = query = *hq;
+
+  if (!query) {
+    SU_DEBUG_5(("sres_decode_msg: matching query for id=%u\n", m->m_id));
+    return -1;
+  }
+
+  assert(query && m->m_id == query->q_id);
+
+  if ((m->m_flags & 15) == SRES_FORMAT_ERR && query->q_edns)
+    return SRES_EDNS0_ERR;
+
+  /* Scan question section */
+  for (i = 0; i < m->m_qdcount; i++) {
+    char name[1024];
+    uint16_t qtype, qclass;
+    m_get_domain(name, sizeof(name), m, 0); /* Query domain */
+    qtype = m_get_uint16(m);  /* Query type */
+    qclass = m_get_uint16(m); /* Query class */
+  }
+
+  if (m->m_error) {
+    SU_DEBUG_5(("sres_decode_msg: %s\n", m->m_error));
+    return -1;
+  }
+
+  err = m->m_flags & SRES_HDR_RCODE;
+
+  if (m->m_ancount == 0 && err == 0)
+    err = SRES_RECORD_ERR;
+
+  if (err == SRES_RECORD_ERR || 
+      err == SRES_NAME_ERR || 
+      err == SRES_UNIMPL_ERR)
+    errorcount = 1;
+
+  total = errorcount + m->m_ancount + m->m_nscount + m->m_arcount;
+
+  answers = su_zalloc(chome, (total + 1) * sizeof answers[0]);
+  if (!answers)
+    return -1;
+
+  /* Scan resource records */
+  for (i = 0; i < total; i++) {
+    if (i < errorcount)
+      rr = error = sres_create_error_rr(res->res_cache, query, err);
+    else
+      rr = sres_create_record(res, m);
+ 
+    if (!rr) {
+      SU_DEBUG_5(("sres_create_record: %s\n", m->m_error));
+      break;
+    }
+
+    if (error && rr->sr_type == sres_type_soa) {
+      sres_soa_record_t *soa = (sres_soa_record_t *)rr;
+      if (error->sr_ttl > soa->soa_minimum && soa->soa_minimum > 10)
+	  error->sr_ttl = soa->soa_minimum;
+    }
+
+    answers[i] = rr;
+  }
+
+  if (i < total) {
+    for (i = 0; i < total; i++)
+      sres_cache_free_record(res->res_cache, answers[i]);
+    su_free(chome, answers);
+    return -1;
+  }
+
+  for (i = 0; i < total; i++) {
+    rr = answers[i];
+
+    if (i < m->m_ancount + errorcount)
+      /* Increase reference count of entry passed in answers */
+      rr->sr_refcount++;
+    else
+      /* Do not pass extra records to user */
+      answers[i] = NULL;	
+
+    sres_cache_store(res->res_cache, rr, res->res_now);
+  }
+
+  *return_answers = answers;
+
+  return err;
+}  
+
+static
+sres_record_t *
+sres_create_record(sres_resolver_t *res, sres_message_t *m)
+{
+  sres_cache_t *cache = res->res_cache;
+  sres_record_t *sr, sr0[1];
+
+  uint16_t m_size;
+  char name[1025];
+  int len;
+  char btype[8], bclass[8];
+
+  sr = memset(sr0, 0, sizeof sr0);
+  
+  len = m_get_domain(sr->sr_name = name, sizeof(name) - 1, m, 0); /* Name */
+  sr->sr_type = m_get_uint16(m);  /* Type */
+  sr->sr_class = m_get_uint16(m); /* Class */
+  sr->sr_ttl = m_get_uint32(m);   /* TTL */
+  sr->sr_rdlen = m_get_uint16(m); /* rdlength */
+  sr->sr_parsed = 1;		
+  if (m->m_error)
+    goto error;
+
+  name[len] = 0;
+
+  SU_DEBUG_9(("RR received %s %s %s %d rdlen=%d\n", name,
+	      sres_record_type(sr->sr_type, btype),
+	      sres_record_class(sr->sr_class, bclass),
+	      sr->sr_ttl, sr->sr_rdlen));
+
+  if (m->m_offset + sr->sr_rdlen > m->m_size) {
+    m->m_error = "truncated message";
+    goto error;
+  }
+
+  m_size = m->m_size;
+  /* limit m_size to indicated rdlen, check whether record is truncated */
+  m->m_size = m->m_offset + sr->sr_rdlen;
+
+  switch (sr->sr_type) {
+  case sres_type_soa:
+    sr = sres_init_rr_soa(cache, sr->sr_soa, m);
+    break;
+  case sres_type_a:
+    sr = sres_init_rr_a(cache, sr->sr_a, m);
+    break;
+  case sres_type_a6:
+    sr = sres_init_rr_a6(cache, sr->sr_a6, m);
+    break;
+  case sres_type_aaaa:
+    sr = sres_init_rr_aaaa(cache, sr->sr_aaaa, m);
+    break;
+  case sres_type_cname:
+    sr = sres_init_rr_cname(cache, sr->sr_cname, m);
+    break;
+  case sres_type_ptr:
+    sr = sres_init_rr_ptr(cache, sr->sr_ptr, m);
+    break;
+  case sres_type_srv:
+    sr = sres_init_rr_srv(cache, sr->sr_srv, m);
+    break;
+  case sres_type_naptr:
+    sr = sres_init_rr_naptr(cache, sr->sr_naptr, m);
+    break;
+  default:
+    sr = sres_init_rr_unknown(cache, sr->sr_record, m);
+    break;
+  }
+
+  if (m->m_error)
+    goto error;
+
+  if (sr == sr0)
+    sr = sres_cache_alloc_record(cache, sr, 0);
+
+  if (sr == NULL) {
+    m->m_error = "memory exhausted";
+    goto error;
+  }
+
+  /* Fill in the common fields */
+  m->m_size = m_size;
+
+  return sr;
+
+ error:  
+  if (sr && sr != sr0)
+    sres_cache_free_record(cache, sr);
+  SU_DEBUG_5(("%s: %s\n", "sres_create_record", m->m_error));
+  return NULL;
+}
+
+/** Decode SOA record */
+static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
+				       sres_soa_record_t *soa,
+				       sres_message_t *m)
+{
+  uint16_t moffset, roffset;
+  int mnamelen, rnamelen;
+
+  soa->soa_record->r_size = sizeof *soa;
+
+  moffset = m->m_offset, mnamelen = m_get_domain(NULL, 0, m, 0) + 1;
+  roffset = m->m_offset, rnamelen = m_get_domain(NULL, 0, m, 0) + 1;
+
+  soa->soa_serial = m_get_uint32(m);
+  soa->soa_refresh = m_get_uint32(m);
+  soa->soa_retry = m_get_uint32(m);
+  soa->soa_expire = m_get_uint32(m);
+  soa->soa_minimum = m_get_uint32(m);
+  
+  if (m->m_error)
+    return NULL;
+
+  soa = (void *)sres_cache_alloc_record(cache, (void *)soa,
+					mnamelen + rnamelen);
+
+  if (soa) {
+    char *mname, *rname;
+
+    assert(moffset > 0 && roffset > 0 && mnamelen > 1 && rnamelen > 1);
+
+    m_get_domain(mname = (char *)(soa + 1), mnamelen, m, moffset);
+    soa->soa_mname = mname;
+
+    m_get_domain(rname = mname + mnamelen, rnamelen, m, roffset);
+    soa->soa_rname = rname;
+  }
+
+  return (sres_record_t *)soa;
+}
+
+/** Decode A record */
+static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
+				     sres_a_record_t *a,
+				     sres_message_t *m)
+{
+  a->a_record->r_size = sizeof *a;
+
+  a->a_addr.s_addr = htonl(m_get_uint32(m));
+
+  return (sres_record_t *)a;
+}
+
+/** Decode A6 record. See @RFC2874 */
+static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
+				      sres_a6_record_t *a6,
+				      sres_message_t *m)
+{
+
+  int suffixlen = 0, i;
+  int prefixlen = 0;
+  uint16_t offset;
+
+  a6->a6_record->r_size = sizeof *a6;
+
+  a6->a6_prelen = m_get_uint8(m);
+
+  if (a6->a6_prelen > 128) {
+    m->m_error = "Invalid prefix length in A6 record";
+    return NULL;
+  }
+
+  suffixlen = (128 + 7 - a6->a6_prelen) / 8;
+  for (i = 16 - suffixlen; i < 16; i++)
+    a6->a6_suffix.u6_addr[i] = m_get_uint8(m);
+
+  if (a6->a6_prelen > 0) {
+    /* Zero pad bits */
+    a6->a6_suffix.u6_addr[16 - suffixlen] &= 0xff >> (a6->a6_prelen & 7);
+
+    offset = m->m_offset, prefixlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+    if (m->m_error)
+      return NULL;
+
+    a6 = (void *)sres_cache_alloc_record(cache, (void *)a6, prefixlen);
+    if (a6)
+      m_get_domain(a6->a6_prename = (char *)(a6 + 1), prefixlen, m, offset);
+  }
+
+  return (sres_record_t *)a6;
+}
+
+/** Decode AAAA record */
+static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
+					sres_aaaa_record_t *aaaa,
+					sres_message_t *m)
+{
+  aaaa->aaaa_record->r_size = sizeof *aaaa;
+
+  if (m->m_offset + sizeof(aaaa->aaaa_addr) <= m->m_size) {
+    memcpy(&aaaa->aaaa_addr, m->m_data + m->m_offset, sizeof(aaaa->aaaa_addr));
+    m->m_offset += sizeof(aaaa->aaaa_addr);
+  }
+  else
+    m->m_error = "truncated AAAA record";
+
+  return (sres_record_t *)aaaa;
+}
+
+/** Decode CNAME record */
+static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
+					 sres_cname_record_t *cn,
+					 sres_message_t *m)
+{
+  uint16_t offset;
+  int dlen;
+
+  cn->cn_record->r_size = sizeof *cn;
+
+  offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+  if (m->m_error)
+    return NULL;
+
+  cn = (void *)sres_cache_alloc_record(cache, (void *)cn, dlen);
+  if (cn)
+    m_get_domain(cn->cn_cname = (char *)(cn + 1), dlen, m, offset);
+
+  return (sres_record_t *)cn;
+}
+
+/** Decode PTR record */
+static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
+				       sres_ptr_record_t *ptr,
+				       sres_message_t *m)
+{
+  uint16_t offset;
+  int dlen;
+
+  ptr->ptr_record->r_size = sizeof *ptr;
+
+  offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+  if (m->m_error)
+    return NULL;
+
+  ptr = (void *)sres_cache_alloc_record(cache, (void *)ptr, dlen);
+  if (ptr)
+    m_get_domain(ptr->ptr_domain = (char *)(ptr + 1), dlen, m, offset);
+
+  return (sres_record_t *)ptr;
+}
+
+/** Decode SRV record */
+static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
+				       sres_srv_record_t *srv,
+				       sres_message_t *m)
+{
+  uint16_t offset;
+  int dlen;
+
+  srv->srv_record->r_size = sizeof *srv;
+
+  srv->srv_priority = m_get_uint16(m);
+  srv->srv_weight = m_get_uint16(m);
+  srv->srv_port = m_get_uint16(m);
+  offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+  if (m->m_error)
+    return NULL;
+  
+  srv = (void *)sres_cache_alloc_record(cache, (void *)srv, dlen);
+  if (srv)
+    m_get_domain(srv->srv_target = (char *)(srv + 1), dlen, m, offset);
+
+  return (sres_record_t *)srv;
+}
+
+/** Decode NAPTR record */
+static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
+					 sres_naptr_record_t *na,
+					 sres_message_t *m)
+{
+  uint16_t offset[4];
+  int len[4];
+
+  na->na_record->r_size = sizeof *na;
+
+  na->na_order = m_get_uint16(m);
+  na->na_prefer = m_get_uint16(m);
+
+  offset[0] = m->m_offset, len[0] = m_get_string(NULL, 0, m, 0) + 1;
+  offset[1] = m->m_offset, len[1] = m_get_string(NULL, 0, m, 0) + 1;
+  offset[2] = m->m_offset, len[2] = m_get_string(NULL, 0, m, 0) + 1;
+  offset[3] = m->m_offset, len[3] = m_get_domain(NULL, 0, m, 0) + 1;
+
+  if (m->m_error)
+    return NULL;
+
+  na = (void *)sres_cache_alloc_record(cache, (void *)na,
+				       len[0] + len[1] + len[2] + len[3]);
+  if (na) {
+    char *s = (char *)(na + 1);
+    m_get_string(na->na_flags = s, len[0], m, offset[0]), s += len[0];
+    m_get_string(na->na_services = s, len[1], m, offset[1]), s += len[1];
+    m_get_string(na->na_regexp = s, len[2], m, offset[2]), s += len[2];
+    m_get_domain(na->na_replace = s, len[3], m, offset[3]), s += len[3];
+  }
+
+  return (sres_record_t *)na;
+}
+
+/** Decode unknown record */
+static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
+					   sres_common_t *r,
+					   sres_message_t *m)
+{
+  if (m->m_offset + r->r_rdlen > m->m_size)
+    m->m_error = "truncated record";
+
+  if (m->m_error)
+    return NULL;
+
+  r->r_size = sizeof *r;
+
+  r = (void *)sres_cache_alloc_record(cache, (void *)r, r->r_rdlen + 1);
+  if (r) {
+    char *data = (char *)(r + 1);
+
+    r->r_parsed = 0;
+
+    memcpy(data, m->m_data + m->m_offset, r->r_rdlen);
+    m->m_offset += r->r_rdlen;
+    data[r->r_rdlen] = 0;
+  }
+
+  return (sres_record_t *)r;
+}
+
+static
+sres_record_t *sres_create_error_rr(sres_cache_t *cache,
+				    sres_query_t const *q,
+				    uint16_t errcode)
+{
+  sres_record_t *sr, r[1];
+  char buf[SRES_MAXDNAME];
+
+  sr = memset(r, 0, sizeof *sr);
+
+  sr->sr_name = (char *)sres_toplevel(buf, sizeof buf, q->q_name);
+  sr->sr_size = sizeof *sr;
+  sr->sr_status = errcode;
+  sr->sr_type = q->q_type;
+  sr->sr_class = q->q_class;
+  sr->sr_ttl = 10 * 60;
+
+  return sres_cache_alloc_record(cache, sr, 0);
+}
+
+/* Message processing primitives */
+
+static
+void
+m_put_uint16(sres_message_t *m, 
+	     uint16_t h)
+{
+  uint8_t *p;
+
+  if (m->m_error)
+    return;
+
+  p = m->m_data + m->m_offset;
+  m->m_offset += sizeof h;
+
+  if (m->m_offset > m->m_size) {
+    m->m_error = "message size overflow";
+    return;
+  }
+
+  p[0] = h >> 8; p[1] = h;
+}
+
+static
+void 
+m_put_uint32(sres_message_t *m, 
+	     uint32_t w)
+{
+  uint8_t *p;
+
+  if (m->m_error)
+    return;
+
+  p = m->m_data + m->m_offset;
+  m->m_offset += sizeof w;
+
+  if (m->m_offset > m->m_size) {
+    m->m_error = "message size overflow";
+    return;
+  }
+
+  p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w;
+}
+
+/*
+ * Put domain into query
+ */
+static
+uint16_t
+m_put_domain(sres_message_t *m,
+	     char const *domain, 
+	     uint16_t top,
+	     char const *topdomain)
+{
+  char const *label;
+  size_t llen;
+
+  if (m->m_error)
+    return top;
+
+  /* Copy domain into query label at a time */
+  for (label = domain; label && label[0]; label += llen) {
+    if (label[0] == '.' && label[1] != '\0') {
+      m->m_error = "empty label";
+      return 0;
+    }
+
+    llen = strcspn(label, ".");
+
+    if (llen >= 64) {
+      m->m_error = "too long label";
+      return 0;
+    }
+    if (m->m_offset + llen + 1 > m->m_size) {
+      m->m_error = "message size overflow";
+      return 0;
+    }
+
+    m->m_data[m->m_offset++] = (uint8_t)llen;
+    memcpy(m->m_data + m->m_offset, label, llen);
+    m->m_offset += (uint8_t)llen;
+
+    if (label[llen] == '\0')
+      break;
+    if (llen == 0)
+      return top;
+    if (label[llen + 1])
+      llen++;
+  }
+
+  if (top) {
+    m_put_uint16(m, 0xc000 | top);
+    return top;
+  }
+  else if (topdomain) {
+    uint16_t retval = m->m_offset;
+    m_put_domain(m, topdomain, 0, NULL);
+    return retval;
+  }
+  else if (m->m_offset < m->m_size)
+    m->m_data[m->m_offset++] = '\0';
+  else
+    m->m_error = "message size overflow";
+
+  return 0;
+}
+
+static
+uint32_t
+m_get_uint32(sres_message_t *m)
+{
+  uint8_t const *p = m->m_data + m->m_offset;
+
+  if (m->m_error)
+    return 0;
+
+  m->m_offset += 4;
+
+  if (m->m_offset > m->m_size) {
+    m->m_error = "truncated message";
+    return 0;
+  }
+
+  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static
+uint16_t 
+m_get_uint16(sres_message_t *m)
+{
+  uint8_t const *p = m->m_data + m->m_offset;
+
+  if (m->m_error)
+    return 0;
+
+  m->m_offset += 2;
+
+  if (m->m_offset > m->m_size) {
+    m->m_error = "truncated message";
+    return 0;
+  }
+
+  return (p[0] << 8) | p[1];
+}
+
+static
+uint8_t 
+m_get_uint8(sres_message_t *m)
+{
+  uint8_t const *p = m->m_data + m->m_offset;
+
+  if (m->m_error)
+    return 0;
+
+  m->m_offset += 1;
+
+  if (m->m_offset > m->m_size) {
+    m->m_error = "truncated message";
+    return 0;
+  }
+
+  return p[0];
+}
+
+/**
+ * Get a string.
+ */
+static int m_get_string(char *d, 
+			int n,
+			sres_message_t *m,
+			uint16_t offset)
+{
+  uint8_t size;
+  uint8_t *p = m->m_data;
+  int save_offset;
+
+  if (m->m_error)
+    return 0;
+
+  if (offset == 0)
+    offset = m->m_offset, save_offset = 1;
+  else
+    save_offset = 0;
+
+  size = p[offset++];
+  
+  if (size + offset >= m->m_size) {
+    m->m_error = "truncated message";
+    return size;
+  }
+
+  offset += size;
+
+  if (save_offset)
+    m->m_offset = offset;
+
+  if (n == 0 || d == NULL)
+    return size;		/* Just return the size (without NUL). */
+
+  memcpy(d, p + offset - size, size < n ? size : n);
+
+  if (size < n)
+    d[size] = '\0';		/* NUL terminate */
+
+  return size;
+}
+
+/**
+ * Uncompress a domain.
+ *
+ * @param offset start uncompression from this point in message
+ */
+static int m_get_domain(char *d, 
+			int n,
+			sres_message_t *m,
+			uint16_t offset)
+{
+  uint8_t cnt;
+  int i = 0;
+  uint8_t *p = m->m_data;
+  uint16_t new_offset;
+  int save_offset;
+
+  if (m->m_error)
+    return 0;
+
+  if (d == NULL) 
+    n = 0;
+
+  if (offset == 0)
+    offset = m->m_offset, save_offset = 1;
+  else
+    save_offset = 0;
+
+  while ((cnt = p[offset++])) {
+    if (cnt >= 0xc0) {
+      if (offset >= m->m_size) {
+        m->m_error = "truncated message";
+        return 0;
+      }
+
+      new_offset = ((cnt & 0x3F) << 8) + p[offset++];
+
+      if (save_offset)
+        m->m_offset = offset;
+
+      if (new_offset <= 0 || new_offset >= m->m_size) {
+        m->m_error = "invalid domain compression";
+        return 0;
+      }
+
+      offset = new_offset;
+      save_offset = 0;
+    } 
+    else {
+      if (offset + cnt >= m->m_size) {
+        m->m_error = "truncated message";
+        return 0;
+      }
+      if (i + cnt + 1 < n) {
+        memcpy(d + i, p + offset, cnt);
+        d[i + cnt] = '.';
+      }
+
+      i += cnt + 1;
+      offset += cnt;
+    }  
+  }
+
+  if (i == 0) { 
+    if (i < n) 
+      d[i] = '.';
+    i++; 
+  }
+
+  if (i < n)
+    d[i] = '\0';
+
+  if (save_offset)
+    m->m_offset = offset;
+
+  return i;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,433 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres_blocking.c
+ * @brief Blocking interface for Sofia DNS Resolver implementation.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Fri Mar 24 15:23:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef _int8 int8_t;
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define HAVE_SELECT 1
+#else
+#define SOCKET_ERROR   (-1)
+#define INVALID_SOCKET ((sres_socket_t)-1)
+#endif
+
+typedef struct sres_blocking_s sres_blocking_t;
+typedef struct sres_blocking_context_s sres_blocking_context_t;
+
+#define SRES_CONTEXT_T struct sres_blocking_context_s
+#define SRES_ASYNC_T struct sres_blocking_s
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_async.h"
+#include <sofia-sip/su_errno.h>
+
+#if HAVE_POLL
+#include <poll.h>
+#elif HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+struct sres_blocking_s
+{
+  int              n_sockets;
+#if HAVE_POLL
+  struct pollfd    fds[SRES_MAX_NAMESERVERS];
+#elif HAVE_SELECT
+  struct { sres_socket_t fd; } fds[SRES_MAX_NAMESERVERS];
+#else
+#error No wait mechanism!
+#endif
+  sres_record_t ***return_records;  
+};
+
+struct sres_blocking_context_s
+{
+  int          ready;
+  sres_resolver_t *resolver;
+  sres_blocking_t *block;
+  sres_query_t *query;
+  sres_record_t ***return_records;  
+};
+
+static
+int sres_blocking_update(sres_blocking_t *b,
+			 sres_socket_t new_socket,
+			 sres_socket_t old_socket)
+{
+  int i, N = b->n_sockets;
+
+  if (old_socket == new_socket) {
+    if (old_socket == INVALID_SOCKET) {
+      free(b);      /* Destroy us */
+    }
+    return 0;
+  }
+
+  if (old_socket != INVALID_SOCKET) {
+    for (i = 0; i < N; i++) {
+      if (b->fds[i].fd == old_socket)
+	break;
+    }
+    if (i == N)
+      return -1;
+
+    N--;
+    b->fds[i].fd = b->fds[N].fd;
+    b->fds[N].fd = INVALID_SOCKET;
+#if HAVE_POLL
+    b->fds[i].events = b->fds[N].events;
+    b->fds[N].events = 0;
+#endif
+
+    b->n_sockets = N;
+  }
+  
+  if (new_socket != INVALID_SOCKET) {
+    if (N == SRES_MAX_NAMESERVERS)
+      return -1;
+    b->fds[N].fd = new_socket;
+#if HAVE_POLL
+    b->fds[N].events = POLLIN;
+#endif
+    b->n_sockets = N + 1;
+  }
+
+  return 0;
+}
+
+static
+int sres_blocking_complete(sres_blocking_context_t *c)
+{
+  while (!c->ready) {
+    int n, i;
+#if HAVE_POLL
+    n = poll(c->block->fds, c->block->n_sockets, 500);
+    if (n < 0) {
+      c->ready = n;
+    }
+    else if (n == 0) {
+      sres_resolver_timer(c->resolver, -1);
+    }
+    else for (i = 0; i < c->block->n_sockets; i++) {
+      if (c->block->fds[i].revents | POLLERR)
+	sres_resolver_error(c->resolver, c->block->fds[i].fd);
+      if (c->block->fds[i].revents | POLLIN)
+	sres_resolver_receive(c->resolver, c->block->fds[i].fd);
+    }
+#elif HAVE_SELECT
+    fd_set readfds[1], errorfds[1];
+    struct timeval timeval[1];
+
+    FD_ZERO(readfds);
+    FD_ZERO(errorfds);
+
+    timeval->tv_sec = 0;
+    timeval->tv_usec = 500000;
+
+    for (i = 0, n = 0; i < c->block->n_sockets; i++) {
+      FD_SET(c->block->fds[i].fd, readfds);
+      FD_SET(c->block->fds[i].fd, errorfds);
+      if (c->block->fds[i].fd >= n)
+	n = c->block->fds[i].fd + 1;
+    }
+
+    n = select(n, readfds, NULL, errorfds, timeval);
+  
+    if (n <= 0)
+      sres_resolver_timer(c->resolver, -1);
+    else for (i = 0; n > 0 && i < c->block->n_sockets; i++) {
+      if (FD_ISSET(c->block->fds[i].fd, errorfds))
+        sres_resolver_error(c->resolver, c->block->fds[i].fd);
+      else if (FD_ISSET(c->block->fds[i].fd, readfds))
+	sres_resolver_receive(c->resolver, c->block->fds[i].fd);
+      else
+	continue;
+      n--;
+    }
+#endif
+  }
+
+  return c->ready;
+}
+
+static
+void sres_blocking_callback(sres_blocking_context_t *c, 
+			    sres_query_t *query,
+			    sres_record_t **answers)
+{
+  c->ready = 1;
+  *c->return_records = answers;
+}
+
+static 
+sres_blocking_t *sres_set_blocking(sres_resolver_t *res)
+{
+  sres_blocking_t *b;
+  int i;
+
+  b = sres_resolver_get_async(res, sres_blocking_update); 
+  if (b)
+    return b;
+
+  /* Check if resolver is already in asynchronous mode */
+  if (sres_resolver_get_async(res, NULL))
+    return NULL;
+
+  /* Create a synchronous (blocking) interface towards resolver */
+  b = calloc(1, sizeof *b);
+
+  for (i = 0; i < SRES_MAX_NAMESERVERS; i++)
+    b->fds[i].fd = INVALID_SOCKET;
+  
+  if (!sres_resolver_set_async(res, sres_blocking_update, b, 0)) {
+    free(b), b = NULL;
+  }
+
+  return b;
+}
+
+/** Return true (and set resolver in blocking mode) if resolver can block. */
+int sres_is_blocking(sres_resolver_t *res)
+{
+  if (res == NULL)
+    return 0;
+  return sres_set_blocking(res) != NULL;
+}
+
+/**Send a DNS query, wait for response, return results.
+ *
+ * Sends a DNS query with specified @a type and @a domain to the DNS server,
+ * if @a ignore_cache is not given or no records are found from cache. 
+ * Function returns an error record with nonzero status if no response is
+ * received from DNS server.
+ *
+ * @param res pointer to resolver object
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param domain domain name to query
+ * @param ignore_cache ignore cached answers if nonzero
+ * @param return_records return-value parameter for dns records
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR EOPNOTSUPP  resolver @a res is in asynchronous mode 
+ *
+ * @sa sres_query(), sres_blocking_search()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_query(sres_resolver_t *res,
+			uint16_t type,
+			char const *domain,
+			int ignore_cache,
+			sres_record_t ***return_records)
+{
+  sres_blocking_context_t c[1];
+  sres_record_t **cached;
+
+  if (return_records == NULL)
+    return su_seterrno(EFAULT);
+
+  *return_records = NULL;
+
+  c->block = sres_set_blocking(res);
+  if (c->block == NULL)
+    return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */ 
+
+  if (!ignore_cache) {
+    cached = sres_cached_answers(res, type, domain);
+    if (cached) {
+      *return_records = cached;
+      return 0;
+    }
+  }
+
+  c->ready = 0;
+  c->resolver = res;
+  c->return_records = return_records;
+  c->query = sres_query(res, sres_blocking_callback, c, type, domain);
+
+  return sres_blocking_complete(c);
+}
+
+/** Search DNS, return results.
+ *
+ * Search for @a name with specified @a type and @a name from the DNS server. 
+ * If the @a name does not contain enought dots, the search domains are
+ * appended to the name and resulting domain name are also queried.
+ *
+ * @param res pointer to resolver object
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param name host or domain name to search from DNS
+ * @param ignore_cache ignore cached answers if nonzero
+ * @param return_records return-value parameter for dns records
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR EOPNOTSUPP  resolver @a res is in asynchronous mode 
+ *
+ * @sa sres_blocking_query(), sres_search()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_search(sres_resolver_t *res,
+			 uint16_t type,
+			 char const *name,
+			 int ignore_cache,
+			 sres_record_t ***return_records)
+{
+  sres_blocking_context_t c[1];
+  sres_record_t **cached;
+
+  if (return_records == NULL)
+    return su_seterrno(EFAULT);
+
+  *return_records = NULL;
+
+  c->block = sres_set_blocking(res);
+  if (c->block == NULL)
+    return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */ 
+
+  if (!ignore_cache) {
+    cached = sres_search_cached_answers(res, type, name);
+    if (cached) {
+      *return_records = cached;
+      return 0;
+    }
+  }
+
+  c->ready = 0;
+  c->resolver = res;
+  c->return_records = return_records;
+  c->query = sres_search(res, sres_blocking_callback, c, type, name);
+
+  return sres_blocking_complete(c);
+}
+
+/** Send a a reverse DNS query, return results.
+ *
+ * Sends a reverse DNS query with specified @a type and @a domain to the DNS
+ * server if @a ignore_cache is not given or no cached records are found from
+ * the cache. Function returns an error record with nonzero status if no
+ * response is received from DNS server.
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR EOPNOTSUPP  resolver @a res is in asynchronous mode 
+ *
+ * @sa sres_blocking_query(), sres_query_sockaddr(), sres_cached_answers_sockaddr()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+				 uint16_t type,
+				 struct sockaddr const *addr,
+				 int ignore_cache,
+				 sres_record_t ***return_records)
+{
+  sres_blocking_context_t c[1];
+  sres_record_t **cached;
+
+  if (return_records == NULL)
+    return errno = EFAULT, -1;
+
+  *return_records = NULL;
+
+  c->block = sres_set_blocking(res);
+  if (c->block == NULL)
+    return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */ 
+
+  if (!ignore_cache) {
+    cached = sres_cached_answers_sockaddr(res, type, addr);
+    if (cached) {
+      *return_records = cached;
+      return 0;
+    }
+  }
+
+  c->ready = 0;
+  c->resolver = res;
+  c->return_records = return_records;
+  c->query = sres_query_sockaddr(res, sres_blocking_callback, c, type, addr);
+
+  return sres_blocking_complete(c);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,450 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres_cache.c
+ * @brief Cache for Sofia DNS Resolver.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else 
+#if defined(_WIN32)
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <time.h>
+
+#include "sofia-resolv/sres_cache.h"
+#include "sofia-resolv/sres_record.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/htable.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <limits.h>
+
+#include <assert.h>
+
+#define SU_LOG sresolv_log
+
+#include <sofia-sip/su_debug.h>
+
+typedef struct sres_rr_hash_entry_s sres_rr_hash_entry_t;
+
+HTABLE_DECLARE_WITH(sres_htable, ht, sres_rr_hash_entry_t, unsigned, size_t);
+
+struct sres_rr_hash_entry_s {
+  unsigned int   rr_hash_key;
+  time_t         rr_received;
+  sres_record_t *rr;
+};
+
+#define SRES_HENTRY_HASH(e) ((e)->rr_hash_key)
+
+struct sres_cache
+{
+  su_home_t           cache_home[1];
+  time_t              cache_cleaned;
+  sres_htable_t       cache_hash[1];
+};
+
+#define sr_refcount sr_record->r_refcount
+#define sr_name     sr_record->r_name
+#define sr_status   sr_record->r_status
+#define sr_size     sr_record->r_size
+#define sr_type     sr_record->r_type
+#define sr_class    sr_record->r_class
+#define sr_ttl      sr_record->r_ttl
+#define sr_rdlen    sr_record->r_rdlen
+#define sr_rdata    sr_generic->g_data
+
+/* ---------------------------------------------------------------------- */
+/* Internal prototypes */
+
+#define LOCK(cache) (su_home_mutex_lock((cache)->cache_home) == 0)
+#define UNLOCK(cache) (su_home_mutex_unlock((cache)->cache_home))
+
+static inline
+void _sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer);
+static inline
+void _sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers);
+
+static unsigned sres_hash_key(const char *string);
+
+HTABLE_PROTOS_WITH(sres_htable, ht, sres_rr_hash_entry_t, unsigned, size_t);
+
+
+/* ---------------------------------------------------------------------- */
+/* Public functions */
+
+/** Create a resolver cache object.
+ *
+ * @param n initial size of cache
+ */
+sres_cache_t *sres_cache_new(int n)
+{
+  sres_cache_t *cache = su_home_new(sizeof *cache);
+
+  if (cache) {
+    su_home_threadsafe(cache->cache_home);
+    if (sres_htable_resize(cache->cache_home, cache->cache_hash, n) < 0)
+      su_home_unref(cache->cache_home), cache = NULL;
+  }
+
+  return cache;
+}
+
+/** Increase reference count on a resolver cache object. */
+sres_cache_t *sres_cache_ref(sres_cache_t *cache)
+{
+  return su_home_ref(cache->cache_home);
+}
+
+/** Decrease the reference count on a resolver cache object. */
+void sres_cache_unref(sres_cache_t *cache)
+{
+  su_home_unref(cache->cache_home);
+}
+
+/** Get a list of matching records from cache. */
+int sres_cache_get(sres_cache_t *cache,
+		   uint16_t type,
+		   char const *domain,
+		   sres_record_t ***return_cached)
+{
+  sres_record_t **result = NULL, *rr = NULL;
+  sres_rr_hash_entry_t **rr_iter, **rr_iter2;
+  int result_size, rr_count = 0;
+  unsigned hash;
+  time_t now;
+  char b[8];
+
+  if (!domain || !return_cached)
+    return -1;
+
+  *return_cached = NULL;
+
+  SU_DEBUG_9(("%s(%p, %s, \"%s\") called\n", "sres_cache_get",
+	      cache, sres_record_type(type, b), domain));
+
+  hash = sres_hash_key(domain);
+
+  if (!LOCK(cache))
+    return -1;
+
+  time(&now);
+
+  /* First pass: just count the number of rr:s for array allocation */
+  rr_iter2 = sres_htable_hash(cache->cache_hash, hash);
+
+  /* Find the domain records from the hash table */
+  for (rr_iter = rr_iter2; 
+       rr_iter && *rr_iter; 
+       rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+    rr = (*rr_iter)->rr;
+
+    if (rr != NULL &&
+	(uint32_t)(now - (*rr_iter)->rr_received) <= rr->sr_ttl &&
+        (type == sres_qtype_any || rr->sr_type == type) &&
+        rr->sr_name != NULL &&
+        strcasecmp(rr->sr_name, domain) == 0) 
+      rr_count++;
+  }
+
+  if (rr_count == 0) {
+    UNLOCK(cache);
+    return 0;
+  }
+
+  result_size = (sizeof *result) * (rr_count + 1);
+  result = su_zalloc(cache->cache_home, result_size);
+  if (result == NULL) {
+    UNLOCK(cache);
+    return -1;
+  }
+
+  /* Second pass: add the rr pointers to the allocated array */
+
+  for (rr_iter = rr_iter2, rr_count = 0; 
+       rr_iter && *rr_iter; 
+       rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+    rr = (*rr_iter)->rr;
+
+    if (rr != NULL &&
+	(uint32_t)(now - (*rr_iter)->rr_received) <= rr->sr_ttl &&
+        (type == sres_qtype_any || rr->sr_type == type) &&
+        rr->sr_name != NULL &&
+        strcasecmp(rr->sr_name, domain) == 0) {
+      SU_DEBUG_9(("rr found in cache: %s %02d\n", 
+		  rr->sr_name, rr->sr_type));
+
+      result[rr_count++] = rr;
+      rr->sr_refcount++;
+    }
+  }
+
+  result[rr_count] = NULL;
+
+  UNLOCK(cache);
+
+  SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get", 
+	      cache, sres_record_type(type, b), domain, rr_count));
+
+  *return_cached = result;
+
+  return rr_count;
+}
+
+sres_record_t *
+sres_cache_alloc_record(sres_cache_t *cache,
+			sres_record_t const *template,
+			size_t extra)
+{
+  sres_record_t *sr;
+  size_t size, name_length;
+
+  size = template->sr_size;
+
+  assert(size >= sizeof(sres_common_t));
+  assert(template->sr_name != NULL);
+
+  name_length = strlen(template->sr_name);
+
+  sr = su_alloc(cache->cache_home, size + extra + name_length + 1);
+
+  if (sr) {
+    char *s = (char *)sr + size + extra;
+    sr->sr_refcount = 0;
+    sr->sr_name = memcpy(s, template->sr_name, name_length);
+    sr->sr_name[name_length] = '\0';
+    memcpy(&sr->sr_status, &template->sr_status,
+	   size - offsetof(sres_common_t, r_status));
+  }
+    
+  return sr;
+}
+
+/** Free a record that has not been stored. */
+void sres_cache_free_record(sres_cache_t *cache, void *rr)
+{
+  sres_record_t *sr = rr;
+
+  if (sr) {
+    assert(sr->sr_refcount == 0);
+    su_free(cache->cache_home, rr);
+  }
+}
+
+/** Store record to cache */
+void 
+sres_cache_store(sres_cache_t *cache, sres_record_t *rr, time_t now)
+{
+  sres_rr_hash_entry_t **rr_iter, *rr_hash_entry;
+  unsigned hash;
+
+  if (rr == NULL)
+    return;
+
+  hash = sres_hash_key(rr->sr_name);
+
+  if (!LOCK(cache))
+    return;
+
+  if (sres_htable_is_full(cache->cache_hash))
+    sres_htable_resize(cache->cache_home, cache->cache_hash, 0);
+
+  for (rr_iter = sres_htable_hash(cache->cache_hash, hash);
+       (rr_hash_entry = *rr_iter); 
+       rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+    sres_record_t *or = rr_hash_entry->rr;
+
+    if (or == NULL)
+      continue;
+    if (rr_hash_entry->rr_hash_key != hash)
+      continue;
+    if (or->sr_type != rr->sr_type)
+      continue;
+    if (!!or->sr_name != !!rr->sr_name)
+      continue;
+    if (or->sr_name != rr->sr_name && 
+	strcasecmp(or->sr_name, rr->sr_name) != 0)
+      continue;
+    if (rr->sr_type != sres_type_soa /* There can be only one */
+	&& sres_record_compare(or, rr))
+      continue;
+    
+    /* There was an old entry in the cache.. Zap it, replace this with it */
+    rr_hash_entry->rr_received = now;
+    rr_hash_entry->rr = rr;
+    rr->sr_refcount++;
+    
+    _sres_cache_free_one(cache, or);
+
+    UNLOCK(cache);
+
+    return;
+  }
+  
+  rr_hash_entry = su_zalloc(cache->cache_home, sizeof(*rr_hash_entry));
+  if (rr_hash_entry) {
+    rr_hash_entry->rr_hash_key = hash;
+    rr_hash_entry->rr_received = now;
+    rr_hash_entry->rr = rr;
+    rr->sr_refcount++;
+
+    cache->cache_hash->ht_used++;
+  }
+  
+  *rr_iter = rr_hash_entry;
+
+  UNLOCK(cache);
+}
+
+/** Free the list records. */
+void sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers)
+{
+  if (answers && LOCK(cache)) {
+      _sres_cache_free_answers(cache, answers);
+    UNLOCK(cache);
+  }
+}
+
+/** Free and zero one record. */
+void sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer)
+{
+  if (LOCK(cache)) {
+    _sres_cache_free_one(cache, answer);
+    UNLOCK(cache);
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Private functions */
+
+static inline
+void _sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers)
+{
+  int i;
+
+  for (i = 0; answers[i] != NULL; i++) {
+    if (answers[i]->sr_refcount <= 1)
+      su_free(cache->cache_home, answers[i]);
+    else 
+      answers[i]->sr_refcount--;
+    answers[i] = NULL;
+  }
+
+  su_free(cache->cache_home, answers);
+}
+
+static inline
+void _sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer)
+{
+  if (answer) {
+    if (answer->sr_refcount <= 1)
+      su_free(cache->cache_home, answer);
+    else 
+      answer->sr_refcount--;
+  }
+}
+
+/** Calculate a hash key for a string */
+static
+unsigned
+sres_hash_key(const char *string)
+{
+  unsigned int result = 0;
+  
+  while (string && *string)
+    result = result * 797 + (unsigned char) * (string++);
+
+  if (result == 0)
+    result--;
+
+  return result;
+}
+
+void sres_cache_clean(sres_cache_t *cache, time_t now)
+{
+  size_t i;
+
+  if (now < cache->cache_cleaned + SRES_CACHE_TIMER_INTERVAL)
+    return;
+
+  if (!LOCK(cache))
+    return;
+
+  /* Clean cache from old entries */
+  cache->cache_cleaned = now;
+
+  for (i = 0; i < cache->cache_hash->ht_size; i++) {
+    sres_rr_hash_entry_t *e;
+      
+    while ((e = cache->cache_hash->ht_table[i]) != NULL) {
+      if ((uint32_t)(now - e->rr_received) <= e->rr->sr_ttl)
+	break;
+	
+      sres_htable_remove(cache->cache_hash, e);
+      
+      _sres_cache_free_one(cache, e->rr);
+    }
+  }
+
+  UNLOCK(cache);
+}
+
+HTABLE_BODIES_WITH(sres_htable, ht, sres_rr_hash_entry_t, SRES_HENTRY_HASH,
+		   unsigned, size_t);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,362 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sresolv.c
+ * @brief Sofia DNS Resolver interface using su_root_t.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#define SU_TIMER_ARG_T  struct sres_sofia_s
+#define SU_WAKEUP_ARG_T struct sres_sofia_register_s
+#define SRES_ASYNC_T    struct sres_sofia_s
+
+#include <sofia-sip/sresolv.h>
+
+#define SU_LOG sresolv_log
+#include <sofia-sip/su_debug.h>
+
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+/* Glue functions for Sofia root (reactor) */
+
+#define TAG_NAMESPACE "sres"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+tag_typedef_t srestag_any = NSTAG_TYPEDEF(*);
+tag_typedef_t srestag_resolv_conf = STRTAG_TYPEDEF(resolv_conf);
+tag_typedef_t srestag_resolv_conf_ref = REFTAG_TYPEDEF(srestag_resolv_conf);
+
+tag_typedef_t srestag_cache = PTRTAG_TYPEDEF(cache);
+tag_typedef_t srestag_cache_ref = REFTAG_TYPEDEF(srestag_cache);
+
+typedef struct sres_sofia_s sres_sofia_t;
+typedef struct sres_sofia_register_s sres_sofia_register_t;
+
+struct sres_sofia_register_s {
+  sres_sofia_t *reg_ptr;
+  su_socket_t reg_socket;
+  int reg_index;		/**< Registration index */
+};
+
+struct sres_sofia_s {
+  sres_resolver_t *srs_resolver;
+  su_root_t  	  *srs_root;
+  su_timer_t 	  *srs_timer;
+  su_socket_t      srs_socket;
+  sres_sofia_register_t srs_reg[SRES_MAX_NAMESERVERS];
+};
+
+static int sres_sofia_update(sres_sofia_t *, 
+			     su_socket_t new_socket,
+			     su_socket_t old_socket);
+
+static void sres_sofia_timer(su_root_magic_t *magic, 
+			     su_timer_t *t,
+			     sres_sofia_t *arg);
+
+static int sres_sofia_set_timer(sres_sofia_t *srs, unsigned long interval);
+
+static int sres_sofia_poll(su_root_magic_t *, su_wait_t *, 
+			   sres_sofia_register_t *);
+
+/**Create a resolver.
+ *
+ * The function sres_resolver_create() is used to allocate and initialize
+ * the resolver object using the Sofia asynchronous reactor #su_root_t.
+ */
+sres_resolver_t *
+sres_resolver_create(su_root_t *root, 
+		     char const *conf_file_path,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  sres_resolver_t *res;
+  sres_sofia_t *srs;
+  sres_cache_t *cache = NULL;
+  ta_list ta;
+
+  if (root == NULL)
+    return su_seterrno(EFAULT), (void *)NULL;
+
+  ta_start(ta, tag, value);
+  tl_gets(ta_args(ta),
+	  SRESTAG_RESOLV_CONF_REF(conf_file_path),
+	  SRESTAG_CACHE_REF(cache),
+	  TAG_END());
+  ta_end(ta);
+
+  res = sres_resolver_new_with_cache(conf_file_path, cache, NULL);
+  srs = res ? su_zalloc(0, sizeof *srs) : NULL;
+
+  if (res && srs) {
+    su_timer_t *t;
+
+    srs->srs_resolver = res;
+    srs->srs_root = root;
+    srs->srs_socket = INVALID_SOCKET;
+
+    sres_resolver_set_async(res, sres_sofia_update, srs, 0);
+    
+    t = su_timer_create(su_root_task(root), SRES_RETRANSMIT_INTERVAL);
+    srs->srs_timer = t;
+
+    if (!srs->srs_timer)
+      SU_DEBUG_3(("sres: cannot create timer\n"));
+#if nomore
+    else if (su_timer_set_for_ever(t, sres_sofia_timer, srs) < 0)
+      SU_DEBUG_3(("sres: cannot set timer\n"));
+#else
+    else if (sres_resolver_set_timer_cb(res, sres_sofia_set_timer, srs) < 0)
+      SU_DEBUG_3(("sres: cannot set timer cb\n"));
+#endif
+    else
+      return res;		/* Success! */
+
+    sres_resolver_destroy(res), res = NULL;
+  }
+
+  return res;
+}
+
+/** Destroy a resolver object. */
+int 
+sres_resolver_destroy(sres_resolver_t *res)
+{
+  sres_sofia_t *srs;
+
+  if (res == NULL)
+    return su_seterrno(EFAULT);
+
+  srs = sres_resolver_get_async(res, sres_sofia_update);
+  if (srs == NULL)
+    return su_seterrno(EINVAL);
+
+  /* Remove sockets from too, zap timers. */
+  sres_sofia_update(srs, INVALID_SOCKET, INVALID_SOCKET); 
+
+  sres_resolver_unref(res); 
+
+  return 0;
+}
+
+/**Update registered socket.
+ *
+ * @retval 0 if success
+ * @retval -1 upon failure
+ */
+static int sres_sofia_update(sres_sofia_t *srs,
+			     su_socket_t new_socket,
+			     su_socket_t old_socket)
+{
+  char const *what = NULL;
+  su_wait_t wait[1];
+  sres_sofia_register_t *reg = NULL;
+  sres_sofia_register_t *old_reg = NULL;
+  int i, index = -1, error = 0;
+  int N = SRES_MAX_NAMESERVERS;
+
+  SU_DEBUG_9(("sres_sofia_update(%p, %d, %d)\n", srs, 
+	      (int)new_socket, (int)old_socket));
+
+  if (srs == NULL)
+    return 0;
+
+  if (srs->srs_root == NULL)
+    return -1;
+
+  if (old_socket == new_socket) {
+    if (old_socket == INVALID_SOCKET) {
+      sres_resolver_set_async(srs->srs_resolver, sres_sofia_update, NULL, 0);
+      /* Destroy srs */
+      for (i = 0; i < N; i++) {
+	if (!srs->srs_reg[i].reg_index)
+	  continue;
+	su_root_deregister(srs->srs_root, srs->srs_reg[i].reg_index);
+	memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i]));
+      }
+      su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
+      su_free(NULL, srs);
+    }
+    return 0;
+  }
+
+  if (old_socket != INVALID_SOCKET)
+    for (i = 0; i < N; i++)
+      if ((srs->srs_reg + i)->reg_socket == old_socket) {
+	old_reg = srs->srs_reg + i;
+	break;
+      }
+
+  if (new_socket != INVALID_SOCKET) {
+    if (old_reg == NULL) {
+      for (i = 0; i < N; i++) {
+	if (!(srs->srs_reg + i)->reg_ptr)
+	  break;
+      }
+      if (i > N)
+	return su_seterrno(ENOMEM);
+
+      reg = srs->srs_reg + i;
+    }
+    else 
+      reg = old_reg;
+  }
+
+  if (reg) {
+    if (su_wait_create(wait, new_socket, SU_WAIT_IN | SU_WAIT_ERR) == -1) {
+      reg = NULL;
+      what = "su_wait_create";
+      error = su_errno();
+    }
+
+    if (reg)
+      index = su_root_register(srs->srs_root, wait, sres_sofia_poll, reg, 0);
+
+    if (index < 0) {
+      reg = NULL;
+      what = "su_root_register";
+      error = su_errno();
+      su_wait_destroy(wait);
+    }
+  }
+
+  if (old_reg) {
+    if (old_socket == srs->srs_socket)
+      srs->srs_socket = INVALID_SOCKET;
+    su_root_deregister(srs->srs_root, old_reg->reg_index);
+    memset(old_reg, 0, sizeof *old_reg);
+  }
+
+  if (reg) {
+    srs->srs_socket = new_socket;
+
+    reg->reg_ptr = srs;
+    reg->reg_socket = new_socket;
+    reg->reg_index = index;
+  }
+
+  if (!what)
+    return 0;		/* success */
+
+  SU_DEBUG_3(("sres: %s: %s\n", what, su_strerror(error)));
+
+  return su_seterrno(error);			
+}
+
+
+/** Return a socket registered to su_root_t object.
+ *
+ * @retval sockfd if succesful
+ * @retval INVALID_SOCKET (-1) upon an error
+ *
+ * @ERRORS
+ * @ERROR EFAULT Invalid argument passed.
+ * @ERROR EINVAL Resolver is not using su_root_t.
+ */
+su_socket_t sres_resolver_root_socket(sres_resolver_t *res)
+{
+  sres_sofia_t *srs;
+  int i, N = SRES_MAX_NAMESERVERS;
+
+  if (res == NULL)
+    return (void)su_seterrno(EFAULT), INVALID_SOCKET;
+
+  srs = sres_resolver_get_async(res, sres_sofia_update);
+
+  if (!srs)
+    return su_seterrno(EINVAL);
+
+  if (sres_resolver_set_async(res, sres_sofia_update, srs, 1) < 0)
+    return INVALID_SOCKET;
+
+  if (srs->srs_socket != INVALID_SOCKET)
+    return srs->srs_socket;
+
+  for (i = 0; i < N; i++) {
+    if (!srs->srs_reg[i].reg_ptr)
+      break;
+  }
+
+  if (i < N) {
+    srs->srs_socket = srs->srs_reg[i].reg_socket;
+  }
+  else {
+    su_socket_t socket;
+    if (sres_resolver_sockets(res, &socket, 1) < 0)
+      return INVALID_SOCKET;
+  }
+
+  return srs->srs_socket; 
+}
+
+
+/** Sofia timer wrapper. */
+static 
+void 
+sres_sofia_timer(su_root_magic_t *magic, su_timer_t *t, sres_sofia_t *srs)
+{
+  sres_resolver_timer(srs->srs_resolver, -1);
+}
+
+/** Sofia timer set wrapper. */
+static 
+int
+sres_sofia_set_timer(sres_sofia_t *srs, unsigned long interval)
+{
+  if (interval > SU_DURATION_MAX)
+    interval = SU_DURATION_MAX;
+  return su_timer_set_interval(srs->srs_timer, sres_sofia_timer, srs,
+			       (su_duration_t)interval);
+}
+
+
+/** Sofia poll/select wrapper, called by su_root_t object */
+static 
+int 
+sres_sofia_poll(su_root_magic_t *magic, 
+		su_wait_t *w, 
+		sres_sofia_register_t *reg)
+{
+  sres_sofia_t *srs = reg->reg_ptr;
+  int retval = 0;
+  su_socket_t socket = reg->reg_socket;
+  int events = su_wait_events(w, socket);
+
+  if (events & SU_WAIT_ERR)
+    retval = sres_resolver_error(srs->srs_resolver, socket);
+  if (events & SU_WAIT_IN)
+    retval = sres_resolver_receive(srs->srs_resolver, socket);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,263 @@
+/**@MODULEPAGE "sresolv" - Asynchronous DNS Resolver
+
+ at section sresolv_meta Module Information
+
+The Sofia @b sresolv module consists of an asynchronous DNS resolver with
+EDNS extensions. The interface to library using #su_root_t is declared in
+<sofia-sip/sresolv.h>.
+
+An alternative interface is defined by <sofia-resolv/sres.h>,
+<sofia-resolv/sres_record.h>, <sofia-resolv/sres_async.h>, and
+<sofia-resolv/sres_cache.h>.
+
+ at sa @RFC1034, @RFC1035, @RFC1886, @RFC2671, @RFC2782, @RFC2915
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at todo Caching Policy and Cache Poisoning
+
+The policy for caching non-authoritave entries should be solved.
+
+ at section sresolv_overview Why Sofia Resolver?
+
+The generally available open source DNS libraries are either synchronous,
+that is, they block the thread making the query or they resolve only host
+names. As SIP protocol uses NAPTR and SRV records in addition ot the usual A
+or AAAA records, these DNS libraries are inadequate for a SIP application.
+
+Sofia resolver uses the usual configuration for DNS. In Unix-based systems,
+the DNS configuration is stored in the file /etc/resolv.conf, on Windows, it
+is available through the registry. Sofia resolvers reloads the configuration
+when it detect that it has been changed. 
+
+In addition to the configuration files, the environment variables
+#SRES_OPTIONS and #RES_OPTIONS can be used to change the behaviour of the
+resolver.
+
+ at section sresolv_interfaces Using Sofia Resolver
+
+Sofia resolver works usually asynchronously, in other words, it generates a
+a query, sends it to DNS server and returns immediately to the caller. When
+a response is received and the query is completed, sresolv signals
+application through a callback function.
+
+The application can either explicitly poll(2) or select(2) on file
+descriptors used by resolver and call the driver functions, or it can use
+ at ref su_root_t "su root" a pointer to a #su_root_t object. Third option is to
+use resolver synchronously with sres_blocking_query().
+
+There is an internal cache used by sresolv. The query functions add
+records to the cache: using the cache is made similar as if receiving
+entries directly from DNS server.
+
+Please note that you have to create a separate resolver object for each
+thread using Sofia resolver. The resolver objects can share the cache,
+however.
+
+ at section sofia_sip_sresolv_h Interface in <sofia-sip/sresolv.h>
+
+The simple use of Sofia resolver driven from #su_root_t is defined in
+<sofia-sip/sresolv.h>. The resolver object can be created with
+sres_resolver_create(). The provided @ref su_root_t "root object" takes care
+of calling the sres_query() and sres_query_sockaddr() callback functions.
+
+ at code
+#include <sofia-sip/sresolv.h>
+
+sres_resolver_t *sres_resolver_create(su_root_t *root, 
+				      char const *resolv_conf,
+				      tag_type_t, tag_value_t, ...);
+
+int sres_resolver_destroy(sres_resolver_t *res);
+
+ at endcode
+
+ at section sres_query Sending DNS Queries
+
+The second part of interface is used when sending DNS queries:
+
+ at code 
+sres_query_t *sres_query(sres_resolver_t *res,
+			 sres_answer_f *callback,
+			 sres_context_t *context,
+			 int socket,
+			 uint16_t type,
+			 char const *domain);
+
+sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
+				  sres_answer_f *callback,
+				  sres_context_t *context,
+				  int socket,
+				  uint16_t type,
+				  struct sockaddr const *addr);
+
+void sres_query_bind(sres_query_t *q,
+                     sres_answer_f *callback,
+                     sres_context_t *context);
+ at endcode
+
+ at section sres_record Handling DNS Records
+
+The third part is used to handle the records which were returned by DNS
+query or stored into the cache:
+
+ at code
+sres_record_t **sres_cached_answers(sres_resolver_t *res,
+				    uint16_t type,
+				    char const *domain);
+
+sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
+                                             uint16_t type,
+					     struct sockaddr const *addr);
+
+int sres_sort_answers(sres_resolver_t *res, sres_record_t **answers);
+
+int sres_filter_answers(sres_resolver_t *sres, sres_record_t **answers, 
+			uint16_t type);
+
+void sres_free_answers(sres_resolver_t *res, sres_record_t **answers);
+
+void sres_free_answer(sres_resolver_t *res, sres_record_t *answer);
+
+ at endcode
+
+ at section sofia_resolv_sres_h Interface in <sofia-resolv/sres.h>
+
+The generic interface to Sofia resolver is defined in <sofia-resolv/sres.h>. 
+The first part of interface consists of functions for handling resolver
+objects:
+
+ at code
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres.h>
+
+sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
+
+sres_resolver_t *sres_resolver_new_with_cache(char const *conf_file_path,
+					      sres_cache_t *cache,
+			                      char const *options, ...);
+
+sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
+void sres_resolver_unref(sres_resolver_t *res);
+
+sres_resolver_t *sres_resolver_copy(sres_resolver_t *);
+
+void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
+void *sres_resolver_get_userdata(sres_resolver_t const *res);
+
+ at endcode
+
+ at subsection sresolv_blocking Using Sofia Resolver Synchronously
+
+The blocking interface defined in <sofia-resolv/sres.h> makes it possible to
+use Sofia resolver synchronously, that is, the function call making the DNS
+query does not return until the query is responded or it times out.
+
+ at code
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres.h>
+
+int sres_blocking_query(sres_resolver_t *res,
+			uint16_t type,
+			char const *domain,
+			sres_record_t ***return_records);
+
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+				 uint16_t type,
+				 struct sockaddr const *addr,
+				 sres_record_t ***return_records);
+
+ at endcode
+
+ at subsection sresolv_async Asynchronous Interface in <sofia-resolv/sres_async.h>
+
+It is also possible to use resolver asynchronously without #su_root_t object. 
+
+ at code
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres_async.h>
+
+sres_async_t *sres_resolver_set_async(sres_resolver_t *res, 
+				      sres_update_f *update,
+				      sres_async_t *async,
+				      int update_all);
+sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
+				      sres_update_f *update);
+
+int sres_resolver_sockets(sres_resolver_t const *res, int *sockets, int n);
+void sres_resolver_timer(sres_resolver_t *, int socket);
+
+int sres_resolver_receive(sres_resolver_t *res, int socket);
+int sres_resolver_error(sres_resolver_t *res, int socket);
+
+ at endcode
+
+Here is a short code fragment showing how to use resolver driven from
+#su_root_t:
+
+ at code
+
+#define SRES_CONTEXT_T struct context
+
+#include <sofia-sip/sresolv.h>
+
+...
+
+struct context
+{
+  ...
+  su_root_t *root;
+  sres_resolver_t *sres;
+  sres_query_t *query;
+  ...
+} *context;
+
+...
+
+  context->sres = sres_resolver_create(context->root, NULL, TAG_END());
+
+...
+
+  sres_record_t *results;
+
+  results = sres_cached_answers(context->sres, sres_type_naptr, domain);
+  if (results) {
+    process_natpr(context, NULL, results);
+  }
+  else {
+    context->query = sres_query(context->sres, 
+                                process_natpr, context,
+	                        sres_type_naptr, domain);
+    if (!context->query)
+      process_naptr(context, NULL, NULL);
+  }
+}
+...
+
+void process_natpr(sres_context_t *context,
+		   sres_query_t *q,
+		   sres_record_t *answers[])
+{
+  sres_sort_answers(context->sres, answers);
+ 
+  ...
+ 
+  sres_free_answers(context->sres, answers);
+}
+ at endcode
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2020 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE test_sresolv.c Test module for sresolv
+ * 
+ * @author Mikko Haataja
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <sofia-resolv/sres.h>
+#include <sofia-resolv/sres_async.h>
+#include <sofia-resolv/sres_record.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_POLL
+#include <poll.h>
+#elif HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+char const name[] = "test_sresolv";
+
+struct sres_context_s
+{
+  su_home_t        home[1];
+  sres_resolver_t *resolver;
+  sres_query_t    *query;
+  sres_record_t  **result;
+
+  int              timeout;
+  int              sink;
+  int              sinkidx;
+  char const      *sinkconf;
+  
+  int              ready;
+  int              n_sockets;
+  sres_socket_t    sockets[SRES_MAX_NAMESERVERS];
+#if HAVE_POLL
+  struct pollfd    fds[SRES_MAX_NAMESERVERS];
+#endif
+};
+
+static void test_answer(sres_context_t *ctx, sres_query_t *query,
+			sres_record_t **answer);
+static void test_answer_multi(sres_context_t *ctx, sres_query_t *query,
+			      sres_record_t **answer);
+
+static int tstflags = 0;
+
+#if 1
+
+#if HAVE_POLL && 0
+
+static
+int setblocking(sres_socket_t s, int blocking)
+{
+  unsigned mode = fcntl(s, F_GETFL, 0);
+
+  if (mode < 0)
+     return -1;
+
+  if (blocking) 
+    mode &= ~(O_NDELAY | O_NONBLOCK);
+  else
+    mode |= O_NDELAY | O_NONBLOCK;
+
+  return fcntl(s, F_SETFL, mode);
+}
+
+/** Test few assumptions about sockets */
+static
+int test_socket(sres_context_t *ctx)
+{
+  int af;
+  su_sockeet_t s1, s2, s3, s4;
+  struct sockaddr_storage a[1];
+  struct sockaddr_storage a1[1], a2[1], a3[1], a4[1];
+  struct sockaddr_in *sin = (void *)a;
+  struct sockaddr_in *sin3 = (void *)a3, *sin4 = (void *)a4;
+  struct sockaddr *sa = (void *)a;
+  struct sockaddr *sa3 = (void *)a3, *sa4 = (void *)a4;
+  socklen_t alen, a1len, a2len, a3len, a4len;
+  char buf[16];
+
+  BEGIN();
+
+  af = AF_INET;
+
+  for (;;) {
+    TEST_1((s1 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+    TEST_1((s2 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+    TEST_1((s3 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+    TEST_1((s4 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+
+    TEST_1(setblocking(s1, 0) == 0);
+    TEST_1(setblocking(s2, 0) == 0);
+    TEST_1(setblocking(s3, 0) == 0);
+    TEST_1(setblocking(s4, 0) == 0);
+    
+    memset(a, 0, sizeof a);
+    memset(a1, 0, sizeof a1);
+    memset(a2, 0, sizeof a2);
+    memset(a3, 0, sizeof a3);
+    memset(a4, 0, sizeof a4);
+
+#if HAVE_SA_LEN
+    a1->ss_len = a2->ss_len = a3->ss_len = a4->ss_len = sizeof a1;
+#endif
+    a1->ss_family = a2->ss_family = a3->ss_family = a4->ss_family = af;
+
+    if (af == AF_INET)
+      a1len = a2len = a3len = a4len = sizeof (struct sockaddr_in);
+    else
+      a1len = a2len = a3len = a4len = sizeof (struct sockaddr_in6);
+
+    if (af == AF_INET) {
+      TEST_1(inet_pton(af, "127.0.0.1", &sin3->sin_addr) > 0);
+      TEST_1(inet_pton(af, "127.0.0.1", &sin4->sin_addr) > 0);
+    } else {
+    }
+
+    TEST(bind(s3, (struct sockaddr *)a3, a3len), 0);
+    TEST(bind(s4, (struct sockaddr *)a4, a4len), 0);
+    
+    alen = sizeof a;
+    TEST(getsockname(s3, (struct sockaddr *)a, &alen), 0);
+    sin3->sin_port = sin->sin_port; 
+    memset(sin->sin_zero, 0, sizeof sin->sin_zero);
+    TEST(alen, a3len); TEST_M(a, a3, a3len);
+
+    alen = sizeof a;
+    TEST(getsockname(s4, (struct sockaddr *)a, &alen), 0);
+    sin4->sin_port = sin->sin_port;
+    memset(sin->sin_zero, 0, sizeof sin->sin_zero);
+    TEST(alen, a4len); TEST_M(a, a4, a4len);
+
+    TEST(connect(s1, sa3, a3len), 0);
+    TEST(getsockname(s1, (struct sockaddr *)a1, &a1len), 0);
+    TEST(connect(s2, sa4, a4len), 0);
+    TEST(getsockname(s2, (struct sockaddr *)a2, &a2len), 0);
+
+    TEST(sendto(s1, "foo", 3, 0, sa4, a4len), 3);
+    TEST(recvfrom(s4, buf, sizeof buf, 0, sa, &alen), 3);
+    TEST(sendto(s4, "bar", 3, 0, sa, alen), 3);
+    TEST(recvfrom(s2, buf, sizeof buf, 0, sa, &alen), -1);
+    TEST(recvfrom(s1, buf, sizeof buf, 0, sa, &alen), 3);
+
+    su_close(s1), su_close(s2), su_close(s3), su_close(s4);
+
+    break;
+  }
+
+  END();
+}
+
+#endif
+
+static unsigned offset;
+
+#define TEST_RUN(ctx) \
+  { sres_free_answers(ctx->resolver, ctx->result); ctx->result = NULL;	\
+    ctx->query = NULL; run(ctx); TEST_1(ctx->query); }
+
+
+static
+int poll_sockets(sres_context_t *ctx)
+{
+  int i, n, events;
+
+  n = ctx->n_sockets;
+
+  events = poll(ctx->fds, ctx->n_sockets, ctx->timeout ? 50 : 500);
+      
+  if (!events)
+    return events;
+
+  for (i = 0; i < n; i++) {
+    if (ctx->fds[i].revents & POLLERR)
+      sres_resolver_error(ctx->resolver, ctx->fds[i].fd);
+    if (ctx->fds[i].revents & POLLIN)
+      sres_resolver_receive(ctx->resolver, ctx->fds[i].fd);
+  }
+  
+  return events;
+}
+
+#define BREAK(ctx) (ctx->ready = 1)
+static void run(sres_context_t *ctx)
+{
+  for (ctx->ready = 0; !ctx->ready; ) {
+    poll_sockets(ctx);
+
+    if (ctx->timeout) {
+      ctx->timeout <<= 1;
+      offset += ctx->timeout;
+    }
+    
+    /* No harm is done (except wasted CPU) if timer is called more often */
+    sres_resolver_timer(ctx->resolver, -1); 
+  }
+}
+
+int test_soa(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_soa_record_t *rr_soa;
+
+  char const *domain = "example.com";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_soa, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_soa, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = sres_cached_answers(res, sres_type_soa, domain));
+  
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr_soa = result[0]->sr_soa;
+  TEST(rr_soa->soa_record->r_type, sres_type_soa);
+  TEST(rr_soa->soa_record->r_class, sres_class_in);
+
+  TEST_S(rr_soa->soa_mname, "ns.example.com.");
+  TEST_S(rr_soa->soa_rname, "root.example.com.");
+  TEST(rr_soa->soa_serial, 2002042901);
+  TEST(rr_soa->soa_refresh, 7200);
+  TEST(rr_soa->soa_retry, 600);
+  TEST(rr_soa->soa_expire, 36000000);
+  TEST(rr_soa->soa_minimum, 60);
+
+  sres_free_answers(res, result);
+
+  END();
+}
+
+int test_naptr(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_naptr_record_t *rr;
+  char const *domain = "example.com";
+  int i;
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_naptr, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(result[0]);
+
+  for (i = 0; result[i] != NULL; i++) {
+    rr = (sres_naptr_record_t *) result[i]->sr_naptr;
+                                        
+    switch(rr->na_order) {
+    case 20:
+      TEST(rr->na_record->r_type, sres_type_naptr);
+      TEST(rr->na_record->r_class, sres_class_in);
+      TEST(rr->na_record->r_ttl, 60);
+      TEST(rr->na_order, 20);
+      TEST(rr->na_prefer, 50);
+      TEST_S(rr->na_flags, "s");
+      TEST_S(rr->na_services, "SIPS+D2T");
+      TEST_S(rr->na_regexp, "");
+      TEST_S(rr->na_replace, "_sips._tcp.example.com.");
+      break;
+
+    case 40:
+      TEST(rr->na_record->r_type, sres_type_naptr);
+      TEST(rr->na_record->r_class, sres_class_in);
+      TEST(rr->na_record->r_ttl, 60);
+      TEST(rr->na_order, 40);
+      TEST(rr->na_prefer, 15);
+      TEST_S(rr->na_flags, "s");
+      TEST_S(rr->na_services, "SIP+D2U");
+      TEST_S(rr->na_regexp, "");
+      TEST_S(rr->na_replace, "_sip._udp.example.com.");
+      break;
+
+    case 50:
+      TEST(rr->na_record->r_type, sres_type_naptr);
+      TEST(rr->na_record->r_class, sres_class_in);
+      TEST(rr->na_record->r_ttl, 60);
+      TEST(rr->na_order, 50);
+      TEST(rr->na_prefer, 15);
+      TEST_S(rr->na_flags, "u");
+      TEST_S(rr->na_services, "TEST+D2U");
+      TEST_S(rr->na_regexp, "/(tst:([^@]+@))?example.com$/\\1operator.com/i");
+      TEST_S(rr->na_replace, ".");
+      break;
+
+    case 80:
+      TEST(rr->na_record->r_type, sres_type_naptr);
+      TEST(rr->na_record->r_class, sres_class_in);
+      TEST(rr->na_record->r_ttl, 60);
+      TEST(rr->na_order, 80);
+      TEST(rr->na_prefer, 25);
+      TEST_S(rr->na_flags, "s");
+      TEST_S(rr->na_services, "SIP+D2T");
+      TEST_S(rr->na_regexp, "");
+      TEST_S(rr->na_replace, "_sip._tcp.example.com.");
+      break;
+
+    default:
+      TEST_1(0);
+    }
+  }
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  END();
+}
+
+char const longname[1026] = 
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.";
+
+char name2048[2049] = 
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+  "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+  "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+  "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+  "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+  "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+  "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+  "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+  "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+  "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+  "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+  "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+  "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+  "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+  "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+  "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+  "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+  "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+  "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+  "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+  "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+  "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh";
+
+int test_a(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_query_t *query;
+  sres_record_t **result;
+  const sres_a_record_t *rr_a;
+  char const *domain = "sip00.example.com";
+  char name1025[1026] = 
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+		  
+		  ".";
+
+  BEGIN();
+
+  TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+  name1025[1024] = '\0';
+
+  TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+  name1025[1023] = '\0';
+
+  TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+  TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name2048));
+
+  query = sres_query(res, test_answer, ctx, sres_type_a, longname);
+  TEST_1(query);
+  sres_query_bind(query, NULL, NULL);
+  
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
+
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(result[0]);
+  TEST(result[0]->sr_record->r_status, 0);
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  TEST(rr_a->a_record->r_ttl, 60);
+
+  TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
+  TEST(result[0]->sr_record->r_status, 0);
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  TEST(rr_a->a_record->r_ttl, 60);
+  TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+  sres_free_answers(res, result);
+
+  /* Try sub-queries */
+  TEST_1(sres_search(res, test_answer, ctx, sres_type_a, "sip00"));
+
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+
+  for (;*result; result++)
+    if (result[0]->sr_a->a_record->r_type == sres_type_a)
+      break;
+
+  TEST(result[0]->sr_record->r_status, 0);
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  TEST(rr_a->a_record->r_ttl, 60);
+  TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  /* Try missing domain */
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a, 
+			 "no-sip.example.com"));
+
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST(result[0]->sr_record->r_status, SRES_NAME_ERR);
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  /* Error gets TTL from example.com SOA record minimum time */
+  TEST(rr_a->a_record->r_ttl, 60);
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  /* Try domain without A record => 
+     we should get a record with SRES_RECORD_ERR */
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a, 
+			 "aaaa.example.com"));
+
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST(result[0]->sr_record->r_status, SRES_RECORD_ERR);
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  /* Error gets TTL from example.com SOA record minimum time */
+  TEST(rr_a->a_record->r_ttl, 60);
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  /* Cached search */
+  TEST_1(result = sres_search_cached_answers(res, sres_type_a, "sip00"));
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_status, 0);
+  TEST_S(rr_a->a_record->r_name, "sip00.example.com.");
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+  TEST(rr_a->a_record->r_ttl, 60);
+  TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+  if (result[1]) {
+    TEST(result[1]->sr_a->a_record->r_type, sres_type_a);
+  }
+
+  sres_free_answers(res, result), result = NULL;
+
+  /* Cached search */
+  TEST_1(result = sres_cached_answers(res, sres_type_a, "no-sip.example.com"));
+  TEST_1(rr_a = result[0]->sr_a);
+  TEST(rr_a->a_record->r_status, SRES_NAME_ERR);
+  TEST(rr_a->a_record->r_type, sres_type_a);
+  TEST(rr_a->a_record->r_class, sres_class_in);
+
+  sres_free_answers(res, result), result = NULL;
+
+  END();
+}
+
+#if HAVE_SIN6
+int test_a6(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_a6_record_t *rr_a6;
+  char buf[50] = {0};
+  char const *domain = "oldns.example.com";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(result[0]);
+  
+  rr_a6 = result[0]->sr_a6;
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 0);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:210:a4ff:fe8d:6a46");
+
+  TEST_P(rr_a6->a6_prename, NULL);
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_a6, domain));
+  TEST_1(rr_a6 = result[0]->sr_a6);
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 0);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:210:a4ff:fe8d:6a46");
+
+  TEST_P(rr_a6->a6_prename, NULL);
+
+  sres_free_answers(res, result), result = NULL;
+
+  END();
+}
+
+int test_a6_prefix(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_a6_record_t *rr_a6;
+  char buf[50] = {0};
+  char const *domain = "a6.example.com";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(rr_a6 = result[0]->sr_a6);
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 64);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), 
+	 "::a08:20ff:fe7d:e7ac");
+
+  TEST_S(rr_a6->a6_prename, "mynet.example.com.");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  /* Check parsing of special case: no prefix */
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, "full.example.com"));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(rr_a6 = result[0]->sr_a6);
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 0);
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), 
+	 "3ff0:12:3012:c006:a08:20ff:fe7d:e7ac");
+  TEST_P(rr_a6->a6_prename, NULL);
+ 
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  /* Check parsing of special case: no suffix */
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, "alias6.example.com"));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(rr_a6 = result[0]->sr_a6);
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 128);
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), "::");
+  TEST_S(rr_a6->a6_prename, "a6.example.com.");
+ 
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_a6, domain));
+
+  TEST_1(rr_a6 = result[0]->sr_a6);
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 64);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), 
+	 "::a08:20ff:fe7d:e7ac");
+
+  TEST_S(rr_a6->a6_prename, "mynet.example.com.");
+
+  sres_free_answers(res, result), result = NULL;
+
+  END();
+}
+
+int test_aaaa(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_aaaa_record_t *rr_aaaa;
+  char buf[50] = {0};
+  char const *domain = "sip03.example.com";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_aaaa, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(rr_aaaa = result[0]->sr_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+  TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:206:5bff:fe55:4630");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_aaaa, domain));
+  
+  TEST_1(rr_aaaa = result[0]->sr_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+  TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:206:5bff:fe55:4630");
+
+  sres_free_answers(res, result), result = NULL;
+
+  END();
+}
+#endif /* HAVE_SIN6 */
+
+int test_srv(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_srv_record_t *rr;
+  char const *domain = "_sips._tcp.example.com";
+  int i;
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_srv, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+
+  for (i = 0; result[i] != NULL; i++) {
+    TEST_1(rr = (sres_srv_record_t *) result[i]->sr_srv);
+    
+    switch(rr->srv_priority) {
+    case 3:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 100);
+      TEST(rr->srv_port, 5061);
+      TEST_S(rr->srv_target, "sip00.example.com.");
+      break;
+
+    case 4:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 50);
+      TEST(rr->srv_port, 5050);
+      TEST_S(rr->srv_target, "sip02.example.com.");
+      break;
+
+    case 5:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 10);
+      TEST(rr->srv_port, 5060);
+      TEST_S(rr->srv_target, "sip01.example.com.");
+      break;
+
+    default:
+      TEST_1(0);
+    }
+  }
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  TEST_1(result = sres_cached_answers(res, sres_type_srv, domain));
+
+  for (i = 0; result[i] != NULL; i++) {
+    TEST_1(rr = (sres_srv_record_t *) result[i]->sr_srv);
+    
+    switch(rr->srv_priority) {
+    case 3:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 100);
+      TEST(rr->srv_port, 5061);
+      TEST_S(rr->srv_target, "sip00.example.com.");
+      break;
+
+    case 4:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 50);
+      TEST(rr->srv_port, 5050);
+      TEST_S(rr->srv_target, "sip02.example.com.");
+      break;
+
+    case 5:
+      TEST(rr->srv_record->r_type, sres_type_srv);
+      TEST(rr->srv_record->r_class, sres_class_in);
+      TEST(rr->srv_record->r_ttl, 60);
+      TEST(rr->srv_weight, 10);
+      TEST(rr->srv_port, 5060);
+      TEST_S(rr->srv_target, "sip01.example.com.");
+      break;
+
+    default:
+      TEST_1(0);
+    }
+  }
+
+  sres_free_answers(res, result), result = NULL;
+
+  END();
+}
+
+int test_cname(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_cname_record_t *rr;
+  char const *domain = "sip.example.com";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
+  TEST_RUN(ctx);
+
+  TEST_1(result = ctx->result);
+  TEST_1(rr = result[0]->sr_cname);
+  TEST(rr->cn_record->r_class, sres_class_in);
+  TEST(rr->cn_record->r_type, sres_type_cname);
+  TEST(rr->cn_record->r_ttl, 60);
+  TEST_S(rr->cn_cname, "sip00.example.com.");
+
+  sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+  END();
+}
+
+int test_ptr_ipv4(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_ptr_record_t *rr;
+  char const *domain = "1.0.0.127.in-addr.arpa";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_ptr, domain));
+  TEST_RUN(ctx);
+
+  result = ctx->result;
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr = result[0]->sr_ptr;
+  TEST_1(rr != NULL);
+  TEST(rr->ptr_record->r_class, sres_class_in);
+  TEST(rr->ptr_record->r_type, sres_type_ptr);
+  TEST_S(rr->ptr_domain, "localhost.");
+
+  END();
+}
+
+int test_ptr_ipv4_sockaddr(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  sres_query_t *query;
+  const sres_ptr_record_t *rr;
+  struct sockaddr_in sin = {0};
+  
+  inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
+  sin.sin_family = AF_INET;
+
+  BEGIN();
+
+  query = sres_query_sockaddr(res, test_answer, ctx,
+				   sres_qtype_any, (struct sockaddr*)&sin);
+  TEST_1(query != NULL);
+
+  TEST_RUN(ctx);
+
+  result = ctx->result;
+  
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr = result[0]->sr_ptr;
+  TEST_1(rr != NULL);
+  TEST(rr->ptr_record->r_type, sres_type_ptr);
+  TEST(rr->ptr_record->r_class, sres_class_in);
+  TEST_S(rr->ptr_domain, "localhost.");
+
+  END();
+}
+
+#if HAVE_SIN6
+int test_ptr_ipv6(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_ptr_record_t *rr;
+  char const *domain = 
+    "c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0.0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int";
+
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx, sres_type_ptr, domain));
+  TEST_RUN(ctx);
+
+  result = ctx->result;
+  
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr = result[0]->sr_ptr;
+  TEST_1(rr != NULL);
+  TEST(rr->ptr_record->r_type, sres_type_ptr);
+  TEST(rr->ptr_record->r_class, sres_class_in);
+  TEST_S(rr->ptr_domain, "sip01.example.com.");
+
+  END();
+}
+
+int test_ptr_ipv6_sockaddr(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_ptr_record_t *rr;
+  struct sockaddr_in6 sin6 = {0};
+
+  BEGIN();
+
+  inet_pton(AF_INET6, "3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac", 
+            &sin6.sin6_addr);
+
+  sin6.sin6_family = AF_INET6;
+
+  ctx->query = 
+    sres_query_sockaddr(res, test_answer, ctx,
+			     sres_type_ptr, (struct sockaddr*)&sin6);
+  TEST_1(ctx->query != NULL);
+
+  TEST_RUN(ctx);
+
+  result = ctx->result;
+  
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr = result[0]->sr_ptr;
+  TEST_1(rr != NULL);
+  TEST(rr->ptr_record->r_type, sres_type_ptr);
+  TEST(rr->ptr_record->r_class, sres_class_in);
+  TEST_S(rr->ptr_domain, "sip01.example.com.");
+
+  END();
+}
+#endif /* HAVE_SIN6 */
+
+/* Test sres_cached_answers(), sres_sort_answers(), sres_free_answers() */
+int test_cache(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  int ok = 0;
+  sres_record_t *sort_array[3];
+  sres_record_t **result;
+  sres_query_t *query;
+  const sres_record_t *rr = NULL;
+  const sres_a6_record_t *rr_a6;
+  const sres_aaaa_record_t *rr_aaaa;
+  const sres_cname_record_t *rr_cname;
+  const sres_ptr_record_t *rr_ptr;
+#if HAVE_SIN6
+  struct sockaddr_in6 sin6 = {0};
+#endif
+  char const *domain;
+  char buf[50] = {0};
+  int i, j;
+
+  BEGIN();
+
+  sres_query(res, test_answer_multi, ctx,
+		  sres_qtype_any, "example.com");
+
+  sres_query(res, test_answer_multi, ctx,
+		  sres_qtype_any, "_sips._tcp.example.com");
+
+  sres_query(res, test_answer_multi, ctx, 
+		  sres_qtype_any, "sip.example.com");
+
+  sres_query(res, test_answer_multi, ctx,
+		  sres_qtype_any, "subnet.example.com");
+
+#if HAVE_SIN6
+  sres_query(res, test_answer_multi, ctx,
+		  sres_type_aaaa, "mgw02.example.com");
+
+  inet_pton(AF_INET6, 
+            "3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac", 
+            &sin6.sin6_addr);
+
+  sin6.sin6_family = AF_INET6;
+
+  query = sres_query_sockaddr(res, test_answer_multi, ctx,
+				   sres_qtype_any, (struct sockaddr *)&sin6);
+
+  TEST_1(query != NULL);
+#endif
+
+  TEST_RUN(ctx);
+
+  /* For a chance, a fully qualified domain name with final "." */
+  domain = "example.com.";
+  
+  result = sres_cached_answers(res, 
+			       sres_qtype_any,
+			       domain);
+  
+  TEST_1(result != NULL);
+
+  for (i = 0; result[i] != NULL; i++) {
+    rr = result[i];
+
+    if (rr->sr_record->r_type == sres_type_naptr) {
+      const sres_naptr_record_t *rr_naptr = rr->sr_naptr;
+      switch(rr_naptr->na_order) {
+      case 20:
+        TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+        TEST(rr_naptr->na_record->r_class, sres_class_in);
+        TEST(rr_naptr->na_record->r_ttl, 60);
+        TEST(rr_naptr->na_order, 20);
+        TEST(rr_naptr->na_prefer, 50);
+        TEST_S(rr_naptr->na_flags, "s");
+        TEST_S(rr_naptr->na_services, "SIPS+D2T");
+        TEST_S(rr_naptr->na_regexp, "");
+        TEST_S(rr_naptr->na_replace, "_sips._tcp.example.com.");
+        ok |= 1;
+        break;
+
+      case 40:
+        TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+        TEST(rr_naptr->na_record->r_class, sres_class_in);
+        TEST(rr_naptr->na_record->r_ttl, 60);
+        TEST(rr_naptr->na_order, 40);
+        TEST(rr_naptr->na_prefer, 15);
+        TEST_S(rr_naptr->na_flags, "s");
+        TEST_S(rr_naptr->na_services, "SIP+D2U");
+        TEST_S(rr_naptr->na_regexp, "");
+        TEST_S(rr_naptr->na_replace, "_sip._udp.example.com.");
+        ok |= 2;
+        break;
+
+      case 50:
+        TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+        TEST(rr_naptr->na_record->r_class, sres_class_in);
+        TEST(rr_naptr->na_record->r_ttl, 60);
+        TEST(rr_naptr->na_order, 50);
+        TEST(rr_naptr->na_prefer, 15);
+        TEST_S(rr_naptr->na_flags, "u");
+        TEST_S(rr_naptr->na_services, "TEST+D2U");
+
+        TEST_S(rr_naptr->na_regexp, 
+	       "/(tst:([^@]+@))?example.com$/\\1operator.com/i");
+
+        TEST_S(rr_naptr->na_replace, ".");
+        break;
+
+      case 80:
+        TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+        TEST(rr_naptr->na_record->r_class, sres_class_in);
+        TEST(rr_naptr->na_record->r_ttl, 60);
+        TEST(rr_naptr->na_order, 80);
+        TEST(rr_naptr->na_prefer, 25);
+        TEST_S(rr_naptr->na_flags, "s");
+        TEST_S(rr_naptr->na_services, "SIP+D2T");
+        TEST_S(rr_naptr->na_regexp, "");
+        TEST_S(rr_naptr->na_replace, "_sip._tcp.example.com.");
+        ok |= 4;
+        break;
+
+      default:
+        TEST_1(0);
+      }
+    }
+  }
+  
+  TEST(ok, 7);
+
+  /* Reverse order before sorting */
+  for (j = 0; j < --i; j++) {
+    sres_record_t *swap = result[j];
+    result[j] = result[i];
+    result[i] = swap;
+  }
+
+  /* Test sorting */
+  sres_sort_answers(res, result);
+
+  /* Sort all records with themselves */
+  for (i = 0; result[i]; i++) {
+    sort_array[0] = result[i], sort_array[1] = result[i], sort_array[2] = NULL;
+    sres_sort_answers(res, sort_array);
+  }
+  
+  /* Test free */ 
+  for (i = 0; result[i]; i++) {
+    sres_free_answer(res, result[i]);
+    result[i] = NULL;
+  }
+
+  /* Test sres_free_answers() */
+  sres_free_answers(res, result);
+
+  result = sres_cached_answers(res, 
+			       sres_qtype_any,
+			       "_sips._tcp.example.com");
+  
+  TEST_1(result != NULL);
+
+  ok = 0;
+
+  for (i = 0; result[i] != NULL; i++) {
+    sres_srv_record_t *rr_srv = result[i]->sr_srv;
+
+    TEST(rr_srv->srv_record->r_type, sres_type_srv);
+    switch(rr_srv->srv_priority) {
+    case 3:
+      TEST(rr_srv->srv_record->r_type, sres_type_srv);
+      TEST(rr_srv->srv_record->r_class, sres_class_in);
+      TEST(rr_srv->srv_record->r_ttl, 60);
+      TEST(rr_srv->srv_weight, 100);
+      TEST(rr_srv->srv_port, 5061);
+      TEST_S(rr_srv->srv_target, "sip00.example.com.");
+      ok |= 1;
+      break;
+
+    case 4:
+      TEST(rr_srv->srv_record->r_type, sres_type_srv);
+      TEST(rr_srv->srv_record->r_class, sres_class_in);
+      TEST(rr_srv->srv_record->r_ttl, 60);
+      TEST(rr_srv->srv_weight, 50);
+      TEST(rr_srv->srv_port, 5050);
+      TEST_S(rr_srv->srv_target, "sip02.example.com.");
+      ok |= 2;
+      break;
+
+    case 5:
+      TEST(rr_srv->srv_record->r_type, sres_type_srv);
+      TEST(rr_srv->srv_record->r_class, sres_class_in);
+      TEST(rr_srv->srv_record->r_ttl, 60);
+      TEST(rr_srv->srv_weight, 10);
+      TEST(rr_srv->srv_port, 5060);
+      TEST_S(rr_srv->srv_target, "sip01.example.com.");
+      ok |= 4;
+      break;
+
+    default:
+      TEST_1(0);
+    }
+  }
+
+  TEST(ok, 7);
+
+  /* Reverse order before sorting */
+  for (j = 0; j < --i; j++) {
+    sres_record_t *swap = result[j];
+    result[j] = result[i];
+    result[i] = swap;
+  }
+
+  sres_sort_answers(res, result);
+  sres_free_answers(res, result);
+
+  domain = "sip.example.com";
+  result = sres_cached_answers(res, 
+			       sres_qtype_any,
+			       domain);
+
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr_cname = result[0]->sr_cname;
+  TEST(rr_cname->cn_record->r_type, sres_type_cname);
+  TEST(rr_cname->cn_record->r_class, sres_class_in);
+  TEST(rr_cname->cn_record->r_ttl, 60);
+  TEST_S(rr_cname->cn_cname, "sip00.example.com.");
+
+  sres_free_answers(res, result);
+
+#if HAVE_SIN6
+  domain = "subnet.example.com";
+  result = sres_cached_answers(res, 
+			       sres_qtype_any,
+			       domain);
+
+  TEST_1(result != NULL);
+  TEST_1(result[0] != NULL);
+
+  rr_a6 = result[0]->sr_a6;
+  TEST(rr_a6->a6_record->r_type, sres_type_a6);
+  TEST(rr_a6->a6_record->r_class, sres_class_in);
+  TEST(rr_a6->a6_record->r_ttl, 60);
+  TEST(rr_a6->a6_prelen, 0);
+
+  TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), "3ff0::");
+
+  TEST_P(rr_a6->a6_prename, NULL);
+
+  sres_free_answers(res, result);
+
+  domain = "mgw02.example.com";
+  TEST_1(result = sres_cached_answers(res, sres_type_aaaa, domain));
+  TEST_1(rr_aaaa = result[0]->sr_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+  TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+  TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:206:5bff:fe55:462f");
+  sres_free_answers(res, result);
+
+  result = sres_cached_answers_sockaddr(res, 
+                                        sres_type_ptr,
+                                        (struct sockaddr *)&sin6);
+  
+  TEST_1(result != NULL);
+
+  rr_ptr = result[0]->sr_ptr;
+  TEST_1(rr_ptr != NULL);
+
+  TEST(rr_ptr->ptr_record->r_type, sres_type_ptr);
+  TEST(rr_ptr->ptr_record->r_class, sres_class_in);
+  TEST_S(rr_ptr->ptr_domain, "sip01.example.com.");    
+
+  sres_free_answers(res, result);
+#endif /* HAVE_SIN6 */
+
+  END();
+}
+
+#if HAVE_SIN6
+int test_query_one_type(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  const sres_aaaa_record_t *rr_aaaa;
+  char buf[50] = {0};
+  
+  BEGIN();
+
+  TEST_1(sres_query(res, test_answer, ctx,
+			 sres_type_aaaa, "mgw02.example.com"));
+  TEST_RUN(ctx);
+  TEST_1(result = ctx->result);
+  TEST_1(result[0] != NULL);
+
+  TEST_1(rr_aaaa = result[0]->sr_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+  TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+  TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+  TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)), 
+	 "3ffe:1200:3012:c000:206:5bff:fe55:462f");
+
+  TEST_P(result[1], NULL);
+
+  END();
+}
+#endif /* HAVE_SIN6*/
+
+#ifdef _WIN32
+#include <fcntl.h>
+#endif
+
+int sink_make(sres_context_t *ctx)
+{
+  char *tmpdir = getenv("TMPDIR");
+  char *template;
+  int fd, sink;
+  struct sockaddr_in sin[1];
+  socklen_t sinsize = sizeof sin;
+  FILE *f;
+  
+  BEGIN();
+
+  sink = socket(AF_INET, SOCK_DGRAM, 0); TEST_1(sink != -1);
+  TEST(getsockname(sink, (struct sockaddr *)sin, &sinsize), 0);
+  sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  TEST(bind(sink, (struct sockaddr *)sin, sinsize), 0);
+  TEST(getsockname(sink, (struct sockaddr *)sin, &sinsize), 0);
+
+  ctx->sink = sink;
+
+  template = su_sprintf(ctx->home, "%s/test_sresolv.XXXXXX", 
+			tmpdir ? tmpdir : "/tmp");
+  TEST_1(template);
+
+#ifndef _WIN32  
+  fd = mkstemp(template); TEST_1(fd != -1);
+#else
+  fd = open(template, O_WRONLY); TEST_1(fd != -1);
+#endif  
+
+  f = fdopen(fd, "w"); TEST_1(f);
+  fprintf(f, 
+	  "domain example.com\n"
+	  "search foo.bar.com\n"
+	  "port %u\n", 
+	  ntohs(sin->sin_port));
+  fclose(f);
+
+  ctx->sinkconf = template;
+
+  END();
+}
+
+#if 0
+int recv_sink(su_root_magic_t *rm, su_wait_t *w, sres_context_t *ctx)
+{
+  union {
+    char bytes[8192];
+    unsigned short shorts[4096];
+  } buffer[1];
+
+  su_wait_events(w, ctx->sink);
+  recv(ctx->sink, buffer->bytes, sizeof buffer, 0);
+
+  return 0;
+}
+
+int sink_init(sres_context_t *ctx)
+{
+  su_wait_t w[1];
+  BEGIN();
+
+  TEST(su_wait_create(w, ctx->sink, SU_WAIT_IN), 0);
+  ctx->sinkidx = su_root_register(ctx->root, w, recv_sink, ctx, 0);
+  TEST_1(ctx->sinkidx != 0);
+
+  END();
+}
+
+int sink_deinit(sres_context_t *ctx)
+{
+  BEGIN();
+
+  if (ctx->sinkidx)
+    su_root_deregister(ctx->root, ctx->sinkidx);
+  ctx->sinkidx = 0;
+  su_close(ctx->sink), ctx->sink = -1;
+
+  END();
+}
+#endif
+
+int test_timeout(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  /* const sres_soa_record_t *rr_soa; */
+  char const *domain = "test";
+
+  BEGIN();
+
+  sres_query(res, test_answer, ctx, sres_type_a, domain);
+
+  ctx->timeout = 1;
+  TEST_RUN(ctx);
+  ctx->timeout = 0;
+
+  TEST_P(ctx->result, NULL);
+
+  result = sres_cached_answers(res, sres_type_a, domain);
+
+#if 0
+  TEST_1(result); TEST_1(result[0] != NULL);
+
+  rr_soa = result[0]->sr_soa;
+  TEST(rr_soa->soa_record->r_type, sres_type_soa);
+  TEST(rr_soa->soa_record->r_class, sres_class_in);
+  TEST_S(rr_soa->soa_record->r_name, "example.com.");
+  TEST(rr_soa->soa_record->r_status, SRES_TIMEOUT_ERR);
+
+  sres_free_answers(res, result);
+#else
+  /* Currently, we do not create error records */
+  TEST_1(result == NULL);
+#endif
+
+  END();
+}
+
+static void test_answer(sres_context_t *ctx,
+		 sres_query_t *q,
+		 sres_record_t **answer)
+{
+  ctx->query = q;
+  if (ctx->result)
+    sres_free_answers(ctx->resolver, ctx->result);
+  ctx->result = answer; 
+  BREAK(ctx);
+}
+
+static void test_answer_multi(sres_context_t *ctx,
+		       sres_query_t *q,
+		       sres_record_t **answer)
+{
+  static int count = 0;
+
+  ctx->query = q;
+
+  count++;
+
+  sres_free_answers(ctx->resolver, answer);
+
+  if (count == 6)
+    BREAK(ctx);
+}
+
+#include <sys/time.h>
+
+/* Fake time() implementation, used by sresolv library */
+time_t time(time_t *tp)
+{
+  struct timeval tv[1];
+
+#ifndef _WIN32
+  gettimeofday(tv, NULL);
+#else
+  return 0;
+#endif
+
+  if (tp)
+    *tp = tv->tv_sec + offset;
+
+  return tv->tv_sec + offset;
+}
+
+int test_expiration(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_record_t **result;
+  char const *domain = "example.com";
+
+  BEGIN();
+
+  offset = 3600;		/* Time suddenly proceeds by an hour.. */
+
+  sres_resolver_timer(res, -1);
+
+  result = sres_cached_answers(res, sres_qtype_any, domain);
+
+  TEST_P(result, NULL);  /* the cache should be empty after 15 secs */
+
+  END();
+}
+
+#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
+#define hex(c) ((c >= '0' && c <= '9') ? (c - '0') : (c - 'a' + 10))
+
+/* Convert lowercase hex to binary */
+static
+void *hex2bin(char const *test_name,
+	      char const *hex1, char const *hex2, unsigned *binsize)
+{
+  char output[2048];
+  char *bin;
+  char const *b;
+  int j;
+
+  if (hex1 == NULL || binsize == NULL)
+    return NULL;
+
+  for (b = hex1, j = 0; b;) {
+    while (b[0]) {
+      if (is_hexdigit(b[0])) {
+	if (!is_hexdigit(b[1])) {
+	  fprintf(stderr, "%s: hex2bin: invalid hex '%c'\n", test_name, b[1]);
+	  exit(2);
+	}
+
+	output[j++] = (hex(b[0]) << 4) | hex(b[1]);
+	if (j == sizeof(output)) {
+	  fprintf(stderr, "%s:%u: hex2bin: buffer too small\n",
+		  __FILE__, __LINE__);
+	  exit(2);
+	}
+	b++;
+      } else if (b[0] != ' ') {
+	fprintf(stderr, "%s: hex2bin: invalid nonhex '%c'\n", test_name,
+		b[0]);
+	exit(2);
+      }
+      b++;
+    }
+    b = hex2, hex2 = NULL;
+  }
+
+  bin = malloc(j);
+  if (bin == NULL)
+    perror("malloc"), exit(2);
+
+  return memcpy(bin, output, *binsize = j);
+}
+
+static char const hextest[] =
+  "                        34 44 85 80 00 01 00 04 "
+  "00 01 00 08 07 65 78 61 6d 70 6c 65 03 63 6f 6d "
+  "00 00 23 00 01 c0 0c 00 23 00 01 00 00 00 3c 00 "
+  "26 00 28 00 0f 01 73 07 53 49 50 2b 44 32 55 00 "
+  "04 5f 73 69 70 04 5f 75 64 70 07 65 78 61 6d 70 "
+  "6c 65 03 63 6f 6d 00 c0 42 00 23 00 01 00 00 00 "
+  "3c 00 3e 00 32 00 0f 01 75 08 54 45 53 54 2b 44 "
+  "32 55 2d 2f 28 74 73 74 3a 28 5b 5e 40 5d 2b 40 "
+  "29 29 3f 65 78 61 6d 70 6c 65 2e 63 6f 6d 24 2f "
+  "5c 31 6f 70 65 72 61 74 6f 72 2e 63 6f 6d 2f 69 "
+  "00 c0 42 00 23 00 01 00 00 00 3c 00 26 00 50 00 "
+  "19 01 73 07 53 49 50 2b 44 32 54 00 04 5f 73 69 "
+  "70 04 5f 74 63 70 07 65 78 61 6d 70 6c 65 03 63 "
+  "6f 6d 00 c0 be 00 23 00 01 00 00 00 3c 00 28 00 "
+  "14 00 32 01 73 08 53 49 50 53 2b 44 32 54 00 05 "
+  "5f 73 69 70 73 04 5f 74 63 70 07 65 78 61 6d 70 "
+  "6c 65 03 63 6f 6d 00 c0 f2 00 02 00 01 00 00 00 "
+  "3c 00 05 02 6e 73 c0 f2 05 73 69 70 30 30 c0 f2 "
+  "00 01 00 01 00 00 00 3c 00 04 c2 02 bc 85 c1 10 "
+  "00 1c 00 01 00 00 00 3c 00 10 3f f0 00 10 30 12 "
+  "c0 00 02 c0 95 ff fe e2 4b 78 05 73 69 70 30 32 "
+  "c0 f2 00 01 00 01 00 00 00 3c 00 04 c2 02 bc 87 "
+  "c1 42 00 1c 00 01 00 00 00 3c 00 10 3f fe 12 00 "
+  "30 12 c0 06 02 06 5b ff fe 55 46 2f 05 73 69 70 "
+  "30 31 c0 f2 00 01 00 01 00 00 00 3c 00 04 c2 02 "
+  "bc 86 c1 74 00 1c 00 01 00 00 00 3c 00 10 3f f0 "
+  "00 12 30 12 c0 06 0a 08 20 ff fe 7d e7 ac c1 0b "
+  "00 01 00 01 00 00 00 3c 00 04 c2 02 bc 85 c1 0b "
+  "00 26 00 01 00 00 00 3c 00 11 00 3f fe 12 00 30 "
+  "12 c0 00 02 10 a4 ff fe 8d 6a 46 ";
+
+int test_net(sres_context_t *ctx)
+{
+  sres_resolver_t *res = ctx->resolver;
+  sres_query_t *q = NULL;
+  int c = ctx->sink;
+  struct sockaddr_storage ss[1];
+  struct sockaddr *sa = (void *)ss;
+  socklen_t salen = sizeof ss, binlen;
+  char *bin;
+  int i, n;
+  char const *domain = "example.com";
+  char query[512];
+
+  BEGIN();
+
+  TEST_1(ctx->sink != -1 && ctx->sink != 0);
+
+  /* Prepare for test_answer() callback */
+  sres_free_answers(ctx->resolver, ctx->result); 
+  ctx->result = NULL;
+  ctx->query = NULL; 
+
+  /* Get canned response */
+  TEST_1(bin = hex2bin(__func__, hextest, NULL, &binlen));
+
+  /* Send responses with one erroneus byte */
+  for (i = 1; i < (int)binlen; i++) {
+    if (!q) {
+      /* We got an error => make new query */
+      TEST_1(q = sres_query(res, test_answer, ctx, /* Send query */
+				 sres_type_naptr, domain));
+      TEST_1((n = recvfrom(c, query, sizeof query, 0, sa, &salen)) != -1);
+      memcpy(bin, query, 2); /* Copy ID */
+    }
+    if (i != 1)
+      bin[i] ^= 0xff;
+    else
+      bin[3] ^= SRES_FORMAT_ERR; /* format error -> EDNS0 failure */
+    n = sendto(c, bin, binlen, 0, sa, salen);
+    if (i != 1)
+      bin[i] ^= 0xff;
+    else
+      bin[3] ^= SRES_FORMAT_ERR;
+    if (n == -1)
+      perror("sendto");
+
+    while (!poll_sockets(ctx))
+      ;
+
+    if (ctx->query)
+      q = NULL;
+  }
+
+  /* Send runt responses */
+  for (i = 1; i <= (int)binlen; i++) {
+    if (!q) {
+      /* We got an error => make new query */
+      TEST_1(q = sres_query(res, test_answer, ctx, /* Send query */
+				 sres_type_naptr, domain));
+      TEST_1((n = recvfrom(c, query, sizeof query, 0, sa, &salen)) != -1);
+      memcpy(bin, query, 2); /* Copy ID */
+    }
+    n = sendto(c, bin, i, 0, sa, salen);
+    if (n == -1)
+      perror("sendto");
+    while (!poll_sockets(ctx))
+      ;
+
+    if (ctx->query)
+      q = NULL;
+  }
+
+  free(bin);
+
+  END();
+}
+
+
+/* Test API function argument validation */
+static
+int test_api_errors(sres_context_t *noctx)
+{
+  sres_context_t ctx[1];
+  sres_resolver_t *res;
+  int s, fd;
+  int sockets[20];
+  struct sockaddr sa[1] = {{ 0 }};
+  char *template = NULL;
+  FILE *f;
+
+  BEGIN();
+
+  memset(ctx, 0, sizeof ctx);
+
+  template = su_sprintf(ctx->home, ".test_sresolv_api.conf.XXXXXX");
+  TEST_1(template);
+  
+  TEST_1(res = sres_resolver_new(NULL));
+  TEST(su_home_threadsafe((su_home_t *)res), 0);
+  TEST_VOID(sres_resolver_unref(res));
+
+#ifndef _WIN32
+  fd = mkstemp(template); TEST_1(fd != -1);
+#else
+  fd = open(template, O_WRONLY); TEST_1(fd != -1);
+#endif  
+
+  f = fdopen(fd, "w"); TEST_1(f);
+  fprintf(f, "domain example.com\n");
+  fclose(f);
+
+  /* Test also LOCALDOMAIN handling */
+  putenv("LOCALDOMAIN=localdomain");
+
+  TEST_1(res = sres_resolver_new(template));
+  TEST(su_home_threadsafe((su_home_t *)res), 0);
+
+  unlink(template);
+  
+  s = sockets[0];
+  
+  TEST_P(sres_resolver_ref(NULL), NULL);
+  TEST(errno, EFAULT);
+  sres_resolver_unref(NULL);
+
+  TEST_P(sres_resolver_set_userdata(NULL, NULL), NULL);
+  TEST(errno, EFAULT);
+
+  TEST_P(sres_resolver_get_userdata(NULL), NULL);
+
+  TEST_P(sres_resolver_get_userdata(res), NULL);
+  TEST_P(sres_resolver_set_userdata(res, sa), NULL);
+  TEST_P(sres_resolver_get_userdata(res), sa);
+  TEST_P(sres_resolver_set_userdata(res, NULL), sa); 
+  TEST_P(sres_resolver_get_userdata(res), NULL);
+
+  errno = 0;
+  TEST_P(sres_query(NULL, test_answer, ctx, sres_type_a, "com"), NULL);
+  TEST(errno, EFAULT); errno = 0;
+  TEST_P(sres_query(res, test_answer, ctx, sres_type_a, NULL), NULL);
+  TEST(errno, EFAULT); errno = 0;
+  TEST_P(sres_query_sockaddr(res, test_answer, ctx,
+			     sres_qtype_any, sa), NULL);
+#if defined(EAFNOSUPPORT)
+  TEST(errno, EAFNOSUPPORT); errno = 0;
+#endif
+
+  TEST_P(sres_cached_answers(NULL, sres_qtype_any, "example.com"), NULL);
+  TEST(errno, EFAULT); errno = 0;
+  TEST_P(sres_cached_answers(res, sres_qtype_any, NULL), NULL);
+  TEST(errno, EFAULT); errno = 0;
+  TEST_P(sres_cached_answers(res, sres_qtype_any, name2048), NULL);
+  TEST(errno, ENAMETOOLONG); errno = 0;
+  TEST_P(sres_cached_answers_sockaddr(res, sres_qtype_any, sa), NULL);
+  TEST(errno, EAFNOSUPPORT); errno = 0;
+
+  sres_free_answer(res, NULL);
+  sres_free_answers(res, NULL);
+  sres_sort_answers(res, NULL);
+
+  sres_free_answer(NULL, NULL);
+  sres_free_answers(NULL, NULL);
+  sres_sort_answers(NULL, NULL);
+
+  sres_resolver_unref(res);
+  
+  END();
+}
+
+
+static
+int test_init(sres_context_t *ctx, char const *conf_file)
+{
+  BEGIN();
+
+  sres_resolver_t *res;
+  int i, n;
+
+  ctx->query = NULL, ctx->result = NULL;
+
+  TEST_1(ctx->resolver = res = sres_resolver_new(conf_file));
+  TEST(su_home_threadsafe((su_home_t *)ctx->resolver), 0);
+  n = sres_resolver_sockets(res, NULL, 0);
+  ctx->n_sockets = n;
+  TEST_1(n < SRES_MAX_NAMESERVERS);
+  TEST(sres_resolver_sockets(res, ctx->sockets, n), n);
+  
+  for (i = 0; i < n; i++) {
+    ctx->fds[i].fd = ctx->sockets[i];
+    ctx->fds[i].events = POLLIN | POLLERR;
+  }
+  
+  TEST_P(sres_resolver_ref(ctx->resolver), ctx->resolver);
+  sres_resolver_unref(ctx->resolver);
+
+  END();
+}
+
+static
+int test_deinit(sres_context_t *ctx)
+{
+  offset += 2 * 36000000;
+
+  sres_resolver_timer(ctx->resolver, -1); /* Zap everything */
+
+  sres_free_answers(ctx->resolver, ctx->result); ctx->result = NULL;
+
+  su_free(ctx->home, (void *)ctx->sinkconf); ctx->sinkconf = NULL;
+
+  sres_resolver_unref(ctx->resolver); ctx->resolver = NULL;
+
+  offset = 0;
+  memset(ctx, 0, sizeof ctx);
+  ctx->home->suh_size = sizeof ctx;
+  
+  return 0;
+}
+
+static
+int test_conf_errors(sres_context_t *ctx, char const *conf_file)
+{
+  sres_resolver_t *res;
+  sres_socket_t socket;
+  int n;
+
+  BEGIN();
+
+  TEST_1(res = sres_resolver_new(conf_file));
+  n = sres_resolver_sockets(res, NULL, 0);
+  TEST_1(n > 0);
+    
+  TEST(sres_resolver_sockets(res, &socket, 1), n);
+
+#if HAVE_SA_LEN			
+  /* We fail this test in BSD systems */
+  /* conf_file looks like this:
+--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--
+nameserver 0.0.0.2
+nameserver 1.1.1.1.1
+search example.com
+port $port
+-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8--
+  */
+  printf("%s:%u: %s test should be updated\n", 
+	 __FILE__, __LINE__, __func__);
+#else
+  TEST_P(sres_query(res, test_answer, ctx, sres_type_a, "example.com"), NULL);
+#endif
+    
+  sres_resolver_unref(res);
+
+  END();
+}
+
+void
+fill_stack(void)
+{
+  int i,array[32768];
+
+  for (i = 0; i < 32768; i++)
+    array[i] = i ^ 0xdeadbeef;
+}
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+#endif
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v] [-l level] [-] [conf-file] [error-conf-file]\n", 
+	  name);
+}
+
+#include <sofia-sip/su_log.h>
+
+extern su_log_t sresolv_log[];
+
+int main(int argc, char **argv)
+{
+  int i;
+  int error = 0;
+  int o_attach = 0, o_alarm = 1;
+  sres_context_t ctx[1] = {{{SU_HOME_INIT(ctx)}}};
+
+  for (i = 1; argv[i]; i++) {
+    if (argv[i][0] != '-')
+      break;
+    else if (strcmp(argv[i], "-") == 0) {
+      i++; break;
+    }
+    else if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "--no-alarm") == 0) {
+      o_alarm = 0;
+    }
+    else if (strcmp(argv[i], "--attach") == 0) {
+      o_attach = 1;
+    }
+    else if (strncmp(argv[i], "-l", 2) == 0) {
+      int level = 3;
+      char *rest = NULL;
+
+      if (argv[i][2])
+	level = strtol(argv[i] + 2, &rest, 10);
+      else if (argv[i + 1])
+	level = strtol(argv[i + 1], &rest, 10), i++;
+      else
+	level = 3, rest = "";
+
+      if (rest == NULL || *rest)
+	usage();
+      
+      su_log_set_level(sresolv_log, level);
+    } else
+      usage();
+  }
+
+  if (o_attach) {
+    char buf[8];
+
+    fprintf(stderr, "test_sresolv: started with pid %u"
+	    " (press enter to continue)\n", getpid());
+
+    fgets(buf, sizeof buf, stdin);
+  }
+#if HAVE_ALARM
+  else if (o_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm); 
+  }
+#endif
+
+  if (!(TSTFLAGS & tst_verbatim)) {
+    su_log_soft_set_level(sresolv_log, 0);
+  }
+
+#if 0
+  if (sink_make(ctx) == 0)
+  {
+    error |= test_init(ctx, ctx->sinkconf);
+    error |= sink_init(ctx);
+    error |= test_net(ctx);
+    error |= test_timeout(ctx);
+    error |= sink_deinit(ctx);
+    error |= test_deinit(ctx);
+  }
+#endif
+
+  offset = 0;
+
+  if (argv[i]) {
+    /* These tests are run with (local) nameserver,
+     */
+    int initerror = test_init(ctx, argv[i]);
+    if (!initerror) { 
+      error |= test_a(ctx);
+      error |= test_soa(ctx);
+      error |= test_naptr(ctx);
+#if HAVE_SIN6
+      error |= test_a6(ctx);
+      error |= test_a6_prefix(ctx);
+      error |= test_aaaa(ctx);
+#endif
+      error |= test_srv(ctx);
+      error |= test_cname(ctx);
+      error |= test_ptr_ipv4(ctx);
+      error |= test_ptr_ipv4_sockaddr(ctx);
+#if HAVE_SIN6
+      error |= test_ptr_ipv6(ctx);
+      error |= test_ptr_ipv6_sockaddr(ctx);
+#endif
+      error |= test_cache(ctx);
+#if HAVE_SIN6
+      error |= test_query_one_type(ctx);
+#endif
+      error |= test_expiration(ctx);
+    }
+    error |= test_deinit(ctx) | initerror;
+
+    if (argv[i + 1]) {
+      error |= test_conf_errors(ctx, argv[i + 1]);
+    }
+  }
+
+  error |= test_api_errors(ctx);
+
+  return error;
+}
+
+
+#else /* HAVE_POLL */
+
+int main(int argc, char **argv)
+{
+  printf("*** Test not supported without POLL API ***\n");
+  return 0;
+}
+#endif /* HAVE_POLL */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,244 @@
+2006-07-11  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip/stun_common.h: New defines for STUN attributes defined
+	in RFC3489bis. Some old defines have been deprecated, but are still
+	supported in the API.
+
+2006-05-22  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am: Install the stunc tool.
+
+2006-05-07  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip/stun.h: Added new NAT types stun_nattype_t. The
+	naming is now compliant with the terms used by IETF BEHAVE 
+	documents.
+
+2006-05-06  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip/stun.h (stun_nattype_str): Added a new function to the
+	public API.
+	
+	* sofia-sip/stun.h (stun_nattype): Modified the function signature.
+
+	* sofia-sip/stun.h (stun_state_t): Moved all request-specific states
+	to private stun_req_state_t struct in stun.c.
+
+2006-05-05  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip/stun.h, stun.c: Removed various deprecated functions
+	that were already commented out from the code. Closed sf.net
+	bug #1456403.
+
+2006-03-27  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* stun.h: Added stun_server_address().
+
+	* stun.h: Added stun_dns_lookup*() interface.
+
+	* stun.h: Renamed get_nattype to test_nattype and
+	get_lifetime to test_lifetime. Removed deprecated
+	wrappers.
+
+	* stun.h: Deprecated stun_handle_release().
+
+2006-01-26  Martti Mela  <martti.mela at nokia.com>
+
+	* STUN: initial keepalive dispatcher
+
+	M ./libsofia-sip-ua/stun/stun.c -28 +149
+	M ./libsofia-sip-ua/stun/stun.h +9
+	M ./libsofia-sip-ua/stun/stun_tag.c +16
+	M ./libsofia-sip-ua/stun/stun_tag.h +6
+	M ./libsofia-sip-ua/stun/stunc.c +6
+
+2006-02-09  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* stun_tag.h: Added STUN_DOMAIN() and STUN_REQUIRE_INTEGRITY(). 
+	Deprecated STUN_INTEGRITY.
+
+	* stun.c: Mark wait entries as deregistered after
+	su_root_deregister().
+
+2006-01-26  Martti Mela  <martti.mela at nokia.com>
+
+	* STUN: initial keepalive dispatcher
+
+	M ./libsofia-sip-ua/stun/stun.c -28 +149
+	M ./libsofia-sip-ua/stun/stun.h +9
+	M ./libsofia-sip-ua/stun/stun_tag.c +16
+	M ./libsofia-sip-ua/stun/stun_tag.h +6
+	M ./libsofia-sip-ua/stun/stunc.c +6
+
+2006-01-19  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: assign_socket() now takes care of socket registering and
+	binding operations
+
+2006-01-17  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: tls callback now fails if connect() fails. Random
+	cleanup.
+
+2006-01-15  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: bug fixes in get NAT type.
+
+	* stun.h: changed request_get_localinfo() to
+	discovery_get_address()
+
+	* stunc.c: debugging info cleanup
+
+	* stun_common.c, stun_common.h: cleanup + SU_DEBUG is now
+	determined from stun_internal.h
+
+	* stun_internal.h: included stun_common.h
+
+	* torture_stun.c: updated get_localinfo() to get_address()
+	
+2006-01-13  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: actions are now very separate from each other. Bug fixes.
+
+	* stun.h: added some new error states
+
+	* stunc.c: passing STUN_SOCKET() for each of the actions.
+
+2006-01-11  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: Fixed bug in timing problem in get_lifetime. Added
+	stun_message_length() and stun_handle_process_message() for
+	glueing into TPORT.
+
+	* stunc.c: Removed unnecessary su_root_break()s.
+	
+2006-01-10  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: First working version of get_lifetime functionality. All
+	stun_requests are now destroyed automatically by their timers if
+	the request's state is marked as "stun_dispose_me".
+
+	* stun.h: Updated stun_lifetime() API, moved discovery type enums
+	here from stun.c.
+
+2006-01-05  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: Finished get_nattype functionality. Might
+	work. Different stun actions are now kept in stun_discovery_t struct.
+
+	* stun.h: Updated event to support nattype discovery; get_nattype
+	definition, too.
+
+	* stunc.c: Support for discovery events
+
+	* torture_stun.c: stun_states_t -> stun_state_t
+
+2006-01-04  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: Functionality changed to support transactions; initial
+	support for NAT type discovery
+
+	* stun.h: API changed to support transactions
+
+	* stun_internal.h: API changed to support transactions
+
+	* stun_tag.[ch]: added tag STUNTAG_ACTION for different actions
+	(lifetime, NAT type, bind, keepalive)
+
+	* stunc.c: enabled get_nattype
+
+	* torture_stun.c: changed to support new API
+
+	*stun_common.h: removed NAT type strings to stun.c.
+
+2005-12-19  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: fixed TLS and bind timers.
+
+	* stun_common.c: changed every SU_DEBUG to contain __func__.
+
+2005-12-19  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.c: TLS connection works now.
+
+	* stun.h: removed stun_socket_t references, replaced by
+	stun_handle functionality.
+
+	* stunc.c, torture_stun.c: modified in accordance to stun.h.
+	
+2005-12-16  Martti Mela  <martti.mela at nokia.com>
+
+	* stun.h: changed stun_engine_t to stun_handle_t.
+
+	* stun.c: STUN handle is now created independently of
+	stun_connect_start(). Callback events have now string
+	representation, too.
+
+	* stunc.c, torture_stun.c: behave now in conformance to stun.h
+	
+2005-12-15  Martti Mela  <martti.mela at nokia.com>
+
+	* STUN updated to work asynchronously.
+
+	* stun.c: added timeout timer for connect() (defaults to 8 seconds).
+
+	* stun_internal.h: added.
+
+	* stun.h: Does not contain functions that are interal. Cleaned the API. Specified
+	more states for stun_states_t.
+
+2005-11-19  Kai Vehmanen  <kaiv at .devtag.AUTHORS>
+
+	* stun.h (stun_set_uname_pwd): Changed from unsigned to signed 
+	char pointers for passing username and password.
+
+2005-11-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* stun.c: Print the error state code if discovery
+	process fails.
+	* stunc.c (stun_bind_test): The fd_set was not
+	properly reseted between calls to select().
+
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Always building stun tags.
+
+    M ./libsofia-sip-ua/stun/Makefile.am -3 +3
+
+2005-10-24  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* stun.c: Fixed stun_bind() behaviour when STUN 
+	discovery fails. Added enum for tracking client
+	state.
+
+2005-10-18  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Checking that we have got valid server address as parameter.
+
+    M ./libsofia-sip-ua/stun/stun.c -6 +14
+
+  * Added stun_is_requested().
+
+    M ./libsofia-sip-ua/stun/stun.c +22
+    M ./libsofia-sip-ua/stun/stun.h +2
+
+  * Added tagged call stun_engine_tcreate().
+
+    M ./libsofia-sip-ua/stun/Makefile.am -10 +7
+    M ./libsofia-sip-ua/stun/stun.c -7 +44
+    M ./libsofia-sip-ua/stun/stun.h +7
+    A ./libsofia-sip-ua/stun/stun_tag.c
+    A ./libsofia-sip-ua/stun/stun_tag.h
+
+2005-10-13  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* stun_common.h, stun.h: Updated inline docs to use
+	the doxygen syntax.
+
+	* stun_common.c: Fixed memory leaks.
+
+	* stun.c (stun_engine_create): Add hostname resolving.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+PROJECT_NAME         = "stun"
+OUTPUT_DIRECTORY     = ../docs/html/stun
+
+INPUT 		     = stun.docs sofia-sip .
+
+ at INCLUDE 	     = ../docs/Doxyfile.conf
+
+TAGFILES            += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE     = ../docs/stun.doxytags

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+#
+# Makefile.am @template@ for stun module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# General options
+
+AUTOMAKE_OPTIONS = 	foreign
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		$(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+stun_lib_sources = 	stun.c stun_common.c stun_dns.c stun_mini.c
+
+noinst_LTLIBRARIES = 	libstun.la
+
+bin_PROGRAMS    =       stunc
+check_PROGRAMS = 	lookup_stun_server
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/stun.h sofia-sip/stun_common.h \
+			sofia-sip/stun_tag.h
+libstun_la_SOURCES = 	$(stun_lib_sources) \
+			stun_tag.c stun_tag_ref.c stun_internal.h
+
+BUILT_SOURCES =		stun_tag_ref.c
+
+COVERAGE_INPUT = 	$(libstun_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD =			\
+			libstun.la
+			../sresolv/libsresolv.la \
+			../su/libsu.la
+
+stunc_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+lookup_stun_server_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+# ----------------------------------------------------------------------
+# tests
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile stun.docs cert.pem key.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS =		LIST=stun_tag_list

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,679 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for stun module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# General options
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libstun_la_SOURCES) lookup_stun_server.c stunc.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = stunc$(EXEEXT)
+check_PROGRAMS = lookup_stun_server$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/stun
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libstun_la_LIBADD =
+am__objects_1 = stun.lo stun_common.lo stun_dns.lo stun_mini.lo
+am_libstun_la_OBJECTS = $(am__objects_1) stun_tag.lo stun_tag_ref.lo
+libstun_la_OBJECTS = $(am_libstun_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" \
+	"$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+lookup_stun_server_SOURCES = lookup_stun_server.c
+lookup_stun_server_OBJECTS = lookup_stun_server.$(OBJEXT)
+lookup_stun_server_DEPENDENCIES = libstun.la ../sresolv/libsresolv.la \
+	../su/libsu.la
+stunc_SOURCES = stunc.c
+stunc_OBJECTS = stunc.$(OBJEXT)
+stunc_DEPENDENCIES = libstun.la ../sresolv/libsresolv.la \
+	../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libstun_la_SOURCES) lookup_stun_server.c stunc.c
+DIST_SOURCES = $(libstun_la_SOURCES) lookup_stun_server.c stunc.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AUTOMAKE_OPTIONS = foreign
+
+# ----------------------------------------------------------------------
+# Header paths
+INCLUDES = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+stun_lib_sources = stun.c stun_common.c stun_dns.c stun_mini.c
+noinst_LTLIBRARIES = libstun.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+			sofia-sip/stun.h sofia-sip/stun_common.h \
+			sofia-sip/stun_tag.h
+
+libstun_la_SOURCES = $(stun_lib_sources) \
+			stun_tag.c stun_tag_ref.c stun_internal.h
+
+BUILT_SOURCES = stun_tag_ref.c
+COVERAGE_INPUT = $(libstun_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = \
+			libstun.la
+
+stunc_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+lookup_stun_server_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+# ----------------------------------------------------------------------
+# tests
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile stun.docs cert.pem key.pem
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+TAG_DLL_FLAGS = LIST=stun_tag_list
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  libsofia-sip-ua/stun/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  libsofia-sip-ua/stun/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libstun.la: $(libstun_la_OBJECTS) $(libstun_la_DEPENDENCIES) 
+	$(LINK)  $(libstun_la_LDFLAGS) $(libstun_la_OBJECTS) $(libstun_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	     || test -f $$p1 \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+lookup_stun_server$(EXEEXT): $(lookup_stun_server_OBJECTS) $(lookup_stun_server_DEPENDENCIES) 
+	@rm -f lookup_stun_server$(EXEEXT)
+	$(LINK) $(lookup_stun_server_LDFLAGS) $(lookup_stun_server_OBJECTS) $(lookup_stun_server_LDADD) $(LIBS)
+stunc$(EXEEXT): $(stunc_OBJECTS) $(stunc_DEPENDENCIES) 
+	@rm -f stunc$(EXEEXT)
+	$(LINK) $(stunc_LDFLAGS) $(stunc_OBJECTS) $(stunc_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/lookup_stun_server.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_dns.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_mini.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stunc.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binPROGRAMS install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-binPROGRAMS \
+	uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+			../sresolv/libsresolv.la \
+			../su/libsu.la
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD
+VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv
+bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy
+dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X
+DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw
+EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l
+dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT
+EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp
+MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw
+L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN
+BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX
+9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4=
+-----END CERTIFICATE-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNwL4lYKbpzzlmC5beaQXeQ
+2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAAQJBALjkK+jc2+iihI98riEF
+oudmkNziSRTYjnwjx8mCoAjPWviB3c742eO3FG4/soi1jD9A5alihEOXfUzloenr
+8IECIQD3B5+0l+68BA/6d76iUNqAAV8djGTzvxnCxycnxPQydQIhAMXt4trUI3nc
+a+U8YL2HPFA3gmhBsSICbq2OptOCnM7hAiEA6Xi3JIQECob8YwkRj29DU3/4WYD7
+WLPgsQpwo1GuSpECICGsnWH5oaeD9t9jbFoSfhJvv0IZmxdcLpRcpslpeWBBAiEA
+6/5B8J0GHdJq89FHwEG/H2eVVUYu5y/aD6sgcm+0Avg=
+-----END RSA PRIVATE KEY-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file lookup_stun_server.c 
+ * @brief Test app for STUN DNS-SRV lookups.
+ *
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @todo TODO
+ * - picks one UDP and TLS target:port
+ * - does not pick up A/AAAA records that might be delivered
+ *   in 'Additional Data' section as defined in RFC2782
+ */
+
+#include <stdio.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_wait.h>
+#define STUN_MAGIC_T su_root_t
+#include <sofia-sip/stun.h>
+
+static char* g_domain = NULL;
+
+static void lookup_cb(stun_dns_lookup_t *self,
+		      su_root_t *root)
+{
+# define RESULT(x) (x == 0 ? "OK" : "ERRORS")
+
+  const char *tcp_target = NULL, *udp_target = NULL, *stp_target = NULL;
+  uint16_t tcp_port = 0, udp_port = 0, stp_port = 0;
+  int res = 0;
+
+  printf("STUN DNS-SRV lookup results:\n"); 
+
+  res = stun_dns_lookup_udp_addr(self, &udp_target, &udp_port);
+  printf(" _stun._udp.%s:     %s:%u (%s).\n", g_domain, udp_target, udp_port, RESULT(res)); 
+
+  res = stun_dns_lookup_tcp_addr(self, &tcp_target, &tcp_port);
+  printf(" _stun._tcp.%s:     %s:%u (%s).\n", g_domain, tcp_target, tcp_port, RESULT(res)); 
+
+  res = stun_dns_lookup_stp_addr(self, &stp_target, &stp_port);
+  printf(" _stun-tls._tcp.%s: %s:%u (%s).\n", g_domain, stp_target, stp_port, RESULT(res)); 
+
+  su_root_break(root);
+}
+
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  stun_dns_lookup_t *lookup;
+  
+  if (argc < 2) {
+    printf("usage: ./lookup_stun_server <domain>\n");
+    return -1;
+  }
+
+  g_domain = argv[1];
+
+  /* step: initialize sofia su OS abstraction layer */
+  su_init();
+
+  /* step: create a su event loop and connect it to glib */
+  root = su_root_create(NULL);
+
+  /* step: initiate the DNS-SRV lookup */
+  lookup = stun_dns_lookup(root, root, lookup_cb, g_domain);
+ 
+  if (lookup) {
+    /* step: enter the main loop (break fro lookup_cb()) */
+    su_root_run(root);
+
+    /* step: free any allocated resources */
+    stun_dns_lookup_destroy(lookup);
+  }
+  else {
+    printf("ERROR: failed to create lookup object.\n");
+  }
+
+  su_root_destroy(root);
+  su_deinit();
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2635 @@
+
+
+
+
+
+
+Network Working Group                                       J. Rosenberg
+Request for Comments: 3489                                 J. Weinberger
+Category: Standards Track                                    dynamicsoft
+                                                              C. Huitema
+                                                               Microsoft
+                                                                 R. Mahy
+                                                                   Cisco
+                                                              March 2003
+
+
+        STUN - Simple Traversal of User Datagram Protocol (UDP)
+               Through Network Address Translators (NATs)
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   Simple Traversal of User Datagram Protocol (UDP) Through Network
+   Address Translators (NATs) (STUN) is a lightweight protocol that
+   allows applications to discover the presence and types of NATs and
+   firewalls between them and the public Internet.  It also provides the
+   ability for applications to determine the public Internet Protocol
+   (IP) addresses allocated to them by the NAT.  STUN works with many
+   existing NATs, and does not require any special behavior from them.
+   As a result, it allows a wide variety of applications to work through
+   existing NAT infrastructure.
+
+Table of Contents
+
+   1.   Applicability Statement ...................................    3
+   2.   Introduction ..............................................    3
+   3.   Terminology ...............................................    4
+   4.   Definitions ...............................................    5
+   5.   NAT Variations ............................................    5
+   6.   Overview of Operation .....................................    6
+   7.   Message Overview ..........................................    8
+   8.   Server Behavior ...........................................   10
+        8.1   Binding Requests ....................................   10
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 1]
+
+RFC 3489                          STUN                        March 2003
+
+
+        8.2   Shared Secret Requests ..............................   13
+   9.   Client Behavior ...........................................   14
+        9.1   Discovery ...........................................   15
+        9.2   Obtaining a Shared Secret ...........................   15
+        9.3   Formulating the Binding Request .....................   17
+        9.4   Processing Binding Responses ........................   17
+   10.  Use Cases .................................................   19
+        10.1  Discovery Process ...................................   19
+        10.2  Binding Lifetime Discovery ..........................   21
+        10.3  Binding Acquisition .................................   23
+   11.  Protocol Details ..........................................   24
+        11.1  Message Header ......................................   25
+        11.2  Message Attributes ..................................   26
+              11.2.1  MAPPED-ADDRESS ..............................   27
+              11.2.2  RESPONSE-ADDRESS ............................   27
+              11.2.3  CHANGED-ADDRESS .............................   28
+              11.2.4  CHANGE-REQUEST ..............................   28
+              11.2.5  SOURCE-ADDRESS ..............................   28
+              11.2.6  USERNAME ....................................   28
+              11.2.7  PASSWORD ....................................   29
+              11.2.8  MESSAGE-INTEGRITY ...........................   29
+              11.2.9  ERROR-CODE ..................................   29
+              11.2.10 UNKNOWN-ATTRIBUTES ..........................   31
+              11.2.11 REFLECTED-FROM ..............................   31
+   12.  Security Considerations ...................................   31
+        12.1  Attacks on STUN .....................................   31
+              12.1.1  Attack I: DDOS Against a Target .............   32
+              12.1.2  Attack II: Silencing a Client ...............   32
+              12.1.3  Attack III: Assuming the Identity of a Client   32
+              12.1.4  Attack IV: Eavesdropping ....................   33
+        12.2  Launching the Attacks ...............................   33
+              12.2.1  Approach I: Compromise a Legitimate
+                      STUN Server .................................   33
+              12.2.2  Approach II: DNS Attacks ....................   34
+              12.2.3  Approach III: Rogue Router or NAT ...........   34
+              12.2.4  Approach IV: MITM ...........................   35
+              12.2.5  Approach V: Response Injection Plus DoS .....   35
+              12.2.6  Approach VI: Duplication ....................   35
+        12.3  Countermeasures .....................................   36
+        12.4  Residual Threats ....................................   37
+   13.  IANA Considerations .......................................   38
+   14.  IAB Considerations ........................................   38
+        14.1  Problem Definition ..................................   38
+        14.2  Exit Strategy .......................................   39
+        14.3  Brittleness Introduced by STUN ......................   40
+        14.4  Requirements for a Long Term Solution ...............   42
+        14.5  Issues with Existing NAPT Boxes .....................   43
+        14.6  In Closing ..........................................   43
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 2]
+
+RFC 3489                          STUN                        March 2003
+
+
+   15.  Acknowledgments ...........................................   44
+   16.  Normative References ......................................   44
+   17.  Informative References ....................................   44
+   18.  Authors' Addresses ........................................   46
+   19.  Full Copyright Statement...................................   47
+
+1.  Applicability Statement
+
+   This protocol is not a cure-all for the problems associated with NAT.
+   It does not enable incoming TCP connections through NAT.  It allows
+   incoming UDP packets through NAT, but only through a subset of
+   existing NAT types.  In particular, STUN does not enable incoming UDP
+   packets through symmetric NATs (defined below), which are common in
+   large enterprises.  STUN's discovery procedures are based on
+   assumptions on NAT treatment of UDP; such assumptions may prove
+   invalid down the road as new NAT devices are deployed.  STUN does not
+   work when it is used to obtain an address to communicate with a peer
+   which happens to be behind the same NAT.  STUN does not work when the
+   STUN server is not in a common shared address realm.  For a more
+   complete discussion of the limitations of STUN, see Section 14.
+
+2.  Introduction
+
+   Network Address Translators (NATs), while providing many benefits,
+   also come with many drawbacks.  The most troublesome of those
+   drawbacks is the fact that they break many existing IP applications,
+   and make it difficult to deploy new ones.  Guidelines have been
+   developed [8] that describe how to build "NAT friendly" protocols,
+   but many protocols simply cannot be constructed according to those
+   guidelines.  Examples of such protocols include almost all peer-to-
+   peer protocols, such as multimedia communications, file sharing and
+   games.
+
+   To combat this problem, Application Layer Gateways (ALGs) have been
+   embedded in NATs.  ALGs perform the application layer functions
+   required for a particular protocol to traverse a NAT.  Typically,
+   this involves rewriting application layer messages to contain
+   translated addresses, rather than the ones inserted by the sender of
+   the message.  ALGs have serious limitations, including scalability,
+   reliability, and speed of deploying new applications.  To resolve
+   these problems, the Middlebox Communications (MIDCOM) protocol is
+   being developed [9].  MIDCOM allows an application entity, such as an
+   end client or network server of some sort (like a Session Initiation
+   Protocol (SIP) proxy [10]) to control a NAT (or firewall), in order
+   to obtain NAT bindings and open or close pinholes.  In this way, NATs
+   and applications can be separated once more, eliminating the need for
+   embedding ALGs in NATs, and resolving the limitations imposed by
+   current architectures.
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 3]
+
+RFC 3489                          STUN                        March 2003
+
+
+   Unfortunately, MIDCOM requires upgrades to existing NAT and
+   firewalls, in addition to application components.  Complete upgrades
+   of these NAT and firewall products will take a long time, potentially
+   years.  This is due, in part, to the fact that the deployers of NAT
+   and firewalls are not the same people who are deploying and using
+   applications.  As a result, the incentive to upgrade these devices
+   will be low in many cases.  Consider, for example, an airport
+   Internet lounge that provides access with a NAT.  A user connecting
+   to the NATed network may wish to use a peer-to-peer service, but
+   cannot, because the NAT doesn't support it.  Since the administrators
+   of the lounge are not the ones providing the service, they are not
+   motivated to upgrade their NAT equipment to support it, using either
+   an ALG, or MIDCOM.
+
+   Another problem is that the MIDCOM protocol requires that the agent
+   controlling the middleboxes know the identity of those middleboxes,
+   and have a relationship with them which permits control.  In many
+   configurations, this will not be possible.  For example, many cable
+   access providers use NAT in front of their entire access network.
+   This NAT could be in addition to a residential NAT purchased and
+   operated by the end user.  The end user will probably not have a
+   control relationship with the NAT in the cable access network, and
+   may not even know of its existence.
+
+   Many existing proprietary protocols, such as those for online games
+   (such as the games described in RFC 3027 [11]) and Voice over IP,
+   have developed tricks that allow them to operate through NATs without
+   changing those NATs.  This document is an attempt to take some of
+   those ideas, and codify them into an interoperable protocol that can
+   meet the needs of many applications.
+
+   The protocol described here, Simple Traversal of UDP Through NAT
+   (STUN), allows entities behind a NAT to first discover the presence
+   of a NAT and the type of NAT, and then to learn the addresses
+   bindings allocated by the NAT.  STUN requires no changes to NATs, and
+   works with an arbitrary number of NATs in tandem between the
+   application entity and the public Internet.
+
+3.  Terminology
+
+   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
+   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
+   and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119
+   [1] and indicate requirement levels for compliant STUN
+   implementations.
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 4]
+
+RFC 3489                          STUN                        March 2003
+
+
+4.  Definitions
+
+   STUN Client: A STUN client (also just referred to as a client)
+      is an entity that generates STUN requests.  A STUN client can
+      execute on an end system, such as a user's PC, or can run in a
+      network element, such as a conferencing server.
+
+   STUN Server: A STUN Server (also just referred to as a server)
+      is an entity that receives STUN requests, and sends STUN
+      responses.  STUN servers are generally attached to the public
+      Internet.
+
+5.  NAT Variations
+
+   It is assumed that the reader is familiar with NATs.  It has been
+   observed that NAT treatment of UDP varies among implementations.  The
+   four treatments observed in implementations are:
+
+   Full Cone: A full cone NAT is one where all requests from the
+      same internal IP address and port are mapped to the same external
+      IP address and port.  Furthermore, any external host can send a
+      packet to the internal host, by sending a packet to the mapped
+      external address.
+
+   Restricted Cone: A restricted cone NAT is one where all requests
+      from the same internal IP address and port are mapped to the same
+      external IP address and port.  Unlike a full cone NAT, an external
+      host (with IP address X) can send a packet to the internal host
+      only if the internal host had previously sent a packet to IP
+      address X.
+
+   Port Restricted Cone: A port restricted cone NAT is like a
+      restricted cone NAT, but the restriction includes port numbers.
+      Specifically, an external host can send a packet, with source IP
+      address X and source port P, to the internal host only if the
+      internal host had previously sent a packet to IP address X and
+      port P.
+
+   Symmetric: A symmetric NAT is one where all requests from the
+      same internal IP address and port, to a specific destination IP
+      address and port, are mapped to the same external IP address and
+      port.  If the same host sends a packet with the same source
+      address and port, but to a different destination, a different
+      mapping is used.  Furthermore, only the external host that
+      receives a packet can send a UDP packet back to the internal host.
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 5]
+
+RFC 3489                          STUN                        March 2003
+
+
+   Determining the type of NAT is important in many cases.  Depending on
+   what the application wants to do, it may need to take the particular
+   behavior into account.
+
+6.  Overview of Operation
+
+   This section is descriptive only.  Normative behavior is described in
+   Sections 8 and 9.
+
+                            /-----\
+                          // STUN  \\
+                         |   Server  |
+                          \\       //
+                            \-----/
+
+
+                       +--------------+             Public Internet
+       ................|     NAT 2    |.......................
+                       +--------------+
+
+
+                       +--------------+             Private NET 2
+       ................|     NAT 1    |.......................
+                       +--------------+
+
+                            /-----\
+                          // STUN  \\
+                         |   Client  |
+                          \\       //               Private NET 1
+                            \-----/
+
+                     Figure 1: STUN Configuration
+
+   The typical STUN configuration is shown in Figure 1.  A STUN client
+   is connected to private network 1.  This network connects to private
+   network 2 through NAT 1.  Private network 2 connects to the public
+   Internet through NAT 2.  The STUN server resides on the public
+   Internet.
+
+   STUN is a simple client-server protocol.  A client sends a request to
+   a server, and the server returns a response.  There are two types of
+   requests - Binding Requests, sent over UDP, and Shared Secret
+   Requests, sent over TLS [2] over TCP.  Shared Secret Requests ask the
+   server to return a temporary username and password.  This username
+   and password are used in a subsequent Binding Request and Binding
+   Response, for the purposes of authentication and message integrity.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 6]
+
+RFC 3489                          STUN                        March 2003
+
+
+   Binding requests are used to determine the bindings allocated by
+   NATs.  The client sends a Binding Request to the server, over UDP.
+   The server examines the source IP address and port of the request,
+   and copies them into a response that is sent back to the client.
+   There are some parameters in the request that allow the client to ask
+   that the response be sent elsewhere, or that the server send the
+   response from a different address and port.  There are attributes for
+   providing message integrity and authentication.
+
+   The trick is using STUN to discover the presence of NAT, and to learn
+   and use the bindings they allocate.
+
+   The STUN client is typically embedded in an application which needs
+   to obtain a public IP address and port that can be used to receive
+   data.  For example, it might need to obtain an IP address and port to
+   receive Real Time Transport Protocol (RTP) [12] traffic.  When the
+   application starts, the STUN client within the application sends a
+   STUN Shared Secret Request to its server, obtains a username and
+   password, and then sends it a Binding Request.  STUN servers can be
+   discovered through DNS SRV records [3], and it is generally assumed
+   that the client is configured with the domain to use to find the STUN
+   server.  Generally, this will be the domain of the provider of the
+   service the application is using (such a provider is incented to
+   deploy STUN servers in order to allow its customers to use its
+   application through NAT).  Of course, a client can determine the
+   address or domain name of a STUN server through other means.  A STUN
+   server can even be embedded within an end system.
+
+   The STUN Binding Request is used to discover the presence of a NAT,
+   and to discover the public IP address and port mappings generated by
+   the NAT.  Binding Requests are sent to the STUN server using UDP.
+   When a Binding Request arrives at the STUN server, it may have passed
+   through one or more NATs between the STUN client and the STUN server.
+   As a result, the source address of the request received by the server
+   will be the mapped address created by the NAT closest to the server.
+   The STUN server copies that source IP address and port into a STUN
+   Binding Response, and sends it back to the source IP address and port
+   of the STUN request.  For all of the NAT types above, this response
+   will arrive at the STUN client.
+
+   When the STUN client receives the STUN Binding Response, it compares
+   the IP address and port in the packet with the local IP address and
+   port it bound to when the request was sent.  If these do not match,
+   the STUN client is behind one or more NATs.  In the case of a full-
+   cone NAT, the IP address and port in the body of the STUN response
+   are public, and can be used by any host on the public Internet to
+   send packets to the application that sent the STUN request.  An
+   application need only listen on the IP address and port from which
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 7]
+
+RFC 3489                          STUN                        March 2003
+
+
+   the STUN request was sent. Any packets sent by a host on the public
+   Internet to the public address and port learned by STUN will be
+   received by the application.
+
+   Of course, the host may not be behind a full-cone NAT.  Indeed, it
+   doesn't yet know what type of NAT it is behind.  To determine that,
+   the client uses additional STUN Binding Requests.  The exact
+   procedure is flexible, but would generally work as follows.  The
+   client would send a second STUN Binding Request, this time to a
+   different IP address, but from the same source IP address and port.
+   If the IP address and port in the response are different from those
+   in the first response, the client knows it is behind a symmetric NAT.
+   To determine if it's behind a full-cone NAT, the client can send a
+   STUN Binding Request with flags that tell the STUN server to send a
+   response from a different IP address and port than the request was
+   received on.  In other words, if the client sent a Binding Request to
+   IP address/port A/B using a source IP address/port of X/Y, the STUN
+   server would send the Binding Response to X/Y using source IP
+   address/port C/D.  If the client receives this response, it knows it
+   is behind a full cone NAT.
+
+   STUN also allows the client to ask the server to send the Binding
+   Response from the same IP address the request was received on, but
+   with a different port.  This can be used to detect whether the client
+   is behind a port restricted cone NAT or just a restricted cone NAT.
+
+   It should be noted that the configuration in Figure 1 is not the only
+   permissible configuration.  The STUN server can be located anywhere,
+   including within another client.  The only requirement is that the
+   STUN server is reachable by the client, and if the client is trying
+   to obtain a publicly routable address, that the server reside on the
+   public Internet.
+
+7.  Message Overview
+
+   STUN messages are TLV (type-length-value) encoded using big endian
+   (network ordered) binary.  All STUN messages start with a STUN
+   header, followed by a STUN payload.  The payload is a series of STUN
+   attributes, the set of which depends on the message type.  The STUN
+   header contains a STUN message type, transaction ID, and length.  The
+   message type can be Binding Request, Binding Response, Binding Error
+   Response, Shared Secret Request, Shared Secret Response, or Shared
+   Secret Error Response.  The transaction ID is used to correlate
+   requests and responses.  The length indicates the total length of the
+   STUN payload, not including the header.  This allows STUN to run over
+   TCP.  Shared Secret Requests are always sent over TCP (indeed, using
+   TLS over TCP).
+
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 8]
+
+RFC 3489                          STUN                        March 2003
+
+
+   Several STUN attributes are defined.  The first is a MAPPED-ADDRESS
+   attribute, which is an IP address and port.  It is always placed in
+   the Binding Response, and it indicates the source IP address and port
+   the server saw in the Binding Request.  There is also a RESPONSE-
+   ADDRESS attribute, which contains an IP address and port.  The
+   RESPONSE-ADDRESS attribute can be present in the Binding Request, and
+   indicates where the Binding Response is to be sent.  It's optional,
+   and when not present, the Binding Response is sent to the source IP
+   address and port of the Binding Request.
+
+   The third attribute is the CHANGE-REQUEST attribute, and it contains
+   two flags to control the IP address and port used to send the
+   response.  These flags are called "change IP" and "change port"
+   flags.  The CHANGE-REQUEST attribute is allowed only in the Binding
+   Request.  The "change IP" and "change port" flags are useful for
+   determining whether the client is behind a restricted cone NAT or
+   restricted port cone NAT.  They instruct the server to send the
+   Binding Responses from a different source IP address and port.  The
+   CHANGE-REQUEST attribute is optional in the Binding Request.
+
+   The fourth attribute is the CHANGED-ADDRESS attribute.  It is present
+   in Binding Responses.  It informs the client of the source IP address
+   and port that would be used if the client requested the "change IP"
+   and "change port" behavior.
+
+   The fifth attribute is the SOURCE-ADDRESS attribute.  It is only
+   present in Binding Responses.  It indicates the source IP address and
+   port where the response was sent from.  It is useful for detecting
+   twice NAT configurations.
+
+   The sixth attribute is the USERNAME attribute.  It is present in a
+   Shared Secret Response, which provides the client with a temporary
+   username and password (encoded in the PASSWORD attribute).  The
+   USERNAME is also present in Binding Requests, serving as an index to
+   the shared secret used for the integrity protection of the Binding
+   Request.  The seventh attribute, PASSWORD, is only found in Shared
+   Secret Response messages.  The eight attribute is the MESSAGE-
+   INTEGRITY attribute, which contains a message integrity check over
+   the Binding Request or Binding Response.
+
+   The ninth attribute is the ERROR-CODE attribute.  This is present in
+   the Binding Error Response and Shared Secret Error Response.  It
+   indicates the error that has occurred.  The tenth attribute is the
+   UNKNOWN-ATTRIBUTES attribute, which is present in either the Binding
+   Error Response or Shared Secret Error Response.  It indicates the
+   mandatory attributes from the request which were unknown.  The
+   eleventh attribute is the REFLECTED-FROM attribute, which is present
+   in Binding Responses.  It indicates the IP address and port of the
+
+
+
+Rosenberg, et al.           Standards Track                     [Page 9]
+
+RFC 3489                          STUN                        March 2003
+
+
+   sender of a Binding Request, used for traceability purposes to
+   prevent certain denial-of-service attacks.
+
+8.  Server Behavior
+
+   The server behavior depends on whether the request is a Binding
+   Request or a Shared Secret Request.
+
+8.1  Binding Requests
+
+   A STUN server MUST be prepared to receive Binding Requests on four
+   address/port combinations - (A1, P1), (A2, P1), (A1, P2), and (A2,
+   P2).  (A1, P1) represent the primary address and port, and these are
+   the ones obtained through the client discovery procedures below.
+   Typically, P1 will be port 3478, the default STUN port.  A2 and P2
+   are arbitrary.  A2 and P2 are advertised by the server through the
+   CHANGED-ADDRESS attribute, as described below.
+
+   It is RECOMMENDED that the server check the Binding Request for a
+   MESSAGE-INTEGRITY attribute.  If not present, and the server requires
+   integrity checks on the request, it generates a Binding Error
+   Response with an ERROR-CODE attribute with response code 401.  If the
+   MESSAGE-INTEGRITY attribute was present, the server computes the HMAC
+   over the request as described in Section 11.2.8.  The key to use
+   depends on the shared secret mechanism.  If the STUN Shared Secret
+   Request was used, the key MUST be the one associated with the
+   USERNAME attribute present in the request.  If the USERNAME attribute
+   was not present, the server MUST generate a Binding Error Response.
+   The Binding Error Response MUST include an ERROR-CODE attribute with
+   response code 432.  If the USERNAME is present, but the server
+   doesn't remember the shared secret for that USERNAME (because it
+   timed out, for example), the server MUST generate a Binding Error
+   Response.  The Binding Error Response MUST include an ERROR-CODE
+   attribute with response code 430.  If the server does know the shared
+   secret, but the computed HMAC differs from the one in the request,
+   the server MUST generate a Binding Error Response with an ERROR-CODE
+   attribute with response code 431.  The Binding Error Response is sent
+   to the IP address and port the Binding Request came from, and sent
+   from the IP address and port the Binding Request was sent to.
+
+   Assuming the message integrity check passed, processing continues.
+   The server MUST check for any attributes in the request with values
+   less than or equal to 0x7fff which it does not understand.  If it
+   encounters any, the server MUST generate a Binding Error Response,
+   and it MUST include an ERROR-CODE attribute with a 420 response code.
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 10]
+
+RFC 3489                          STUN                        March 2003
+
+
+   That response MUST contain an UNKNOWN-ATTRIBUTES attribute listing
+   the attributes with values less than or equal to 0x7fff which were
+   not understood.  The Binding Error Response is sent to the IP address
+   and port the Binding Request came from, and sent from the IP address
+   and port the Binding Request was sent to.
+
+   Assuming the request was correctly formed, the server MUST generate a
+   single Binding Response.  The Binding Response MUST contain the same
+   transaction ID contained in the Binding Request.  The length in the
+   message header MUST contain the total length of the message in bytes,
+   excluding the header.  The Binding Response MUST have a message type
+   of "Binding Response".
+
+   The server MUST add a MAPPED-ADDRESS attribute to the Binding
+   Response.  The IP address component of this attribute MUST be set to
+   the source IP address observed in the Binding Request.  The port
+   component of this attribute MUST be set to the source port observed
+   in the Binding Request.
+
+   If the RESPONSE-ADDRESS attribute was absent from the Binding
+   Request, the destination address and port of the Binding Response
+   MUST be the same as the source address and port of the Binding
+   Request.  Otherwise, the destination address and port of the Binding
+   Response MUST be the value of the IP address and port in the
+   RESPONSE-ADDRESS attribute.
+
+   The source address and port of the Binding Response depend on the
+   value of the CHANGE-REQUEST attribute and on the address and port the
+   Binding Request was received on, and are summarized in Table 1.
+
+   Let Da represent the destination IP address of the Binding Request
+   (which will be either A1 or A2), and Dp represent the destination
+   port of the Binding Request (which will be either P1 or P2).  Let Ca
+   represent the other address, so that if Da is A1, Ca is A2.  If Da is
+   A2, Ca is A1.  Similarly, let Cp represent the other port, so that if
+   Dp is P1, Cp is P2.  If Dp is P2, Cp is P1.  If the "change port"
+   flag was set in CHANGE-REQUEST attribute of the Binding Request, and
+   the "change IP" flag was not set, the source IP address of the
+   Binding Response MUST be Da and the source port of the Binding
+   Response MUST be Cp.  If the "change IP" flag was set in the Binding
+   Request, and the "change port" flag was not set, the source IP
+   address of the Binding Response MUST be Ca and the source port of the
+   Binding Response MUST be Dp.  When both flags are set, the source IP
+   address of the Binding Response MUST be Ca and the source port of the
+   Binding Response MUST be Cp.  If neither flag is set, or if the
+   CHANGE-REQUEST attribute is absent entirely, the source IP address of
+   the Binding Response MUST be Da and the source port of the Binding
+   Response MUST be Dp.
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 11]
+
+RFC 3489                          STUN                        March 2003
+
+
+      Flags          Source Address  Source Port   CHANGED-ADDRESS
+      none           Da              Dp            Ca:Cp
+      Change IP      Ca              Dp            Ca:Cp
+      Change port    Da              Cp            Ca:Cp
+      Change IP and
+        Change port  Ca              Cp            Ca:Cp
+
+   Table 1: Impact of Flags on Packet Source and CHANGED-ADDRESS
+
+   The server MUST add a SOURCE-ADDRESS attribute to the Binding
+   Response, containing the source address and port used to send the
+   Binding Response.
+
+   The server MUST add a CHANGED-ADDRESS attribute to the Binding
+   Response.  This contains the source IP address and port that would be
+   used if the client had set the "change IP" and "change port" flags in
+   the Binding Request.  As summarized in Table 1, these are Ca and Cp,
+   respectively, regardless of the value of the CHANGE-REQUEST flags.
+
+   If the Binding Request contained both the USERNAME and MESSAGE-
+   INTEGRITY attributes, the server MUST add a MESSAGE-INTEGRITY
+   attribute to the Binding Response.  The attribute contains an HMAC
+   [13] over the response, as described in Section 11.2.8.  The key to
+   use depends on the shared secret mechanism.  If the STUN Shared
+   Secret Request was used, the key MUST be the one associated with the
+   USERNAME attribute present in the Binding Request.
+
+   If the Binding Request contained a RESPONSE-ADDRESS attribute, the
+   server MUST add a REFLECTED-FROM attribute to the response.  If the
+   Binding Request was authenticated using a username obtained from a
+   Shared Secret Request, the REFLECTED-FROM attribute MUST contain the
+   source IP address and port where that Shared Secret Request came
+   from.  If the username present in the request was not allocated using
+   a Shared Secret Request, the REFLECTED-FROM attribute MUST contain
+   the source address and port of the entity which obtained the
+   username, as best can be verified with the mechanism used to allocate
+   the username.  If the username was not present in the request, and
+   the server was willing to process the request, the REFLECTED-FROM
+   attribute SHOULD contain the source IP address and port where the
+   request came from.
+
+   The server SHOULD NOT retransmit the response.  Reliability is
+   achieved by having the client periodically resend the request, each
+   of which triggers a response from the server.
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 12]
+
+RFC 3489                          STUN                        March 2003
+
+
+8.2 Shared Secret Requests
+
+   Shared Secret Requests are always received on TLS connections.  When
+   the server receives a request from the client to establish a TLS
+   connection, it MUST proceed with TLS, and SHOULD present a site
+   certificate.  The TLS ciphersuite TLS_RSA_WITH_AES_128_CBC_SHA [4]
+   SHOULD be used.  Client TLS authentication MUST NOT be done, since
+   the server is not allocating any resources to clients, and the
+   computational burden can be a source of attacks.
+
+   If the server receives a Shared Secret Request, it MUST verify that
+   the request arrived on a TLS connection.  If it did not receive the
+   request over TLS, it MUST generate a Shared Secret Error Response,
+   and it MUST include an ERROR-CODE attribute with a 433 response code.
+   The destination for the error response depends on the transport on
+   which the request was received.  If the Shared Secret Request was
+   received over TCP, the Shared Secret Error Response is sent over the
+   same connection the request was received on.  If the Shared Secret
+   Request was receive over UDP, the Shared Secret Error Response is
+   sent to the source IP address and port that the request came from.
+
+   The server MUST check for any attributes in the request with values
+   less than or equal to 0x7fff which it does not understand.  If it
+   encounters any, the server MUST generate a Shared Secret Error
+   Response, and it MUST include an ERROR-CODE attribute with a 420
+   response code.  That response MUST contain an UNKNOWN-ATTRIBUTES
+   attribute listing the attributes with values less than or equal to
+   0x7fff which were not understood.  The Shared Secret Error Response
+   is sent over the TLS connection.
+
+   All Shared Secret Error Responses MUST contain the same transaction
+   ID contained in the Shared Secret Request. The length in the message
+   header MUST contain the total length of the message in bytes,
+   excluding the header.  The Shared Secret Error Response MUST have a
+   message type of "Shared Secret Error Response" (0x0112).
+
+   Assuming the request was properly constructed, the server creates a
+   Shared Secret Response.  The Shared Secret Response MUST contain the
+   same transaction ID contained in the Shared Secret Request.  The
+   length in the message header MUST contain the total length of the
+   message in bytes, excluding the header.  The Shared Secret Response
+   MUST have a message type of "Shared Secret Response".  The Shared
+   Secret Response MUST contain a USERNAME attribute and a PASSWORD
+   attribute.  The USERNAME attribute serves as an index to the
+   password, which is contained in the PASSWORD attribute.  The server
+   can use any mechanism it chooses to generate the username.  However,
+   the username MUST be valid for a period of at least 10 minutes.
+   Validity means that the server can compute the password for that
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 13]
+
+RFC 3489                          STUN                        March 2003
+
+
+   username.  There MUST be a single password for each username.  In
+   other words, the server cannot, 10 minutes later, assign a different
+   password to the same username.  The server MUST hand out a different
+   username for each distinct Shared Secret Request.  Distinct, in this
+   case, implies a different transaction ID.  It is RECOMMENDED that the
+   server explicitly invalidate the username after ten minutes.  It MUST
+   invalidate the username after 30 minutes.  The PASSWORD contains the
+   password bound to that username.  The password MUST have at least 128
+   bits.  The likelihood that the server assigns the same password for
+   two different usernames MUST be vanishingly small, and the passwords
+   MUST be unguessable.  In other words, they MUST be a
+   cryptographically random function of the username.
+
+   These requirements can still be met using a stateless server, by
+   intelligently computing the USERNAME and PASSWORD.  One approach is
+   to construct the USERNAME as:
+
+      USERNAME = <prefix,rounded-time,clientIP,hmac>
+
+   Where prefix is some random text string (different for each shared
+   secret request), rounded-time is the current time modulo 20 minutes,
+   clientIP is the source IP address where the Shared Secret Request
+   came from, and hmac is an HMAC [13] over the prefix, rounded-time,
+   and client IP, using a server private key.
+
+   The password is then computed as:
+
+      password = <hmac(USERNAME,anotherprivatekey)>
+
+   With this structure, the username itself, which will be present in
+   the Binding Request, contains the source IP address where the Shared
+   Secret Request came from.  That allows the server to meet the
+   requirements specified in Section 8.1 for constructing the
+   REFLECTED-FROM attribute.  The server can verify that the username
+   was not tampered with, using the hmac present in the username.
+
+   The Shared Secret Response is sent over the same TLS connection the
+   request was received on.  The server SHOULD keep the connection open,
+   and let the client close it.
+
+9.  Client Behavior
+
+   The behavior of the client is very straightforward.  Its task is to
+   discover the STUN server, obtain a shared secret, formulate the
+   Binding Request, handle request reliability, and process the Binding
+   Responses.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 14]
+
+RFC 3489                          STUN                        March 2003
+
+
+9.1  Discovery
+
+   Generally, the client will be configured with a domain name of the
+   provider of the STUN servers.  This domain name is resolved to an IP
+   address and port using the SRV procedures specified in RFC 2782 [3].
+
+   Specifically, the service name is "stun".  The protocol is "udp" for
+   sending Binding Requests, or "tcp" for sending Shared Secret
+   Requests.  The procedures of RFC 2782 are followed to determine the
+   server to contact.  RFC 2782 spells out the details of how a set of
+   SRV records are sorted and then tried.  However, it only states that
+   the client should "try to connect to the (protocol, address,
+   service)" without giving any details on what happens in the event of
+   failure.  Those details are described here for STUN.
+
+   For STUN requests, failure occurs if there is a transport failure of
+   some sort (generally, due to fatal ICMP errors in UDP or connection
+   failures in TCP).  Failure also occurs if the transaction fails due
+   to timeout.  This occurs 9.5 seconds after the first request is sent,
+   for both Shared Secret Requests and Binding Requests.  See Section
+   9.3 for details on transaction timeouts for Binding Requests.  If a
+   failure occurs, the client SHOULD create a new request, which is
+   identical to the previous, but has a different transaction ID and
+   MESSAGE INTEGRITY attribute (the HMAC will change because the
+   transaction ID has changed).  That request is sent to the next
+   element in the list as specified by RFC 2782.
+
+   The default port for STUN requests is 3478, for both TCP and UDP.
+   Administrators SHOULD use this port in their SRV records, but MAY use
+   others.
+
+   If no SRV records were found, the client performs an A record lookup
+   of the domain name.  The result will be a list of IP addresses, each
+   of which can be contacted at the default port.
+
+   This would allow a firewall admin to open the STUN port, so hosts
+   within the enterprise could access new applications. Whether they
+   will or won't do this is a good question.
+
+9.2 Obtaining a Shared Secret
+
+   As discussed in Section 12, there are several attacks possible on
+   STUN systems.  Many of these are prevented through integrity of
+   requests and responses.  To provide that integrity, STUN makes use of
+   a shared secret between client and server, used as the keying
+   material for an HMAC used in both the Binding Request and Binding
+   Response.  STUN allows for the shared secret to be obtained in any
+   way (for example, Kerberos [14]).  However, it MUST have at least 128
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 15]
+
+RFC 3489                          STUN                        March 2003
+
+
+   bits of randomness.  In order to ensure interoperability, this
+   specification describes a TLS-based mechanism.  This mechanism,
+   described in this section, MUST be implemented by clients and
+   servers.
+
+   First, the client determines the IP address and port that it will
+   open a TCP connection to.  This is done using the discovery
+   procedures in Section 9.1.  The client opens up the connection to
+   that address and port, and immediately begins TLS negotiation [2].
+   The client MUST verify the identity of the server.  To do that, it
+   follows the identification procedures defined in Section 3.1 of RFC
+   2818 [5]. Those procedures assume the client is dereferencing a URI.
+   For purposes of usage with this specification, the client treats the
+   domain name or IP address used in Section 9.1 as the host portion of
+   the URI that has been dereferenced.
+
+   Once the connection is opened, the client sends a Shared Secret
+   request.  This request has no attributes, just the header.  The
+   transaction ID in the header MUST meet the requirements outlined for
+   the transaction ID in a binding request, described in Section 9.3
+   below.  The server generates a response, which can either be a Shared
+   Secret Response or a Shared Secret Error Response.
+
+   If the response was a Shared Secret Error Response, the client checks
+   the response code in the ERROR-CODE attribute.  Interpretation of
+   those response codes is identical to the processing of Section 9.4
+   for the Binding Error Response.
+
+   If a client receives a Shared Secret Response with an attribute whose
+   type is greater than 0x7fff, the attribute MUST be ignored.  If the
+   client receives a Shared Secret Response with an attribute whose type
+   is less than or equal to 0x7fff, the response is ignored.
+
+   If the response was a Shared Secret Response, it will contain a short
+   lived username and password, encoded in the USERNAME and PASSWORD
+   attributes, respectively.
+
+   The client MAY generate multiple Shared Secret Requests on the
+   connection, and it MAY do so before receiving Shared Secret Responses
+   to previous Shared Secret Requests.  The client SHOULD close the
+   connection as soon as it has finished obtaining usernames and
+   passwords.
+
+   Section 9.3 describes how these passwords are used to provide
+   integrity protection over Binding Requests, and Section 8.1 describes
+   how it is used in Binding Responses.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 16]
+
+RFC 3489                          STUN                        March 2003
+
+
+9.3  Formulating the Binding Request
+
+   A Binding Request formulated by the client follows the syntax rules
+   defined in Section 11.  Any two requests that are not bit-wise
+   identical, and not sent to the same server from the same IP address
+   and port, MUST carry different transaction IDs. The transaction ID
+   MUST be uniformly and randomly distributed between 0 and 2**128 - 1.
+   The large range is needed because the transaction ID serves as a form
+   of randomization, helping to prevent replays of previously signed
+   responses from the server.  The message type of the request MUST be
+   "Binding Request".
+
+   The RESPONSE-ADDRESS attribute is optional in the Binding Request.
+   It is used if the client wishes the response to be sent to a
+   different IP address and port than the one the request was sent from.
+   This is useful for determining whether the client is behind a
+   firewall, and for applications that have separated control and data
+   components.  See Section 10.3 for more details.  The CHANGE-REQUEST
+   attribute is also optional.  Whether it is present depends on what
+   the application is trying to accomplish.  See Section 10 for some
+   example uses.
+
+   The client SHOULD add a MESSAGE-INTEGRITY and USERNAME attribute to
+   the Binding Request.  This MESSAGE-INTEGRITY attribute contains an
+   HMAC [13].  The value of the username, and the key to use in the
+   MESSAGE-INTEGRITY attribute depend on the shared secret mechanism.
+   If the STUN Shared Secret Request was used, the USERNAME must be a
+   valid username obtained from a Shared Secret Response within the last
+   nine minutes.  The shared secret for the HMAC is the value of the
+   PASSWORD attribute obtained from the same Shared Secret Response.
+
+   Once formulated, the client sends the Binding Request.  Reliability
+   is accomplished through client retransmissions.  Clients SHOULD
+   retransmit the request starting with an interval of 100ms, doubling
+   every retransmit until the interval reaches 1.6s.  Retransmissions
+   continue with intervals of 1.6s until a response is received, or a
+   total of 9 requests have been sent. If no response is received by 1.6
+   seconds after the last request has been sent, the client SHOULD
+   consider the transaction to have failed. In other words, requests
+   would be sent at times 0ms, 100ms, 300ms, 700ms, 1500ms, 3100ms,
+   4700ms, 6300ms, and 7900ms. At 9500ms, the client considers the
+   transaction to have failed if no response has been received.
+
+9.4  Processing Binding Responses
+
+   The response can either be a Binding Response or Binding Error
+   Response.  Binding Error Responses are always received on the source
+   address and port the request was sent from.  A Binding Response will
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 17]
+
+RFC 3489                          STUN                        March 2003
+
+
+   be received on the address and port placed in the RESPONSE-ADDRESS
+   attribute of the request.  If none was present, the Binding Responses
+   will be received on the source address and port the request was sent
+   from.
+
+   If the response is a Binding Error Response, the client checks the
+   response code from the ERROR-CODE attribute of the response.  For a
+   400 response code, the client SHOULD display the reason phrase to the
+   user.  For a 420 response code, the client SHOULD retry the request,
+   this time omitting any attributes listed in the UNKNOWN-ATTRIBUTES
+   attribute of the response.  For a 430 response code, the client
+   SHOULD obtain a new shared secret, and retry the Binding Request with
+   a new transaction.  For 401 and 432 response codes, if the client had
+   omitted the USERNAME or MESSAGE-INTEGRITY attribute as indicated by
+   the error, it SHOULD try again with those attributes.  For a 431
+   response code, the client SHOULD alert the user, and MAY try the
+   request again after obtaining a new username and password.  For a 500
+   response code, the client MAY wait several seconds and then retry the
+   request.  For a 600 response code, the client MUST NOT retry the
+   request, and SHOULD display the reason phrase to the user.  Unknown
+   attributes between 400 and 499 are treated like a 400, unknown
+   attributes between 500 and 599 are treated like a 500, and unknown
+   attributes between 600 and 699 are treated like a 600.  Any response
+   between 100 and 399 MUST result in the cessation of request
+   retransmissions, but otherwise is discarded.
+
+   If a client receives a response with an attribute whose type is
+   greater than 0x7fff, the attribute MUST be ignored.  If the client
+   receives a response with an attribute whose type is less than or
+   equal to 0x7fff, request retransmissions MUST cease, but the entire
+   response is otherwise ignored.
+
+   If the response is a Binding Response, the client SHOULD check the
+   response for a MESSAGE-INTEGRITY attribute.  If not present, and the
+   client placed a MESSAGE-INTEGRITY attribute into the request, it MUST
+   discard the response.  If present, the client computes the HMAC over
+   the response as described in Section 11.2.8.  The key to use depends
+   on the shared secret mechanism.  If the STUN Shared Secret Request
+   was used, the key MUST be same as used to compute the MESSAGE-
+   INTEGRITY attribute in the request.  If the computed HMAC differs
+   from the one in the response, the client MUST discard the response,
+   and SHOULD alert the user about a possible attack.  If the computed
+   HMAC matches the one from the response, processing continues.
+
+   Reception of a response (either Binding Error Response or Binding
+   Response) to a Binding Request will terminate retransmissions of that
+   request.  However, clients MUST continue to listen for responses to a
+   Binding Request for 10 seconds after the first response.  If it
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 18]
+
+RFC 3489                          STUN                        March 2003
+
+
+   receives any responses in this interval with different message types
+   (Binding Responses and Binding Error Responses, for example) or
+   different MAPPED-ADDRESSes, it is an indication of a possible attack.
+   The client MUST NOT use the MAPPED-ADDRESS from any of the responses
+   it received (either the first or the additional ones), and SHOULD
+   alert the user.
+
+   Furthermore, if a client receives more than twice as many Binding
+   Responses as the number of Binding Requests it sent, it MUST NOT use
+   the MAPPED-ADDRESS from any of those responses, and SHOULD alert the
+   user about a potential attack.
+
+   If the Binding Response is authenticated, and the MAPPED-ADDRESS was
+   not discarded because of a potential attack, the CLIENT MAY use the
+   MAPPED-ADDRESS and SOURCE-ADDRESS attributes.
+
+10.  Use Cases
+
+   The rules of Sections 8 and 9 describe exactly how a client and
+   server interact to send requests and get responses.  However, they do
+   not dictate how the STUN protocol is used to accomplish useful tasks.
+   That is at the discretion of the client.  Here, we provide some
+   useful scenarios for applying STUN.
+
+10.1  Discovery Process
+
+   In this scenario, a user is running a multimedia application which
+   needs to determine which of the following scenarios applies to it:
+
+   o  On the open Internet
+
+   o  Firewall that blocks UDP
+
+   o  Firewall that allows UDP out, and responses have to come back to
+      the source of the request (like a symmetric NAT, but no
+      translation.  We call this a symmetric UDP Firewall)
+
+   o  Full-cone NAT
+
+   o  Symmetric NAT
+
+   o  Restricted cone or restricted port cone NAT
+
+   Which of the six scenarios applies can be determined through the flow
+   chart described in Figure 2.  The chart refers only to the sequence
+   of Binding Requests; Shared Secret Requests will, of course, be
+   needed to authenticate each Binding Request used in the sequence.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 19]
+
+RFC 3489                          STUN                        March 2003
+
+
+   The flow makes use of three tests.  In test I, the client sends a
+   STUN Binding Request to a server, without any flags set in the
+   CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute.
+   This causes the server to send the response back to the address and
+   port that the request came from.  In test II, the client sends a
+   Binding Request with both the "change IP" and "change port" flags
+   from the CHANGE-REQUEST attribute set.  In test III, the client sends
+   a Binding Request with only the "change port" flag set.
+
+   The client begins by initiating test I.  If this test yields no
+   response, the client knows right away that it is not capable of UDP
+   connectivity.  If the test produces a response, the client examines
+   the MAPPED-ADDRESS attribute.  If this address and port are the same
+   as the local IP address and port of the socket used to send the
+   request, the client knows that it is not natted.  It executes test
+   II.
+
+   If a response is received, the client knows that it has open access
+   to the Internet (or, at least, its behind a firewall that behaves
+   like a full-cone NAT, but without the translation).  If no response
+   is received, the client knows its behind a symmetric UDP firewall.
+
+   In the event that the IP address and port of the socket did not match
+   the MAPPED-ADDRESS attribute in the response to test I, the client
+   knows that it is behind a NAT.  It performs test II.  If a response
+   is received, the client knows that it is behind a full-cone NAT.  If
+   no response is received, it performs test I again, but this time,
+   does so to the address and port from the CHANGED-ADDRESS attribute
+   from the response to test I.  If the IP address and port returned in
+   the MAPPED-ADDRESS attribute are not the same as the ones from the
+   first test I, the client knows its behind a symmetric NAT.  If the
+   address and port are the same, the client is either behind a
+   restricted or port restricted NAT.  To make a determination about
+   which one it is behind, the client initiates test III.  If a response
+   is received, its behind a restricted NAT, and if no response is
+   received, its behind a port restricted NAT.
+
+   This procedure yields substantial information about the operating
+   condition of the client application.  In the event of multiple NATs
+   between the client and the Internet, the type that is discovered will
+   be the type of the most restrictive NAT between the client and the
+   Internet.  The types of NAT, in order of restrictiveness, from most
+   to least, are symmetric, port restricted cone, restricted cone, and
+   full cone.
+
+   Typically, a client will re-do this discovery process periodically to
+   detect changes, or look for inconsistent results.  It is important to
+   note that when the discovery process is redone, it should not
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 20]
+
+RFC 3489                          STUN                        March 2003
+
+
+   generally be done from the same local address and port used in the
+   previous discovery process.  If the same local address and port are
+   reused, bindings from the previous test may still be in existence,
+   and these will invalidate the results of the test.  Using a different
+   local address and port for subsequent tests resolves this problem.
+   An alternative is to wait sufficiently long to be confident that the
+   old bindings have expired (half an hour should more than suffice).
+
+10.2 Binding Lifetime Discovery
+
+   STUN can also be used to discover the lifetimes of the bindings
+   created by the NAT.  In many cases, the client will need to refresh
+   the binding, either through a new STUN request, or an application
+   packet, in order for the application to continue to use the binding.
+   By discovering the binding lifetime, the client can determine how
+   frequently it needs to refresh.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 21]
+
+RFC 3489                          STUN                        March 2003
+
+
+                        +--------+
+                        |  Test  |
+                        |   I    |
+                        +--------+
+                             |
+                             |
+                             V
+                            /\              /\
+                         N /  \ Y          /  \ Y             +--------+
+          UDP     <-------/Resp\--------->/ IP \------------->|  Test  |
+          Blocked         \ ?  /          \Same/              |   II   |
+                           \  /            \? /               +--------+
+                            \/              \/                    |
+                                             | N                  |
+                                             |                    V
+                                             V                    /\
+                                         +--------+  Sym.      N /  \
+                                         |  Test  |  UDP    <---/Resp\
+                                         |   II   |  Firewall   \ ?  /
+                                         +--------+              \  /
+                                             |                    \/
+                                             V                     |Y
+                  /\                         /\                    |
+   Symmetric  N  /  \       +--------+   N  /  \                   V
+      NAT  <--- / IP \<-----|  Test  |<--- /Resp\               Open
+                \Same/      |   I    |     \ ?  /               Internet
+                 \? /       +--------+      \  /
+                  \/                         \/
+                  |                           |Y
+                  |                           |
+                  |                           V
+                  |                           Full
+                  |                           Cone
+                  V              /\
+              +--------+        /  \ Y
+              |  Test  |------>/Resp\---->Restricted
+              |   III  |       \ ?  /
+              +--------+        \  /
+                                 \/
+                                  |N
+                                  |       Port
+                                  +------>Restricted
+
+                 Figure 2: Flow for type discovery process
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 22]
+
+RFC 3489                          STUN                        March 2003
+
+
+   To determine the binding lifetime, the client first sends a Binding
+   Request to the server from a particular socket, X.  This creates a
+   binding in the NAT.  The response from the server contains a MAPPED-
+   ADDRESS attribute, providing the public address and port on the NAT.
+   Call this Pa and Pp, respectively.  The client then starts a timer
+   with a value of T seconds.  When this timer fires, the client sends
+   another Binding Request to the server, using the same destination
+   address and port, but from a different socket, Y.  This request
+   contains a RESPONSE-ADDRESS address attribute, set to (Pa,Pp).  This
+   will create a new binding on the NAT, and cause the STUN server to
+   send a Binding Response that would match the old binding, if it still
+   exists.  If the client receives the Binding Response on socket X, it
+   knows that the binding has not expired.  If the client receives the
+   Binding Response on socket Y (which is possible if the old binding
+   expired, and the NAT allocated the same public address and port to
+   the new binding), or receives no response at all, it knows that the
+   binding has expired.
+
+   The client can find the value of the binding lifetime by doing a
+   binary search through T, arriving eventually at the value where the
+   response is not received for any timer greater than T, but is
+   received for any timer less than T.
+
+   This discovery process takes quite a bit of time, and is something
+   that will typically be run in the background on a device once it
+   boots.
+
+   It is possible that the client can get inconsistent results each time
+   this process is run.  For example, if the NAT should reboot, or be
+   reset for some reason, the process may discover a lifetime than is
+   shorter than the actual one.  For this reason, implementations are
+   encouraged to run the test numerous times, and be prepared to get
+   inconsistent results.
+
+10.3  Binding Acquisition
+
+   Consider once more the case of a VoIP phone.  It used the discovery
+   process above when it started up, to discover its environment.  Now,
+   it wants to make a call.  As part of the discovery process, it
+   determined that it was behind a full-cone NAT.
+
+   Consider further that this phone consists of two logically separated
+   components - a control component that handles signaling, and a media
+   component that handles the audio, video, and RTP [12].  Both are
+   behind the same NAT.  Because of this separation of control and
+   media, we wish to minimize the communication required between them.
+   In fact, they may not even run on the same host.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 23]
+
+RFC 3489                          STUN                        March 2003
+
+
+   In order to make a voice call, the phone needs to obtain an IP
+   address and port that it can place in the call setup message as the
+   destination for receiving audio.
+
+   To obtain an address, the control component sends a Shared Secret
+   Request to the server, obtains a shared secret, and then sends a
+   Binding Request to the server.  No CHANGE-REQUEST attribute is
+   present in the Binding Request, and neither is the RESPONSE-ADDRESS
+   attribute.  The Binding Response contains a mapped address.  The
+   control component then formulates a second Binding Request.  This
+   request contains a RESPONSE-ADDRESS, which is set to the mapped
+   address learned from the previous Binding Response.  This Binding
+   Request is passed to the media component, along with the IP address
+   and port of the STUN server.  The media component sends the Binding
+   Request.  The request goes to the STUN server, which sends the
+   Binding Response back to the control component.  The control
+   component receives this, and now has learned an IP address and port
+   that will be routed back to the media component that sent the
+   request.
+
+   The client will be able to receive media from anywhere on this mapped
+   address.
+
+   In the case of silence suppression, there may be periods where the
+   client receives no media.  In this case, the UDP bindings could
+   timeout (UDP bindings in NATs are typically short; 30 seconds is
+   common).  To deal with this, the application can periodically
+   retransmit the query in order to keep the binding fresh.
+
+   It is possible that both participants in the multimedia session are
+   behind the same NAT.  In that case, both will repeat this procedure
+   above, and both will obtain public address bindings.  When one sends
+   media to the other, the media is routed to the NAT, and then turns
+   right back around to come back into the enterprise, where it is
+   translated to the private address of the recipient.  This is not
+   particularly efficient, and unfortunately, does not work in many
+   commercial NATs.  In such cases, the clients may need to retry using
+   private addresses.
+
+11. Protocol Details
+
+   This section presents the detailed encoding of a STUN message.
+
+   STUN is a request-response protocol.  Clients send a request, and the
+   server sends a response.  There are two requests, Binding Request,
+   and Shared Secret Request.  The response to a Binding Request can
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 24]
+
+RFC 3489                          STUN                        March 2003
+
+
+   either be the Binding Response or Binding Error Response.  The
+   response to a Shared Secret Request can either be a Shared Secret
+   Response or a Shared Secret Error Response.
+
+   STUN messages are encoded using binary fields.  All integer fields
+   are carried in network byte order, that is, most significant byte
+   (octet) first.  This byte order is commonly known as big-endian.  The
+   transmission order is described in detail in Appendix B of RFC 791
+   [6].  Unless otherwise noted, numeric constants are in decimal (base
+   10).
+
+11.1  Message Header
+
+   All STUN messages consist of a 20 byte header:
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |      STUN Message Type        |         Message Length        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                            Transaction ID
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                                                   |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   The Message Types can take on the following values:
+
+      0x0001  :  Binding Request
+      0x0101  :  Binding Response
+      0x0111  :  Binding Error Response
+      0x0002  :  Shared Secret Request
+      0x0102  :  Shared Secret Response
+      0x0112  :  Shared Secret Error Response
+
+   The message length is the count, in bytes, of the size of the
+   message, not including the 20 byte header.
+
+   The transaction ID is a 128 bit identifier.  It also serves as salt
+   to randomize the request and the response.  All responses carry the
+   same identifier as the request they correspond to.
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 25]
+
+RFC 3489                          STUN                        March 2003
+
+
+11.2  Message Attributes
+
+   After the header are 0 or more attributes.  Each attribute is TLV
+   encoded, with a 16 bit type, 16 bit length, and variable value:
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |         Type                  |            Length             |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                             Value                             ....
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   The following types are defined:
+
+   0x0001: MAPPED-ADDRESS
+   0x0002: RESPONSE-ADDRESS
+   0x0003: CHANGE-REQUEST
+   0x0004: SOURCE-ADDRESS
+   0x0005: CHANGED-ADDRESS
+   0x0006: USERNAME
+   0x0007: PASSWORD
+   0x0008: MESSAGE-INTEGRITY
+   0x0009: ERROR-CODE
+   0x000a: UNKNOWN-ATTRIBUTES
+   0x000b: REFLECTED-FROM
+
+   To allow future revisions of this specification to add new attributes
+   if needed, the attribute space is divided into optional and mandatory
+   ones.  Attributes with values greater than 0x7fff are optional, which
+   means that the message can be processed by the client or server even
+   though the attribute is not understood.  Attributes with values less
+   than or equal to 0x7fff are mandatory to understand, which means that
+   the client or server cannot process the message unless it understands
+   the attribute.
+
+   The MESSAGE-INTEGRITY attribute MUST be the last attribute within a
+   message.  Any attributes that are known, but are not supposed to be
+   present in a message (MAPPED-ADDRESS in a request, for example) MUST
+   be ignored.
+
+   Table 2 indicates which attributes are present in which messages.  An
+   M indicates that inclusion of the attribute in the message is
+   mandatory, O means its optional, C means it's conditional based on
+   some other aspect of the message, and N/A means that the attribute is
+   not applicable to that message type.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 26]
+
+RFC 3489                          STUN                        March 2003
+
+
+                                         Binding  Shared  Shared  Shared
+                       Binding  Binding  Error    Secret  Secret  Secret
+   Att.                Req.     Resp.    Resp.    Req.    Resp.   Error
+                                                                  Resp.
+   _____________________________________________________________________
+   MAPPED-ADDRESS      N/A      M        N/A      N/A     N/A     N/A
+   RESPONSE-ADDRESS    O        N/A      N/A      N/A     N/A     N/A
+   CHANGE-REQUEST      O        N/A      N/A      N/A     N/A     N/A
+   SOURCE-ADDRESS      N/A      M        N/A      N/A     N/A     N/A
+   CHANGED-ADDRESS     N/A      M        N/A      N/A     N/A     N/A
+   USERNAME            O        N/A      N/A      N/A     M       N/A
+   PASSWORD            N/A      N/A      N/A      N/A     M       N/A
+   MESSAGE-INTEGRITY   O        O        N/A      N/A     N/A     N/A
+   ERROR-CODE          N/A      N/A      M        N/A     N/A     M
+   UNKNOWN-ATTRIBUTES  N/A      N/A      C        N/A     N/A     C
+   REFLECTED-FROM      N/A      C        N/A      N/A     N/A     N/A
+
+   Table 2: Summary of Attributes
+
+   The length refers to the length of the value element, expressed as an
+   unsigned integral number of bytes.
+
+11.2.1 MAPPED-ADDRESS
+
+   The MAPPED-ADDRESS attribute indicates the mapped IP address and
+   port.  It consists of an eight bit address family, and a sixteen bit
+   port, followed by a fixed length value representing the IP address.
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |x x x x x x x x|    Family     |           Port                |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                             Address                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   The port is a network byte ordered representation of the mapped port.
+   The address family is always 0x01, corresponding to IPv4.  The first
+   8 bits of the MAPPED-ADDRESS are ignored, for the purposes of
+   aligning parameters on natural boundaries.  The IPv4 address is 32
+   bits.
+
+11.2.2 RESPONSE-ADDRESS
+
+   The RESPONSE-ADDRESS attribute indicates where the response to a
+   Binding Request should be sent.  Its syntax is identical to MAPPED-
+   ADDRESS.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 27]
+
+RFC 3489                          STUN                        March 2003
+
+
+11.2.3  CHANGED-ADDRESS
+
+   The CHANGED-ADDRESS attribute indicates the IP address and port where
+   responses would have been sent from if the "change IP" and "change
+   port" flags had been set in the CHANGE-REQUEST attribute of the
+   Binding Request.  The attribute is always present in a Binding
+   Response, independent of the value of the flags.  Its syntax is
+   identical to MAPPED-ADDRESS.
+
+11.2.4 CHANGE-REQUEST
+
+   The CHANGE-REQUEST attribute is used by the client to request that
+   the server use a different address and/or port when sending the
+   response.  The attribute is 32 bits long, although only two bits (A
+   and B) are used:
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   The meaning of the flags is:
+
+   A: This is the "change IP" flag.  If true, it requests the server
+      to send the Binding Response with a different IP address than the
+      one the Binding Request was received on.
+
+   B: This is the "change port" flag.  If true, it requests the
+      server to send the Binding Response with a different port than the
+      one the Binding Request was received on.
+
+11.2.5 SOURCE-ADDRESS
+
+   The SOURCE-ADDRESS attribute is present in Binding Responses.  It
+   indicates the source IP address and port that the server is sending
+   the response from.  Its syntax is identical to that of MAPPED-
+   ADDRESS.
+
+11.2.6 USERNAME
+
+   The USERNAME attribute is used for message integrity.  It serves as a
+   means to identify the shared secret used in the message integrity
+   check.  The USERNAME is always present in a Shared Secret Response,
+   along with the PASSWORD.  It is optionally present in a Binding
+   Request when message integrity is used.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 28]
+
+RFC 3489                          STUN                        March 2003
+
+
+   The value of USERNAME is a variable length opaque value.  Its length
+   MUST be a multiple of 4 (measured in bytes) in order to guarantee
+   alignment of attributes on word boundaries.
+
+11.2.7 PASSWORD
+
+   The PASSWORD attribute is used in Shared Secret Responses.  It is
+   always present in a Shared Secret Response, along with the USERNAME.
+
+   The value of PASSWORD is a variable length value that is to be used
+   as a shared secret.  Its length MUST be a multiple of 4 (measured in
+   bytes) in order to guarantee alignment of attributes on word
+   boundaries.
+
+11.2.8 MESSAGE-INTEGRITY
+
+   The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [13] of the
+   STUN message.  It can be present in Binding Requests or Binding
+   Responses.  Since it uses the SHA1 hash, the HMAC will be 20 bytes.
+   The text used as input to HMAC is the STUN message, including the
+   header, up to and including the attribute preceding the MESSAGE-
+   INTEGRITY attribute. That text is then padded with zeroes so as to be
+   a multiple of 64 bytes.  As a result, the MESSAGE-INTEGRITY attribute
+   MUST be the last attribute in any STUN message.  The key used as
+   input to HMAC depends on the context.
+
+11.2.9 ERROR-CODE
+
+   The ERROR-CODE attribute is present in the Binding Error Response and
+   Shared Secret Error Response.  It is a numeric value in the range of
+   100 to 699 plus a textual reason phrase encoded in UTF-8, and is
+   consistent in its code assignments and semantics with SIP [10] and
+   HTTP [15].  The reason phrase is meant for user consumption, and can
+   be anything appropriate for the response code.  The lengths of the
+   reason phrases MUST be a multiple of 4 (measured in bytes).  This can
+   be accomplished by added spaces to the end of the text, if necessary.
+   Recommended reason phrases for the defined response codes are
+   presented below.
+
+   To facilitate processing, the class of the error code (the hundreds
+   digit) is encoded separately from the rest of the code.
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 29]
+
+RFC 3489                          STUN                        March 2003
+
+
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                   0                     |Class|     Number    |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      Reason Phrase (variable)                                ..
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   The class represents the hundreds digit of the response code.  The
+   value MUST be between 1 and 6.  The number represents the response
+   code modulo 100, and its value MUST be between 0 and 99.
+
+   The following response codes, along with their recommended reason
+   phrases (in brackets) are defined at this time:
+
+   400 (Bad Request): The request was malformed.  The client should not
+        retry the request without modification from the previous
+        attempt.
+
+   401 (Unauthorized): The Binding Request did not contain a MESSAGE-
+        INTEGRITY attribute.
+
+   420 (Unknown Attribute): The server did not understand a mandatory
+        attribute in the request.
+
+   430 (Stale Credentials): The Binding Request did contain a MESSAGE-
+        INTEGRITY attribute, but it used a shared secret that has
+        expired.  The client should obtain a new shared secret and try
+        again.
+
+   431 (Integrity Check Failure): The Binding Request contained a
+        MESSAGE-INTEGRITY attribute, but the HMAC failed verification.
+        This could be a sign of a potential attack, or client
+        implementation error.
+
+   432 (Missing Username): The Binding Request contained a MESSAGE-
+        INTEGRITY attribute, but not a USERNAME attribute.  Both must be
+        present for integrity checks.
+
+   433 (Use TLS): The Shared Secret request has to be sent over TLS, but
+        was not received over TLS.
+
+   500 (Server Error): The server has suffered a temporary error. The
+        client should try again.
+
+   600 (Global Failure:) The server is refusing to fulfill the request.
+        The client should not retry.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 30]
+
+RFC 3489                          STUN                        March 2003
+
+
+11.2.10 UNKNOWN-ATTRIBUTES
+
+   The UNKNOWN-ATTRIBUTES attribute is present only in a Binding Error
+   Response or Shared Secret Error Response when the response code in
+   the ERROR-CODE attribute is 420.
+
+   The attribute contains a list of 16 bit values, each of which
+   represents an attribute type that was not understood by the server.
+   If the number of unknown attributes is an odd number, one of the
+   attributes MUST be repeated in the list, so that the total length of
+   the list is a multiple of 4 bytes.
+
+   0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      Attribute 1 Type           |     Attribute 2 Type        |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      Attribute 3 Type           |     Attribute 4 Type    ...
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+11.2.11 REFLECTED-FROM
+
+   The REFLECTED-FROM attribute is present only in Binding Responses,
+   when the Binding Request contained a RESPONSE-ADDRESS attribute.  The
+   attribute contains the identity (in terms of IP address) of the
+   source where the request came from.  Its purpose is to provide
+   traceability, so that a STUN server cannot be used as a reflector for
+   denial-of-service attacks.
+
+   Its syntax is identical to the MAPPED-ADDRESS attribute.
+
+12.  Security Considerations
+
+12.1 Attacks on STUN
+
+   Generally speaking, attacks on STUN can be classified into denial of
+   service attacks and eavesdropping attacks.  Denial of service attacks
+   can be launched against a STUN server itself, or against other
+   elements using the STUN protocol.
+
+   STUN servers create state through the Shared Secret Request
+   mechanism.  To prevent being swamped with traffic, a STUN server
+   SHOULD limit the number of simultaneous TLS connections it will hold
+   open by dropping an existing connection when a new connection request
+   arrives (based on an Least Recently Used (LRU) policy, for example).
+   Similarly, it SHOULD limit the number of shared secrets it will
+   store, in the event that the server is storing the shared secrets.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 31]
+
+RFC 3489                          STUN                        March 2003
+
+
+   The attacks of greater interest are those in which the STUN server
+   and client are used to launch DOS attacks against other entities,
+   including the client itself.
+
+   Many of the attacks require the attacker to generate a response to a
+   legitimate STUN request, in order to provide the client with a faked
+   MAPPED-ADDRESS.  The attacks that can be launched using such a
+   technique include:
+
+12.1.1 Attack I: DDOS Against a Target
+
+   In this case, the attacker provides a large number of clients with
+   the same faked MAPPED-ADDRESS that points to the intended target.
+   This will trick all the STUN clients into thinking that their
+   addresses are equal to that of the target.  The clients then hand out
+   that address in order to receive traffic on it (for example, in SIP
+   or H.323 messages).  However, all of that traffic becomes focused at
+   the intended target.  The attack can provide substantial
+   amplification, especially when used with clients that are using STUN
+   to enable multimedia applications.
+
+12.1.2 Attack II: Silencing a Client
+
+   In this attack, the attacker seeks to deny a client access to
+   services enabled by STUN (for example, a client using STUN to enable
+   SIP-based multimedia traffic).  To do that, the attacker provides
+   that client with a faked MAPPED-ADDRESS.  The MAPPED-ADDRESS it
+   provides is an IP address that routes to nowhere.  As a result, the
+   client won't receive any of the packets it expects to receive when it
+   hands out the MAPPED-ADDRESS.
+
+   This exploitation is not very interesting for the attacker.  It
+   impacts a single client, which is frequently not the desired target.
+   Moreover, any attacker that can mount the attack could also deny
+   service to the client by other means, such as preventing the client
+   from receiving any response from the STUN server, or even a DHCP
+   server.
+
+12.1.3 Attack III: Assuming the Identity of a Client
+
+   This attack is similar to attack II.  However, the faked MAPPED-
+   ADDRESS points to the attacker themself.  This allows the attacker to
+   receive traffic which was destined for the client.
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 32]
+
+RFC 3489                          STUN                        March 2003
+
+
+12.1.4 Attack IV: Eavesdropping
+
+   In this attack, the attacker forces the client to use a MAPPED-
+   ADDRESS that routes to itself.  It then forwards any packets it
+   receives to the client.  This attack would allow the attacker to
+   observe all packets sent to the client.  However, in order to launch
+   the attack, the attacker must have already been able to observe
+   packets from the client to the STUN server.  In most cases (such as
+   when the attack is launched from an access network), this means that
+   the attacker could already observe packets sent to the client.  This
+   attack is, as a result, only useful for observing traffic by
+   attackers on the path from the client to the STUN server, but not
+   generally on the path of packets being routed towards the client.
+
+12.2 Launching the Attacks
+
+   It is important to note that attacks of this nature (injecting
+   responses with fake MAPPED-ADDRESSes) require that the attacker be
+   capable of eavesdropping requests sent from the client to the server
+   (or to act as a MITM for such attacks).  This is because STUN
+   requests contain a transaction identifier, selected by the client,
+   which is random with 128 bits of entropy.  The server echoes this
+   value in the response, and the client ignores any responses that
+   don't have a matching transaction ID.  Therefore, in order for an
+   attacker to provide a faked response that is accepted by the client,
+   the attacker needs to know what the transaction ID in the request
+   was.  The large amount of randomness, combined with the need to know
+   when the client sends a request, precludes attacks that involve
+   guessing the transaction ID.
+
+   Since all of the above attacks rely on this one primitive - injecting
+   a response with a faked MAPPED-ADDRESS - preventing the attacks is
+   accomplished by preventing this one operation.  To prevent it, we
+   need to consider the various ways in which it can be accomplished.
+   There are several:
+
+12.2.1 Approach I: Compromise a Legitimate STUN Server
+
+   In this attack, the attacker compromises a legitimate STUN server
+   through a virus or Trojan horse.  Presumably, this would allow the
+   attacker to take over the STUN server, and control the types of
+   responses it generates.
+
+   Compromise of a STUN server can also lead to discovery of open ports.
+   Knowledge of an open port creates an opportunity for DoS attacks on
+   those ports (or DDoS attacks if the traversed NAT is a full cone
+   NAT).  Discovering open ports is already fairly trivial using port
+   probing, so this does not represent a major threat.
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 33]
+
+RFC 3489                          STUN                        March 2003
+
+
+12.2.2 Approach II: DNS Attacks
+
+   STUN servers are discovered using DNS SRV records.  If an attacker
+   can compromise the DNS, it can inject fake records which map a domain
+   name to the IP address of a STUN server run by the attacker.  This
+   will allow it to inject fake responses to launch any of the attacks
+   above.
+
+12.2.3 Approach III: Rogue Router or NAT
+
+   Rather than compromise the STUN server, an attacker can cause a STUN
+   server to generate responses with the wrong MAPPED-ADDRESS by
+   compromising a router or NAT on the path from the client to the STUN
+   server.  When the STUN request passes through the rogue router or
+   NAT, it rewrites the source address of the packet to be that of the
+   desired MAPPED-ADDRESS.  This address cannot be arbitrary.  If the
+   attacker is on the public Internet (that is, there are no NATs
+   between it and the STUN server), and the attacker doesn't modify the
+   STUN request, the address has to have the property that packets sent
+   from the STUN server to that address would route through the
+   compromised router.  This is because the STUN server will send the
+   responses back to the source address of the request.  With a modified
+   source address, the only way they can reach the client is if the
+   compromised router directs them there.  If the attacker is on the
+   public Internet, but they can modify the STUN request, they can
+   insert a RESPONSE-ADDRESS attribute into the request, containing the
+   actual source address of the STUN request.  This will cause the
+   server to send the response to the client, independent of the source
+   address the STUN server sees.  This gives the attacker the ability to
+   forge an arbitrary source address when it forwards the STUN request.
+
+   If the attacker is on a private network (that is, there are NATs
+   between it and the STUN server), the attacker will not be able to
+   force the server to generate arbitrary MAPPED-ADRESSes in responses.
+   They will only be able force the STUN server to generate MAPPED-
+   ADDRESSes which route to the private network.  This is because the
+   NAT between the attacker and the STUN server will rewrite the source
+   address of the STUN request, mapping it to a public address that
+   routes to the private network.  Because of this, the attacker can
+   only force the server to generate faked mapped addresses that route
+   to the private network.  Unfortunately, it is possible that a low
+   quality NAT would be willing to map an allocated public address to
+   another public address (as opposed to an internal private address),
+   in which case the attacker could forge the source address in a STUN
+   request to be an arbitrary public address.  This kind of behavior
+   from NATs does appear to be rare.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 34]
+
+RFC 3489                          STUN                        March 2003
+
+
+12.2.4 Approach IV: MITM
+
+   As an alternative to approach III, if the attacker can place an
+   element on the path from the client to the server, the element can
+   act as a man-in-the-middle.  In that case, it can intercept a STUN
+   request, and generate a STUN response directly with any desired value
+   of the MAPPED-ADDRESS field.  Alternatively, it can forward the STUN
+   request to the server (after potential modification), receive the
+   response, and forward it to the client.  When forwarding the request
+   and response, this attack is subject to the same limitations on the
+   MAPPED-ADDRESS described in Section 12.2.3.
+
+12.2.5 Approach V: Response Injection Plus DoS
+
+   In this approach, the attacker does not need to be a MITM (as in
+   approaches III and IV).  Rather, it only needs to be able to
+   eavesdrop onto a network segment that carries STUN requests.  This is
+   easily done in multiple access networks such as ethernet or
+   unprotected 802.11.  To inject the fake response, the attacker
+   listens on the network for a STUN request.  When it sees one, it
+   simultaneously launches a DoS attack on the STUN server, and
+   generates its own STUN response with the desired MAPPED-ADDRESS
+   value.  The STUN response generated by the attacker will reach the
+   client, and the DoS attack against the server is aimed at preventing
+   the legitimate response from the server from reaching the client.
+   Arguably, the attacker can do without the DoS attack on the server,
+   so long as the faked response beats the real response back to the
+   client, and the client uses the first response, and ignores the
+   second (even though it's different).
+
+12.2.6 Approach VI: Duplication
+
+   This approach is similar to approach V.  The attacker listens on the
+   network for a STUN request.  When it sees it, it generates its own
+   STUN request towards the server.  This STUN request is identical to
+   the one it saw, but with a spoofed source IP address.  The spoofed
+   address is equal to the one that the attacker desires to have placed
+   in the MAPPED-ADDRESS of the STUN response.  In fact, the attacker
+   generates a flood of such packets.  The STUN server will receive the
+   one original request, plus a flood of duplicate fake ones.  It
+   generates responses to all of them.  If the flood is sufficiently
+   large for the responses to congest routers or some other equipment,
+   there is a reasonable probability that the one real response is lost
+   (along with many of the faked ones), but the net result is that only
+   the faked responses are received by the STUN client.  These responses
+   are all identical and all contain the MAPPED-ADDRESS that the
+   attacker wanted the client to use.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 35]
+
+RFC 3489                          STUN                        March 2003
+
+
+   The flood of duplicate packets is not needed (that is, only one faked
+   request is sent), so long as the faked response beats the real
+   response back to the client, and the client uses the first response,
+   and ignores the second (even though it's different).
+
+   Note that, in this approach, launching a DoS attack against the STUN
+   server or the IP network, to prevent the valid response from being
+   sent or received, is problematic.  The attacker needs the STUN server
+   to be available to handle its own request.  Due to the periodic
+   retransmissions of the request from the client, this leaves a very
+   tiny window of opportunity.  The attacker must start the DoS attack
+   immediately after the actual request from the client, causing the
+   correct response to be discarded, and then cease the DoS attack in
+   order to send its own request, all before the next retransmission
+   from the client.  Due to the close spacing of the retransmits (100ms
+   to a few seconds), this is very difficult to do.
+
+   Besides DoS attacks, there may be other ways to prevent the actual
+   request from the client from reaching the server.  Layer 2
+   manipulations, for example, might be able to accomplish it.
+
+   Fortunately, Approach IV is subject to the same limitations
+   documented in Section 12.2.3, which limit the range of MAPPED-
+   ADDRESSes the attacker can cause the STUN server to generate.
+
+12.3 Countermeasures
+
+   STUN provides mechanisms to counter the approaches described above,
+   and additional, non-STUN techniques can be used as well.
+
+   First off, it is RECOMMENDED that networks with STUN clients
+   implement ingress source filtering (RFC 2827 [7]).  This is
+   particularly important for the NATs themselves.  As Section 12.2.3
+   explains, NATs which do not perform this check can be used as
+   "reflectors" in DDoS attacks.  Most NATs do perform this check as a
+   default mode of operation.  We strongly advise people that purchase
+   NATs to ensure that this capability is present and enabled.
+
+   Secondly, it is RECOMMENDED that STUN servers be run on hosts
+   dedicated to STUN, with all UDP and TCP ports disabled except for the
+   STUN ports.  This is to prevent viruses and Trojan horses from
+   infecting STUN servers, in order to prevent their compromise.  This
+   helps mitigate Approach I (Section 12.2.1).
+
+   Thirdly, to prevent the DNS attack of Section 12.2.2, Section 9.2
+   recommends that the client verify the credentials provided by the
+   server with the name used in the DNS lookup.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 36]
+
+RFC 3489                          STUN                        March 2003
+
+
+   Finally, all of the attacks above rely on the client taking the
+   mapped address it learned from STUN, and using it in application
+   layer protocols.  If encryption and message integrity are provided
+   within those protocols, the eavesdropping and identity assumption
+   attacks can be prevented.  As such, applications that make use of
+   STUN addresses in application protocols SHOULD use integrity and
+   encryption, even if a SHOULD level strength is not specified for that
+   protocol.  For example, multimedia applications using STUN addresses
+   to receive RTP traffic would use secure RTP [16].
+
+   The above three techniques are non-STUN mechanisms.  STUN itself
+   provides several countermeasures.
+
+   Approaches IV (Section 12.2.4), when generating the response locally,
+   and V (Section 12.2.5) require an attacker to generate a faked
+   response.  This attack is prevented using the message integrity
+   mechanism provided in STUN, described in Section 8.1.
+
+   Approaches III (Section 12.2.3) IV (Section 12.2.4), when using the
+   relaying technique, and VI (12.2.6), however, are not preventable
+   through server signatures.  Both approaches are most potent when the
+   attacker can modify the request, inserting a RESPONSE-ADDRESS that
+   routes to the client.  Fortunately, such modifications are
+   preventable using the message integrity techniques described in
+   Section 9.3.  However, these three approaches are still functional
+   when the attacker modifies nothing but the source address of the STUN
+   request. Sadly, this is the one thing that cannot be protected
+   through cryptographic means, as this is the change that STUN itself
+   is seeking to detect and report.  It is therefore an inherent
+   weakness in NAT, and not fixable in STUN.  To help mitigate these
+   attacks, Section 9.4 provides several heuristics for the client to
+   follow.  The client looks for inconsistent or extra responses, both
+   of which are signs of the attacks described above.  However, these
+   heuristics are just that - heuristics, and cannot be guaranteed to
+   prevent attacks.  The heuristics appear to prevent the attacks as we
+   know how to launch them today.  Implementors should stay posted for
+   information on new heuristics that might be required in the future.
+   Such information will be distributed on the IETF MIDCOM mailing list,
+   midcom at ietf.org.
+
+12.4 Residual Threats
+
+   None of the countermeasures listed above can prevent the attacks
+   described in Section 12.2.3 if the attacker is in the appropriate
+   network paths.  Specifically, consider the case in which the attacker
+   wishes to convince client C that it has address V.  The attacker
+   needs to have a network element on the path between A and the server
+   (in order to modify the request) and on the path between the server
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 37]
+
+RFC 3489                          STUN                        March 2003
+
+
+   and V so that it can forward the response to C.  Furthermore, if
+   there is a NAT between the attacker and the server, V must also be
+   behind the same NAT.  In such a situation, the attacker can either
+   gain access to all the application-layer traffic or mount the DDOS
+   attack described in Section 12.1.1.  Note that any host which exists
+   in the correct topological relationship can be DDOSed.  It need not
+   be using STUN.
+
+13.  IANA Considerations
+
+   STUN cannot be extended.  Changes to the protocol are made through a
+   standards track revision of this specification.  As a result, no IANA
+   registries are needed.  Any future extensions will establish any
+   needed registries.
+
+14.  IAB Considerations
+
+   The IAB has studied the problem of "Unilateral Self Address Fixing",
+   which is the general process by which a client attempts to determine
+   its address in another realm on the other side of a NAT through a
+   collaborative protocol reflection mechanism (RFC 3424 [17]).  STUN is
+   an example of a protocol that performs this type of function.  The
+   IAB has mandated that any protocols developed for this purpose
+   document a specific set of considerations.  This section meets those
+   requirements.
+
+14.1 Problem Definition
+
+   From RFC 3424 [17], any UNSAF proposal must provide:
+
+      Precise definition of a specific, limited-scope problem that is to
+      be solved with the UNSAF proposal.  A short term fix should not be
+      generalized to solve other problems; this is why "short term fixes
+      usually aren't".
+
+   The specific problems being solved by STUN are:
+
+   o  Provide a means for a client to detect the presence of one or more
+      NATs between it and a server run by a service provider on the
+      public Internet.  The purpose of such detection is to determine
+      additional steps that might be necessary in order to receive
+      service from that particular provider.
+
+   o  Provide a means for a client to detect the presence of one or more
+      NATs between it and another client, where the second client is
+      reachable from the first, but it is not known whether the second
+      client resides on the public Internet.
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 38]
+
+RFC 3489                          STUN                        March 2003
+
+
+   o  Provide a means for a client to obtain an address on the public
+      Internet from a non-symmetric NAT, for the express purpose of
+      receiving incoming UDP traffic from another host, targeted to that
+      address.
+
+   STUN does not address TCP, either incoming or outgoing, and does not
+   address outgoing UDP communications.
+
+14.2 Exit Strategy
+
+   From [17], any UNSAF proposal must provide:
+
+      Description of an exit strategy/transition plan.  The better short
+      term fixes are the ones that will naturally see less and less use
+      as the appropriate technology is deployed.
+
+   STUN comes with its own built in exit strategy.  This strategy is the
+   detection operation that is performed as a precursor to the actual
+   UNSAF address-fixing operation.  This discovery operation, documented
+   in Section 10.1, attempts to discover the existence of, and type of,
+   any NATS between the client and the service provider network.  Whilst
+   the detection of the specific type of NAT may be brittle, the
+   discovery of the existence of NAT is itself quite robust.  As NATs
+   are phased out through the deployment of IPv6, the discovery
+   operation will return immediately with the result that there is no
+   NAT, and no further operations are required.  Indeed, the discovery
+   operation itself can be used to help motivate deployment of IPv6; if
+   a user detects a NAT between themselves and the public Internet, they
+   can call up their access provider and complain about it.
+
+   STUN can also help facilitate the introduction of midcom.  As
+   midcom-capable NATs are deployed, applications will, instead of using
+   STUN (which also resides at the application layer), first allocate an
+   address binding using midcom.  However, it is a well-known limitation
+   of midcom that it only works when the agent knows the middleboxes
+   through which its traffic will flow.  Once bindings have been
+   allocated from those middleboxes, a STUN detection procedure can
+   validate that there are no additional middleboxes on the path from
+   the public Internet to the client.  If this is the case, the
+   application can continue operation using the address bindings
+   allocated from midcom.  If it is not the case, STUN provides a
+   mechanism for self-address fixing through the remaining midcom-
+   unaware middleboxes.  Thus, STUN provides a way to help transition to
+   full midcom-aware networks.
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 39]
+
+RFC 3489                          STUN                        March 2003
+
+
+14.3  Brittleness Introduced by STUN
+
+   From [17], any UNSAF proposal must provide:
+
+      Discussion of specific issues that may render systems more
+      "brittle".  For example, approaches that involve using data at
+      multiple network layers create more dependencies, increase
+      debugging challenges, and make it harder to transition.
+
+   STUN introduces brittleness into the system in several ways:
+
+   o  The discovery process assumes a certain classification of devices
+      based on their treatment of UDP.  There could be other types of
+      NATs that are deployed that would not fit into one of these molds.
+      Therefore, future NATs may not be properly detected by STUN.  STUN
+      clients (but not servers) would need to change to accommodate
+      that.
+
+   o  The binding acquisition usage of STUN does not work for all NAT
+      types.  It will work for any application for full cone NATs only.
+      For restricted cone and port restricted cone NAT, it will work for
+      some applications depending on the application. Application
+      specific processing will generally be needed.  For symmetric NATs,
+      the binding acquisition will not yield a usable address.  The
+      tight dependency on the specific type of NAT makes the protocol
+      brittle.
+
+   o  STUN assumes that the server exists on the public Internet.  If
+      the server is located in another private address realm, the user
+      may or may not be able to use its discovered address to
+      communicate with other users.  There is no way to detect such a
+      condition.
+
+   o  The bindings allocated from the NAT need to be continuously
+      refreshed.  Since the timeouts for these bindings is very
+      implementation specific, the refresh interval cannot easily be
+      determined.  When the binding is not being actively used to
+      receive traffic, but to wait for an incoming message, the binding
+      refresh will needlessly consume network bandwidth.
+
+   o  The use of the STUN server as an additional network element
+      introduces another point of potential security attack.  These
+      attacks are largely prevented by the security measures provided by
+      STUN, but not entirely.
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 40]
+
+RFC 3489                          STUN                        March 2003
+
+
+   o  The use of the STUN server as an additional network element
+      introduces another point of failure.  If the client cannot locate
+      a STUN server, or if the server should be unavailable due to
+      failure, the application cannot function.
+
+   o  The use of STUN to discover address bindings will result in an
+      increase in latency for applications.  For example, a Voice over
+      IP application will see an increase of call setup delays equal to
+      at least one RTT to the STUN server.
+
+   o  The discovery of binding lifetimes is prone to error.  It assumes
+      that the same lifetime will exist for all bindings. This may not
+      be true if the NAT uses dynamic binding lifetimes to handle
+      overload, or if the NAT itself reboots during the discovery
+      process.
+
+   o  STUN imposes some restrictions on the network topologies for
+      proper operation.  If client A obtains an address from STUN server
+      X, and sends it to client B, B may not be able to send to A using
+      that IP address.  The address will not work if any of the
+      following is true:
+
+      -  The STUN server is not in an address realm that is a common
+         ancestor (topologically) of both clients A and B.  For example,
+         consider client A and B, both of which have residential NAT
+         devices.  Both devices connect them to their cable operators,
+         but both clients have different providers. Each provider has a
+         NAT in front of their entire network, connecting it to the
+         public Internet.  If the STUN server used by A is in A's cable
+         operator's network, an address obtained by it will not be
+         usable by B.  The STUN server must be in the network which is a
+         common ancestor to both - in this case, the public Internet.
+
+      -  The STUN server is in an address realm that is a common
+         ancestor to both clients, but both clients are behind the same
+         NAT connecting to that address realm.  For example, if the two
+         clients in the previous example had the same cable operator,
+         that cable operator had a single NAT connecting their network
+         to the public Internet, and the STUN server was on the public
+         Internet, the address obtained by A would not be usable by B.
+         That is because some NATs will not accept an internal packet
+         sent to a public IP address which is mapped back to an internal
+         address.  To deal with this, additional protocol mechanisms or
+         configuration parameters need to be introduced which detect
+         this case.
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 41]
+
+RFC 3489                          STUN                        March 2003
+
+
+   o  Most significantly, STUN introduces potential security threats
+      which cannot be eliminated.  This specification describes
+      heuristics that can be used to mitigate the problem, but it is
+      provably unsolvable given what STUN is trying to accomplish.
+      These security problems are described fully in Section 12.
+
+14.4 Requirements for a Long Term Solution
+
+   From [17], any UNSAF proposal must provide:
+
+      Identify requirements for longer term, sound technical solutions
+      -- contribute to the process of finding the right longer term
+      solution.
+
+   Our experience with STUN has led to the following requirements for a
+   long term solution to the NAT problem:
+
+   Requests for bindings and control of other resources in a NAT
+      need to be explicit.  Much of the brittleness in STUN derives from
+      its guessing at the parameters of the NAT, rather than telling the
+      NAT what parameters to use.
+
+   Control needs to be "in-band".  There are far too many scenarios
+      in which the client will not know about the location of
+      middleboxes ahead of time.  Instead, control of such boxes needs
+      to occur in-band, traveling along the same path as the data will
+      itself travel.  This guarantees that the right set of middleboxes
+      are controlled.  This is only true for first-party controls;
+      third-party controls are best handled using the midcom framework.
+
+   Control needs to be limited.  Users will need to communicate
+      through NATs which are outside of their administrative control.
+      In order for providers to be willing to deploy NATs which can be
+      controlled by users in different domains, the scope of such
+      controls needs to be extremely limited - typically, allocating a
+      binding to reach the address where the control packets are coming
+      from.
+
+   Simplicity is Paramount.  The control protocol will need to be
+      implement in very simple clients.  The servers will need to
+      support extremely high loads.  The protocol will need to be
+      extremely robust, being the precursor to a host of application
+      protocols.  As such, simplicity is key.
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 42]
+
+RFC 3489                          STUN                        March 2003
+
+
+14.5 Issues with Existing NAPT Boxes
+
+   From [17], any UNSAF proposal must provide:
+
+      Discussion of the impact of the noted practical issues with
+      existing, deployed NA[P]Ts and experience reports.
+
+   Several of the practical issues with STUN involve future proofing -
+   breaking the protocol when new NAT types get deployed.  Fortunately,
+   this is not an issue at the current time, since most of the deployed
+   NATs are of the types assumed by STUN.  The primary usage STUN has
+   found is in the area of VoIP, to facilitate allocation of addresses
+   for receiving RTP [12] traffic.  In that application, the periodic
+   keepalives are provided by the RTP traffic itself.  However, several
+   practical problems arise for RTP.  First, RTP assumes that RTCP
+   traffic is on a port one higher than the RTP traffic.  This pairing
+   property cannot be guaranteed through NATs that are not directly
+   controllable.  As a result, RTCP traffic may not be properly
+   received.  Protocol extensions to SDP have been proposed which
+   mitigate this by allowing the client to signal a different port for
+   RTCP [18].  However, there will be interoperability problems for some
+   time.
+
+   For VoIP, silence suppression can cause a gap in the transmission of
+   RTP packets.  This could result in the loss of a binding in the
+   middle of a call, if that silence period exceeds the binding timeout.
+   This can be mitigated by sending occasional silence packets to keep
+   the binding alive.  However, the result is additional brittleness;
+   proper operation depends on the silence suppression algorithm in use,
+   the usage of a comfort noise codec, the duration of the silence
+   period, and the binding lifetime in the NAT.
+
+14.6 In Closing
+
+   The problems with STUN are not design flaws in STUN.  The problems in
+   STUN have to do with the lack of standardized behaviors and controls
+   in NATs.  The result of this lack of standardization has been a
+   proliferation of devices whose behavior is highly unpredictable,
+   extremely variable, and uncontrollable.  STUN does the best it can in
+   such a hostile environment.  Ultimately, the solution is to make the
+   environment less hostile, and to introduce controls and standardized
+   behaviors into NAT.  However, until such time as that happens, STUN
+   provides a good short term solution given the terrible conditions
+   under which it is forced to operate.
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 43]
+
+RFC 3489                          STUN                        March 2003
+
+
+15.  Acknowledgments
+
+   The authors would like to thank Cedric Aoun, Pete Cordell, Cullen
+   Jennings, Bob Penfield and Chris Sullivan for their comments, and
+   Baruch Sterman and Alan Hawrylyshen for initial implementations.
+   Thanks for Leslie Daigle, Allison Mankin, Eric Rescorla, and Henning
+   Schulzrinne for IESG and IAB input on this work.
+
+16.  Normative References
+
+   [1]  Bradner, S., "Key words for use in RFCs to indicate requirement
+        levels", BCP 14, RFC 2119, March 1997.
+
+   [2]  Dierks, T. and C. Allen, "The TLS protocol Version 1.0", RFC
+        2246, January 1999.
+
+   [3]  Gulbrandsen, A., Vixie, P. and L. Esibov, "A DNS RR for
+        specifying the location of services (DNS SRV)", RFC 2782,
+        February 2000.
+
+   [4]  Chown, P., "Advanced Encryption Standard (AES) Ciphersuites for
+        Transport Layer Security (TLS)", RFC 3268, June 2002.
+
+   [5]  Rescorla, E., "HTTP over TLS", RFC 2818, May 2000.
+
+   [6]  Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.
+
+   [7]  Ferguson, P. and D. Senie, "Network Ingress Filtering: Defeating
+        Denial of Service Attacks which employ IP Source Address
+        Spoofing", BCP 38, RFC 2827, May 2000.
+
+17.  Informative References
+
+   [8]  Senie, D., "Network Address Translator (NAT)-Friendly
+        Application Design Guidelines", RFC 3235, January 2002.
+
+   [9]  Srisuresh, P., Kuthan, J., Rosenberg, J., Molitor, A. and A.
+        Rayhan, "Middlebox Communication Architecture and Framework",
+        RFC 3303, August 2002.
+
+   [10] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A.,
+        Peterson, J., Sparks, R., Handley, M. and E. Schooler, "SIP:
+        Session Initiation Protocol", RFC 3261, June 2002.
+
+   [11] Holdrege, M. and P. Srisuresh, "Protocol Complications with the
+        IP Network Address Translator", RFC 3027, January 2001.
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 44]
+
+RFC 3489                          STUN                        March 2003
+
+
+   [12] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson,
+        "RTP:  A Transport Protocol for Real-Time Applications", RFC
+        1889, January 1996.
+
+   [13] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing
+        for Message Authentication", RFC 2104, February 1997.
+
+   [14] Kohl, J. and C. Neuman, "The kerberos Network Authentication
+        Service (V5)", RFC 1510, September 1993.
+
+   [15] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+        Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+        HTTP/1.1", RFC 2616, June 1999.
+
+   [16] Baugher M., et al., "The secure real-time transport protocol",
+        Work in Progress.
+
+   [17] Daigle, L., Editor, "IAB Considerations for UNilateral Self-
+        Address Fixing (UNSAF) Across Network Address Translation", RFC
+        3424, November 2002.
+
+   [18] Huitema, C., "RTCP attribute in SDP", Work in Progress.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 45]
+
+RFC 3489                          STUN                        March 2003
+
+
+18. Authors' Addresses
+
+   Jonathan Rosenberg
+   dynamicsoft
+   72 Eagle Rock Avenue
+   First Floor
+   East Hanover, NJ 07936
+
+   EMail: jdrosen at dynamicsoft.com
+
+
+   Joel Weinberger
+   dynamicsoft
+   72 Eagle Rock Avenue
+   First Floor
+   East Hanover, NJ 07936
+
+   EMail: jweinberger at dynamicsoft.com
+
+
+   Christian Huitema
+   Microsoft Corporation
+   One Microsoft Way
+   Redmond, WA 98052-6399
+
+   EMail: huitema at microsoft.com
+
+
+   Rohan Mahy
+   Cisco Systems
+   101 Cooper St
+   Santa Cruz, CA 95060
+
+   EMail: rohan at cisco.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 46]
+
+RFC 3489                          STUN                        March 2003
+
+
+19. Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al.           Standards Track                    [Page 47]
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_H
+/** Defined when <sofia-sip/stun.h> has been included. */
+#define STUN_H
+
+/**@file sofia-sip/stun.h STUN module public interface
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#include "sofia-sip/stun_common.h"
+
+#include <sofia-sip/su_localinfo.h>
+
+SOFIA_BEGIN_DECLS
+
+typedef struct stun_handle_s     stun_handle_t;
+typedef struct stun_request_s    stun_request_t;
+typedef struct stun_discovery_s  stun_discovery_t;
+typedef struct stun_dns_lookup_s stun_dns_lookup_t;
+
+typedef struct stun_mini_s     stun_mini_t;
+
+#ifndef STUN_MAGIC_T 
+#define STUN_MAGIC_T            struct stun_magic_t
+#endif
+/** STUN server context */
+typedef STUN_MAGIC_T stun_magic_t;
+
+#ifndef STUN_DISCOVERY_MAGIC_T 
+#define STUN_DISCOVERY_MAGIC_T            struct stun_discovery_magic_t
+#endif
+/** STUN discovery_ context */
+typedef STUN_DISCOVERY_MAGIC_T stun_discovery_magic_t;
+
+/** Name and version of STUN software */
+SOFIAPUBVAR char const stun_version[];
+
+/**
+ * STUN Action types. These define the current discovery process.
+ * Defined as a bitmap.
+ */
+typedef enum stun_action_s {
+  stun_action_no_action = 1,
+  stun_action_tls_query = 2,
+  stun_action_binding_request = 4,
+  stun_action_keepalive = 8,
+  stun_action_test_nattype = 16,
+  stun_action_test_lifetime = 32,
+} stun_action_t;
+
+/**
+ * NAT types
+ *
+ * XXX: should be extended to distinguish between filtering and
+ *      mapping allocation behaviour (see IETF BEHAVE documents)
+ *
+ * Note: the NAT type detection algorithm can fail in 
+ *       case where the NAT behaves in a nondeterministic 
+ *       fashion.
+ **/
+typedef enum stun_nattype_e {
+  stun_nat_unknown = 0, 
+      
+  /* no NAT between client and STUN server */
+  stun_open_internet,     
+
+  /* UDP communication blocked by FW */
+  stun_udp_blocked,       
+
+  /* No NAT, but a FW element is performing address and port
+   * restricted filtering. */
+  stun_sym_udp_fw,        
+
+  /* Endpoint independent filtering (endpoint independent mapping) 
+   * RFC3489 full cone NAT. */
+  stun_nat_full_cone,     
+
+  /* Address restricted filtering (endpoint independent mapping),
+   * RFC3489 restricted cone NAT. */
+  stun_nat_res_cone,      
+
+  /* Address and port restricted filtering (endpoint 
+   * independent mapping), RFC3489 port restricted cone */
+  stun_nat_port_res_cone, 
+
+  /* Endpoint independent filtering, endpoint dependent mapping. */
+  stun_nat_ei_filt_ad_map, 
+
+  /* Address dependent filtering, endpoint dependent mapping. */
+  stun_nat_ad_filt_ad_map, 
+
+  /* Address and port dependent filtering, endpoint dependent mapping 
+   * RFC3489 symmetric NAT). */
+  stun_nat_adp_filt_ad_map, 
+
+} stun_nattype_t;
+
+/**
+ * States of the STUN client->server query process.
+ *
+ * @see stun_bind()
+ * @see stun_obtain_shared_secret()
+ * @see stun_test_nattype()
+ * @see stun_test_lifetime()
+ */ 
+typedef enum stun_state_e {
+  
+  stun_no_assigned_event,
+
+  /* TLS events; see stun_obtain_shared_request() */
+  stun_tls_connecting,          /**< Connecting to TLS port */
+  stun_tls_ssl_connecting,      /**< Started the TLS/SSL handshake */
+  stun_tls_writing,             /**< Next step: send request */
+  stun_tls_closing,             /**< Closing TLS connection */
+  stun_tls_reading,             /**< Request send, waiting for response */
+  stun_tls_done,                /**< Shared-secret acquired */
+
+  /* STUN discovery events */
+  stun_discovery_done,          /**< Discovery process done */
+
+  /* STUN errors */
+  /* Do not change the order! Errors need to be after stun_error */
+
+  stun_error,                   /**< Generic error in discovery process */
+  stun_tls_connection_timeout,  /**< No response to connect attempt */
+  stun_tls_connection_failed,   /**< No response from TLS/SSL server  */
+  stun_tls_ssl_connect_failed,  /**< TLS/SSL handshake failed */
+
+  stun_discovery_error,         /**< Error in discovery process */
+  stun_discovery_timeout,       /**< No response to discovery request */
+
+} stun_state_t;
+
+/* -------------------------------------------------------------------
+ * Calback function prototypes (signals emitted by the stack) */
+
+/* Per discovery */
+typedef void (*stun_discovery_f)(stun_discovery_magic_t *magic,
+				 stun_handle_t *sh,
+				 stun_discovery_t *sd,
+				 stun_action_t action,
+				 stun_state_t event);
+
+/** Callback invoked by stun handle when it has a message to send. */
+typedef int (*stun_send_callback)(stun_magic_t *magic,
+				  stun_handle_t *sh,
+				  int socket,
+				  void *data,
+				  unsigned len,
+				  int only_a_keepalive);
+
+/** Callback for delivering DNS lookup results */
+typedef void (*stun_dns_lookup_f)(stun_dns_lookup_t *self,
+				  stun_magic_t *magic);
+
+/* -------------------------------------------------------------------
+ * Functions for managing STUN handles. */
+
+SOFIAPUBFUN stun_handle_t *stun_handle_init(su_root_t *root,
+					    tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN void stun_handle_destroy(stun_handle_t *sh);
+
+SOFIAPUBFUN su_root_t *stun_root(stun_handle_t *sh);
+SOFIAPUBFUN int stun_is_requested(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN char const *stun_str_state(stun_state_t state);
+SOFIAPUBFUN su_addrinfo_t const *stun_server_address(stun_handle_t *sh);
+
+SOFIAPUBFUN
+int stun_process_message(stun_handle_t *sh, su_socket_t s,
+			 su_sockaddr_t *sa, socklen_t salen,
+			 void *data, isize_t len);
+SOFIAPUBFUN
+int stun_process_request(su_socket_t s, stun_msg_t *req,
+			 int sid, su_sockaddr_t *from_addr,
+			 socklen_t from_len);
+
+/* ------------------------------------------------------------------- 
+ * Functions for 'Binding Discovery' usage (RFC3489/3489bis) */
+
+SOFIAPUBFUN
+int stun_obtain_shared_secret(stun_handle_t *sh, stun_discovery_f,
+			      stun_discovery_magic_t *magic,
+			      tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN 
+int stun_bind(stun_handle_t *sh, 
+	      stun_discovery_f, stun_discovery_magic_t *magic,
+	      tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN 
+int stun_discovery_get_address(stun_discovery_t *sd,
+			       void *addr,
+			       socklen_t *return_addrlen);
+SOFIAPUBFUN su_socket_t stun_discovery_get_socket(stun_discovery_t *sd);
+SOFIAPUBFUN int stun_discovery_release_socket(stun_discovery_t *sd);
+
+SOFIAPUBFUN
+int stun_test_nattype(stun_handle_t *sh,
+		       stun_discovery_f, stun_discovery_magic_t *magic,
+		       tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN char const *stun_nattype_str(stun_discovery_t *sd);
+SOFIAPUBFUN stun_nattype_t stun_nattype(stun_discovery_t *sd);
+
+SOFIAPUBFUN
+int stun_test_lifetime(stun_handle_t *sh,
+		       stun_discovery_f, stun_discovery_magic_t *magic,
+		       tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int stun_lifetime(stun_discovery_t *sd);
+
+/* ------------------------------------------------------------------- 
+ * Functions for 'Connectivity Check' and 'NAT Keepalives' usages (RFC3489bis) */
+
+SOFIAPUBFUN 
+int stun_set_uname_pwd(stun_handle_t *sh,
+		       const char *uname,
+		       isize_t len_uname, 
+		       const char *pwd,
+		       isize_t len_pwd);
+
+SOFIAPUBFUN int stun_msg_is_keepalive(uint16_t data);
+SOFIAPUBFUN int stun_message_length(void *data, isize_t len, int end_of_message);
+
+/* Create a keepalive dispatcher for bound SIP sockets */
+
+SOFIAPUBFUN 
+int stun_keepalive(stun_handle_t *sh,
+		   su_sockaddr_t *sa,
+		   tag_type_t tag, tag_value_t value,
+		   ...);
+SOFIAPUBFUN int stun_keepalive_destroy(stun_handle_t *sh, su_socket_t s);
+
+/* -------------------------------------------------------------------
+ * Functions for 'Short-Term password' usage (RFC3489bis) */
+
+/* (not implemented, see stun_request_shared_secret()) */
+
+/* -------------------------------------------------------------------
+ * Functions for STUN server discovery using DNS (RFC3489/3489bis) */
+
+SOFIAPUBFUN 
+stun_dns_lookup_t *stun_dns_lookup(stun_magic_t *magic, 
+				   su_root_t *root,
+				   stun_dns_lookup_f func, 
+				   const char *domain);
+SOFIAPUBFUN void stun_dns_lookup_destroy(stun_dns_lookup_t *self);
+
+SOFIAPUBFUN int stun_dns_lookup_udp_addr(stun_dns_lookup_t *,
+					 const char **target, uint16_t *port);
+SOFIAPUBFUN int stun_dns_lookup_tcp_addr(stun_dns_lookup_t *self,
+					 const char **target, uint16_t *port);
+SOFIAPUBFUN int stun_dns_lookup_stp_addr(stun_dns_lookup_t *self,
+					 const char **target, uint16_t *port);
+
+/* -------------------------------------------------------------------
+ * Functions for minimal STUN server */
+
+SOFIAPUBFUN stun_mini_t *stun_mini_create(void);
+SOFIAPUBFUN void stun_mini_destroy(stun_mini_t *);
+
+SOFIAPUBFUN int stun_mini_add_socket(stun_mini_t *server,
+				     su_socket_t socket);
+SOFIAPUBFUN int stun_mini_remove_socket(stun_mini_t *server,
+					su_socket_t socket);
+
+SOFIAPUBFUN void stun_mini_request(stun_mini_t *server, su_socket_t socket,
+				   void *msg, ssize_t msglen,
+				   void *addr, socklen_t addrlen);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(STUN_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_COMMON_H
+/** Defined when <sofia-sip/stun_common.h> has been included. */
+#define STUN_COMMON_H
+
+/**
+ * @file sofia-sip/stun_common.h
+ * @brief 
+ * 
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * 
+ * @date Created: Fri Oct  3 13:39:55 2003 ppessi
+ * 
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Define Message Types */
+#define BINDING_REQUEST               0x0001
+#define BINDING_RESPONSE              0x0101
+#define BINDING_ERROR_RESPONSE        0x0111
+#define SHARED_SECRET_REQUEST         0x0002
+#define SHARED_SECRET_RESPONSE        0x0102
+#define SHARED_SECRET_ERROR_RESPONSE  0x0112
+
+/* Define Attribute Types */
+#define MAPPED_ADDRESS                0x0001
+#define RESPONSE_ADDRESS              0x0002
+#define CHANGE_REQUEST                0x0003
+#define SOURCE_ADDRESS                0x0004
+#define CHANGED_ADDRESS               0x0005
+#define USERNAME                      0x0006
+#define PASSWORD                      0x0007
+#define MESSAGE_INTEGRITY             0x0008
+#define ERROR_CODE                    0x0009
+#define UNKNOWN_ATTRIBUTES            0x000a
+#define REFLECTED_FROM                0x000b
+#define STUN_A_REALM                  0x0014 /* XXX: check value in 3489bis-05+ */
+#define STUN_A_NONCE                  0x0015 /* XXX: check value in 3489bis-05+ */
+#define STUN_A_XOR_MAPPED_ADDRESS     0x0020
+#define STUN_A_FINGERPRINT            0x0023
+#define STUN_A_SERVER                 0x8022
+#define STUN_A_ALTERNATE_SERVER       0x8023
+#define STUN_A_REFRESH_INTERVAL       0x8024
+
+/* Defines for mandatory and optional attributes */
+#define STUN_A_LAST_MANDATORY         0x0023 /**< largest attribute in the current 
+						spec (see above for exceptions
+						for buggy servers) */
+#define STUN_A_OPTIONAL               0x7fff
+
+/* Compability attribute types */
+#define STUN_A_ALTERNATE_SERVER_DEP   0x000e /**< historic from early fc3489bis drafts */
+#define STUN_A_BUGGYSERVER_XORONLY    0x0021 /**< workaround for stund-0.94 and older */
+#define STUN_A_BUGGYSERVER_SERVER     0x0022 /**< workaround for stund-0.94 and older */
+#define LARGEST_ATTRIBUTE             STUN_A_LAST_MANDATORY /**< deprecated API */
+#define OPTIONAL_ATTRIBUTE            STUN_A_OPTIONAL /**< deprecated API */
+
+/* Stun response codes */
+#define STUN_400_BAD_REQUEST             400
+#define STUN_401_UNAUTHORIZED            401
+#define STUN_420_UNKNOWN_ATTRIBUTE       420
+#define STUN_430_STALE_CREDENTIALS       430
+#define STUN_431_INTEGRITY_CHECK_FAILURE 431
+#define STUN_432_MISSING_USERNAME        432
+#define STUN_433_USE_TLS                 433
+#define STUN_500_SERVER_ERROR            500
+#define STUN_600_GLOBAL_FAILURE          600
+
+/* flags for CHANGE_REQUEST */
+#define STUN_CR_CHANGE_IP               0x0004
+#define STUN_CR_CHANGE_PORT             0x0002
+
+/* mask for ERROR_CODE */
+#define STUN_EC_CLASS                   0x0070
+#define STUN_EC_NUM                     0x000F
+
+#define RAND_MAX_16                     65535
+
+#define STUN_TID_BYTES                  16
+
+/* other protocol specific parameters */
+#define STUN_MAX_RETRX                  5 /* should be 8? */
+#define STUN_MAX_RETRX_INT              1600  /**< max retrx interval in
+						   millisec */
+#define STUN_DEFAULT_PORT               3478  /**< from RFC3489 */
+
+/*
+ * STUN header format
+ */
+  /*
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |         message type          |       message length          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                                                               |
+   |                       Transaction ID                          |
+   |                                                               |
+   |                                                               |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  */
+struct stun_buffer_s {
+  unsigned char *data;      /**< Pointer to data */
+  unsigned size;            /**< Size of buffer */
+};
+
+typedef struct stun_buffer_s stun_buffer_t;
+
+typedef struct {
+  uint16_t msg_type;        /**< message type */
+  uint16_t msg_len;         /**< message length */
+  uint8_t tran_id[16];      /**< transaction id, 128 bits */
+} stun_hdr_t;
+
+typedef struct stun_attr_s {
+  uint16_t attr_type;       /**< attribute type */
+  void *pattr;              /**< pointer to corresponding attribute */
+  stun_buffer_t enc_buf;    /**< encoded attribue */
+  struct stun_attr_s *next; /**< next attribute */
+} stun_attr_t;
+
+typedef struct {
+  stun_hdr_t stun_hdr;
+  stun_attr_t *stun_attr;
+  stun_buffer_t enc_buf;    /**< to store already encoded stun msg */
+} stun_msg_t;
+
+/* stun attribute definition */
+/* stun_sockaddr_t is used for:
+   MAPPED_ADDRESS
+   RESPONSE_ADDRESS
+   SOURCE_ADDRESS
+   CHANGED_ADDRESS
+   REFLECTED_FROM
+*/
+typedef struct sockaddr_in stun_attr_sockaddr_t;
+
+/* CHANGE_REQUEST attribute */
+typedef struct stun_attr_uint32_s {
+  uint32_t value;
+} stun_attr_uint32_t;
+
+typedef stun_attr_uint32_t stun_attr_changerequest_t;
+
+/* ERROR_CODE attribute */
+typedef struct {
+  int code;
+  char *phrase;
+} stun_attr_errorcode_t;
+
+/* USERNAME attribute */
+/* typedef struct {
+  stun_buffer_t *uname;
+} stun_attr_username_t;
+*/
+typedef stun_buffer_t stun_attr_username_t;
+
+/* PASSWORD attribute */
+typedef stun_buffer_t stun_attr_password_t;
+
+/* UNKNOWN_ATTRIBUTES attribute */
+typedef struct stun_attr_unknownattributes_s{
+  uint16_t attr_type[2];
+  struct stun_attr_unknownattributes_s *next;
+} stun_attr_unknownattributes_t;
+
+/* Common functions */
+int stun_parse_message(stun_msg_t *msg);
+int stun_parse_attribute(stun_msg_t *msg, unsigned char *p);
+int stun_parse_attr_address(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_unknown_attributes(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_buffer(stun_attr_t *attr, const unsigned char *p, unsigned len);
+
+stun_attr_t *stun_get_attr(stun_attr_t *attr, uint16_t attr_type);
+
+int stun_encode_address(stun_attr_t *attr);
+int stun_encode_uint32(stun_attr_t *attr);
+int stun_encode_buffer(stun_attr_t *attr);
+int stun_encode_error_code(stun_attr_t *attr);
+int stun_encode_message_integrity(stun_attr_t *attr, unsigned char *buf, int len, stun_buffer_t *pwd);
+int stun_encode_type_len(stun_attr_t *attr, uint16_t len);
+int stun_encode_response_address(stun_attr_t *attr);
+
+int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd); 
+
+int stun_copy_buffer(stun_buffer_t *p, stun_buffer_t *p2);
+void stun_init_buffer(stun_buffer_t *p);
+int stun_free_buffer(stun_buffer_t *p);
+int stun_free_message(stun_msg_t *msg);
+
+int stun_init_message(stun_msg_t *msg);
+/* int stun_send_message(int sockfd, struct sockaddr_in *to_addr, stun_msg_t *msg, stun_buffer_t *pwd); */
+int stun_encode_message(stun_msg_t *msg, stun_buffer_t *pwd);
+
+char const *stun_response_phrase(int status);
+void debug_print(stun_buffer_t *buf);
+char const *stun_attr_phrase(uint16_t type);
+
+/**Determines and returns local IP address
+ *
+ * Address is determined using su_getlocalinfo() function.
+ *
+ * @param family        network address family in use
+ * @return local ip address
+ */
+char *stun_determine_ip_address(int family);
+
+SOFIA_END_DECLS
+
+#endif /* !defined STUN_COMMON_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_TAG_H
+#define STUN_TAG_H
+/**@file sofia-sip/stun_tag.h  Tags for STUN.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Tue Oct 18 20:13:50 EEST 2005 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_IO_H
+#include <sofia-sip/su_tag_io.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/*****************************************
+ * Note: see documentation in stun_tag.c *
+ *****************************************/
+
+#define STUNTAG_ANY()         stuntag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t stuntag_any;
+
+#define STUNTAG_DOMAIN(x)  stuntag_domain, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_domain;
+#define STUNTAG_DOMAIN_REF(x) stuntag_domain_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_domain_ref;
+
+#define STUNTAG_SERVER(x)  stuntag_server, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_server;
+#define STUNTAG_SERVER_REF(x) stuntag_server_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_server_ref;
+
+#define STUNTAG_REQUIRE_INTEGRITY(x) stuntag_require_integrity, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_require_integrity;
+#define STUNTAG_REQUIRE_INTEGRITY_REF(x) stuntag_require_integrity_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_require_integrity_ref;
+
+#define STUNTAG_INTEGRITY(x) stuntag_integrity, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_integrity;
+#define STUNTAG_INTEGRITY_REF(x) stuntag_integrity_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_integrity_ref;
+
+#define STUNTAG_SOCKET(x) stuntag_socket, tag_socket_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_socket;
+#define STUNTAG_SOCKET_REF(x) stuntag_socket_ref, tag_socket_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_socket_ref;
+
+#define STUNTAG_REGISTER_EVENTS(x) stuntag_register_events, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_register_events;
+#define STUNTAG_REGISTER_EVENTS_REF(x) stuntag_register_events_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_register_events_ref;
+
+#define STUNTAG_ACTION(x) stuntag_action, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_action;
+#define STUNTAG_ACTION_REF(x) stuntag_action_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_action_ref;
+
+#define STUNTAG_CHANGE_IP(x) stuntag_change_ip, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_change_ip;
+#define STUNTAG_CHANGE_IP_REF(x) stuntag_change_ip_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_change_ip_ref;
+
+#define STUNTAG_CHANGE_PORT(x) stuntag_change_port, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_change_port;
+#define STUNTAG_CHANGE_PORT_REF(x) stuntag_change_port_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_change_port_ref;
+
+#define STUNTAG_TIMEOUT(x) stuntag_timeout, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t stuntag_timeout;
+#define STUNTAG_TIMEOUT_REF(x) stuntag_timeout_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_timeout_ref;
+
+
+SOFIA_END_DECLS
+
+#endif /* STUN_TAG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun.c STUN client module
+ *
+ * See RFC 3489/3489bis for further information.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * 
+ * @date Created: Thu Jul 24 17:21:00 2003 ppessi
+ */
+
+#include "config.h" 
+
+#include <assert.h>
+#include <string.h>
+
+#define SU_ROOT_MAGIC_T struct stun_magic_t
+
+#include "sofia-sip/stun.h"
+#include "stun_internal.h"
+#include "sofia-sip/stun_tag.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#if defined(HAVE_OPENSSL)
+#include <openssl/opensslv.h>
+#endif
+
+#if !defined(ETIMEDOUT) && defined(_WIN32)
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+
+/* Missing socket symbols */
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stun";
+#endif
+
+/** STUN log. */
+su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", 3) }; 
+
+/**@var STUN_DEBUG
+ *
+ * Environment variable determining the debug log level for @b stun module.
+ *
+ * The STUN_DEBUG environment variable is used to determine the debug logging
+ * level for @b stun module. The default level is 3.
+ * 
+ * @sa <sofia-sip/su_debug.h>, stun_log, SOFIA_DEBUG
+ */
+extern char const STUN__DEBUG[];
+
+enum {
+  STUN_SENDTO_TIMEOUT = 1000,
+  STUN_TLS_CONNECT_TIMEOUT = 8000,
+};
+
+/**
+ * States of STUN requests. See stun_state_e for states
+ * discovery processes.
+ */ 
+typedef enum stun_req_state_e {
+  stun_req_no_assigned_event,
+  stun_req_dispose_me,            /**< request can be disposed */
+  stun_req_discovery_init,
+  stun_req_discovery_processing,
+
+  stun_req_error,
+  stun_req_timeout
+} stun_req_state_t;
+
+#define CHG_IP		0x001
+#define CHG_PORT	0x004
+
+#define x_insert(l, n, x) \
+ ((l) ? (l)->x##_prev = &(n)->x##_next : 0, \
+  (n)->x##_next = (l), (n)->x##_prev = &(l), (l) = (n))
+
+#define x_remove(n, x) \
+  ((*(n)->x##_prev = (n)->x##_next) ? \
+   (n)->x##_next->x##_prev = (n)->x##_prev : 0)
+
+#define x_is_inserted(n, x) ((n)->x##_prev != NULL)
+
+struct stun_discovery_s {
+  stun_discovery_t   *sd_next, **sd_prev; /**< Linked list */
+
+  stun_handle_t          *sd_handle;
+  stun_discovery_f        sd_callback;
+  stun_discovery_magic_t *sd_magic;
+
+  tagi_t          *sd_tags;          /** stored tags for the discovery */
+
+
+  su_addrinfo_t    sd_pri_info;      /**< server primary info */
+  su_sockaddr_t    sd_pri_addr[1];   /**< server primary address */
+
+  su_addrinfo_t    sd_sec_info;      /**< server secondary info */
+  su_sockaddr_t    sd_sec_addr[1];   /**< server secondary address */
+
+  stun_action_t    sd_action;        /**< My action */
+  stun_state_t     sd_state;         /**< Progress states */
+
+  su_socket_t      sd_socket;        /**< target socket */
+  su_sockaddr_t    sd_bind_addr[1]; /**< local address */
+
+  su_socket_t      sd_socket2;       /**< Alternative socket */
+
+  int              sd_index;         /**< root_register index */
+
+  /* Binding discovery */
+  su_sockaddr_t    sd_addr_seen_outside[1];   /**< local address */
+
+  /* NAT type related */
+  stun_nattype_t   sd_nattype;       /**< Determined NAT type */
+  int              sd_mapped_addr_match; /** Mapped addresses match? */
+  int              sd_first;         /**< These are the requests  */
+  int              sd_second;
+  int              sd_third;
+  int              sd_fourth;
+
+  /* Life time related */
+  int              sd_lt_cur;
+  int              sd_lt;
+  int              sd_lt_max;
+
+  /* Keepalive timeout */
+  unsigned int     sd_timeout;
+  su_timer_t      *sd_timer;
+};
+
+struct stun_request_s {
+  su_timer_t       *sr_timer;
+  stun_request_t   *sr_next, **sr_prev; /**< Linked list */
+  stun_msg_t       *sr_msg;             /**< STUN message pointer */
+  stun_handle_t    *sr_handle;          /**< backpointer, STUN object */
+
+  su_socket_t       sr_socket;          /**< Alternative socket */
+  su_localinfo_t    sr_localinfo;       /**< local addrinfo */
+  su_sockaddr_t     sr_local_addr[1];   /**< local address */
+  su_sockaddr_t     sr_destination[1];
+
+  stun_state_t      sr_state;           /**< Progress states */
+  int               sr_retry_count;     /**< current retry number */
+  long              sr_timeout;         /**< timeout for next sendto() */
+
+  int               sr_from_y;
+  int               sr_request_mask;    /**< Mask consisting of chg_ip and chg_port */
+  stun_discovery_t *sr_discovery;
+};
+
+struct stun_handle_s
+{
+  su_home_t       sh_home[1];
+  su_root_t      *sh_root;          /**< event loop */
+  int             sh_root_index;    /**< object index of su_root_register() */
+
+  stun_request_t *sh_requests; /**< outgoing requests list */
+  stun_discovery_t *sh_discoveries; /**< Actions list */
+
+  int             sh_max_retries;   /**< max resend for sendto() */
+
+  su_addrinfo_t   sh_pri_info;      /**< server primary info */
+  su_sockaddr_t   sh_pri_addr[1];   /**< server primary address */
+
+  su_addrinfo_t   sh_sec_info;      /**< server secondary info */
+  su_sockaddr_t   sh_sec_addr[1];   /**< server secondary address */
+
+  su_localinfo_t  sh_localinfo;     /**< local addrinfo */
+  su_sockaddr_t   sh_local_addr[1]; /**< local address */
+
+  char           *sh_domain;        /**< domain address for DNS-SRV lookups */
+
+  stun_dns_lookup_t  *sh_dns_lookup;
+  stun_action_t       sh_dns_pend_action; 
+  stun_discovery_f    sh_dns_pend_cb;
+  stun_discovery_magic_t *sh_dns_pend_ctx;
+  tagi_t             *sh_dns_pend_tags;
+
+#if defined(HAVE_OPENSSL)
+  SSL_CTX        *sh_ctx;           /**< SSL context for TLS */
+  SSL            *sh_ssl;           /**< SSL handle for TLS */
+#else
+  void           *sh_ctx;           /**< SSL context for TLS */
+  void           *sh_ssl;           /**< SSL handle for TLS */
+#endif
+
+  stun_msg_t      sh_tls_request;
+  stun_msg_t      sh_tls_response;
+  int             sh_nattype;       /**< NAT-type, see stun_common.h */
+
+  stun_buffer_t   sh_username;
+  stun_buffer_t   sh_passwd;
+
+  int             sh_use_msgint;    /**< try message integrity (TLS) */
+  int             sh_req_msgint;    /**< require use of msg-int (TLS) */
+};
+
+
+#define STUN_STATE_STR(x) case x: return #x
+
+char const *stun_str_state(stun_state_t state)
+{
+  switch (state) {
+  STUN_STATE_STR(stun_no_assigned_event);
+  /* STUN_STATE_STR(stun_req_dispose_me); */
+  STUN_STATE_STR(stun_tls_connecting);
+  STUN_STATE_STR(stun_tls_writing);
+  STUN_STATE_STR(stun_tls_closing);
+  STUN_STATE_STR(stun_tls_reading);
+  STUN_STATE_STR(stun_tls_done);
+  /* STUN_STATE_STR(stun_req_discovery_init); */
+  /* STUN_STATE_STR(stun_req_discovery_processing); */
+  STUN_STATE_STR(stun_discovery_done);
+  STUN_STATE_STR(stun_tls_connection_timeout);
+  STUN_STATE_STR(stun_tls_connection_failed);
+  STUN_STATE_STR(stun_tls_ssl_connect_failed);
+  STUN_STATE_STR(stun_discovery_timeout);
+  /* STUN_STATE_STR(stun_req_timeout); */
+  
+  case stun_error:
+  default: return "stun_error";
+  }
+}
+
+/** 
+ * Returns the NAT type attached to STUN discovery handle.
+ *
+ * @see stun_nattype_str().
+ * @see stun_test_nattype().
+ */
+char const *stun_nattype_str(stun_discovery_t *sd)
+{
+  char const *stun_nattype_str[] = {
+    "NAT type undetermined",
+    "Open Internet",
+    "UDP traffic is blocked or server unreachable",
+    "Symmetric UDP Firewall",
+    "Full-Cone NAT (endpoint independent filtering and mapping)",
+    "Restricted Cone NAT (endpoint independent mapping)",
+    "Port Restricted Cone NAT (endpoint independent mapping)",
+    "Endpoint independent filtering, endpoint dependent mapping",
+    "Address dependent filtering, endpoint dependent mapping",
+    "Symmetric NAT (address and port dependent filtering, endpoint dependent mapping)",
+  };
+
+  if (sd)
+    return stun_nattype_str[sd->sd_nattype];
+  else
+    return stun_nattype_str[stun_nat_unknown];
+}
+
+/**
+ * Returns the detected NAT type.
+ * 
+ * @see stun_nattype_str().
+ * @see stun_test_nattype().
+ */
+stun_nattype_t stun_nattype(stun_discovery_t *sd)
+{
+  if (!sd)
+    return stun_nat_unknown;
+
+  return sd->sd_nattype;
+}
+
+su_addrinfo_t const *stun_server_address(stun_handle_t *sh)
+{
+  return &sh->sh_pri_info;
+}
+
+int stun_lifetime(stun_discovery_t *sd)
+{
+  return sd ? sd->sd_lt_cur : -1;
+}
+
+
+#if defined(HAVE_OPENSSL)
+char const stun_version[] = 
+ "sofia-sip-stun using " OPENSSL_VERSION_TEXT;
+#else
+char const stun_version[] = 
+ "sofia-sip-stun";
+#endif
+
+static int do_action(stun_handle_t *sh, stun_msg_t *binding_response);
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);
+static int process_binding_request(stun_request_t *req, stun_msg_t *binding_response);
+static stun_discovery_t *stun_discovery_create(stun_handle_t *sh,
+					       stun_action_t action,
+					       stun_discovery_f sdf,
+					       stun_discovery_magic_t *magic);
+static int stun_discovery_destroy(stun_discovery_t *sd);
+static int action_bind(stun_request_t *req, stun_msg_t *binding_response);
+static int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response);
+static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_response);
+
+static stun_request_t *stun_request_create(stun_discovery_t *sd);
+static int stun_send_binding_request(stun_request_t *req,
+			      su_sockaddr_t *srvr_addr);
+static int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);
+
+#if defined (__CYGWIN__)
+static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len);
+#endif
+
+/* timers */
+static void stun_sendto_timer_cb(su_root_magic_t *magic, 
+				 su_timer_t *t,
+				 su_timer_arg_t *arg);
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic, 
+				      su_timer_t *t,
+				      su_timer_arg_t *arg);
+static void stun_test_lifetime_timer_cb(su_root_magic_t *magic, 
+					su_timer_t *t,
+					su_timer_arg_t *arg);
+static void stun_keepalive_timer_cb(su_root_magic_t *magic, 
+				    su_timer_t *t,
+				    su_timer_arg_t *arg);
+
+
+static int priv_stun_bind_send(stun_handle_t *sh, stun_request_t *req, stun_discovery_t *sd);
+static int priv_dns_queue_action(stun_handle_t *sh,
+				 stun_action_t action,
+				 stun_discovery_f sdf,
+				 stun_discovery_magic_t *magic,
+				 tag_type_t tag, tag_value_t value, ...);
+
+/**
+ * Return su_root_t assigned to stun_handle_t.
+ *
+ * @param self stun_handle_t object
+ * @return su_root_t object, NULL if self not given.
+ */
+su_root_t *stun_root(stun_handle_t *self)
+{
+  return self ? self->sh_root : NULL;
+}
+
+
+/**
+ * Check if a STUN handle should be created.
+ *
+ * Return true if STUNTAG_SERVER() or STUNTAG_DOMAIN() tags have 
+ * been specified, or otherwise if STUN_SERVER environment variable 
+ * is set.
+ *
+ * @TAGS
+ * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @param tag,value,... tag-value list
+ */
+int stun_is_requested(tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  tagi_t const *t, *t2;
+  char const *stun_server;
+
+  enter;
+
+  ta_start(ta, tag, value);
+  t = tl_find(ta_args(ta), stuntag_server);
+  t2 = tl_find(ta_args(ta), stuntag_domain);
+  if (t && t->t_value) 
+    stun_server = (char *)t->t_value;
+  else if (t2 && t2->t_value)
+    stun_server = (char *)t2->t_value;
+  else
+    stun_server = getenv("STUN_SERVER");
+  ta_end(ta);
+
+  return stun_server != NULL;
+}
+
+
+/** 
+ * Creates a STUN handle.
+ *
+ * The created handles can be used for STUN binding discovery, 
+ * keepalives, and other STUN usages.
+ *
+ * @param root eventloop to used by the stun state machine
+ * @param tag,value,... tag-value list 
+ *
+ * @TAGS
+ * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ * @TAG STUNTAG_REQUIRE_INTEGRITY() true if msg integrity should be
+ * used enforced
+ *
+ */
+stun_handle_t *stun_handle_init(su_root_t *root,
+				tag_type_t tag, tag_value_t value, ...)
+{
+  stun_handle_t *stun = NULL;
+  char const *server = NULL, *domain = NULL;
+  int req_msg_integrity = 1;
+  int err;
+  ta_list ta;
+  
+  enter;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  STUNTAG_SERVER_REF(server),
+	  STUNTAG_DOMAIN_REF(domain),
+	  STUNTAG_REQUIRE_INTEGRITY_REF(req_msg_integrity),
+	  TAG_END());
+
+  ta_end(ta);
+
+  stun = su_home_clone(NULL, sizeof(*stun));
+
+  if (!stun) {
+    SU_DEBUG_3(("%s: %s failed\n", __func__, "su_home_clone()"));
+    return NULL;
+  }
+
+  /* Enviroment overrides */
+  if (getenv("STUN_SERVER")) {
+    server = getenv("STUN_SERVER");
+    SU_DEBUG_5(("%s: using STUN_SERVER=%s\n", __func__, server));
+  }
+
+  SU_DEBUG_5(("%s(\"%s\"): called\n", 
+	      __func__, server));
+
+  /* fail, if no server or a domain for a DNS-SRV lookup is specified */
+  if (!server && !domain) {
+    errno = ENOENT;
+    return NULL;
+  }
+  
+  stun->sh_pri_info.ai_addrlen = 16;
+  stun->sh_pri_info.ai_addr = &stun->sh_pri_addr->su_sa;
+
+  stun->sh_sec_info.ai_addrlen = 16;
+  stun->sh_sec_info.ai_addr = &stun->sh_sec_addr->su_sa;
+
+  stun->sh_localinfo.li_addrlen = 16;
+  stun->sh_localinfo.li_addr = stun->sh_local_addr;
+
+  stun->sh_domain = su_strdup(stun->sh_home, domain);
+  stun->sh_dns_lookup = NULL;
+  
+  if (server) {
+    err = stun_atoaddr(stun->sh_home, AF_INET, &stun->sh_pri_info, server);
+    if (err < 0) {
+      errno = ENOENT;
+      return NULL;
+    }
+  }
+
+  stun->sh_nattype = stun_nat_unknown;
+
+  stun->sh_root     = root;
+  /* always try TLS: */
+  stun->sh_use_msgint = 1;
+  /* whether use of shared-secret msgint is required */
+  stun->sh_req_msgint = req_msg_integrity;
+
+  stun->sh_max_retries = STUN_MAX_RETRX;
+
+  /* initialize username and password */
+  stun_init_buffer(&stun->sh_username);
+  stun_init_buffer(&stun->sh_passwd);
+  
+  stun->sh_nattype = stun_nat_unknown;
+  
+  /* initialize random number generator */
+  srand(time(NULL));
+ 
+  return stun;
+}
+
+/** 
+ * Performs shared secret request/response processing.
+ * Result will be trigged in STUN handle callback (state
+ * one of stun_tls_*).
+ **/
+int stun_obtain_shared_secret(stun_handle_t *sh,
+			      stun_discovery_f sdf,
+			      stun_discovery_magic_t *magic,
+			      tag_type_t tag, tag_value_t value, ...)
+{
+#if defined(HAVE_OPENSSL)
+  int events = -1;
+  int one, err = -1;
+  su_wait_t wait[1] = { SU_WAIT_INIT };
+  su_socket_t s = INVALID_SOCKET;
+  int family;
+  su_addrinfo_t *ai = NULL;
+  stun_discovery_t *sd;
+  /* stun_request_t *req; */
+
+  ta_list ta;
+
+  assert(sh);
+
+  enter;
+
+  if (!sh->sh_pri_addr[0].su_port) {
+    /* no STUN server address, perform a DNS-SRV lookup */
+   
+    ta_list ta;
+    ta_start(ta, tag, value);
+    SU_DEBUG_5(("Delaying STUN shared-secret req. for DNS-SRV query.\n"));
+    err = priv_dns_queue_action(sh, stun_action_tls_query, sdf, magic, ta_tags(ta));
+    ta_end(ta);
+       
+    return err;
+  }
+
+  ai = &sh->sh_pri_info;
+
+  if (sh->sh_use_msgint == 1) {
+    SU_DEBUG_3(("%s: Obtaining shared secret.\n", __func__));
+  }
+  else {
+    SU_DEBUG_3(("No message integrity enabled.\n"));
+    return errno = EFAULT, -1;
+  }
+
+  /* open tcp connection to server */
+  s = su_socket(family = AF_INET, SOCK_STREAM, 0);
+
+  if (s == INVALID_SOCKET) {
+    return STUN_ERROR(errno, socket);
+  }
+
+  /* asynchronous connect() */
+  if (su_setblocking(s, 0) < 0) {
+    return STUN_ERROR(errno, su_setblocking);
+  }
+
+  if (setsockopt(s, SOL_TCP, TCP_NODELAY,
+		 (void *)&one, sizeof one) == -1) {
+    return STUN_ERROR(errno, setsockopt);
+  }
+
+  /* Do an asynchronous connect(). Three error codes are ok,
+   * others cause return -1. */
+  if (connect(s, (struct sockaddr *) &sh->sh_pri_addr, 
+	      ai->ai_addrlen) == SOCKET_ERROR) {
+    err = su_errno();
+    if (err != EINPROGRESS && err != EAGAIN && err != EWOULDBLOCK) {
+      return STUN_ERROR(err, connect);
+    }
+  }
+
+  SU_DEBUG_9(("%s: %s: %s\n", __func__, "connect",
+	      su_strerror(err)));
+  
+  sd = stun_discovery_create(sh, stun_action_tls_query, sdf, magic);
+  sd->sd_socket = s;
+  /* req = stun_request_create(sd); */
+
+  events = SU_WAIT_CONNECT | SU_WAIT_ERR;
+  if (su_wait_create(wait, s, events) == -1)
+    return STUN_ERROR(errno, su_wait_create);
+
+  /* su_root_eventmask(sh->sh_root, sh->sh_root_index, s, events); */
+
+  if ((sd->sd_index =
+       su_root_register(sh->sh_root, wait, stun_tls_callback, (su_wakeup_arg_t *) sd, 0)) == -1) {
+    return STUN_ERROR(errno, su_root_register);
+  }
+
+  ta_start(ta, tag, value);
+  sd->sd_tags = tl_adup(sh->sh_home, ta_args(ta));
+  ta_end(ta);
+
+  sd->sd_state = stun_tls_connecting;
+
+  /* Create and start timer for connect() timeout */
+  SU_DEBUG_3(("%s: creating timeout timer for connect()\n", __func__));
+
+  sd->sd_timer = su_timer_create(su_root_task(sh->sh_root),
+				 STUN_TLS_CONNECT_TIMEOUT);
+
+  su_timer_set(sd->sd_timer, stun_tls_connect_timer_cb, (su_wakeup_arg_t *) sd);
+
+  return 0;
+#else /* !HAVE_OPENSSL */
+  return -1;
+#endif
+}
+
+static stun_request_t *stun_request_create(stun_discovery_t *sd)
+{
+  stun_handle_t *sh = sd->sd_handle;
+  stun_request_t *req = NULL;
+
+  enter;
+
+  req = calloc(sizeof(stun_request_t), 1);
+  if (!req)
+    return NULL;
+
+  req->sr_handle = sh;
+  req->sr_discovery = sd;
+
+  /* This is the default */
+  req->sr_socket = sd->sd_socket;
+  
+  req->sr_localinfo.li_addrlen = sizeof(su_sockaddr_t);
+  req->sr_localinfo.li_addr = req->sr_local_addr;
+  
+  /* default timeout for next sendto() */
+  req->sr_timeout = STUN_SENDTO_TIMEOUT;
+  req->sr_retry_count = 0;
+  /* req->sr_action = action; */
+  req->sr_request_mask = 0;
+  
+  req->sr_msg = calloc(sizeof(stun_msg_t), 1);
+
+  req->sr_state = stun_req_discovery_init;
+  memcpy(req->sr_local_addr, sd->sd_bind_addr, sizeof(su_sockaddr_t));
+
+  /* Insert this request to the request queue */
+  x_insert(sh->sh_requests, req, sr);
+
+  return req;
+}
+
+void stun_request_destroy(stun_request_t *req)
+{
+  stun_handle_t *sh;
+  assert(req);
+
+  enter;
+
+  sh = req->sr_handle;
+
+  if (x_is_inserted(req, sr))
+    x_remove(req, sr);
+
+  req->sr_handle = NULL;
+  req->sr_discovery = NULL;
+  /* memset(req->sr_destination, 0, sizeof(su_sockaddr_t)); */
+
+  if (req->sr_timer) {
+    su_timer_destroy(req->sr_timer);
+    req->sr_timer = NULL;
+    SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+  }
+
+  if (req->sr_msg) {
+    free(req->sr_msg);
+    req->sr_msg = NULL;
+  }
+
+  free(req);
+
+  SU_DEBUG_9(("%s: request destroyed.\n", __func__));
+
+  return;
+}
+
+
+/** Destroy a STUN client */ 
+void stun_handle_destroy(stun_handle_t *sh)
+{ 
+  stun_discovery_t *sd = NULL, *kill = NULL;
+  stun_request_t *a, *b;
+
+  enter;
+
+  if (sh->sh_dns_lookup)
+    stun_dns_lookup_destroy(sh->sh_dns_lookup);
+
+  if (sh->sh_dns_pend_tags)
+    su_free(sh->sh_home, sh->sh_dns_pend_tags);
+
+  for (a = sh->sh_requests; a; ) {
+    b = a->sr_next;
+    stun_request_destroy(a);
+    a = b;
+  }
+
+
+  /* There can be several discoveries using the same socket. It is
+     still enough to deregister the socket in first of them */
+  for (sd = sh->sh_discoveries; sd; ) {
+    kill = sd;
+    sd = sd->sd_next;
+
+    /* Index has same value as sockfd, right? ... or not? */
+    if (kill->sd_index != -1)
+      su_root_deregister(sh->sh_root, kill->sd_index);
+    if (kill->sd_action == stun_action_tls_query)
+      su_close(kill->sd_socket);
+
+    stun_discovery_destroy(kill);
+  }
+
+  stun_free_message(&sh->sh_tls_request);
+  stun_free_message(&sh->sh_tls_response);
+  stun_free_buffer(&sh->sh_username);
+  stun_free_buffer(&sh->sh_passwd);
+
+  su_home_zap(sh->sh_home);
+}
+
+
+/** Create wait object and register it to the handle callback */
+static
+int assign_socket(stun_discovery_t *sd, su_socket_t s, int register_socket) 
+{
+  stun_handle_t *sh = sd->sd_handle;
+  int events;
+  stun_discovery_t *tmp;
+  /* su_localinfo_t clientinfo[1]; */
+  su_sockaddr_t su[1];
+  socklen_t sulen;
+  char addr[SU_ADDRSIZE];
+  int err;
+  
+  su_wait_t wait[1] = { SU_WAIT_INIT };
+
+  enter;
+
+  if (s == INVALID_SOCKET) {
+    SU_DEBUG_3(("%s: invalid socket\n", __func__));
+    return errno = EINVAL, -1;
+  }
+
+  for (tmp = sh->sh_discoveries; tmp; tmp = tmp->sd_next) {
+    if (tmp->sd_socket == s) {
+      sd->sd_socket = s;
+      sd->sd_index = tmp->sd_index;
+      memcpy(sd->sd_bind_addr, tmp->sd_bind_addr, sizeof(su_sockaddr_t));
+      return 0;
+    }
+  }
+  sd->sd_socket = s;
+
+  if (!register_socket)
+    return 0;
+
+  /* set socket asynchronous */
+  if (su_setblocking(s, 0) < 0) {
+    return STUN_ERROR(errno, su_setblocking);
+  }
+
+  /* xxx -- check if socket is already assigned to this root */
+
+  memset(su, 0, sulen = sizeof su);
+
+  /* Try to bind it if not already bound */
+  if (getsockname(s, &su->su_sa, &sulen) == -1 || su->su_port == 0) {
+
+    sulen = su->su_len = sizeof su->su_sin;
+    su->su_family = AF_INET;
+
+#if defined (__CYGWIN__)
+    get_localinfo(AF_INET, su, &sulen);
+#endif
+
+    if ((err = bind(s, &su->su_sa, sulen)) < 0) {
+      SU_DEBUG_3(("%s: bind(%s:%u): %s\n",  __func__, 
+		  inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+		  (unsigned) ntohs(su->su_port),
+		  su_strerror(su_errno())));
+      return -1;
+    }
+
+    if (getsockname(s, &su->su_sa, &sulen) == -1) {
+      return STUN_ERROR(errno, getsockname);
+    }
+  }
+
+  memcpy(&sd->sd_bind_addr, su, sulen);
+
+  SU_DEBUG_3(("%s: local socket is bound to %s:%u\n", __func__,
+	      inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+	      (unsigned) ntohs(su->su_port)));
+
+  events = SU_WAIT_IN | SU_WAIT_ERR;
+
+  if (su_wait_create(wait, s, events) == -1) {
+    return STUN_ERROR(su_errno(), su_wait_create);
+  }
+
+  /* Register receiving function with events specified above */
+  if ((sd->sd_index = su_root_register(sh->sh_root,
+				       wait, stun_bind_callback,
+				       (su_wakeup_arg_t *) sd, 0)) < 0) {
+    return STUN_ERROR(errno, su_root_register);
+  }
+
+  SU_DEBUG_7(("%s: socket registered.\n", __func__));
+
+  return 0;
+}
+
+
+/**
+ * Helper function needed by Cygwin builds.
+ */
+#if defined (__CYGWIN__)
+static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len)
+{
+  su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;
+  int i, error;
+  char addr[SU_ADDRSIZE];
+
+  hints->li_family = family;
+
+  if ((error = su_getlocalinfo(hints, &res)) == 0) {
+    /* try to bind to the first available address */
+    for (i = 0, li = res; li; li = li->li_next) {
+      if (li->li_family != family)
+	continue;
+      if (li->li_scope == LI_SCOPE_HOST)
+	continue;
+
+      assert(*return_len >= li->li_addrlen);
+
+      memcpy(su, li->li_addr, *return_len = li->li_addrlen);
+
+      SU_DEBUG_3(("%s: using local address %s\n", __func__, 
+		  inet_ntop(family, SU_ADDR(su), addr, sizeof(addr))));
+      break;
+    }
+
+    su_freelocalinfo(res);
+    
+    if (!li) {			/* Not found */
+      return STUN_ERROR(error, su_getlocalinfo);
+    }
+
+    return 0;
+  }
+  else {
+    return STUN_ERROR(error, su_getlocalinfo);
+  }
+}
+#endif
+
+static void priv_lookup_cb(stun_dns_lookup_t *self,
+			   stun_magic_t *magic)
+{
+  const char *udp_target = NULL;
+  uint16_t udp_port = 0;
+  int res;
+  stun_handle_t *sh = (stun_handle_t *)magic;
+
+  res = stun_dns_lookup_udp_addr(self, &udp_target, &udp_port);
+  if (res == 0 && udp_target) {
+    /* XXX: assumption that same host and port used for UDP/TLS */
+    stun_atoaddr(sh->sh_home, AF_INET, &sh->sh_pri_info, udp_target);
+    
+    if (udp_port) 
+      sh->sh_pri_addr[0].su_port = htons(udp_port);
+    else
+      sh->sh_pri_addr[0].su_port = htons(STUN_DEFAULT_PORT);
+
+    /* step: now that server address is known, continue 
+     *       the pending action */
+
+    SU_DEBUG_5(("STUN server address found, running queue actions (%d).\n",
+		sh->sh_dns_pend_action));
+
+    switch(sh->sh_dns_pend_action) {
+    case stun_action_tls_query:
+      stun_obtain_shared_secret(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+      break;
+
+    case stun_action_binding_request:
+      stun_bind(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+      break;
+      
+    case stun_action_test_lifetime:
+      stun_test_lifetime(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+      break;
+      
+    case stun_action_test_nattype:
+      stun_test_nattype(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+      break;
+      
+    default:
+      SU_DEBUG_5(("Warning: unknown pending STUN DNS-SRV action.\n"));
+    }
+      }
+  else {
+    /* DNS lookup failed */
+    SU_DEBUG_5(("Warning: STUN DNS-SRV lookup failed.\n"));
+    if (sh->sh_dns_pend_cb) {
+      sh->sh_dns_pend_cb(sh->sh_dns_pend_ctx, sh, NULL,
+			 sh->sh_dns_pend_action, stun_error);
+    }
+  }
+
+  su_free(sh->sh_home, sh->sh_dns_pend_tags), sh->sh_dns_pend_tags = NULL;
+  sh->sh_dns_pend_action = 0;
+  sh->sh_dns_pend_cb = NULL;
+  sh->sh_dns_pend_ctx = NULL;
+}
+
+/**
+ * Queus a discovery process for later execution when DNS-SRV lookup
+ * has been completed.
+ */
+static int priv_dns_queue_action(stun_handle_t *sh,
+				 stun_action_t action,
+				 stun_discovery_f sdf,
+				 stun_discovery_magic_t *magic,
+				 tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+
+  if (!sh->sh_dns_pend_action) {
+    if (!sh->sh_dns_lookup) {
+      sh->sh_dns_lookup = stun_dns_lookup((stun_magic_t*)sh, sh->sh_root, priv_lookup_cb, sh->sh_domain);
+      ta_start(ta, tag, value);
+      assert(sh->sh_dns_pend_tags == NULL);
+      sh->sh_dns_pend_tags = tl_tlist(sh->sh_home, 
+				      ta_tags(ta));
+      ta_end(ta);
+      sh->sh_dns_pend_cb = sdf;
+      sh->sh_dns_pend_ctx = magic;
+
+    }
+    sh->sh_dns_pend_action |= action;
+
+    return 0;
+  }
+  
+  return -1;
+}
+
+static int priv_stun_bind_send(stun_handle_t *sh, stun_request_t *req, stun_discovery_t *sd)
+{
+  int res = stun_send_binding_request(req, sh->sh_pri_addr);
+  if (res < 0) {
+    stun_free_message(req->sr_msg);
+    stun_discovery_destroy(sd);
+  }
+  return res;
+}
+
+/** 
+ * Performs a STUN Binding Discovery (see RFC3489/3489bis) process
+ *
+ * To integrity protect the discovery process, first call 
+ * stun_request_shared_secret() on the handle 'sh'.
+ *
+ * If STUNTAG_REGISTER_SOCKET() is omitted, or set to false, the
+ * client is responsible for socket i/o. Other stun module will
+ * perform the whole discovery process and return the results
+ * via callback 'sdf'.
+ * 
+ * @param sh       pointer to valid stun handle
+ * @param sdf      callback to signal process progress
+ * @param magic    context pointer attached to 'sdf'
+ * @param tag, value, ... list of tagged parameters.
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET() Bind socket handle to STUN (socket handle).
+ * @TAG STUNTAG_REGISTER_SOCKET() Register socket for eventloop owned by STUN (boolean)
+ *
+ * @return
+ * On success, zero is returned.  Upon error, -1 is returned, and @e errno is
+ * set appropriately.
+ * 
+ * @ERRORS
+ * @ERROR EFAULT          An invalid address is given as argument
+ * @ERROR EPROTONOSUPPORT Not a UDP socket.
+ * @ERROR EINVAL          The socket is already bound to an address.
+ * @ERROR EACCESS   	  The address is protected, and the user is not 
+ *                  	  the super-user.
+ * @ERROR ENOTSOCK  	  Argument is a descriptor for a file, not a socket.
+ * @ERROR EAGAIN          Operation in progress. Application should call 
+ *                        stun_bind() again when there is data available on 
+ *                        the socket.
+ */
+int stun_bind(stun_handle_t *sh,
+	      stun_discovery_f sdf,
+	      stun_discovery_magic_t *magic,
+	      tag_type_t tag, tag_value_t value,
+	      ...)
+{
+  su_socket_t s = INVALID_SOCKET;
+  stun_request_t *req = NULL;
+  stun_discovery_t *sd = NULL;
+  ta_list ta;
+  int s_reg = 0;
+  
+  enter;
+
+  if (sh == NULL)
+    return errno = EFAULT, -1;
+
+  if (!sh->sh_pri_addr[0].su_port) {
+    /* no STUN server address, perform a DNS-SRV lookup */
+    int err;
+    ta_list ta;
+    ta_start(ta, tag, value);
+    SU_DEBUG_5(("Delaying STUN bind for DNS-SRV query.\n"));
+    err = priv_dns_queue_action(sh, stun_action_binding_request, sdf, magic, ta_tags(ta));
+    ta_end(ta);
+    return err;
+  }
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  STUNTAG_SOCKET_REF(s),
+	  STUNTAG_REGISTER_EVENTS_REF(s_reg),
+	  TAG_END());
+
+  ta_end(ta);
+
+  sd = stun_discovery_create(sh, stun_action_binding_request, sdf, magic);
+  if (assign_socket(sd, s, s_reg) < 0)
+    return -1;
+
+  req = stun_request_create(sd);
+
+  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0) {
+    stun_discovery_destroy(sd);
+    stun_free_message(req->sr_msg);
+    return -1;
+  }
+
+  /* note: we always report success if bind() succeeds */
+  return priv_stun_bind_send(sh, req, sd);
+}
+
+
+/** 
+ * Returns the address of the public binding allocated by the NAT.
+ *
+ * In case of multiple on path NATs, the binding allocated by
+ * the outermost NAT is returned.
+ *
+ * This function returns the local address seen from outside.
+ * Note that the address is not valid until the event stun_clien_done is launched.
+ */
+int stun_discovery_get_address(stun_discovery_t *sd,
+			       void *addr,
+			       socklen_t *return_addrlen)
+{
+  socklen_t siz;
+  
+  enter;
+
+  assert(sd && addr);
+
+  siz = SU_SOCKADDR_SIZE(sd->sd_addr_seen_outside);
+
+  /* Check if enough memory provided */
+  if (siz > *return_addrlen)
+    return errno = EFAULT, -1;
+  else
+    *return_addrlen = siz;
+
+  memcpy(addr, sd->sd_addr_seen_outside, siz);
+  
+  return 0;
+}
+
+static stun_discovery_t *stun_discovery_create(stun_handle_t *sh,
+					       stun_action_t action,
+					       stun_discovery_f sdf,
+					       stun_discovery_magic_t *magic)
+{
+  stun_discovery_t *sd = NULL;
+
+  enter;
+
+  sd = calloc(1, sizeof(stun_discovery_t));
+
+  sd->sd_action = action;
+  sd->sd_handle = sh;
+  sd->sd_callback = sdf;
+  sd->sd_magic = magic;
+
+  sd->sd_lt_cur = 0;
+  sd->sd_lt = STUN_LIFETIME_EST;
+  sd->sd_lt_max = STUN_LIFETIME_MAX;
+
+  sd->sd_pri_info.ai_addrlen = sizeof sd->sd_pri_addr->su_sin;
+  sd->sd_pri_info.ai_addr = &sd->sd_pri_addr->su_sa;
+
+  /* Insert this action to the discovery queue */
+  x_insert(sh->sh_discoveries, sd, sd);
+
+  return sd;
+}
+
+static int stun_discovery_destroy(stun_discovery_t *sd)
+{
+  stun_handle_t *sh;
+
+  enter;
+
+  if (!sd)
+    return errno = EFAULT, -1;
+
+  sh = sd->sd_handle;
+
+  if (sd->sd_timer) 
+    su_timer_destroy(sd->sd_timer), sd->sd_timer = NULL;
+
+  /* if we are in the queue*/
+  if (x_is_inserted(sd, sd))
+    x_remove(sd, sd);
+
+  sd->sd_next = NULL;
+
+  free(sd);
+  return 0;
+}
+
+/**
+ * Initiates STUN discovery process to find out NAT 
+ * characteristics. 
+ *
+ * Process partly follows the algorithm defined in RFC3489 section 
+ * 10.1. Due the known limitations of RFC3489, some of the tests
+ * are done. 
+ *
+ * Note: does not support STUNTAG_DOMAIN() even if specified to
+ * stun_handle_init().
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET Bind socket for STUN
+ * @TAG STUNTAG_REGISTER_SOCKET Register socket for eventloop owned by STUN
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @return 0 on success, non-zero on error
+ */
+int stun_test_nattype(stun_handle_t *sh,
+		       stun_discovery_f sdf,
+		       stun_discovery_magic_t *magic,
+		       tag_type_t tag, tag_value_t value,
+		       ...)
+{
+  int err = 0, index = 0, s_reg = 0;
+  ta_list ta;
+  char const *server = NULL;
+  stun_request_t *req = NULL;
+  stun_discovery_t *sd = NULL;
+  su_socket_t s = INVALID_SOCKET;
+  su_sockaddr_t *destination = NULL;
+
+  enter;
+
+  if (!sh->sh_pri_addr[0].su_port) {
+    /* no STUN server address, perform a DNS-SRV lookup */
+   
+    ta_list ta;
+    ta_start(ta, tag, value);
+    SU_DEBUG_5(("Delaying STUN get-nat-type req. for DNS-SRV query.\n"));
+    err = priv_dns_queue_action(sh, stun_action_test_nattype, sdf, magic, ta_tags(ta));
+    ta_end(ta);
+       
+    return err;
+  }
+
+  ta_start(ta, tag, value);
+  tl_gets(ta_args(ta),
+	  STUNTAG_SOCKET_REF(s),
+	  STUNTAG_REGISTER_EVENTS_REF(s_reg),
+	  STUNTAG_SERVER_REF(server),
+	  TAG_END());
+
+  ta_end(ta);
+
+  if (s < 0)
+    return errno = EFAULT, -1;
+
+  sd = stun_discovery_create(sh, stun_action_test_nattype, sdf, magic);
+  sd->sd_mapped_addr_match = -1;
+
+  if ((index = assign_socket(sd, s, s_reg)) < 0)
+    return errno = EFAULT, -1;
+
+  /* If no server given, use default address from stun_handle_init() */
+  if (!server) {
+    /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */
+    memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t));
+  }
+  else {
+    err = stun_atoaddr(sh->sh_home, AF_INET, &sd->sd_pri_info, server);
+    memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t));
+  }
+  destination = (su_sockaddr_t *) sd->sd_pri_addr;
+
+  req = stun_request_create(sd);
+  if (stun_make_binding_req(sh, req, req->sr_msg, 
+			    STUNTAG_CHANGE_IP(0), 
+			    STUNTAG_CHANGE_PORT(0),
+			    TAG_END()) < 0) 
+    return -1;
+
+  err = stun_send_binding_request(req, destination);
+  if (err < 0) {
+    stun_free_message(req->sr_msg);
+    return -1;
+  }
+
+  /* Same Public IP and port, Test III, server ip 0 or 1 should be
+     the same */
+  req = stun_request_create(sd);
+  if (stun_make_binding_req(sh, req, req->sr_msg, 
+			    STUNTAG_CHANGE_IP(0), 
+			    STUNTAG_CHANGE_PORT(1),
+			    TAG_END()) < 0) 
+    return -1;
+
+  err = stun_send_binding_request(req, destination);
+  if (err < 0) {
+    stun_free_message(req->sr_msg);
+    return -1;
+  }
+  req = NULL;
+
+  req = stun_request_create(sd);
+  if (stun_make_binding_req(sh, req, req->sr_msg, 
+			    STUNTAG_CHANGE_IP(1), 
+			    STUNTAG_CHANGE_PORT(1),
+			    TAG_END()) < 0) 
+    return -1;
+  
+  err = stun_send_binding_request(req, destination);
+  if (err < 0) {
+    stun_free_message(req->sr_msg);
+  }
+
+  return err;
+}
+
+/********************************************************************
+ * Internal functions
+ *******************************************************************/
+
+#if defined(HAVE_OPENSSL)
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+  stun_discovery_t *sd = arg;
+  stun_handle_t *self = sd->sd_handle;
+  stun_msg_t *msg_req, *resp;
+  int z, err = -1;
+  SSL_CTX* ctx;
+  SSL *ssl;
+  X509* server_cert;
+  unsigned char buf[512];
+  stun_attr_t *password, *username;
+  int state;
+  int events = su_wait_events(w, sd->sd_socket), one = 0;
+  unsigned int onelen;
+
+  enter;
+
+  SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, self,
+	      events & SU_WAIT_CONNECT ? " CONNECTED" : "",
+	      events & SU_WAIT_ERR     ? " ERR"       : "",
+	      events & SU_WAIT_IN      ? " IN"        : "",
+	      events & SU_WAIT_OUT     ? " OUT"       : ""));
+
+  getsockopt(sd->sd_socket, SOL_SOCKET, SO_ERROR,
+	     (void *)&one, &onelen);
+  if (one != 0) {
+    STUN_ERROR(one, SO_ERROR);
+  }
+
+  if (one || events & SU_WAIT_ERR) {
+    su_wait_destroy(w);
+    su_root_deregister(self->sh_root, sd->sd_index);
+    sd->sd_index = -1; /* mark index as deregistered */
+
+    su_timer_reset(sd->sd_timer);
+
+    SU_DEBUG_3(("%s: shared secret not obtained from server. "	\
+		"Proceed without username/password.\n", __func__));
+
+    sd->sd_state = stun_tls_connection_failed;
+
+    if (sd->sd_callback)
+      sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+    return 0;
+  }
+
+  /* Can be NULL, too */
+  ssl  = self->sh_ssl;
+  msg_req  = &self->sh_tls_request;
+  resp = &self->sh_tls_response;
+
+  state = sd->sd_state;
+  switch (state) {
+  case stun_tls_connecting:
+
+    /* compose shared secret request */
+    if (stun_make_sharedsecret_req(msg_req) != 0) {
+      STUN_ERROR(errno, stun_make_sharedsecret_req);
+      stun_free_buffer(&msg_req->enc_buf);
+      return -1;
+    }
+    
+    /* openssl initiation */
+    SSLeay_add_ssl_algorithms();
+    SSL_load_error_strings();
+    ctx = SSL_CTX_new(TLSv1_client_method());
+    self->sh_ctx = ctx;
+
+    if (ctx == NULL) {
+      STUN_ERROR(errno, SSL_CTX_new);
+      stun_free_buffer(&msg_req->enc_buf);
+      return -1;
+    }
+    
+    if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") == 0) {
+      STUN_ERROR(errno, SSL_CTX_set_cipher_list);
+      stun_free_buffer(&msg_req->enc_buf);
+      return -1;
+    }
+    
+    /* Start TLS negotiation */
+    ssl = SSL_new(ctx);
+    self->sh_ssl = ssl;
+
+    if (SSL_set_fd(ssl, sd->sd_socket) == 0) {
+      STUN_ERROR(err, connect);
+      stun_free_buffer(&msg_req->enc_buf);
+      return -1;
+    }
+
+    /* No break here! Continue to SSL_connect. If SSL_continue returns
+     * less than 1 because of nonblocking, have a different state
+     * (ssl_connecting) for it */
+
+  case stun_tls_ssl_connecting:
+    events = SU_WAIT_ERR | SU_WAIT_IN;
+    su_root_eventmask(self->sh_root, sd->sd_index,
+		      sd->sd_socket, events);
+
+    z = SSL_connect(ssl);
+    err = SSL_get_error(ssl, z);
+    if (z < 1 && (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)) {
+      sd->sd_state = stun_tls_ssl_connecting;
+      return 0;
+    }
+    else if (z < 1) {
+      su_wait_destroy(w);
+      su_root_deregister(self->sh_root, sd->sd_index);
+      sd->sd_index = -1; /* mark index as deregistered */
+
+      stun_free_buffer(&msg_req->enc_buf);
+      sd->sd_state = stun_tls_connection_failed;
+
+      if (sd->sd_callback)
+	sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+      return -1;
+    }
+    
+    /* Inform application about the progress  */
+    sd->sd_state = stun_tls_writing;
+    /* self->sh_callback(self->sh_context, self, self->sh_state); */
+
+    events = SU_WAIT_ERR | SU_WAIT_OUT;
+    su_root_eventmask(self->sh_root, sd->sd_index,
+		      sd->sd_socket, events);
+
+    break;
+
+  case stun_tls_writing:
+
+    events = SU_WAIT_ERR | SU_WAIT_IN;
+    su_root_eventmask(self->sh_root, sd->sd_index,
+		      sd->sd_socket, events);
+
+    SU_DEBUG_3(("TLS connection using %s\n", SSL_get_cipher(ssl)));
+    
+    server_cert = SSL_get_peer_certificate(ssl); 
+    if(server_cert) {
+      SU_DEBUG_3(("\t subject: %s\n", X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0)));
+      SU_DEBUG_3(("\t issuer: %s\n", X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0)));
+    }
+    X509_free(server_cert);
+    
+    z = SSL_write(ssl, msg_req->enc_buf.data, msg_req->enc_buf.size);
+    
+    if (z < 0) {
+      err = SSL_get_error(ssl, z);
+      if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+	return 0;
+      else {
+	STUN_ERROR(errno, SSL_write);
+	stun_free_buffer(&msg_req->enc_buf);
+	return -1;
+      }
+    }
+    sd->sd_state = stun_tls_reading;
+
+    break;
+
+  case stun_tls_reading:
+    events = SU_WAIT_ERR | SU_WAIT_OUT;
+    su_root_eventmask(self->sh_root, sd->sd_index,
+		      sd->sd_socket, events);
+
+    SU_DEBUG_5(("Shared Secret Request sent to server:\n"));
+    debug_print(&msg_req->enc_buf);
+
+    z = SSL_read(ssl, buf, sizeof(buf));
+    if (z <= 0) {
+      err = SSL_get_error(ssl, z);
+      if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+	return 0;
+      else {
+	stun_free_buffer(&msg_req->enc_buf);
+	return -1;
+      }
+    }
+
+    /* We end up here after there's something to read from the
+     * socket */
+    resp->enc_buf.size = z;
+    resp->enc_buf.data = malloc(z);
+    memcpy(resp->enc_buf.data, buf, z);
+    SU_DEBUG_5(("Shared Secret Response received from server:\n"));
+    debug_print(&resp->enc_buf);
+
+    /* closed TLS connection */
+    SSL_shutdown(ssl);
+
+    su_close(sd->sd_socket), sd->sd_socket = INVALID_SOCKET;
+
+    SSL_free(self->sh_ssl), ssl = NULL;
+    SSL_CTX_free(self->sh_ctx), ctx = NULL;
+
+    stun_free_buffer(&msg_req->enc_buf);
+  
+    /* process response */
+    if (stun_parse_message(resp) < 0) {
+      perror("stun_parse_message");
+      stun_free_buffer(&resp->enc_buf);
+      return -1;
+    }
+
+    switch(resp->stun_hdr.msg_type) {
+    case SHARED_SECRET_RESPONSE:
+      username = stun_get_attr(resp->stun_attr, USERNAME);
+      password = stun_get_attr(resp->stun_attr, PASSWORD);
+      if (username != NULL && password != NULL) {
+	/* move result to se */
+	stun_copy_buffer(&self->sh_username, username->pattr);
+	stun_copy_buffer(&self->sh_passwd, password->pattr);
+      }
+      break;
+
+    case SHARED_SECRET_ERROR_RESPONSE:
+      if (stun_process_error_response(resp) < 0) {
+	SU_DEBUG_5(("Error in Shared Secret Error Response.\n")); 
+      }
+      stun_free_buffer(&resp->enc_buf);
+      return -1;
+    
+      break;
+
+    default:
+      break;
+    }
+    
+    su_wait_destroy(w);
+    su_root_deregister(self->sh_root, sd->sd_index);
+    sd->sd_index = -1; /* mark index as deregistered */
+
+    self->sh_use_msgint = 1;
+    sd->sd_state = stun_tls_done;
+
+    if (sd->sd_callback)
+      sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+#else
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+  return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+
+#if defined(HAVE_OPENSSL)
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic, 
+				      su_timer_t *t,
+				      su_timer_arg_t *arg)
+{
+  stun_discovery_t *sd = arg;
+  stun_handle_t *sh = sd->sd_handle;
+
+  enter;
+
+  su_timer_destroy(t);
+  if (t == sd->sd_timer) {
+    sd->sd_timer = NULL;
+  }
+
+  SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+
+  if (sd->sd_state != stun_tls_connecting)
+    return;
+
+  SU_DEBUG_7(("%s: connect() timeout.\n", __func__));
+
+  su_root_deregister(sh->sh_root, sd->sd_index);
+  sd->sd_index = -1; /* mark index as deregistered */
+  
+  sd->sd_state = stun_tls_connection_timeout;
+  sd->sd_callback(sd->sd_magic, sh, sd, sd->sd_action, sd->sd_state);
+
+  return;
+}
+#else
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic, 
+				      su_timer_t *t,
+				      su_timer_arg_t *arg)
+{
+}
+#endif /* HAVE_OPENSSL */
+
+/** Compose a STUN message of the format defined by stun_msg_t
+ *  result encoded in enc_buf ready for sending as well.
+ */
+int stun_make_sharedsecret_req(stun_msg_t *msg)
+{
+
+  int i, len; 
+  uint16_t tmp;
+
+  /* compose header */
+  msg->stun_hdr.msg_type = SHARED_SECRET_REQUEST;
+  msg->stun_hdr.msg_len = 0; /* actual len computed by
+				stun_send_message */
+  for (i = 0; i < STUN_TID_BYTES; i++) {
+    msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);
+  } 
+  
+  /* no buffer assigned yet */
+  stun_init_buffer(&msg->enc_buf);
+  
+  msg->enc_buf.data = malloc(20);
+  msg->enc_buf.size = 20;
+
+  tmp = htons(msg->stun_hdr.msg_type);
+  len = 0;
+  
+  memcpy(msg->enc_buf.data, &tmp, sizeof(tmp));
+  len+=sizeof(tmp);
+
+  tmp = htons(msg->stun_hdr.msg_len);
+  memcpy(msg->enc_buf.data+len, &tmp, sizeof(tmp));
+  len+=sizeof(tmp);
+
+  memcpy(msg->enc_buf.data+len, msg->stun_hdr.tran_id, STUN_TID_BYTES);
+  len+=STUN_TID_BYTES;
+    
+  return 0;
+}
+
+
+/* Return action of the request. If no request, return default value */
+static inline
+stun_action_t get_action(stun_request_t *req)
+{
+  stun_discovery_t *sd = NULL;
+
+  /* XXX -- if no sr_handle something is leaking... */
+  if (!req || !req->sr_discovery || !req->sr_handle)
+    return stun_action_no_action;
+
+  sd = req->sr_discovery;
+  return sd->sd_action;
+}
+
+
+/* Find request from the request queue, based on TID */
+static inline
+stun_request_t *find_request(stun_handle_t *self, void *id)
+{
+  void *match;
+  stun_request_t *req = NULL;
+  int len = STUN_TID_BYTES;
+
+  for (req = self->sh_requests; req; req = req->sr_next) {
+    match = req->sr_msg->stun_hdr.tran_id;
+    if (memcmp(match, id, len) == 0) {
+      return req;
+    }
+  }
+
+  return NULL;
+}
+
+/** Process socket event */
+static int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+  stun_discovery_t *sd = arg;
+  stun_handle_t *self = sd->sd_handle;
+
+  int retval = -1, err = -1, dgram_len;
+  char addr[SU_ADDRSIZE];
+  stun_msg_t binding_response, *msg;
+  unsigned char dgram[512] = { 0 };
+  su_sockaddr_t recv;
+  socklen_t recv_len;
+  su_socket_t s = sd->sd_socket;
+  int events = su_wait_events(w, s);
+
+  enter;
+
+  SU_DEBUG_7(("%s(%p): events%s%s%s\n", __func__, self,
+	      events & SU_WAIT_IN ? " IN" : "",
+	      events & SU_WAIT_OUT ? " OUT" : "",
+	      events & SU_WAIT_ERR ? " ERR" : ""));
+
+  if (!(events & SU_WAIT_IN || events & SU_WAIT_OUT)) {
+    /* su_wait_destroy(w); */
+    /* su_root_deregister(self->sh_root, self->ss_root_index); */
+    /* self->sh_state = stun_bind_error; */
+    return 0;
+  }
+
+  /* receive response */
+  recv_len = sizeof(recv);
+  dgram_len = su_recvfrom(s, dgram, sizeof(dgram), 0, &recv, &recv_len);
+  err = errno;
+  if ((dgram_len < 0) && (err != EAGAIN)) {
+    /* su_wait_destroy(w); */
+    /* su_root_deregister(self->sh_root, self->ss_root_index); */
+    STUN_ERROR(err, recvfrom);
+    /* stun_free_message(binding_request); */
+    return err;
+  }
+  else if (dgram_len <= 0) {
+    STUN_ERROR(err, recvfrom);
+    /* No data available yet, wait for the event. */
+    return 0;
+  }
+
+  /* Message received. */
+  binding_response.enc_buf.data = (unsigned char *) malloc(dgram_len);
+  binding_response.enc_buf.size = dgram_len;
+  memcpy(binding_response.enc_buf.data, dgram, dgram_len);
+
+  
+  SU_DEBUG_5(("%s: response from server %s:%u\n", __func__,
+	      inet_ntop(recv.su_family, SU_ADDR(&recv), addr, sizeof(addr)),
+	      ntohs(recv.su_port)));
+
+  debug_print(&binding_response.enc_buf);      
+
+  /* Parse here the incoming message. */
+  if (stun_parse_message(&binding_response) < 0) {
+    stun_free_message(&binding_response);
+    SU_DEBUG_5(("%s: Error parsing response.\n", __func__));
+    return retval;
+  }
+
+  /* Based on the decoded payload, find the corresponding request
+   * (based on TID). */
+
+  do_action(self, &binding_response);
+
+  if (binding_response.enc_buf.size)
+    free(binding_response.enc_buf.data);
+
+  {
+    stun_attr_t **a, *b;
+
+    msg = &binding_response;
+    for (a = &msg->stun_attr; *a;) {
+      
+      if ((*a)->pattr)
+	free((*a)->pattr);
+      
+      if ((*a)->enc_buf.data)
+	free((*a)->enc_buf.data);
+      
+      b = *a;
+      b = b->next;
+      free(*a);
+      *a = NULL;
+      *a = b;
+    }
+  }
+
+  return 0;
+}
+
+/** Choose the right state machine */
+static int do_action(stun_handle_t *sh, stun_msg_t *msg)
+{
+  stun_request_t *req = NULL;
+  stun_action_t action = stun_action_no_action;
+  void *id;
+
+  enter;
+
+  if (!sh)
+    return errno = EFAULT, -1;
+
+  id = msg->stun_hdr.tran_id;
+  req = find_request(sh, id);
+  if (!req) {
+    SU_DEBUG_7(("warning: unable to find matching TID for response\n"));
+    return 0;
+  }
+
+  action = get_action(req);
+
+  /* Based on the action, use different state machines */
+  switch (action) {
+  case stun_action_binding_request:
+    action_bind(req, msg);
+    break;
+
+  case stun_action_test_nattype:
+    action_determine_nattype(req, msg);
+    break;
+
+  case stun_action_test_lifetime:
+    process_test_lifetime(req, msg);
+    break;
+
+  case stun_action_keepalive:
+    SU_DEBUG_3(("%s: Response to keepalive received.\n", __func__));
+    req->sr_state = stun_req_dispose_me;
+    break;
+
+  case stun_action_no_action:
+    SU_DEBUG_3(("%s: Unknown response. No matching request found.\n", __func__));
+    req->sr_state = stun_req_dispose_me;
+    break;
+
+  default:
+    SU_DEBUG_3(("%s: bad action.\n", __func__));
+    req->sr_state = stun_req_error;
+
+    req->sr_state = stun_req_dispose_me;
+    break;
+  }
+  
+  return 0;
+}
+
+static int process_binding_request(stun_request_t *req, stun_msg_t *binding_response)
+{
+  int retval = -1, clnt_addr_len;
+  stun_attr_t *mapped_addr, *chg_addr;
+  stun_handle_t *self = req->sr_handle;
+  su_localinfo_t *clnt_info = &req->sr_localinfo;
+  su_sockaddr_t *clnt_addr = clnt_info->li_addr;
+  stun_msg_t *binding_request;
+  stun_discovery_t *sd = req->sr_discovery;
+
+  enter;
+
+  binding_request = req->sr_msg;
+
+  switch (binding_response->stun_hdr.msg_type) {
+  case BINDING_RESPONSE:
+    if (stun_validate_message_integrity(binding_response, &self->sh_passwd) < 0) {
+      stun_free_message(binding_request);
+      stun_free_message(binding_response);
+      return retval;
+    }
+
+    memset(clnt_addr, 0, sizeof(su_sockaddr_t));
+    clnt_addr_len = sizeof(su_sockaddr_t);
+    mapped_addr = stun_get_attr(binding_response->stun_attr, MAPPED_ADDRESS);
+
+    if (mapped_addr != NULL) {
+      memcpy(clnt_addr, mapped_addr->pattr, clnt_addr_len);
+      retval = 0;
+    }
+
+    /* update alternative server address */
+    if (sd->sd_sec_addr->su_family == 0) {
+      /* alternative server address not present */
+      chg_addr = stun_get_attr(binding_response->stun_attr, CHANGED_ADDRESS);
+
+      if (chg_addr != NULL)
+	memcpy(sd->sd_sec_addr, chg_addr->pattr, sizeof(struct sockaddr_in));
+    }
+
+    break;
+    
+  case BINDING_ERROR_RESPONSE:
+  default:
+    if (stun_process_error_response(binding_response) < 0) {
+      SU_DEBUG_3(("%s: Error in Binding Error Response.\n", __func__));
+    }
+    req->sr_state = stun_discovery_error;
+      
+    break;
+  }
+
+  return retval;
+
+}
+
+static void stun_test_lifetime_timer_cb(su_root_magic_t *magic, 
+				       su_timer_t *t,
+				       su_timer_arg_t *arg)
+{
+  stun_request_t *req = arg;
+  stun_discovery_t *sd = req->sr_discovery;
+  su_sockaddr_t *destination;
+
+  int err;
+
+  enter;
+
+  su_timer_destroy(t);
+
+  destination = (su_sockaddr_t *) sd->sd_pri_addr;
+  err = stun_send_binding_request(req, destination);
+  if (err < 0) {
+    stun_free_message(req->sr_msg);
+    return;
+  }
+
+
+  return;
+
+}
+
+static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_response)
+{
+  stun_discovery_t *sd = req->sr_discovery;
+  stun_request_t *new;
+  stun_handle_t *sh = req->sr_handle;
+  su_localinfo_t *li;
+  su_sockaddr_t *sa;
+  su_timer_t *sockfdy_timer = NULL;
+  su_socket_t sockfdy = sd->sd_socket2;
+  int err;
+  stun_action_t action = get_action(req);
+  su_sockaddr_t *destination;
+
+  /* Even the first message could not be delivered */
+  if ((req->sr_state == stun_req_timeout) && (req->sr_from_y == -1)) {
+    SU_DEBUG_0(("%s: lifetime determination failed.\n", __func__));
+    sd->sd_state = stun_discovery_timeout;
+
+    /* Use per discovery specific callback */
+    if (sd->sd_callback)
+      sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+    req->sr_state = stun_req_dispose_me;
+    return 0;
+  }
+
+  if (abs(sd->sd_lt_cur - sd->sd_lt) <= STUN_LIFETIME_CI) {
+    sd->sd_state = stun_discovery_done;
+
+    /* Use per discovery specific callback */
+    if (sd->sd_callback)
+      sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+    req->sr_state = stun_req_dispose_me;
+    return 0;
+  }
+
+  /* We come here as a response to a request send from the sockfdy */
+  if (req->sr_from_y == 1) {
+    req->sr_state = stun_req_dispose_me, req = NULL;
+
+    new = stun_request_create(sd);
+    new->sr_from_y = 0;
+    if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0) 
+      return -1;
+
+    destination = (su_sockaddr_t *) sd->sd_pri_addr;
+    err = stun_send_binding_request(new, destination);
+    if (err < 0) {
+      stun_free_message(new->sr_msg);
+      return -1;
+    }
+    return 0;
+  }
+  else if (req->sr_from_y == 0) {
+    if (req->sr_state != stun_discovery_timeout) {
+      /* mapping with X still valid */
+      sd->sd_lt_cur = sd->sd_lt;
+      sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_max) / 2;
+
+      SU_DEBUG_1(("%s: Response received from socket X, " \
+		  "lifetime at least %d sec, next trial: %d sec\n",
+		  __func__, sd->sd_lt_cur, sd->sd_lt));
+    }
+    else {
+      sd->sd_lt_max = sd->sd_lt;
+      sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_cur) / 2;
+      SU_DEBUG_1(("%s: No response received from socket X, " \
+		  "lifetime at most %d sec, next trial: %d sec\n",
+		  __func__, sd->sd_lt_max, sd->sd_lt));
+    }
+  }
+
+  /* Rock, we come from sockfdx */
+  process_binding_request(req, binding_response);
+
+  li = &req->sr_localinfo;
+  sa = req->sr_local_addr;
+  stun_free_message(binding_response);
+  
+  /* Destroy me with the bad mofo timer */
+  req->sr_state = stun_req_dispose_me, req = NULL;
+  
+  new = stun_request_create(sd);
+  /* Use sockfdy */
+  new->sr_socket = sockfdy;
+  new->sr_from_y = 1;
+
+  if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0) 
+    return -1;
+
+  stun_add_response_address(new->sr_msg, (struct sockaddr_in *) sa);
+
+  /* Create and start timer */
+  sockfdy_timer = su_timer_create(su_root_task(sh->sh_root), sd->sd_lt);
+  su_timer_set(sockfdy_timer, stun_test_lifetime_timer_cb, (su_wakeup_arg_t *) new);
+
+  return 0;
+}
+
+
+static int action_bind(stun_request_t *req, stun_msg_t *binding_response)
+{
+  su_localinfo_t *li = NULL;
+  su_sockaddr_t *sa = NULL;
+  stun_discovery_t *sd = req->sr_discovery;
+  stun_handle_t *sh = req->sr_handle;
+  stun_action_t action;
+
+  enter;
+  action = get_action(req);
+
+  process_binding_request(req, binding_response);
+
+  li = &req->sr_localinfo;
+  sa = req->sr_local_addr;
+
+  memcpy(sd->sd_addr_seen_outside, sa, sizeof(su_sockaddr_t));
+
+  sd->sd_state = stun_discovery_done;
+  
+  if (sd->sd_callback)
+    sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+  req->sr_state = stun_req_dispose_me;
+
+  return 0;
+}
+
+/**
+ * Returns a non-zero value if some local interface address
+ * matches address in su.
+ */
+static int priv_find_matching_localadress(su_sockaddr_t *su)
+{
+  su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;
+  int af;
+  char addr[SU_ADDRSIZE];
+
+  SU_DEBUG_5(("%s: checking if %s is a local address.\n", __func__, 
+	      inet_ntop(AF_INET, SU_ADDR(su), addr, sizeof(addr))));
+
+  hints->li_family = af = su->su_family;
+
+  if (su_getlocalinfo(hints, &res) != 0)
+    return 0;
+
+  /* check if any of the address match 'sockaddr'  */
+  for (li = res; li; li = li->li_next) {
+    if (li->li_family != af)
+      continue;
+      
+    if (memcmp(SU_ADDR(su), SU_ADDR(li->li_addr), SU_ADDRLEN(su)) == 0) {
+      SU_DEBUG_5(("%s: found matching local address\n", __func__));
+      break;
+    }
+
+    SU_DEBUG_9(("%s: skipping local address %s.\n", __func__, 
+		inet_ntop(af, SU_ADDR(li->li_addr), addr, sizeof(addr))));
+  }  
+
+  su_freelocalinfo(res);
+
+  return li != NULL;
+}
+
+/**
+ * Helper function for action_determine_nattype().
+ */
+static void priv_mark_discovery_done(stun_discovery_t *sd, 
+				     stun_handle_t *sh, 
+				     stun_action_t action, 
+				     stun_request_t *req)
+{
+  sd->sd_state = stun_discovery_done;
+  if (sd->sd_callback)
+    sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+  req->sr_state = stun_req_dispose_me;
+}
+
+/**
+ * Handles responses related to the NAT type discovery process.
+ * 
+ * The requests for Tests I-III are sent in parallel, so the
+ * callback has to keep track of which requests have been received
+ * and postpone decisions until enough responses have been processed.
+ *
+ * @see stun_test_nattype().
+ */
+static int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response)
+{
+  stun_handle_t *sh = req->sr_handle;
+  su_localinfo_t *li = NULL;
+  stun_discovery_t *sd = req->sr_discovery;
+  stun_action_t action;
+  int err;
+  /* test status: 0 not received, -1 timeout, 1 response received */
+  int reply_res;
+
+  enter;
+
+  action = get_action(req);
+
+  /* if the NAT type is already detected, ignore this request */
+  if (!sd || (sd->sd_nattype != stun_nat_unknown)) {
+    req->sr_state = stun_req_dispose_me;
+    /* stun_request_destroy(req); */
+    return 0;
+  }
+
+  /* parse first the response payload */
+  if (binding_response)
+    process_binding_request(req, binding_response);
+
+  /* get pointer to MAPPED-ADDRESS of req */
+  li = &req->sr_localinfo;
+
+  /* check whether the response timed out or not */
+  if (req->sr_state == stun_req_timeout) 
+    reply_res = -1;
+  else
+    reply_res = 1;
+
+  /* note: Test I completed - reply from the destination address
+   *       where we sent our packet  */
+  if (req->sr_request_mask == 0 && sd->sd_first == 0) {
+    sd->sd_first = reply_res;
+    if (reply_res)
+      memcpy(sd->sd_addr_seen_outside, li->li_addr, sizeof(su_sockaddr_t));
+  }
+
+  /* note: Test II completed - reply from another address and port  */
+  else if ((req->sr_request_mask & CHG_IP) &&
+	   (req->sr_request_mask & CHG_PORT))
+    sd->sd_second = reply_res;
+
+  /* note: Test III completed -  reply from another port  */
+  else if (req->sr_request_mask & CHG_PORT)
+    sd->sd_third = reply_res;
+
+  /* note: Test IV completed - request and reply to another port */
+  else if (req->sr_request_mask == 0 && sd->sd_fourth == 2) {
+    sd->sd_fourth = reply_res;
+
+    /* SU_DEBUG_5(("Comparing reported MAPPED ADDRESSES %s:%u vs %s:%u.\n",
+       inet_ntoa(sd->sd_addr_seen_outside[0].su_sin.sin_addr),
+       sd->sd_addr_seen_outside[0].su_port,
+       inet_ntoa(li->li_addr->su_sin.sin_addr),
+       li->li_addr->su_port)); */
+
+    /* note: check whether MAPPED-ADDRESS address has changed (when 
+     *       sending to a different IP:port -> NAT mapping behaviour) */
+    if (su_cmp_sockaddr(sd->sd_addr_seen_outside, li->li_addr) != 0) {
+      sd->sd_mapped_addr_match = 0;
+    }
+    else {
+      sd->sd_mapped_addr_match = 1;
+    }
+  }
+
+  SU_DEBUG_9(("stun natcheck status: 1st=%d, 2nd=%d, 3rd=%d, 4th=%d, mask=%d, sr_state=%d (timeout=%d, done=%d)..\n",
+	      sd->sd_first, sd->sd_second, sd->sd_third, sd->sd_fourth, req->sr_request_mask, req->sr_state, stun_req_timeout, stun_discovery_done));
+
+  /* case 1: no response to Test-I (symmetric response)
+   *         a FW must be blocking us */
+  if (sd->sd_first < 0) {
+    sd->sd_nattype = stun_udp_blocked;
+    priv_mark_discovery_done(sd, sh, action, req);
+  }
+  /* case 2: mapped address matches our local address 
+   *         not behind a NAT, result of test two determinces
+   *         whether we are behind a symmetric FW or not */
+  else if (sd->sd_first > 0 &&
+	   sd->sd_second && 
+	   priv_find_matching_localadress(sd->sd_addr_seen_outside)) {
+    if (sd->sd_second > 0) 
+      sd->sd_nattype = stun_open_internet;
+    else
+      sd->sd_nattype = stun_sym_udp_fw;
+    priv_mark_discovery_done(sd, sh, action, req);
+  }
+  /* case 3: response ok to Test-II, and behind a NAT 
+   *         do not make conclusions until Test-IV has been scheduled */
+  else if (sd->sd_first > 0 && 
+	   sd->sd_second > 0 &&
+	   sd->sd_fourth) {
+    if (sd->sd_mapped_addr_match == 1)
+      sd->sd_nattype = stun_nat_full_cone;
+    else
+      sd->sd_nattype = stun_nat_ei_filt_ad_map;
+    priv_mark_discovery_done(sd, sh, action, req);
+  }
+  /* case 4: tests I-III done, perform IV 
+   *         see notes below */
+  else if (sd->sd_first > 0 && 
+	   sd->sd_second &&
+	   sd->sd_third &&
+	   sd->sd_fourth == 0) {
+
+    /* 
+     * No response received, so we now perform Test IV using the address
+     * learnt from response to Test-I. 
+     * 
+     * Unfortunately running  this test will potentially affect
+     * results of a subsequent Test-II (depends on NAT binding timeout
+     * values). To get around this, the STUN server would ideally have 
+     * a dedicated IP:port for Test-IV. But within the currents specs,
+     * we need to reuse one of the IP:port addresses already used in 
+     * Test-II by the STUN server to send us packets.
+     */
+
+    SU_DEBUG_7(("Sending STUN NAT type Test-IV request to %s.\n",
+	       inet_ntoa(sd->sd_sec_addr[0].su_sin.sin_addr)));
+    
+    sd->sd_fourth = 2; /* request, -1, 0, 1 reserved for results */
+    req->sr_state = stun_req_dispose_me;
+    req = stun_request_create(sd);
+    err = stun_make_binding_req(sh, req, req->sr_msg,
+				STUNTAG_CHANGE_IP(0),
+				STUNTAG_CHANGE_PORT(0),
+				TAG_END());
+
+    if (err == 0) {
+      err = stun_send_binding_request(req, sd->sd_sec_addr);
+    }
+
+    if (err < 0) {
+      SU_DEBUG_0(("WARNING: Failure in performing STUN Test-IV check. "
+		  "The results related to mapping characteristics may be incorrect."));
+      stun_free_message(req->sr_msg);
+      sd->sd_fourth = -1;
+      /* call function again, sd_fourth stops the recursion */
+      action_determine_nattype(req, binding_response);
+      return -1;
+    }
+    
+    return 0; /* we don't want to dispose this req */
+  }
+  /* case 5: no response Test-II, and success with III
+   *         the NAT is filtering packets from different IP
+   *         do not make conclusions until Test-IV has been scheduled */
+  else if (sd->sd_first > 0 && 
+	   sd->sd_second < 0 &&
+	   sd->sd_third > 0 &&
+	   sd->sd_fourth) {
+    if (sd->sd_mapped_addr_match == 1)
+      sd->sd_nattype = stun_nat_res_cone;
+    else
+      sd->sd_nattype = stun_nat_ad_filt_ad_map;
+    priv_mark_discovery_done(sd, sh, action, req);
+  }
+  /* case 6: no response to Test-II nor III 
+   *         the NAT is filtering packets from different port
+   *         do not make conclusions until Test-IV has been scheduled */
+  else if (sd->sd_first > 0 && 
+	   sd->sd_second < 0 &&
+	   sd->sd_third < 0 &&
+	   sd->sd_fourth) {
+    if (sd->sd_mapped_addr_match == 1)
+      sd->sd_nattype = stun_nat_port_res_cone;
+    else
+      sd->sd_nattype = stun_nat_adp_filt_ad_map;
+    priv_mark_discovery_done(sd, sh, action, req);
+  }
+
+  /* this request of the discovery process can be disposed */
+  req->sr_state = stun_req_dispose_me;
+
+  return 0;
+}
+
+
+static void stun_sendto_timer_cb(su_root_magic_t *magic, 
+				 su_timer_t *t,
+				 su_timer_arg_t *arg)
+{
+  stun_request_t *req = arg;
+  stun_handle_t *sh = req->sr_handle;
+  stun_discovery_t *sd = req->sr_discovery;
+  stun_action_t action = get_action(req);
+  long timeout = 0;
+
+  enter;
+
+  if (req->sr_state == stun_req_dispose_me) {
+    stun_request_destroy(req);
+    SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+    return;
+  }
+
+  ++req->sr_retry_count;
+
+  /* check if max retry count has been exceeded; or if 
+   * action type is NAT type check (XXX: the request attributes
+   * are not passed correctly to resend function) */
+  if (req->sr_retry_count >= sh->sh_max_retries ||
+      action == stun_action_test_nattype) {
+    errno = ETIMEDOUT;
+    STUN_ERROR(errno, stun_sendto_timer_cb);
+
+    stun_free_message(req->sr_msg);
+    free(req->sr_msg), req->sr_msg = NULL;
+
+    /* Either the server was dead, address wrong or STUN_UDP_BLOCKED */
+    /* sd->sd_nattype = stun_udp_blocked; */
+    req->sr_state = stun_req_timeout;
+    
+    /* If the action is binding request, we are done. If action was
+       NAT type determination, process with the state machine. */
+    switch (action) {
+    case stun_action_binding_request:
+      sd->sd_state = stun_discovery_timeout;
+
+      /* Use per discovery specific callback */
+      if (sd->sd_callback)
+	sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+      req->sr_state = stun_req_dispose_me;
+      break;
+
+    case stun_action_test_nattype:
+      action_determine_nattype(req, NULL);
+      break;
+      
+    case stun_action_test_lifetime:
+      process_test_lifetime(req, NULL);
+      break;
+      
+    case stun_action_keepalive:
+      sd->sd_state = stun_discovery_timeout;
+
+      /* Use per discovery specific callback */
+      if (sd->sd_callback)
+	sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+      stun_keepalive_destroy(sh, sd->sd_socket);
+      
+      break;
+
+    default:
+      break;
+      
+      return;
+    }
+
+    /* Destroy me immediately */
+    req->sr_state = stun_req_dispose_me;
+    timeout = 0;
+  }
+  else {
+    SU_DEBUG_3(("%s: Timeout no. %d, retransmitting.\n",
+		__func__, req->sr_retry_count));
+
+    /* Use pre-defined destination address for re-sends */
+    if (stun_send_message(req->sr_socket, req->sr_destination,
+			  req->sr_msg, &(sh->sh_passwd)) < 0) {
+      stun_free_message(req->sr_msg);
+      free(req->sr_msg), req->sr_msg = NULL;
+      return;
+    }
+    timeout = req->sr_timeout *= 2;
+
+  }
+  
+  su_timer_set_at(t, stun_sendto_timer_cb, (su_wakeup_arg_t *) req,
+		  su_time_add(su_now(), timeout));
+  
+  return;
+}
+
+
+/** This function sends a binding request to the address at serv (ip,
+ *  port). which could be the original or alternative socket addresses
+ *  of the STUN server. Local address is provided in cli, and
+ *  resulting mapped address is also saved in cli.
+ *  Return 0 if successful, -1 if failed
+ *
+ * @return
+ * On success, zero is returned.  Upon error, -1 is returned, and @e errno is
+ * set appropriately.
+ * 
+ * @ERRORS
+ * @ERROR EBADF           @a sockfd is not a valid deseriptor.
+ * @ERROR EPROTONOSUPPORT @a sockfd is not an UDP socket.
+ * @ERROR EINVAL          The socket is already bound to an address.
+ * @ERROR EACCESS   	  The address is protected, and the user is not 
+ *                  	  the super-user.
+ * @ERROR ENOTSOCK  	  Argument is a descriptor for a file, not a socket.
+ * @ERROR EAGAIN          Operation in progress. Application should call 
+ *                        stun_bind() again when there is data available on 
+ *                        the socket.
+ * @ERROR ETIMEDOUT       Request timed out.
+ * 
+ */   
+static int stun_send_binding_request(stun_request_t *req,
+				     su_sockaddr_t  *srvr_addr)
+{
+  su_timer_t *sendto_timer = NULL;
+  su_socket_t s;
+  stun_handle_t *sh = req->sr_handle;
+  stun_msg_t *msg =  req->sr_msg;
+
+  assert (sh && srvr_addr);
+
+  enter;
+
+  s = req->sr_socket;
+  memcpy(req->sr_destination, srvr_addr, sizeof(su_sockaddr_t));
+
+  if (stun_send_message(s, srvr_addr, msg, &(sh->sh_passwd)) < 0) {
+    return -1;
+  }
+
+  /* Create and start timer */
+  sendto_timer = su_timer_create(su_root_task(sh->sh_root), STUN_SENDTO_TIMEOUT);
+  su_timer_set(sendto_timer, stun_sendto_timer_cb, (su_wakeup_arg_t *) req);
+
+  req->sr_timer = sendto_timer;
+  req->sr_state = stun_req_discovery_processing;
+
+  return 0;
+}
+
+
+/** Compose a STUN message of the format defined by stun_msg_t */
+int stun_make_binding_req(stun_handle_t *sh,
+			  stun_request_t *req,
+			  stun_msg_t *msg,
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  int i;
+  stun_attr_t *tmp, **p; 
+  int bits = 0;
+  int chg_ip = 0, chg_port = 0; 
+
+  ta_list ta;
+
+  enter;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  STUNTAG_CHANGE_IP_REF(chg_ip),
+	  STUNTAG_CHANGE_PORT_REF(chg_port),
+	  TAG_END());
+
+  ta_end(ta);
+  
+  if (chg_ip)
+    bits |= CHG_IP;
+  if (chg_port)
+    bits |= CHG_PORT;
+
+  if (req)
+    req->sr_request_mask = bits;
+  
+  /* compose header */
+  msg->stun_hdr.msg_type = BINDING_REQUEST;
+  msg->stun_hdr.msg_len = 0; /* actual len computed by
+				stun_send_message */
+  for (i = 0; i < STUN_TID_BYTES; i++) {
+    msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);
+  } 
+  
+  /* optional attributes:
+   * - Response Address
+   * - Change Request X
+   * - Username
+   * - Message-Integrity */
+  msg->stun_attr = NULL;
+  /* CHANGE_REQUEST */
+  p = &(msg->stun_attr);
+
+  if (chg_ip || chg_port) {
+    stun_attr_changerequest_t *attr_cr;
+    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+    tmp->attr_type = CHANGE_REQUEST;
+    attr_cr = (stun_attr_changerequest_t *) malloc(sizeof(stun_attr_changerequest_t));
+    attr_cr->value =
+      (chg_ip ? STUN_CR_CHANGE_IP : 0) | (chg_port ? STUN_CR_CHANGE_PORT : 0);
+
+    tmp->pattr = attr_cr;
+    tmp->next = NULL;
+    *p = tmp; p = &(tmp->next);
+  }
+
+  /* USERNAME */
+  if (sh->sh_use_msgint &&
+      sh->sh_username.data && 
+      sh->sh_passwd.data) {
+    stun_buffer_t *a_pattr = (stun_buffer_t*)malloc(sizeof(stun_buffer_t));
+    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+    tmp->attr_type = USERNAME;
+
+    /* copy USERNAME from STUN handle */
+    a_pattr->data = (void*)malloc(sh->sh_username.size);
+    memcpy(a_pattr->data, sh->sh_username.data, sh->sh_username.size);
+    a_pattr->size = sh->sh_username.size;
+    tmp->pattr = a_pattr;
+
+    tmp->next = NULL;
+    *p = tmp; p = &(tmp->next);
+
+    /* dummy MESSAGE_INTEGRITY attribute, computed later */
+    tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+    tmp->attr_type = MESSAGE_INTEGRITY;
+    tmp->pattr = NULL;
+    tmp->next = NULL;
+    *p = tmp; p = &(tmp->next);
+  }
+
+  /* no buffer assigned yet */
+  msg->enc_buf.data = NULL;
+  msg->enc_buf.size = 0;
+
+  return 0;
+}
+
+int stun_process_response(stun_msg_t *msg)
+{
+
+  enter;
+
+  /* parse msg first */
+  if (stun_parse_message(msg) < 0) {
+    SU_DEBUG_3(("%s: Error parsing response.\n", __func__));
+    return -1;
+  }
+
+  /* check message digest if exists */
+  switch (msg->stun_hdr.msg_type) {
+  case BINDING_RESPONSE:
+    if (stun_process_binding_response(msg) < 0) 
+      return -1;
+    break;
+  case BINDING_ERROR_RESPONSE:
+    if (stun_process_error_response(msg) < 0)
+      return -1;
+    break;
+  default:
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/** process binding response */
+int stun_process_binding_response(stun_msg_t *msg) {
+  /* currently not needed. */
+  return 0;
+}
+
+
+/** process binding error response
+ *  Report error and return
+ */
+int stun_process_error_response(stun_msg_t *msg)
+{
+  stun_attr_t *attr;
+  stun_attr_errorcode_t *ec;
+
+  enter;
+
+  attr = stun_get_attr(msg->stun_attr, ERROR_CODE);
+  if (attr == NULL) {
+    perror("stun_process_error_response");
+    return -1;
+  }
+
+  ec = (stun_attr_errorcode_t *)attr->pattr;
+  
+  SU_DEBUG_5(("%s: Received Binding Error Response:\n", __func__));
+  SU_DEBUG_5(("%s: Error: %d %s\n", __func__, ec->code, ec->phrase));
+
+  return 0;
+}
+
+/**
+ * Sets values for USERNAME and PASSWORD stun fields 
+ * for the handle.
+ */
+int stun_set_uname_pwd(stun_handle_t *sh,
+		       const char *uname,
+		       isize_t len_uname,
+		       const char *pwd,
+		       isize_t len_pwd)
+{
+  enter;
+
+  sh->sh_username.data = malloc(len_uname);
+  if (sh->sh_username.data) {
+    memcpy(sh->sh_username.data, uname, len_uname);
+    sh->sh_username.size = (unsigned)len_uname;
+  }
+  else
+    return -1;
+  
+  sh->sh_passwd.data = malloc(len_pwd);
+  if (sh->sh_passwd.data) {
+    memcpy(sh->sh_passwd.data, pwd, len_pwd);
+    sh->sh_passwd.size = (unsigned)len_pwd;
+  }
+  else
+    return -1;
+
+  sh->sh_use_msgint = 1; /* turn on message integrity ussage */
+  
+  return 0;
+}
+
+  
+/**
+ * Converts character address format to sockaddr_in 
+ */
+int stun_atoaddr(su_home_t *home,
+		 int ai_family,
+		 su_addrinfo_t *info,
+		 char const *in)
+{
+  su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};
+  char const *host;
+  char *port = NULL, tmp[SU_ADDRSIZE];
+  int err;
+  su_sockaddr_t *dstaddr;
+
+  assert(info && in);
+
+  enter;
+
+  dstaddr = (su_sockaddr_t *) info->ai_addr;
+
+  /* note: works only for IPv4 */
+  if (ai_family != AF_INET) 
+    return -1;
+
+  hints->ai_family = ai_family;
+
+  port = strstr(in, ":");
+  if (port == NULL) {
+    host = in;
+  }
+  else {
+    assert((size_t)(port - in) < strlen(in) + 1);
+    memcpy(tmp, in, port - in);
+    tmp[port - in] = 0;
+    host = tmp;
+    ++port;
+  }
+    
+  err = su_getaddrinfo(host, NULL, hints, &res);
+  if (err == 0) {
+    for (ai = res; ai; ai = ai->ai_next) {
+      if (ai->ai_family != AF_INET)
+	continue;
+
+      info->ai_flags = ai->ai_flags;
+      info->ai_family = ai->ai_family;
+      info->ai_socktype = ai->ai_socktype;
+      info->ai_protocol = ai->ai_protocol;
+      info->ai_addrlen = ai->ai_addrlen;
+      info->ai_canonname = su_strdup(home, host);
+      
+      memcpy(&dstaddr->su_sa, res->ai_addr, sizeof(struct sockaddr));
+      break;
+    }
+
+    if (port) 
+      dstaddr->su_port = htons(atoi(port));
+    else
+      dstaddr->su_port = htons(STUN_DEFAULT_PORT);
+  }
+  else {
+    SU_DEBUG_5(("stun_atoaddr: %s(%s): %s\n", "su_getaddrinfo", in,
+		su_gai_strerror(err)));
+  }
+
+  if (res)
+    su_freeaddrinfo(res);
+
+  return err;
+}
+
+/**
+ * Initiates STUN discovery process to find out NAT 
+ * binding life-time settings.
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET Bind socket for STUN
+ * @TAG STUNTAG_REGISTER_EVENTS Register socket for eventloop owned by STUN
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @return 0 on success, non-zero on error
+ */
+int stun_test_lifetime(stun_handle_t *sh,
+		      stun_discovery_f sdf,
+		      stun_discovery_magic_t *magic,
+		      tag_type_t tag, tag_value_t value,
+		      ...)
+{
+  stun_request_t *req = NULL;
+  stun_discovery_t *sd = NULL;
+  ta_list ta;
+  su_socket_t s = INVALID_SOCKET;
+  int err, index = 0, s_reg = 0;
+  char addr[SU_ADDRSIZE];
+  char const *server = NULL;
+  su_socket_t sockfdy;
+  socklen_t y_len;
+  su_sockaddr_t y_addr;
+  su_sockaddr_t *destination;
+
+  assert(sh);
+
+  enter;
+
+  if (!sh->sh_pri_addr[0].su_port) {
+    /* no STUN server address, perform a DNS-SRV lookup */
+   
+    ta_list ta;
+    ta_start(ta, tag, value);
+    SU_DEBUG_5(("Delaying STUN get-lifetime req. for DNS-SRV query.\n"));
+    err = priv_dns_queue_action(sh, stun_action_test_lifetime, sdf, magic, ta_tags(ta));
+    ta_end(ta);
+       
+    return err;
+  }
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  STUNTAG_SOCKET_REF(s),
+	  STUNTAG_REGISTER_EVENTS_REF(s_reg),
+	  STUNTAG_SERVER_REF(server),
+	  TAG_END());
+
+  sd = stun_discovery_create(sh, stun_action_test_lifetime, sdf, magic);
+  if ((index = assign_socket(sd, s, s_reg)) < 0)
+      return errno = EFAULT, -1;
+
+  /* If no server given, use default address from stun_handle_init() */
+  if (!server) {
+    /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */
+    memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t));
+  }
+  else {
+    err = stun_atoaddr(sh->sh_home, AF_INET, &sd->sd_pri_info, server);
+    memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t));
+  }
+  destination = (su_sockaddr_t *) sd->sd_pri_addr;
+
+  req = stun_request_create(sd);
+
+  /* ci = &req->sr_localinfo; */
+
+  /* get local ip address */
+  /* get_localinfo(); */
+
+  /* initialize socket y */
+  sockfdy = su_socket(AF_INET, SOCK_DGRAM, 0);
+
+  /* set socket asynchronous */
+  if (su_setblocking(sockfdy, 0) < 0) {
+    STUN_ERROR(errno, su_setblocking);
+
+    su_close(sockfdy);
+    return errno = EFAULT, -1;
+  }
+
+  sd->sd_socket2 = sockfdy;
+
+  memset(&y_addr, 0, sizeof(y_addr));
+  memcpy(&y_addr, sd->sd_bind_addr, sizeof(y_addr));
+  y_addr.su_port = 0;
+
+  y_len = sizeof(y_addr);
+  if (bind(sockfdy, (struct sockaddr *) &y_addr, y_len) < 0) {
+    return -1;
+  }
+
+  if (getsockname(sockfdy, (struct sockaddr *) &y_addr, &y_len) < 0) {
+    STUN_ERROR(errno, getsockname);
+    return -1;
+  }
+
+  SU_DEBUG_3(("%s: socket y bound to %s:%u\n", __func__,
+	      inet_ntop(y_addr.su_family, SU_ADDR(&y_addr), addr, sizeof(addr)),
+	      (unsigned) ntohs(y_addr.su_port)));
+
+  req->sr_from_y = -1;
+
+  SU_DEBUG_1(("%s: determining binding life time, this may take a while.\n", __func__));
+
+  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0) 
+    return -1;
+
+  err = stun_send_binding_request(req, destination);
+  if (err < 0) {
+    stun_free_message(req->sr_msg);
+    return -1;
+  }
+
+  ta_end(ta);
+
+  return 0;
+}
+
+int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr)
+{
+  stun_attr_sockaddr_t *addr;
+  stun_attr_t *tmp;
+
+  enter;
+
+  tmp = malloc(sizeof(stun_attr_t));
+  tmp->attr_type = RESPONSE_ADDRESS;
+  addr = malloc(sizeof(stun_attr_sockaddr_t));
+  memcpy(addr, mapped_addr, sizeof(stun_attr_sockaddr_t));
+  tmp->pattr = addr;
+  
+  if (req->stun_attr == NULL) {
+    tmp->next = NULL;
+  }
+  else {
+    tmp->next = req->stun_attr;
+  }
+  req->stun_attr = tmp;
+
+  return 0;
+}
+
+
+/**
+ * Determines if the message is STUN message (-1 if not stun). 
+ */
+int stun_msg_is_keepalive(uint16_t data)
+{
+  uint16_t msg_type;
+  /* parse header */
+  msg_type = ntohs(data);
+
+  if (msg_type == BINDING_REQUEST ||
+      msg_type == BINDING_RESPONSE ||
+      msg_type == BINDING_ERROR_RESPONSE) {
+    return 0;
+  }
+
+  return -1;
+}
+
+/**
+ * Determines length of STUN message (0 (-1?) if not stun). 
+ */
+int stun_message_length(void *data, isize_t len, int end_of_message)
+{
+  unsigned char *p;
+  uint16_t msg_type;
+
+  if (len < 4)
+    return -1;
+
+  /* parse header first */
+  p = data;
+  msg_type = (p[0] << 8) | p[1];
+
+  if (msg_type == BINDING_REQUEST ||
+      msg_type == BINDING_RESPONSE ||
+      msg_type == BINDING_ERROR_RESPONSE) {
+    /* return message length */
+    return (p[0] << 8) | p[1];
+  }
+  else
+    return -1;
+}
+
+/** Process incoming message */
+int stun_process_message(stun_handle_t *sh, su_socket_t s, 
+			 su_sockaddr_t *sa, socklen_t salen,
+			 void *data, isize_t len)
+{
+  int retval = -1;
+  stun_msg_t msg;
+
+  enter;
+
+  if (len >= 65536)
+    len = 65536;
+
+  /* Message received. */
+  msg.enc_buf.data = data;
+  msg.enc_buf.size = (unsigned)len;
+ 
+  debug_print(&msg.enc_buf);      
+
+  /* Parse here the incoming message. */
+  if (stun_parse_message(&msg) < 0) {
+    stun_free_message(&msg);
+    SU_DEBUG_5(("%s: Error parsing response.\n", __func__));
+    return retval;
+  }
+
+  if (msg.stun_hdr.msg_type == BINDING_REQUEST) {
+    return stun_process_request(s, &msg, 0, sa, salen);
+  }
+  else if (msg.stun_hdr.msg_type == BINDING_RESPONSE) {
+    /* Based on the decoded payload, find the corresponding request
+     * (based on TID). */
+    return do_action(sh, &msg);
+  }
+
+  return -1;
+}
+
+
+int stun_discovery_release_socket(stun_discovery_t *sd)
+{
+  stun_handle_t *sh = sd->sd_handle;
+
+  if (su_root_deregister(sh->sh_root, sd->sd_index) >= 0) {
+    SU_DEBUG_3(("%s: socket deregistered from STUN \n", __func__));
+    sd->sd_index = -1; /* mark index as deregistered */
+
+    return 0;
+  }
+
+  return -1;
+}
+
+
+/** 
+ * Creates a keepalive dispatcher for bound SIP sockets 
+ */
+int stun_keepalive(stun_handle_t *sh,
+		   su_sockaddr_t *sa,
+		   tag_type_t tag, tag_value_t value,
+		   ...)
+{
+  su_socket_t s = INVALID_SOCKET;
+  unsigned int timeout = 0;
+  ta_list ta;
+  stun_discovery_t *sd;
+  stun_request_t *req;
+  stun_action_t action = stun_action_keepalive;
+  char addr[SU_ADDRSIZE];
+
+  enter;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  STUNTAG_SOCKET_REF(s),
+	  STUNTAG_TIMEOUT_REF(timeout),
+	  TAG_END());
+
+  ta_end(ta);
+
+  if (s < 1 || !sa || timeout == 0)
+    return errno = EFAULT, -1;
+
+  /* If there already is keepalive associated with the given socket,
+   * destroy it. */
+  stun_keepalive_destroy(sh, s);
+  
+  sd = stun_discovery_create(sh, action, NULL, NULL); /* XXX --
+							 specify last
+							 params if
+							 necessary */
+  sd->sd_socket = s;
+  sd->sd_timeout = timeout;
+  memcpy(sd->sd_pri_addr, sa, sizeof(*sa));
+
+  req = stun_request_create(sd);
+
+  SU_DEBUG_3(("%s: Starting to send STUN keepalives to %s:%u\n", __func__, 
+	      inet_ntop(sa->su_family, SU_ADDR(sa), addr, sizeof(addr)),
+	      (unsigned) ntohs(sa->su_port)));
+  
+  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||
+      stun_send_binding_request(req, sa) < 0) {
+    stun_request_destroy(req);
+    stun_discovery_destroy(sd);
+    return -1;
+  }
+  
+  sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout);
+  su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd);
+
+  return 0;
+}
+
+/** Send SIP keepalives */
+static void stun_keepalive_timer_cb(su_root_magic_t *magic, 
+				    su_timer_t *t,
+				    su_timer_arg_t *arg)
+{
+  stun_discovery_t *sd = arg;
+  stun_handle_t *sh = sd->sd_handle;
+  int timeout = sd->sd_timeout;
+  su_sockaddr_t *destination = sd->sd_pri_addr;
+  stun_request_t *req;
+
+  enter;
+
+  su_timer_destroy(t);
+
+  if (sd->sd_state == stun_discovery_timeout)
+    return;
+
+  req = stun_request_create(sd);
+  
+  if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||
+      stun_send_binding_request(req, destination) < 0) {
+    stun_request_destroy(req);
+    stun_discovery_destroy(sd);
+    return;
+  }
+  
+  sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout);
+  su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd);
+
+  return;
+}
+
+/**
+ * Destroys the keepalive dispatcher without touching the socket
+ */
+int stun_keepalive_destroy(stun_handle_t *sh, su_socket_t s)
+{
+  stun_discovery_t *sd = NULL;
+  stun_request_t *req;
+  stun_action_t action = stun_action_keepalive;
+
+  if (sh == NULL)
+    return 1;
+
+  /* Go through the request queue and destroy keepalive requests
+   * associated with the given socket. */
+  for (req = sh->sh_requests; req; req = req->sr_next) {
+    if (req->sr_socket == s && req->sr_discovery->sd_action == action) {
+      req->sr_state = stun_req_dispose_me;
+      if (!sd)
+	sd = req->sr_discovery;
+    }
+  }
+
+  /* No keepalive found */
+  if (!sd)
+    return 1;
+
+  su_timer_destroy(sd->sd_timer), sd->sd_timer = NULL;
+  stun_discovery_destroy(sd);
+
+  return 0;
+}
+
+
+int stun_process_request(su_socket_t s, stun_msg_t *req,
+			 int sid, su_sockaddr_t *from_addr,
+			 socklen_t from_len)
+{
+  stun_msg_t resp;
+  su_sockaddr_t mod_addr[1] = {{ 0 }}, src_addr[1] = {{ 0 }}, chg_addr[1] = {{ 0 }};
+  stun_attr_t *tmp, m_attr[1], s_attr[1], c_attr[1], **p;
+  su_sockaddr_t to_addr;
+  int c, i;
+
+  tmp = stun_get_attr(req->stun_attr, RESPONSE_ADDRESS);
+
+  if (tmp) {
+    memcpy(&to_addr, tmp->pattr, sizeof(to_addr));
+  }
+  else {
+    memcpy(&to_addr, from_addr, sizeof(to_addr));
+  }
+
+  /* compose header */
+  stun_init_message(&resp);
+  resp.stun_hdr.msg_type = BINDING_RESPONSE;
+  resp.stun_hdr.msg_len = 0; /* actual len computed later */
+
+  for (i = 0; i < STUN_TID_BYTES; i++) {
+    resp.stun_hdr.tran_id[i] = req->stun_hdr.tran_id[i];
+  }
+  p = &(resp.stun_attr);
+
+  /* MAPPED-ADDRESS */
+  tmp = m_attr;
+  tmp->attr_type = MAPPED_ADDRESS;
+  memcpy(mod_addr, from_addr, sizeof(*mod_addr));
+  tmp->pattr = mod_addr;
+  tmp->next = NULL;
+  *p = tmp; p = &(tmp->next);
+
+  /* SOURCE-ADDRESS depends on CHANGE_REQUEST */
+  tmp = stun_get_attr(req->stun_attr, CHANGE_REQUEST);
+  if (!tmp) {
+    c = 0;
+  }
+  else {
+    switch (((stun_attr_changerequest_t *) tmp->pattr)->value) {
+    case STUN_CR_CHANGE_IP:
+      c = 1;
+      break;
+
+    case STUN_CR_CHANGE_PORT:
+      c = 2;
+      break;
+
+    case STUN_CR_CHANGE_IP | STUN_CR_CHANGE_PORT: /* bitwise or */
+      c = 3;
+      break;
+
+    default:
+      return -1;    
+    }
+  }   
+
+  tmp = s_attr;
+  tmp->attr_type = SOURCE_ADDRESS;
+
+  /* memcpy(src_addr, &stun_change_map[c][sid], sizeof(*src_addr)); */
+  tmp->pattr = src_addr;
+  tmp->next = NULL;
+  *p = tmp; p = &(tmp->next);
+
+  /* CHANGED-ADDRESS */ /* depends on sid */
+  tmp = c_attr;
+  tmp->attr_type = CHANGED_ADDRESS;
+  /* memcpy(chg_addr, &stun_change_map[3][sid], sizeof(*chg_addr)); */
+  tmp->pattr = chg_addr;
+  tmp->next = NULL;
+  *p = tmp; p = &(tmp->next);
+
+
+  /* no buffer assigned yet */
+  resp.enc_buf.data = NULL;
+  resp.enc_buf.size = 0;
+
+  stun_send_message(s, &to_addr, &resp, NULL);
+  return 0;
+} 
+
+/**
+ * Returns socket attached to the discovery object 
+ */
+su_socket_t stun_discovery_get_socket(stun_discovery_t *sd)
+{
+  assert(sd);
+  return sd->sd_socket;
+}
+
+/* -------------------------------------------------------------------
+ * DEPRECATED functions
+ * -------------------------------------------------------------------
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29 @@
+/**@MODULEPAGE "stun" - STUN Client and Server Module
+
+ at section stun_meta Module Meta Information
+
+The Sofia @b stun module contains macros and functions for STUN server and
+client library.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section stun_contents Contents of stun Module
+
+The stun module contains the public header files as follows:
+- <stun.h>        the public API of the module
+- <stun_common.h> low-level functions for parsing and encoding STUN messages
+- <stun_tag.h>    defines the su tags used by stun
+
+ at section stun_usage Using Sofia STUN Library
+
+To be written. See torture_stun.c and tport/tport.c.
+
+ at section todo Todo
+
+- none at the moment
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,826 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_common.c
+ * @brief 
+ * 
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *  
+ * @date Created: Fri Oct  3 13:40:41 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#ifdef USE_TURN
+#include "../turn/turn_common.h"
+#undef STUN_A_LAST_MANDATORY
+#define STUN_A_LAST_MANDATORY TURN_LARGEST_ATTRIBUTE
+#endif
+
+#include "stun_internal.h"
+
+#include <assert.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "stun_common"
+#endif
+
+const char stun_400_Bad_request[] = "Bad Request",
+  stun_401_Unauthorized[] = "Unauthorized",
+  stun_420_Unknown_attribute[] = "Unknown Attribute",
+  stun_430_Stale_credentials[] = "Stale Credentials",
+  stun_431_Integrity_check_failure[] = "Integrity Check Failure",
+  stun_432_Missing_username[] = "Missing Username",
+  stun_433_Use_tls[] = "Use TLS",
+#ifdef USE_TURN
+  turn_434_Missing_realm[] = "Missing Realm",
+  turn_435_Missing_nonce[] = "Missing Nonce",
+  turn_436_Unknown_username[] = "Unknown Username",
+  turn_437_No_binding[] = "No Binding",
+  turn_439_Illegal_port[] = "Illegal Port",
+#endif
+  stun_500_Server_error[] = "Server Error",
+  stun_600_Global_failure[] = "Global Failure";
+
+#define set16(b, offset, value)			\
+  (((b)[(offset) + 0] = ((value) >> 8) & 255),	\
+   ((b)[(offset) + 1] = (value) & 255))
+
+#define get16(b, offset)	\
+  (((b)[(offset) + 0] << 8) |	\
+   ((b)[(offset) + 1] << 0))
+
+int stun_parse_message(stun_msg_t *msg)
+{
+  unsigned len;
+  int i;
+  unsigned char *p;
+
+  /* parse header first */
+  p = msg->enc_buf.data;
+  msg->stun_hdr.msg_type = get16(p, 0);
+  msg->stun_hdr.msg_len = get16(p, 2); 
+  memcpy(msg->stun_hdr.tran_id, p + 4, STUN_TID_BYTES);
+
+  SU_DEBUG_5(("%s: Parse STUN message: Length = %d\n", __func__,
+	      msg->stun_hdr.msg_len));
+
+  /* parse attributes */
+  len = msg->stun_hdr.msg_len;
+  p = msg->enc_buf.data + 20;
+  msg->stun_attr = NULL;
+  while (len > 0) {
+    i = stun_parse_attribute(msg, p);
+    if (i <= 0) {
+      SU_DEBUG_3(("%s: Error parsing attribute.\n", __func__));
+      return -1;
+    }
+    p += i;
+    len -= i;
+  }
+
+  return 0;
+}
+
+int stun_parse_attribute(stun_msg_t *msg, unsigned char *p)
+{
+  int len;
+  uint16_t attr_type;
+  stun_attr_t *attr, *next;
+
+  attr_type = get16(p, 0);
+  len = get16(p, 2);
+
+  SU_DEBUG_5(("%s: received attribute: Type %02X, Length %d - %s\n", 
+	      __func__, attr_type, len, stun_attr_phrase(attr_type)));
+
+  if (attr_type > STUN_A_LAST_MANDATORY && attr_type < STUN_A_OPTIONAL) {
+    return -1;
+  }
+
+  attr = (stun_attr_t *)calloc(1, sizeof(stun_attr_t));
+  if (!attr)
+    return -1;
+  attr->next = NULL;
+  attr->attr_type = attr_type;
+  p += 4;
+
+  switch (attr->attr_type) {
+  case MAPPED_ADDRESS:
+  case RESPONSE_ADDRESS:
+  case SOURCE_ADDRESS:
+  case CHANGED_ADDRESS:
+  case REFLECTED_FROM:
+#ifdef USE_TURN
+  case TURN_ALTERNATE_SERVER:
+  case TURN_DESTINATION_ADDRESS:
+  case TURN_SOURCE_ADDRESS:
+#endif
+    if (stun_parse_attr_address(attr, p, len) < 0) {
+      free(attr);
+      return -1;
+    }
+    break;
+  case ERROR_CODE:
+    if (stun_parse_attr_error_code(attr, p, len) <0) { free(attr); return -1; }
+    break;
+  case UNKNOWN_ATTRIBUTES:
+    if(stun_parse_attr_unknown_attributes(attr, p, len) <0) { free(attr); return -1; }
+    break;
+  case CHANGE_REQUEST:
+#ifdef USE_TURN
+  case TURN_LIFETIME:
+  case TURN_MAGIC_COOKIE:
+  case TURN_BANDWIDTH:
+#endif
+    if (stun_parse_attr_uint32(attr, p, len) <0) { free(attr); return -1; }
+    break;
+  case USERNAME:
+  case PASSWORD:
+  case STUN_A_REALM:
+  case STUN_A_NONCE:
+#ifdef USE_TURN
+  case TURN_DATA:
+  case TURN_NONCE:
+#endif
+    if (stun_parse_attr_buffer(attr, p, len) <0) { free(attr); return -1; }
+    break;
+  default:
+    /* just copy as is */
+    attr->pattr = NULL;
+    attr->enc_buf.size = len;
+    attr->enc_buf.data = (unsigned char *) malloc(len);
+    memcpy(attr->enc_buf.data, p, len);
+    break;
+  }
+
+  /* skip to end of list */
+  if(msg->stun_attr==NULL) {
+    msg->stun_attr = attr;
+  }
+  else {
+    next = msg->stun_attr;
+    while(next->next!=NULL) {
+      next = next->next;
+    }
+    next->next = attr;
+  }
+  return len+4;
+}
+
+int stun_parse_attr_address(stun_attr_t *attr, 
+			    const unsigned char *p, 
+			    unsigned len)
+{
+  su_sockaddr_t *addr;
+  int addrlen;
+  char ipaddr[SU_ADDRSIZE + 2];
+
+  if (len != 8) {
+    return -1;
+  }
+
+  addrlen = sizeof(su_sockaddr_t);
+  addr = (su_sockaddr_t *) malloc(addrlen);
+
+  if (*(p+1) == 1) { /* expected value for IPv4 */
+    addr->su_sin.sin_family = AF_INET;
+  }
+  else {
+    free(addr);
+    return -1;
+  }
+  memcpy(&addr->su_sin.sin_port, p + 2, 2);
+  memcpy(&addr->su_sin.sin_addr.s_addr, p + 4, 4);
+
+  SU_DEBUG_5(("%s: address attribute: %s:%d\n", __func__,
+	      inet_ntop(addr->su_family, SU_ADDR(addr), ipaddr, sizeof(ipaddr)),
+	      (unsigned) ntohs(addr->su_sin.sin_port)));
+
+  attr->pattr = addr;
+  stun_init_buffer(&attr->enc_buf);
+
+  return 0;
+}
+
+int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len) {
+
+  uint32_t tmp;
+  stun_attr_errorcode_t *error;
+
+  memcpy(&tmp, p, sizeof(uint32_t));
+  tmp = ntohl(tmp);
+  error = (stun_attr_errorcode_t *) malloc(sizeof(*error));
+
+  error->code = (tmp & STUN_EC_CLASS)*100 + (tmp & STUN_EC_NUM);
+
+  error->phrase = (char *) malloc(len-3);
+
+  strncpy(error->phrase, (char*)p+4, len-4);
+  error->phrase[len - 4] = '\0';
+
+  attr->pattr = error;
+  stun_init_buffer(&attr->enc_buf);
+
+  return 0;
+}
+
+int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned len)
+{
+  uint32_t tmp;
+  stun_attr_changerequest_t *cr;
+  cr = (stun_attr_changerequest_t *) malloc(sizeof(*cr));
+  memcpy(&tmp, p, sizeof(uint32_t));
+  cr->value = ntohl(tmp);
+  attr->pattr = cr;
+  stun_init_buffer(&attr->enc_buf);
+
+  return 0;
+}
+
+int stun_parse_attr_buffer(stun_attr_t *attr, const unsigned char *p, unsigned len)
+{
+  stun_buffer_t *buf;
+  buf = (stun_buffer_t *) malloc(sizeof(stun_buffer_t));
+  buf->size = len;
+  buf->data = (unsigned char *) malloc(len);
+  memcpy(buf->data, p, len);
+  attr->pattr = buf;
+  stun_init_buffer(&attr->enc_buf);
+
+  return 0;
+}
+
+int stun_parse_attr_unknown_attributes(stun_attr_t *attr,
+				       const unsigned char *p,
+				       unsigned len)
+{
+  return 0;
+}
+
+/** scan thru attribute list and return the next requested attr */
+stun_attr_t *stun_get_attr(stun_attr_t *attr, uint16_t attr_type) {
+  stun_attr_t *p;
+
+  for (p = attr; p != NULL; p = p->next) {
+    if (p->attr_type == attr_type)
+      break;
+  }
+
+  return p;
+}
+
+void stun_init_buffer(stun_buffer_t *p) {
+  p->data = NULL;
+  p->size = 0;
+}
+
+int stun_free_buffer(stun_buffer_t *p) {
+  if (p->data)
+    free(p->data), p->data = NULL;
+  p->size = 0;
+  return 0;
+}
+
+int stun_copy_buffer(stun_buffer_t *p, stun_buffer_t *p2) {
+  stun_free_buffer(p); /* clean up existing data */
+  p->size = p2->size;
+  p->data = (unsigned char *) malloc(p->size);
+  memcpy(p->data, p2->data, p->size);
+  return p->size;
+}
+
+const char *stun_response_phrase(int status) {
+  if (status <100 || status >600)
+    return NULL;
+
+  switch (status) {
+  case STUN_400_BAD_REQUEST: return stun_400_Bad_request;
+  case STUN_401_UNAUTHORIZED: return stun_401_Unauthorized;
+  case STUN_420_UNKNOWN_ATTRIBUTE: return stun_420_Unknown_attribute;
+  case STUN_430_STALE_CREDENTIALS: return stun_430_Stale_credentials;
+  case STUN_431_INTEGRITY_CHECK_FAILURE: return stun_431_Integrity_check_failure;
+  case STUN_432_MISSING_USERNAME: return stun_432_Missing_username;
+  case STUN_433_USE_TLS: return stun_433_Use_tls;
+#ifdef USE_TURN
+  case TURN_MISSING_REALM: return turn_434_Missing_realm;
+  case TURN_MISSING_NONCE: return turn_435_Missing_nonce;
+  case TURN_UNKNOWN_USERNAME: return turn_436_Unknown_username;
+  case TURN_NO_BINDING: return turn_437_No_binding;
+  case TURN_ILLEGAL_PORT: return turn_439_Illegal_port;
+#endif
+  case STUN_500_SERVER_ERROR: return stun_500_Server_error;
+  case STUN_600_GLOBAL_FAILURE: return stun_600_Global_failure;
+  }
+  return "Response";
+}
+
+/** The set of functions encodes the corresponding attribute to
+ *    network format, and save the result to the enc_buf. Return the
+ *    size of the buffer.
+ */
+
+
+/* This function is used to encode any attribute of the form ADDRESS
+   */
+int stun_encode_address(stun_attr_t *attr) {
+  stun_attr_sockaddr_t *a;
+  uint16_t tmp;
+
+  a = (stun_attr_sockaddr_t *)attr->pattr;
+
+  if (stun_encode_type_len(attr, 8) < 0) {
+    return -1;
+  }
+
+  tmp = htons(0x01); /* FAMILY = 0x01 */
+  memcpy(attr->enc_buf.data+4, &tmp, sizeof(tmp));
+  memcpy(attr->enc_buf.data+6, &a->sin_port, 2);
+  memcpy(attr->enc_buf.data+8, &a->sin_addr.s_addr, 4);
+
+  return attr->enc_buf.size;
+}
+
+int stun_encode_uint32(stun_attr_t *attr) {
+  uint32_t tmp;
+
+  if (stun_encode_type_len(attr, 4) < 0) {
+    return -1;
+  }
+
+  tmp = htonl(((stun_attr_changerequest_t *) attr->pattr)->value);
+  memcpy(attr->enc_buf.data+4, &tmp, 4);
+  return attr->enc_buf.size;
+}
+
+int stun_encode_error_code(stun_attr_t *attr) {
+  short int class, num;
+  size_t phrase_len, padded;
+  stun_attr_errorcode_t *error;
+
+  error = (stun_attr_errorcode_t *) attr->pattr;
+  class = error->code / 100;
+  num = error->code % 100;
+
+  phrase_len = strlen(error->phrase);
+  if (phrase_len + 8 > 65536)
+    phrase_len = 65536 - 8;
+
+  /* note: align the phrase len (see RFC3489:11.2.9) */
+  padded = phrase_len + (phrase_len % 4 == 0 ? 0 : 4 - (phrase_len % 4));
+
+  /* note: error-code has four octets of headers plus the 
+   *       reason field -> len+4 octets */
+  if (stun_encode_type_len(attr, (uint16_t)(padded + 4)) < 0) {
+    return -1;
+  }
+  else {
+    assert(attr->enc_buf.size == padded + 8);
+    memset(attr->enc_buf.data+4, 0, 2);
+    attr->enc_buf.data[6] = class;
+    attr->enc_buf.data[7] = num;
+    /* note: 4 octets of TLV header and 4 octets of error-code header */
+    memcpy(attr->enc_buf.data+8, error->phrase, 
+	   phrase_len);
+    memset(attr->enc_buf.data + 8 + phrase_len, 0, padded - phrase_len);
+  }
+
+  return attr->enc_buf.size;
+}
+
+int stun_encode_buffer(stun_attr_t *attr) {
+  stun_buffer_t *a;
+
+  a = (stun_buffer_t *)attr->pattr;
+  assert(a->size < 65536);
+  if (stun_encode_type_len(attr, (uint16_t)a->size) < 0) {
+    return -1;
+  }
+
+  memcpy(attr->enc_buf.data+4, a->data, a->size);
+  return attr->enc_buf.size;
+}
+
+#if defined(HAVE_OPENSSL)
+int stun_encode_message_integrity(stun_attr_t *attr,
+				  unsigned char *buf,
+				  int len,
+				  stun_buffer_t *pwd) {
+  int padded_len;
+  unsigned int dig_len;
+  unsigned char *padded_text = NULL;
+  void *sha1_hmac;
+
+  if (stun_encode_type_len(attr, 20) < 0) {
+    return -1;
+  }
+
+  /* zero padding */
+  if (len % 64 != 0) {
+
+    padded_len = len + (64 - (len % 64));
+    padded_text = (unsigned char *) malloc(padded_len);
+    memcpy(padded_text, buf, len);
+    memset(padded_text + len, 0, padded_len - len);
+
+    sha1_hmac = HMAC(EVP_sha1(), pwd->data, pwd->size, padded_text, padded_len, NULL, &dig_len);
+  }
+  else {
+    sha1_hmac = HMAC(EVP_sha1(), pwd->data, pwd->size, buf, len, NULL, &dig_len);
+  }
+
+  assert(dig_len == 20);
+
+  memcpy(attr->enc_buf.data + 4, sha1_hmac, 20);
+  free(padded_text);
+  return attr->enc_buf.size;
+}
+#else
+int stun_encode_message_integrity(stun_attr_t *attr,
+				  unsigned char *buf,
+				  int len,
+				  stun_buffer_t *pwd) {
+
+  return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/** this function allocates the enc_buf, fills in type, length */
+int stun_encode_type_len(stun_attr_t *attr, uint16_t len) {
+  uint16_t tmp;
+
+  attr->enc_buf.data = (unsigned char *) malloc(len + 4);
+  memset(attr->enc_buf.data, 0, len + 4);
+
+  tmp = htons(attr->attr_type);
+  memcpy(attr->enc_buf.data, &tmp, 2);
+
+  tmp = htons(len);
+  memcpy(attr->enc_buf.data + 2, &tmp, 2);
+  attr->enc_buf.size = len + 4;
+
+  return 0;
+}
+
+/** 
+ * Validate the message integrity based on given 
+ * STUN password 'pwd'. The received content should be
+ * in msg->enc_buf.
+ */
+int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd)
+{
+
+#if defined(HAVE_OPENSSL)
+  int padded_len, len;
+  unsigned int dig_len;
+  unsigned char dig[20]; /* received sha1 digest */
+  unsigned char *padded_text;
+#endif
+
+  /* password NULL so shared-secret not established and 
+     messege integrity checks can be skipped */
+  if (pwd->data == NULL)
+    return 0;
+
+  /* otherwise the check must match */
+
+#if defined(HAVE_OPENSSL)
+
+  /* message integrity not received */
+  if (stun_get_attr(msg->stun_attr, MESSAGE_INTEGRITY) == NULL) {
+    SU_DEBUG_5(("%s: error: message integrity missing.\n", __func__));
+    return -1;
+  }
+
+  /* zero padding */
+  len = msg->enc_buf.size - 24;
+  padded_len = len + (len % 64 == 0 ? 0 : 64 - (len % 64));
+  padded_text = (unsigned char *) malloc(padded_len);
+  memset(padded_text, 0, padded_len);
+  memcpy(padded_text, msg->enc_buf.data, len);
+
+  memcpy(dig, HMAC(EVP_sha1(), pwd->data, pwd->size, padded_text, padded_len, NULL, &dig_len), 20);
+
+  if (memcmp(dig, msg->enc_buf.data + msg->enc_buf.size - 20, 20) != 0) {
+    /* does not match, but try the test server's password */
+    if (memcmp(msg->enc_buf.data+msg->enc_buf.size-20, "hmac-not-implemented", 20) != 0) {
+      SU_DEBUG_5(("%s: error: message digest problem.\n", __func__));
+      return -1;
+    }
+  }
+  else {
+    SU_DEBUG_5(("%s: message integrity validated.\n", __func__));
+  }
+
+  free(padded_text);
+
+  return 0;
+#else /* HAVE_OPENSSL */
+  return -1;
+#endif
+}
+
+void debug_print(stun_buffer_t *buf) {
+  unsigned i;
+  for(i = 0; i < buf->size/4; i++) {
+    SU_DEBUG_9(("%02x %02x %02x %02x\n",
+		*(buf->data + i*4),
+		*(buf->data + i*4 +1),
+		*(buf->data + i*4 +2),
+		*(buf->data + i*4 +3)));
+    if (i == 4)
+      SU_DEBUG_9(("---------------------\n"));
+  }
+  SU_DEBUG_9(("\n"));
+}
+
+int stun_init_message(stun_msg_t *msg) {
+  msg->stun_hdr.msg_type = 0;
+  msg->stun_hdr.msg_len = 0;
+  msg->stun_attr = NULL;
+  stun_init_buffer(&msg->enc_buf);
+  return 0;
+}
+
+int stun_free_message(stun_msg_t *msg) {
+
+  stun_attr_t *p, *p2;
+
+  /* clearing header */
+  memset(&msg->stun_hdr, 0, sizeof msg->stun_hdr);
+
+  /* clearing attr */
+  p = msg->stun_attr;
+  while(p) {
+    if(p->pattr) {
+      switch(p->attr_type) {
+      case USERNAME:
+      case PASSWORD:
+#ifdef USE_TURN
+      case TURN_DATA:
+      case TURN_NONCE:
+#endif
+	stun_free_buffer(p->pattr);
+	break;
+      default:
+	free(p->pattr);
+      }
+    }
+    stun_free_buffer(&p->enc_buf);
+    p2 = p->next;
+    free(p);
+    p = p2;
+  }
+  msg->stun_attr = NULL;
+
+  /* clearing buffer */
+  stun_free_buffer(&msg->enc_buf);
+
+  return 0;
+}
+
+
+int stun_send_message(su_socket_t s, su_sockaddr_t *to_addr,
+		      stun_msg_t *msg, stun_buffer_t *pwd) 
+{
+  int err;
+  char ipaddr[SU_ADDRSIZE + 2];
+  stun_attr_t **a, *b;
+
+  stun_encode_message(msg, pwd);
+
+  err = su_sendto(s, msg->enc_buf.data, msg->enc_buf.size, 0, 
+		  to_addr, SU_SOCKADDR_SIZE(to_addr));
+
+  free(msg->enc_buf.data), msg->enc_buf.data = NULL;
+  msg->enc_buf.size = 0;
+
+  for (a = &msg->stun_attr; *a;) {
+
+    if ((*a)->pattr)
+      free((*a)->pattr), (*a)->pattr = NULL;
+
+    if ((*a)->enc_buf.data)
+      free((*a)->enc_buf.data), (*a)->enc_buf.data = NULL;
+
+    b = *a;
+    b = b->next;
+    free(*a);
+    *a = NULL;
+    *a = b;
+  }
+
+  if (err > 0) {
+    inet_ntop(to_addr->su_family, SU_ADDR(to_addr), ipaddr, sizeof(ipaddr));
+    SU_DEBUG_5(("%s: message sent to %s:%u\n", __func__,
+		ipaddr, ntohs(to_addr->su_port)));
+
+    debug_print(&msg->enc_buf);
+  }
+  else
+    STUN_ERROR(errno, sendto);
+  
+  return err;
+}  
+
+
+/** Send a STUN message.
+ *  This will convert the stun_msg_t to the binary format based on the
+ *  spec
+ */
+int stun_encode_message(stun_msg_t *msg, stun_buffer_t *pwd) {
+
+  int z = -1, len, buf_len = 0;
+  unsigned char *buf;
+  stun_attr_t *attr, *msg_int=NULL;
+
+  if (msg->enc_buf.data == NULL) {
+    /* convert msg to binary format */
+    /* convert attributes to binary format for transmission */
+    len = 0;
+    for (attr = msg->stun_attr; attr ; attr = attr->next) {
+      switch(attr->attr_type) {
+      case RESPONSE_ADDRESS:
+      case MAPPED_ADDRESS:
+      case SOURCE_ADDRESS:
+      case CHANGED_ADDRESS:
+      case REFLECTED_FROM:	
+#ifdef USE_TURN
+      case TURN_ALTERNATE_SERVER:
+      case TURN_DESTINATION_ADDRESS:
+      case TURN_SOURCE_ADDRESS:
+#endif
+	z = stun_encode_address(attr);
+	break;
+      case CHANGE_REQUEST:
+#ifdef USE_TURN
+      case TURN_LIFETIME:
+      case TURN_MAGIC_COOKIE:
+      case TURN_BANDWIDTH:
+#endif
+	z = stun_encode_uint32(attr);
+	break;
+
+      case USERNAME:
+      case PASSWORD:
+#ifdef USE_TURN
+      case TURN_REALM:
+      case TURN_NONCE:
+      case TURN_DATA:
+#endif
+	z = stun_encode_buffer(attr);
+	break;
+      case MESSAGE_INTEGRITY:
+	msg_int = attr;
+	z = 24;
+	break;
+      case ERROR_CODE:
+	z = stun_encode_error_code(attr);
+      default:
+	break;
+      }
+
+      if(z < 0) return z;
+
+      len += z;
+    }
+
+    msg->stun_hdr.msg_len = len;
+    buf_len = 20 + msg->stun_hdr.msg_len;
+    buf = (unsigned char *) malloc(buf_len);
+    
+    /* convert to binary format for transmission */
+    set16(buf, 0, msg->stun_hdr.msg_type);
+    set16(buf, 2, msg->stun_hdr.msg_len);
+    memcpy(buf + 4, msg->stun_hdr.tran_id, STUN_TID_BYTES);
+
+    len = 20;
+
+    /* attaching encoded attributes */
+    attr = msg->stun_attr;
+    while(attr) {
+      /* attach only if enc_buf is not null */
+      if(attr->enc_buf.data && attr->attr_type != MESSAGE_INTEGRITY) {
+	memcpy(buf+len, (void *)attr->enc_buf.data, attr->enc_buf.size); 
+	len += attr->enc_buf.size;
+      }
+      attr = attr->next;
+    }
+
+    if (msg_int) {
+      /* compute message integrity */
+      if(stun_encode_message_integrity(msg_int, buf, len, pwd)!=24) {
+	free(buf);
+	return -1;
+      }
+      memcpy(buf+len, (void *)msg_int->enc_buf.data, 
+	     msg_int->enc_buf.size);
+    }
+    
+    /* save binary buffer for future reference */
+    if (msg->enc_buf.data)
+      free(msg->enc_buf.data);
+
+    msg->enc_buf.data = buf; msg->enc_buf.size = buf_len;
+  }
+
+  return 0;
+}
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_localinfo.h>
+
+char *stun_determine_ip_address(int family)
+{
+
+  char *local_ip_address;
+  su_localinfo_t *li = NULL, hints[1] = {{ LI_CANONNAME|LI_NUMERIC }};
+  int error;
+  size_t address_size;
+  struct sockaddr_in *sa = NULL;
+  su_sockaddr_t *temp;
+
+  hints->li_family = family;
+  hints->li_canonname = getenv("HOSTADDRESS");
+  if ((error = su_getlocalinfo(hints, &li)) < 0) {
+    SU_DEBUG_5(("%s: stun_determine_ip_address, su_getlocalinfo: %s\n",
+		__func__, su_gli_strerror(error)));
+    return NULL;
+  }
+
+  temp = li->li_addr;
+  sa = &temp->su_sin;
+
+  address_size = strlen(inet_ntoa(sa->sin_addr));
+  
+  local_ip_address = malloc(address_size + 1);
+  strcpy(local_ip_address, (char *) inet_ntoa(sa->sin_addr)); /* otherwise? */
+    
+  su_freelocalinfo(li);
+
+  return local_ip_address;
+
+}
+
+const char *stun_attr_phrase(uint16_t type)
+{
+  switch(type) {
+  case MAPPED_ADDRESS: return "MAPPED-ADDRESS";
+  case RESPONSE_ADDRESS: return "RESPONSE-ADDRESS";
+  case CHANGE_REQUEST: return "CHANGE-REQUEST";
+  case SOURCE_ADDRESS: return "SOURCE-ADDRESS";
+  case CHANGED_ADDRESS: return "CHANGED-ADDRESS";
+  case USERNAME: return "USERNAME";
+  case PASSWORD: return "PASSWORD";
+  case MESSAGE_INTEGRITY: return "MESSAGE-INTEGRITY";
+  case ERROR_CODE: return "ERROR-CODE";
+  case UNKNOWN_ATTRIBUTES: return "UNKNOWN-ATTRIBUTES";
+  case REFLECTED_FROM: return "REFLECTED-FROM";
+  case STUN_A_ALTERNATE_SERVER:
+  case STUN_A_ALTERNATE_SERVER_DEP: 
+    return "ALTERNATE-SERVER";
+  case STUN_A_REALM: return "REALM";
+  case STUN_A_NONCE: return "NONCE";
+  case STUN_A_XOR_MAPPED_ADDRESS: return "XOR-MAPPED-ADDRESS";
+#ifdef USE_TURN
+  case TURN_REALM: return "REALM";
+  case TURN_LIFETIME: return "LIFETIME";
+  case TURN_ALTERNATE_SERVER: return "ALTERNATE_SERVER";
+  case TURN_MAGIC_COOKIE: return "MAGIC_COOKIE";
+  case TURN_BANDWIDTH: return "BANDWIDTH";
+  case TURN_DESTINATION_ADDRESS: return "DESTINATION_ADDRESS";
+  case TURN_SOURCE_ADDRESS: return "SOURCE_ADDRESS";
+  case TURN_DATA: return "DATA";
+  case TURN_NONCE: return "NONCE";
+#endif
+  default: return "Attribute undefined";
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,246 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_dns.c 
+ * @brief Functins to discover STUN server address using DNS-SRV.
+ *
+ * Refs: 
+ *   - RFC3489/3489bis
+ *   - RFC2782
+ * 
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#include "config.h"
+
+#define STUN_SRV_SERVICE_TCP "_stun._tcp"
+#define STUN_SRV_SERVICE_UDP "_stun._udp"
+
+#include <sofia-sip/stun.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_wait.h>
+#define SRES_CONTEXT_T stun_dns_lookup_t
+#include <sofia-sip/sresolv.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stun_dns";
+#endif
+
+#include "stun_internal.h"
+
+struct stun_dns_lookup_s {
+  su_home_t          stun_home[1];
+  su_root_t         *stun_root;
+  stun_magic_t      *stun_magic;
+  sres_resolver_t   *stun_sres;
+  su_socket_t        stun_socket;
+  stun_dns_lookup_f  stun_cb;
+  char              *stun_tcp_target;
+  char              *stun_udp_target;
+  uint16_t           stun_tcp_port;
+  uint16_t           stun_udp_port;
+  unsigned           stun_state:2;       /**< bit0:udp, bit1:tcp */
+};
+
+enum stun_dns_state {
+  stun_dns_udp = 1,
+  stun_dns_tls = 2,
+  stun_dns_done = stun_dns_udp | stun_dns_tls
+};
+
+/**
+ * Internal callback used for gathering DNS replies.
+ */
+static void priv_sres_cb(stun_dns_lookup_t *self,
+			 sres_query_t *q,
+			 sres_record_t **answer)
+{
+  int i;
+
+  sres_sort_answers(self->stun_sres, answer);
+
+  /* note: picks the first ones (sort puts records with most
+   *       weight at start */
+
+  for (i = 0; answer && answer[i] != NULL; i++) {
+    sres_srv_record_t *rr = (sres_srv_record_t *) answer[i]->sr_srv;
+    if (rr && rr->srv_record && rr->srv_record->r_type == sres_type_srv) {
+      const char *tcp_name = STUN_SRV_SERVICE_TCP;
+      const char *udp_name = STUN_SRV_SERVICE_UDP;
+      if ((self->stun_state & stun_dns_tls) == 0 &&
+	  strncmp(rr->srv_record->r_name, tcp_name, strlen(tcp_name)) == 0) {
+	self->stun_tcp_target = su_strdup(self->stun_home, rr->srv_target);
+	self->stun_tcp_port = rr->srv_port;
+	self->stun_state |= stun_dns_tls;
+	SU_DEBUG_5(("%s: stun (tcp) for domain %s is at %s:%u.\n", 
+		    __func__, rr->srv_record->r_name, self->stun_tcp_target, self->stun_tcp_port)); 
+      }
+      else if ((self->stun_state & stun_dns_udp) == 0 &&
+	       strncmp(rr->srv_record->r_name, udp_name, strlen(udp_name)) == 0) {
+	self->stun_udp_target = su_strdup(self->stun_home, rr->srv_target);
+	self->stun_udp_port = rr->srv_port;
+	self->stun_state |= stun_dns_udp;
+	SU_DEBUG_5(("%s: stun (udp) for domain %s is at %s:%u.\n", 
+		    __func__, rr->srv_record->r_name, self->stun_udp_target, self->stun_udp_port)); 
+      }
+    }
+  }
+
+  if (self->stun_state == stun_dns_done) {
+    self->stun_cb(self, self->stun_magic);
+
+    sres_resolver_timer(self->stun_sres, -1);
+  }
+
+  sres_free_answers(self->stun_sres, answer);
+}
+
+/**
+ * Performs a DNS-SRV check for STUN 'stun' (tcp) and
+ * 'stun' (udp) services for 'domain'.
+ *
+ * The result will be delivered asynchronously in the
+ * 'func' callback. 'root' will be used as the event loop.
+ */
+stun_dns_lookup_t *stun_dns_lookup(stun_magic_t *magic, 
+				   su_root_t *root,
+				   stun_dns_lookup_f func, 
+				   const char *domain)
+{
+  stun_dns_lookup_t *self;
+  sres_query_t *query;
+
+  if (!domain || 
+      strlen(domain) + strlen(STUN_SRV_SERVICE_UDP ".") + 1>= SRES_MAXDNAME)
+    return NULL;
+  
+  self = su_home_new(sizeof(stun_dns_lookup_t));
+
+  /* see nta.c:outgoing_answer_srv() */
+  self->stun_magic = magic;
+  self->stun_cb = func;
+  self->stun_root = root;
+  self->stun_sres = sres_resolver_create(root, NULL, TAG_END());
+  if (self->stun_sres) {
+    char srvname[SRES_MAXDNAME + 1];
+
+    snprintf(srvname, sizeof srvname, "%s.%s", STUN_SRV_SERVICE_UDP, domain);
+
+    query = sres_query(self->stun_sres, priv_sres_cb, self,
+		       sres_type_srv,
+		       srvname);
+
+    snprintf(srvname, sizeof srvname, "%s.%s", STUN_SRV_SERVICE_TCP, domain);
+
+    query = sres_query(self->stun_sres, priv_sres_cb, self,
+		       sres_type_srv,
+		       srvname);
+  }
+  else {
+    su_free(NULL, self), self = NULL;
+  }
+  
+  return self;
+}
+
+/**
+ * Destroys the 'self' object created by stun_dns_lookup_destroy().
+ */
+void stun_dns_lookup_destroy(stun_dns_lookup_t *self)
+{
+  if (self->stun_sres)
+    sres_resolver_destroy(self->stun_sres);
+
+  su_home_unref(self->stun_home);
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._udp" service (RFC3489/3489bis).
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ *        SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */ 
+int stun_dns_lookup_udp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+  int result = -1;
+  if (self->stun_state == stun_dns_done) {
+    if (target) *target = self->stun_udp_target;
+    if (port) *port = self->stun_udp_port;
+    result = 0;
+  }
+
+  return result;
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._tcp" service (RFC3489).
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ *        SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */ 
+int stun_dns_lookup_tcp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+  int result = -1;
+  if (self->stun_state == stun_dns_done) {
+    if (target) *target = self->stun_tcp_target;
+    if (port) *port = self->stun_tcp_port;
+    result = 0;
+  }
+
+  return result;
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._udp" service (3489bis, "Short-Term Password").
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ *        SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */ 
+int stun_dns_lookup_stp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+  /* XXX: not implemented */
+  return -1;
+}
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_INTERNAL_H
+/** Defined when <stun_internal.h> has been included. */
+#define STUN_INTERNAL_H
+/**@file stun_internal.h STUN client interface
+ *
+ * @author Martti Mela <martti.mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 0
+#endif
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef STUN_H
+#include "sofia-sip/stun.h"
+#endif
+
+#if defined(HAVE_OPENSSL)
+/* avoid krb5-related build failures */
+#define OPENSSL_NO_KRB5
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#endif
+
+#ifndef STUN_COMMON_H
+#include "sofia-sip/stun_common.h"
+#endif
+
+
+
+#define SU_LOG (stun_log)
+#include <sofia-sip/su_debug.h>
+
+#define enter (void)SU_DEBUG_9(("%s: entering.\n", __func__))
+
+SOFIA_BEGIN_DECLS
+
+extern char const STUN_DEBUG[]; /* dummy declaration for Doxygen */
+
+/* XXX -- mela: note that this are 100 times too small */
+#if 1
+#define STUN_LIFETIME_EST 3500      /**< 6 min? */
+#define STUN_LIFETIME_MAX 18000     /**< 30 min? */
+#define STUN_LIFETIME_CI  50        /**< 5 sec confidence interval */
+#else
+#define STUN_LIFETIME_EST 350      /**< 6 min? */
+#define STUN_LIFETIME_MAX 1800     /**< 30 min? */
+#define STUN_LIFETIME_CI  5        /**< 5 sec confidence interval */
+#endif
+
+#define STUN_ERROR(err, what) \
+  SU_DEBUG_5(("%s: %s: %s\n", __func__, #what, su_strerror(err))), \
+    -1								   \
+
+int stun_is_requested(tag_type_t tag, tag_value_t value, ...);
+
+/* internal functions declaration */
+int stun_make_sharedsecret_req(stun_msg_t *msg);
+
+int stun_send_message(su_socket_t s, su_sockaddr_t *srvr,
+		      stun_msg_t *msg, stun_buffer_t *pwd);
+
+int stun_make_binding_req(stun_handle_t *se, stun_request_t *req,
+			  stun_msg_t *msg, 
+			  tag_type_t, tag_value_t, ...);
+int stun_process_response(stun_msg_t *msg);
+
+int stun_process_binding_response(stun_msg_t *msg);
+int stun_process_error_response(stun_msg_t *msg);
+
+int stun_atoaddr(su_home_t *home, int ai_family, su_addrinfo_t *info, char const *in);
+int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(STUN_INTERNAL_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,388 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_mini.c
+ * @brief Minimal stun server 
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *  
+ * @date Created: Fri Oct  3 13:40:41 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include "stun_internal.h"
+
+#include <assert.h>
+
+typedef struct stun_bound_s stun_bound_t;
+
+struct stun_bound_s
+{
+  stun_bound_t *ss_next;
+  su_socket_t ss_socket;
+  int ss_scope;			/* LI_SCOPE */
+  socklen_t ss_addrlen;
+  union {
+    struct sockaddr_in sin[1];
+    struct sockaddr_storage storage[1];
+    char array[sizeof (struct sockaddr_storage)];
+  } ss_addr;
+};
+
+struct stun_mini_s
+{
+  stun_bound_t *sockets;
+};
+
+static int process_3489_request(stun_mini_t *mini, 
+				stun_msg_t *request, stun_msg_t *response,
+				su_socket_t socket, void *, socklen_t);
+
+static int process_bis_request(stun_mini_t *mini, 
+			       stun_msg_t *request, stun_msg_t *response,
+			       su_socket_t socket, void *, socklen_t);
+
+int send_stun_error(stun_msg_t *response,
+		    int error,
+		    int socket,
+		    void *transaction_id,
+		    void *from,
+		    socklen_t fromlen);
+
+/** Create a stun miniserver */
+stun_mini_t *stun_mini_create(void)
+{
+  return calloc(1, sizeof (stun_mini_t));
+}
+
+/** Destroy a stun miniserver */
+void stun_mini_destroy(stun_mini_t *mini)
+{
+  if (mini) {
+    stun_bound_t *ss, **next;
+    for (next = &mini->sockets; *next; ) {
+      ss = *next;
+      *next = ss->ss_next;
+      free(ss);
+    }
+    free(mini);
+  }
+}
+
+/** Add a socket to stun miniserver. */
+int stun_mini_add_socket(stun_mini_t *mini, su_socket_t socket)
+{
+  stun_bound_t *ss, **next;
+  struct sockaddr_storage addr[1];
+  socklen_t addrlen = sizeof addr;
+
+  if (mini == NULL)
+    return su_seterrno(EFAULT);
+
+  for (next = &mini->sockets; *next; next = &(*next)->ss_next)
+    if (socket == (*next)->ss_socket)
+      return su_seterrno(EEXIST);
+
+  if (getsockname(socket, (void *)addr, &addrlen) < 0)
+    return -1;
+
+  if (addr->ss_family != AF_INET)
+    return su_seterrno(EAFNOSUPPORT);
+
+  ss = calloc(1, offsetof(stun_bound_t, ss_addr.array[addrlen]));
+  
+  ss->ss_socket = socket;
+  ss->ss_scope = su_sockaddr_scope((void *)addr, addrlen);
+
+  memcpy(ss->ss_addr.array, addr, ss->ss_addrlen = addrlen);
+  
+  *next = ss;
+
+  return 0;
+}
+
+/** Remove socket from stun miniserver */
+int stun_mini_remove_socket(stun_mini_t *mini, su_socket_t socket)
+{
+  stun_bound_t *ss, **next;
+
+  if (mini == NULL)
+    return errno = EFAULT, -1;
+
+  for (next = &mini->sockets; *next; next = &(*next)->ss_next)
+    if (socket == (*next)->ss_socket) {
+      ss = *next;
+      *next = ss->ss_next;
+      free(ss);
+      return 0;
+    }
+
+  return errno = ENOENT, -1;
+}
+
+void stun_mini_request(stun_mini_t *mini,
+		       su_socket_t socket,
+		       void *msg, ssize_t msglen,
+		       void *from, socklen_t fromlen)
+{
+  int error;
+  struct {
+    stun_msg_t in[1];
+    stun_msg_t out[1];
+    stun_msg_t error[1];
+  } m;
+  char const *verdict = NULL;
+  uint8_t *data = msg;
+  char buffer[80];
+  uint8_t const magic_cookie[4] = { 0x21, 0x12, 0xA4, 0x42 };
+
+  memset(&m, 0, sizeof m);
+
+  if (mini == NULL || msg == NULL || from == NULL)
+    return;
+    
+  if (msglen < 20)
+    verdict = "runt";
+  else if (data[0] == 1)
+    verdict = "response";
+  else if (data[0] != 0)
+    verdict = "garbage";
+  else if (data[1] == 2)
+    verdict = "shared secret request";
+  else if (data[1] != 1)
+    verdict = "garbage";
+
+  {
+    struct sockaddr_in const *sin = from;
+
+    if (sin->sin_family == AF_INET)
+      inet_ntop(sin->sin_family, &sin->sin_addr, buffer, sizeof buffer);
+    else
+      sprintf(buffer, "<af=%u>", (unsigned)sin->sin_family);
+
+    fprintf(stderr, "stun %s from %s:%u\n",
+	    verdict ? verdict : "request", buffer, ntohs(sin->sin_port));
+
+    if (verdict)
+      return;
+  }
+
+  m.in->enc_buf.data = msg;
+  m.in->enc_buf.size = msglen;
+
+  if (memcmp(data + 4, magic_cookie, sizeof magic_cookie) == 0)
+    error = process_3489_request(mini, m.in, m.out, socket, from, fromlen);
+  else
+    error = process_bis_request(mini, m.in, m.out, socket, from, fromlen);
+
+  if (error)
+    send_stun_error(m.error, error, socket, data + 4, from, fromlen);
+
+  m.in->enc_buf.data = NULL;
+
+  stun_free_message(m.in);
+  stun_free_message(m.out);
+  stun_free_message(m.error);
+}
+
+static
+int process_3489_request(stun_mini_t *mini,
+			 stun_msg_t *request,
+			 stun_msg_t *response,
+			 su_socket_t socket,
+			 void *from, 
+			 socklen_t fromlen)
+{
+  stun_bound_t *ss, *changed = NULL, ss0[1];
+  stun_attr_t *a, **next;
+  stun_attr_sockaddr_t *addr;
+  int change_address = 0;
+
+  if (stun_parse_message(request) < 0) {
+    fprintf(stderr, "stun: error parsing request\n");
+    return STUN_400_BAD_REQUEST;
+  }
+
+  if (request->stun_hdr.msg_type != BINDING_REQUEST) {
+    fprintf(stderr, "stun: not binding request\n");
+    return 0;
+  }
+
+  a = stun_get_attr(request->stun_attr, RESPONSE_ADDRESS);
+  if (a)
+    return STUN_600_GLOBAL_FAILURE;
+ 
+  /* compose header */
+  response->stun_hdr.msg_type = BINDING_RESPONSE;
+  memcpy(response->stun_hdr.tran_id, request->stun_hdr.tran_id, 
+	 sizeof response->stun_hdr.tran_id);
+  
+  next = &response->stun_attr;
+
+  /* MAPPED-ADDRESS */
+  a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+  a->attr_type = MAPPED_ADDRESS;
+  addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+  memcpy(addr, from, sizeof *addr);
+  a->pattr = addr;
+  a->next = NULL;
+  *next = a; next = &a->next;
+
+  /* SOURCE-ADDRESS */ /* depends on CHANGE_REQUEST */
+  a = stun_get_attr(request->stun_attr, CHANGE_REQUEST);
+  if (a)
+    change_address = ((stun_attr_changerequest_t *)a->pattr)->value;
+
+  if (change_address) {
+    struct sockaddr_in const *sin, *sin2;
+    int scope = su_sockaddr_scope(from, fromlen);
+    stun_bound_t *changed_ip = NULL, *same_scope = NULL;
+    
+    sin = from;
+
+    for (changed = mini->sockets; changed; changed = changed->ss_next) {
+      sin2 = changed->ss_addr.sin;
+
+      if (scope != LI_SCOPE_HOST && changed->ss_scope == LI_SCOPE_HOST)
+	continue;
+
+      if (scope != LI_SCOPE_SITE && changed->ss_scope == LI_SCOPE_SITE)
+	continue;
+
+      if (same_scope == NULL)
+	same_scope = changed;
+
+      if (change_address & STUN_CR_CHANGE_IP)
+	if (!memcmp(&sin->sin_addr, &sin2->sin_addr, sizeof sin->sin_addr))
+	  continue;
+
+      if (changed_ip == NULL)
+	changed_ip = changed;
+
+      if (change_address & STUN_CR_CHANGE_PORT)
+	if (sin->sin_port == sin2->sin_port)
+	  continue;
+    }
+
+    if (changed == NULL && (change_address & STUN_CR_CHANGE_IP))
+      /* We don't have socekt with both changed port and ip */
+      changed = changed_ip;
+
+    if (changed == NULL) 
+      changed = same_scope;
+  }
+
+  for (ss = mini->sockets; ss; ss = ss->ss_next)
+    if (socket == ss->ss_socket)
+      break;
+
+  if (ss == NULL) {
+    memset(ss = ss0, 0, sizeof ss0);
+    ss->ss_socket = socket;
+    ss->ss_addrlen = sizeof ss->ss_addr;
+    if (getsockname(socket, (void *)ss->ss_addr.array, &ss->ss_addrlen) < 0)
+      return STUN_500_SERVER_ERROR;
+  }
+
+  a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+  a->attr_type = SOURCE_ADDRESS;
+  addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+  memcpy(addr, ss->ss_addr.array, sizeof *addr);
+  a->pattr = addr;
+  a->next = NULL;
+  *next = a; next = &(a->next);
+
+  if (changed) {
+    socket = changed->ss_socket;
+
+    /* CHANGED-ADDRESS */
+    a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+    a->attr_type = CHANGED_ADDRESS;
+    addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+    memcpy(addr, changed->ss_addr.array, sizeof *addr);
+
+    a->pattr = addr;
+    a->next = NULL;
+    *next = a; next = &(a->next);
+  }
+
+  stun_send_message(socket, (void *)from, response, NULL);
+
+  return 0;
+} 
+
+static int process_bis_request(stun_mini_t *mini, 
+			       stun_msg_t *request, stun_msg_t *response,
+			       su_socket_t socket, 
+			       void *from, socklen_t fromlen)
+{
+  return process_3489_request(mini, request, response, socket, from, fromlen);
+}
+
+int send_stun_error(stun_msg_t *response,
+		    int error,
+		    int socket,
+		    void *transaction_id,
+		    void *from,
+		    socklen_t fromlen)
+{
+  stun_attr_t *attr;
+  stun_attr_errorcode_t *errorcode;
+  char const *phrase = stun_response_phrase(error);
+
+  if (!phrase)
+    error = STUN_500_SERVER_ERROR, phrase = "Internal Server Error";
+
+  stun_init_message(response);
+
+  response->stun_hdr.msg_type = BINDING_ERROR_RESPONSE;
+  response->stun_hdr.msg_len = 0; /* actual len computed later */
+  
+  memcpy(response->stun_hdr.tran_id, transaction_id, 16);
+
+  /* ERROR-CODE */
+  attr = malloc(sizeof *attr); if (!attr) return -1;
+  response->stun_attr = attr;
+  attr->attr_type = ERROR_CODE;
+
+  errorcode = malloc(sizeof(*errorcode));
+  if (!errorcode)
+    return -1;
+  errorcode->code = error;
+  errorcode->phrase = malloc(strlen(phrase) + 1);
+  if (!errorcode->phrase)
+    return -1;
+  strcpy(errorcode->phrase, phrase);
+  attr->pattr = errorcode;
+
+  stun_send_message(socket, from, response, NULL);
+
+  return 0;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,212 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE stun_tag.c  Tags and tag lists for Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Aug  3 20:28:17 EEST 2005
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "stun"
+
+#include <sofia-sip/su_tag_class.h>
+
+/**@def STUNTAG_ANY()
+ * 
+ * Filter tag matching any STUNTAG_*().
+ */
+tag_typedef_t stuntag_any = NSTAG_TYPEDEF(*);
+
+/**@def STUNTAG_DOMAIN(x)
+ * 
+ * The domain to use in DNS-SRV based STUN server discovery.
+ * Note: this is commonly the domain part of a public SIP
+ * address (AOR). See sect 9.1 of RFC3489.
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_invite() \n
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    char const *
+
+ */
+tag_typedef_t stuntag_domain = STRTAG_TYPEDEF(domain);
+
+/**@def STUNTAG_SERVER(x)
+ *
+ * Fully qualified host name, or dotted IP address of the STUN server 
+ * address. If defined, the DNS-SRV based discovery (@see STUNTAG_DOMAIN())
+ * will be skipped. 
+ *
+ * @par Used with
+ *    nua_set_params() \n
+ *    nua_get_params() \n
+ *    nua_invite() \n
+ *    nua_respond()
+ *
+ * @par Parameter type
+ *    char const *
+ *
+ * @par Values
+ *    NULL terminated character string containing a domain name,
+ *    IPv4 address, or IPv6 address.
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_SERVER_REF()
+*/
+tag_typedef_t stuntag_server = STRTAG_TYPEDEF(server);
+
+/**@def STUNTAG_REQUIRE_INTEGRITY(x)
+ *  
+ * Whether to require support for shared-secret based packet
+ * authentication and integrity checks (see sect 9.2 of RFC3489). 
+ * If false, integrity checks are performed only when server supports it.
+ *
+ * @par Used with
+ *    nua_create() \n
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c !=0 enable
+ *    @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_INTEGRITY_REF()
+ */
+tag_typedef_t stuntag_require_integrity = BOOLTAG_TYPEDEF(require_integrity);
+
+/**@def STUNTAG_INTEGRITY(x)
+ *
+ * XXX: should this tag be deprecated in favor of just supporting
+ * STUNTAG_REQURIE_INTEGRITY() instead...?
+ */
+tag_typedef_t stuntag_integrity = BOOLTAG_TYPEDEF(integrity);
+
+/**@def STUNTAG_SOCKET(x)
+ *  
+ * Bind socket for STUN.
+ *
+ * @par Used with
+ *    stun_handle_bind() \n
+ *
+ * @par Parameter type
+ *    int (su_socket_t)
+ *
+ * @par Values
+ *    IPv4 (AF_INET) socket
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_SOCKET_REF()
+ */
+tag_typedef_t stuntag_socket = SOCKETTAG_TYPEDEF(socket);
+
+/**@def STUNTAG_REGISTER_EVENTS(x)
+ *  
+ * Register socket events for eventloop owned by STUN.
+ *
+ * @par Used with
+ *    stun_bind() \n
+ *    stun_get_lifetime() \n
+ *    stun_get_nattype() \n
+ *    stun_keepalive() \n
+ *
+ * @par Parameter type
+ *    bool
+ *
+ * @par Values
+ *    false (0) or true (nonzero)
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_REGISTER_EVENTS_REF()
+ */
+tag_typedef_t stuntag_register_events = BOOLTAG_TYPEDEF(register_events);
+
+/**@def STUNTAG_ACTION(x)
+ *  
+ * Command action for STUN request.
+ *
+ * @par Used with
+ *    stun_handle_bind() \n
+ *
+ * @par Parameter type
+ *    int (stun_action_t)
+ *
+ * @par Values
+ *    See types for stun_action_t in stun.h
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_ACTION_REF()
+ */
+tag_typedef_t stuntag_action = INTTAG_TYPEDEF(action);
+
+/* ---------------------------------------------------------------------- */
+
+/**@def STUNTAG_CHANGE_IP(x)
+ *  
+ * Add CHANGE-REQUEST attribute with "change IP" flag to the request.
+ *
+ * @par Used with
+ *    stun_make_binding_req() \n
+ *
+ * @par Parameter type
+ *    bool
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_CHANGE_IP_REF()
+ */
+tag_typedef_t stuntag_change_ip = BOOLTAG_TYPEDEF(change_ip);
+
+/**@def STUNTAG_CHANGE_PORT(x)
+ *  
+ * Add CHANGE-REQUEST attribute with "change port" flag to the request.
+ *
+ * @par Used with
+ *    stun_make_binding_req() \n
+ *
+ * @par Parameter type
+ *    bool
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_CHANGE_PORT_REF()
+ */
+tag_typedef_t stuntag_change_port = BOOLTAG_TYPEDEF(change_port);
+
+/* ---------------------------------------------------------------------- */
+
+/**@def STUNTAG_TIMEOUT(x)
+ *  
+ * Timeout controls the launching of the STUN keepalive timer.
+ *
+ * @par Used with
+ *    stun_keepalive() \n
+ *
+ * @par Parameter type
+ *    int
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_TIMEOUT_REF()
+ */
+tag_typedef_t stuntag_timeout = INTTAG_TYPEDEF(timeout);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * STUN test client
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * 
+ * @date Created: Thu Jul 24 17:21:00 2003 ppessi
+ */
+
+/**@page stunc STUN test client.
+ * 
+ * @section stunc_synopsis Synopsis
+ * <tt>stunc [OPTIONS] \<stun-server-address\></tt>
+ *
+ * @section stunc_description Description
+ * The @em stunc utility can be used to gather information about possible
+ * NAT devices that are located between the client and STUN server. 
+ *
+ * @em stunc can provide the following information: the IP address and
+ * port as seen by the STUN server, detecting presence of NATs, and
+ * hints on the type of address translation done. It should be noted
+ * that the results of NAT type and life-time detection should be
+ * considered as hints. There is no guarantee that NAT(s) will handle
+ * future packets in the same way.
+ *
+ * @section stunc_options Command Line Options
+ * The @em stunc utility accepts following command line options:
+ *
+ * <dl>
+ *
+ * <dt>-b</dt>
+ * <dd>Perform a STUN binding discovery. @em stunc will report the
+ * client transport address (IP:port) as seen by the STUN server. In
+ * the presence of NATs, this address is allocated by the NAT closest
+ * to the STUN server.
+ * </dd>
+ *
+ * <dt>-l</dt>
+ * <dd>Perform a STUN binding life-time check.
+ * </dd>
+ *
+ * <dt>-n</dt>
+ * <dd>Perform a STUN binding type check. Notice that the results
+ * are only hints. Nondeterministic behaviour, resource exhaustion,
+ * or reboots of network elements can cause changes in NAT behaviour
+ * between successive runs of stunc.
+ * </dd>
+ *
+ * <dt>-r</dt>
+ * <dd>Randomize the local port. Otherwise @em stunc let's the
+ * operating system select a free port.
+ * </dd>
+ *
+ * <dt>-s</dt>
+ * <dd>Request a shared-secret over TLS. Tests whether the STUN server
+ * supports the shared-secret mechanism (needed to protect message 
+ * integrity). Can be combined with @em -b, @em -l and @em -n.
+ * </dd>
+ *
+ * </dl>
+ *
+ * @section stunc_return Return Codes
+ * <table>
+ * <tr><td>0</td><td>when successful</td></tr>
+ * <tr><td>1</td><td>when any errors detected</td></tr>
+ * </table>
+ *
+ * @section stunc_examples Examples
+ *
+ * Discover the NAT binding, use a random local port:
+ * @code
+ * $ stunc stunserver.org -b -r
+ * @endcode
+ *
+ * @section stunc_environment Environment
+ * #STUN_DEBUG
+ * 
+ * @section stunc_bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section stunc_author Authors
+ * - Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ * - Martti Mela <martti -dot mela -at- nokia -dot- com>
+ * - Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+ *
+ * @section stunc_copyright Copyright
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h" 
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+typedef struct stunc_s stunc_t;
+#define SU_ROOT_MAGIC  stunc_t
+#define STUN_MAGIC_T   stunc_t
+#define STUN_DISCOVERY_MAGIC_T  stunc_t
+
+#include "sofia-sip/stun.h"
+#include "sofia-sip/stun_tag.h"
+#include "sofia-sip/sofia_features.h"
+#include <sofia-sip/su.h>
+
+enum {
+  do_secret = 1,
+  do_bind = 2,
+  do_nat_check = 4,
+  do_life_check = 8,
+  do_randomize_port = 16
+};
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stunc";
+#endif
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 0
+#endif
+#define SU_LOG (stun_log)
+#include <sofia-sip/su_debug.h>
+
+void usage(char *name)
+{
+  fprintf(stderr, 
+	  "stunc (%s)\n"
+	  "usage: %s <server> [-b] [-n] [-l] [-r] [-s]\n"
+	  "  -b\tmake a binding request\n"
+	  "  -l\tperform NAT lifetime check\n"
+	  "  -n\tperform NAT type check\n"
+	  "  -r\trandomize the local port\n",
+	  "  -s\trequest shared-secret over TLS (combined with -[bln])\n"
+	  SOFIA_SIP_NAME_VERSION, name);
+  exit(1);
+}
+
+struct stunc_s {
+  su_socket_t  sc_socket;
+  int          sc_flags;
+};
+
+
+static
+void stunc_lifetime_cb(stunc_t *stunc,
+		       stun_handle_t *sh,
+		       stun_discovery_t *sd,
+		       stun_action_t action,
+		       stun_state_t event);
+
+static
+void stunc_nattype_cb(stunc_t *stunc,
+		      stun_handle_t *sh,
+		      stun_discovery_t *sd,
+		      stun_action_t action,
+		      stun_state_t event);
+
+static
+void stunc_bind_cb(stunc_t *stunc,
+		   stun_handle_t *sh,
+		   stun_discovery_t *sd,
+		   stun_action_t action,
+		   stun_state_t event);
+
+static
+void stunc_ss_cb(stunc_t *stunc,
+		 stun_handle_t *sh,
+		 stun_discovery_t *sd,
+		 stun_action_t action,
+		 stun_state_t event)
+{
+  int err;
+  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+  stunc->sc_flags &= ~do_secret;
+  if (!stunc->sc_flags)
+    su_root_break(stun_root(sh));
+
+  switch (event) {
+  case stun_tls_done:
+    if (stunc->sc_flags & do_bind) {
+      err = stun_bind(sh, stunc_bind_cb, stunc,
+		      STUNTAG_SOCKET(stunc->sc_socket),
+		      STUNTAG_REGISTER_EVENTS(1),
+		      TAG_NULL());
+    
+      if (err < 0) {
+	SU_DEBUG_0(("%s: %s  failed\n", __func__, "stun_handle_bind()"));
+	su_root_break(stun_root(sh));
+      }
+    }
+    break;
+    
+  case stun_tls_connection_failed:
+    SU_DEBUG_0(("%s: Obtaining shared secret failed.\n",
+		__func__));
+    stunc->sc_flags &= ~do_bind;
+    if (!stunc->sc_flags)
+      su_root_break(stun_root(sh));
+
+    break;
+
+  case stun_tls_connection_timeout:
+    SU_DEBUG_0(("%s: Timeout when obtaining shared secret.\n",
+		__func__));
+    stunc->sc_flags &= ~do_bind;
+    break;
+
+  default:
+    break;
+  }
+
+  return;
+}
+
+
+static
+void stunc_bind_cb(stunc_t *stunc,
+		   stun_handle_t *sh,
+		   stun_discovery_t *sd,
+		   stun_action_t action,
+		   stun_state_t event)
+{
+  su_sockaddr_t sa[1];
+  char ipaddr[48];
+  socklen_t addrlen;
+
+  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+  stunc->sc_flags &= ~do_bind;
+
+  if (!stunc->sc_flags)
+    su_root_break(stun_root(sh));
+
+  switch (event) {
+  case stun_discovery_done:
+    addrlen = sizeof(*sa);
+    memset(sa, 0, addrlen);
+    
+    if (stun_discovery_get_address(sd, sa, &addrlen) < 0) {
+      SU_DEBUG_0(("%s: stun_discovery_get_address() failed", __func__));
+      return;
+    }
+
+    SU_DEBUG_0(("%s: local address NATed as %s:%u\n", __func__,
+		inet_ntop(sa->su_family, SU_ADDR(sa),
+			  ipaddr, sizeof(ipaddr)),
+		(unsigned) ntohs(sa->su_port)));
+
+  break;
+
+  case stun_discovery_timeout:
+  case stun_discovery_error:
+  case stun_error:
+  default:
+    break;
+  }
+
+  return;
+}
+
+
+static
+void stunc_nattype_cb(stunc_t *stunc,
+		      stun_handle_t *sh,
+		      stun_discovery_t *sd,
+		      stun_action_t action,
+		      stun_state_t event)
+{
+  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+  stunc->sc_flags &= ~do_nat_check;
+
+  if (!stunc->sc_flags)
+    su_root_break(stun_root(sh));
+
+  switch (event) {
+  case stun_discovery_timeout:
+    SU_DEBUG_3(("%s: NAT type determination timeout.\n", __func__));
+    break;
+
+  case stun_discovery_done:
+    SU_DEBUG_3(("%s: NAT type determined to be '%s' (%d).\n", 
+		__func__, stun_nattype_str(sd), (int)stun_nattype(sd)));
+    break;
+
+  case stun_error:
+  default:
+    break;
+  }
+
+  return;
+}
+
+
+static
+void stunc_lifetime_cb(stunc_t *stunc,
+		       stun_handle_t *sh,
+		       stun_discovery_t *sd,
+		       stun_action_t action,
+		       stun_state_t event)
+{
+  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+  stunc->sc_flags &= ~do_life_check;
+
+  if (!stunc->sc_flags)
+    su_root_break(stun_root(sh));
+
+  switch (event) {
+  case stun_discovery_timeout:
+    SU_DEBUG_3(("%s: Lifetime determination timeout.\n", __func__));
+    break;
+
+  case stun_discovery_done:
+    SU_DEBUG_3(("%s: Lifetime determined to be %d.\n", __func__, stun_lifetime(sd)));
+    break;
+
+  case stun_error:
+  default:
+    break;
+  }
+
+  return;
+}
+
+
+int main(int argc, char *argv[])
+{
+  int err = 0, i, sflags = 0;
+  stunc_t stunc[1]; 
+  su_root_t *root;
+  stun_handle_t *sh;
+  su_socket_t s;
+
+  if (su_init() != 0) 
+    return -1;
+
+  root = su_root_create(stunc);
+
+  if (argc < 3)
+    usage(argv[0]);
+
+  for (i = 2; argv[i]; i++) {
+    if (strcmp(argv[i], "-s") == 0)
+      sflags |= do_secret;
+    else if (strcmp(argv[i], "-b") == 0)
+      sflags |= do_bind;
+    else if (strcmp(argv[i], "-n") == 0)
+      sflags |= do_nat_check;
+    else if (strcmp(argv[i], "-l") == 0)
+      sflags |= do_life_check;
+    else if (strcmp(argv[i], "-r") == 0)
+      sflags |= do_randomize_port;
+    else {
+      fprintf(stderr, "Unable to parse option %s.\n", argv[i]);
+      usage(argv[0]);
+    }
+  }
+
+  /* Running this test requires a local STUN server on default port */
+  sh = stun_handle_init(root,
+			STUNTAG_SERVER(argv[1]), 
+			STUNTAG_REQUIRE_INTEGRITY(sflags & do_secret),
+			TAG_NULL()); 
+
+  if (!sh) {
+    SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_handle_init()"));
+    return -1;
+  }
+
+  s = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
+  if (s == -1) {
+    SU_DEBUG_0(("%s: %s  failed: %s\n", __func__,
+		"su_socket()", su_gli_strerror(errno)));
+    return -1;
+  }
+
+  stunc->sc_socket = s;
+  stunc->sc_flags = sflags;
+
+  if (sflags & do_randomize_port) {
+    su_sockaddr_t sockaddr;
+    char ipaddr[SU_ADDRSIZE + 2] = { 0 };
+    socklen_t socklen = sizeof(sockaddr);
+
+    srand((unsigned int)time((time_t *)NULL));
+
+    memset(&sockaddr, 0, sizeof(su_sockaddr_t));
+    sockaddr.su_port = htons((rand() % (65536 - 1024)) + 1024);
+    sockaddr.su_family = AF_INET;
+
+    SU_DEBUG_3(("stunc: Binding to local port %u.\n", ntohs(sockaddr.su_port)));
+  
+    err = bind(s, (struct sockaddr *)&sockaddr, socklen);
+    if (err < 0) {
+      SU_DEBUG_1(("%s: Error %d binding to %s:%u\n", __func__, err,
+		  inet_ntop(sockaddr.su_family, SU_ADDR(&sockaddr), 
+			    ipaddr, sizeof(ipaddr)),
+		  (unsigned) ntohs(sockaddr.su_port)));
+      return -1;
+    }
+
+    stunc->sc_flags &= ~do_randomize_port;
+  }
+
+  if (sflags & do_secret) {
+    if (stun_obtain_shared_secret(sh, stunc_ss_cb, stunc, TAG_NULL()) < 0) {
+      SU_DEBUG_3(("%s: %s failed\n", __func__,
+		  "stun_handle_request_shared_secret()"));
+      return -1;
+    }
+  }
+
+
+  /* If we want to bind and no integrity required */
+  if ((sflags & do_bind) && !(sflags & do_secret)) {
+    err = stun_bind(sh, stunc_bind_cb, stunc,
+		    STUNTAG_SOCKET(s),
+		    STUNTAG_REGISTER_EVENTS(1),
+		    TAG_NULL());
+    
+    if (err < 0) {
+      SU_DEBUG_0(("%s: %s  failed\n", __func__, "stun_bind()"));
+      return -1;
+    }
+  }
+
+  if (sflags & do_nat_check) {
+    err = stun_test_nattype(sh, stunc_nattype_cb, stunc,
+			    STUNTAG_REGISTER_EVENTS(1),
+			    STUNTAG_SOCKET(stunc->sc_socket),
+			    TAG_NULL());
+    
+    if (err < 0) {
+      SU_DEBUG_0(("%s: %s  failed\n", __func__, "stun_test_nattype()"));
+      su_root_break(stun_root(sh));
+    }
+  }
+
+  if (sflags & do_life_check) {
+    err = stun_test_lifetime(sh, stunc_lifetime_cb, stunc,
+			     STUNTAG_REGISTER_EVENTS(1),
+			     STUNTAG_SOCKET(stunc->sc_socket),
+			     TAG_NULL());
+    
+    if (err < 0) {
+      SU_DEBUG_0(("%s: %s  failed\n", __func__, "stun_test_lifetime()"));
+      su_root_break(stun_root(sh));
+    }
+  }
+ 
+  if (err == 0)
+    su_root_run(root);
+
+  stun_handle_destroy(sh);
+  su_root_destroy(root);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+2006-05-03  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* poll_test.c: Renamed call s/su_create_wait/su_wait_create/.
+
+2006-01-17  Martti Mela  <martti.mela at nokia.com>
+
+  * su_localinfo.c: su_getlocalinfo() works now on OS X
+
+  * su_memmem.c: malloc fetched from different header file in OS X
+
+  * su_config.h: reference to su_configure_win32.h removed.
+
+    M ./libsofia-sip-ua/su/su_localinfo.c -8 +97
+
+
+2006-01-13  Martti Mela  <martti.mela at nokia.com>
+
+  * su_wait.h: Added su_wait_socket(). (it returns associated fd)
+
+2005-10-12  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added tl_llist(), tl_vllist(). Better semantics for tl_next().
+
+    M ./libsofia-sip-ua/su/su_tag.h -1 +3
+    M ./libsofia-sip-ua/su/su_tag_test.c -5 +26
+    M ./libsofia-sip-ua/su/su_taglist.c -7 +102
+
+  * su_home_auto() now accepts unaligned pointer.
+
+    M ./libsofia-sip-ua/su/su_alloc.c -4 +11
+
+2005-10-11  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed superfluous assertion failure here.
+
+    M ./libsofia-sip-ua/su/su_root.c -3 +1
+
+2005-10-10  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Using glib in the clone test, too.
+
+    M ./libsofia-sip-ua/su/run_su_test -4 +26
+    M ./libsofia-sip-ua/su/su_test.c -22 +51
+
+  * Fixed su_home_new() documentation.
+
+    M ./libsofia-sip-ua/su/su_alloc.c -4 +2
+
+  * Remove su_home_incref()/su_home_decref() - they were never implemented.
+
+    M ./libsofia-sip-ua/su/su_alloc.h -4
+
+  * Added more debugging information from SU_PORT_DECREF().
+
+    M ./libsofia-sip-ua/su/su_port.c -3 +5
+
+  * Added su_clone_start()/su_clone_wait() tests.
+
+    M ./libsofia-sip-ua/su/su_root_test.c -42 +104
+
+  * Fixed warning about getenv().
+
+    M ./libsofia-sip-ua/su/su_torture.c +1
+
+2005-10-03  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Fixed bug in stack allocation.
+
+    M ./libsofia-sip-ua/su/su_memmem.c -1 +1
+
+  * Improved test coverage. Fixed bug in allocating arrays from stack.
+
+    M ./libsofia-sip-ua/su/su_memmem.c -11 +10
+    M ./libsofia-sip-ua/su/torture_su_memmem.c +119
+
+  * Added constant reference type su_msg_cr[].
+
+    M ./libsofia-sip-ua/su/su_root.c -2 +2
+    M ./libsofia-sip-ua/su/su_wait.h -14 +17
+
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added tl_filtered_tlist().
+
+    M ./libsofia-sip-ua/su/su_tag.h +3
+    M ./libsofia-sip-ua/su/su_taglist.c +16
+
+  * Added su_home_auto().
+
+    M ./libsofia-sip-ua/su/su_alloc.c -10 +55
+    M ./libsofia-sip-ua/su/su_alloc.h +4
+    M ./libsofia-sip-ua/su/su_alloc_test.c +33
+
+2005-08-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Added su_strlst_dup() and su_strlst_copy(). 
+
+	* Added { to BEGIN() and } to END() in <tstdef.h>
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,24 @@
+PROJECT_NAME         = "su"
+OUTPUT_DIRECTORY     = ../docs/html/su
+
+INPUT 		     = su.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES           += ../docs/msg.doxytags=../msg
+TAGFILES           += ../docs/sip.doxytags=../sip
+TAGFILES           += ../docs/docs.doxytags=..
+
+GENERATE_TAGFILE     = ../docs/su.doxytags
+
+ALIASES +=  "SU_TAG=@ingroup su_tag\n"
+
+PREDEFINED += \
+ TSTFLAGS=1 \
+ SU_HAVE_BSDSOCK=0 \
+ su_root_s=su_root_t \
+ _su_task_r=su_task_r
+
+EXCLUDE_PATTERNS      += localinfo.c addrinfo.c
+
+ at INCLUDE =		../sip/sip.doxyaliases

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,119 @@
+#
+# Makefile.am @template@ for su module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libsu.la
+
+bin_PROGRAMS = 		addrinfo localinfo 
+
+if COREFOUNDATION
+OSXSOURCES = \
+	su_osx_runloop.c
+OSXHEADERS = \
+	sofia-sip/su_osx_runloop.h
+OSXPROGS = \
+	torture_su_root_osx test_su_osx
+OSXTESTS = \
+	torture_su_root_osx run_test_su_osx
+else
+OSXSOURCES =
+OSXHEADERS =
+endif
+
+check_PROGRAMS = 	torture_su torture_su_port \
+			torture_su_alloc torture_su_time torture_su_tag \
+			test_htable torture_rbtree \
+			test_memmem torture_su_bm \
+			torture_su_root torture_su_timer \
+			test_su su_proxy test_poll $(OSXPROGS)
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = 		torture_su torture_su_port \
+			torture_su_alloc torture_su_time torture_su_tag \
+			test_htable torture_rbtree \
+			test_memmem torture_su_bm \
+			torture_su_root torture_su_timer \
+			run_addrinfo run_localinfo run_test_su \
+			$(OSXTESTS)
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = su_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/su_types.h sofia-sip/su.h \
+			sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+			sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+			sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+			sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+			sofia-sip/su_time.h sofia-sip/su_tag.h \
+			sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+			sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+			sofia-sip/htable.h sofia-sip/htable2.h \
+			sofia-sip/rbtree.h sofia-sip/su_debug.h \
+			sofia-sip/su_log.h \
+			sofia-sip/su_config.h sofia-sip/su_md5.h \
+			sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+			sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+			$(OSXHEADERS)
+
+nobase_nodist_include_sofia_HEADERS = sofia-sip/su_configure.h
+
+libsu_la_SOURCES = \
+	su.c su_errno.c su_addrinfo.c \
+	su_alloc.c su_alloc_lock.c su_strdup.c su_sprintf.c \
+	su_strlst.c su_vector.c \
+	su_time.c su_time0.c \
+	su_wait.c su_root.c su_timer.c su_port.c su_port.h \
+	su_localinfo.c \
+	su_os_nw.c \
+	su_taglist.c su_tag.c su_tag_io.c \
+	su_log.c su_global_log.c su_default_log.c su_module_debug.h \
+	su_md5.c su_uniqueid.c su_bm.c $(OSXSOURCES)
+
+
+EXTRA_libsu_la_SOURCES = \
+			memmem.c strtoull.c strcasestr.c \
+			memspn.c memcspn.c memccpy.c \
+			inet_ntop.c inet_pton.c getopt.c \
+			su_tag_ref.c
+
+libsu_la_LIBADD = 	$(REPLACE_LIBADD)
+libsu_la_DEPENDENCIES = $(REPLACE_LIBADD)
+
+COVERAGE_INPUT = 	$(libsu_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libsu.la
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = 		Doxyfile su.docs \
+			run_addrinfo run_localinfo run_test_su
+
+dist_pkgdata_SCRIPTS = 	tag_dll.awk
+
+sofia-sip/su_configure.h: sofia-sip/su_configure.h.in
+
+# ----------------------------------------------------------------------
+# Automake options
+
+AUTOMAKE_OPTIONS = 	foreign
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1058 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for su module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# ----------------------------------------------------------------------
+# Build targets
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+
+SOURCES = $(libsu_la_SOURCES) $(EXTRA_libsu_la_SOURCES) addrinfo.c localinfo.c su_proxy.c test_htable.c test_memmem.c test_poll.c test_su.c test_su_osx.c torture_rbtree.c torture_su.c torture_su_alloc.c torture_su_bm.c torture_su_port.c torture_su_root.c torture_su_root_osx.c torture_su_tag.c torture_su_time.c torture_su_timer.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = addrinfo$(EXEEXT) localinfo$(EXEEXT)
+check_PROGRAMS = torture_su$(EXEEXT) torture_su_port$(EXEEXT) \
+	torture_su_alloc$(EXEEXT) torture_su_time$(EXEEXT) \
+	torture_su_tag$(EXEEXT) test_htable$(EXEEXT) \
+	torture_rbtree$(EXEEXT) test_memmem$(EXEEXT) \
+	torture_su_bm$(EXEEXT) torture_su_root$(EXEEXT) \
+	torture_su_timer$(EXEEXT) test_su$(EXEEXT) su_proxy$(EXEEXT) \
+	test_poll$(EXEEXT) $(am__EXEEXT_1)
+DIST_COMMON = $(am__nobase_include_sofia_HEADERS_DIST) \
+	$(dist_pkgdata_SCRIPTS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/su
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__libsu_la_SOURCES_DIST = su.c su_errno.c su_addrinfo.c su_alloc.c \
+	su_alloc_lock.c su_strdup.c su_sprintf.c su_strlst.c \
+	su_vector.c su_time.c su_time0.c su_wait.c su_root.c \
+	su_timer.c su_port.c su_port.h su_localinfo.c su_os_nw.c \
+	su_taglist.c su_tag.c su_tag_io.c su_log.c su_global_log.c \
+	su_default_log.c su_module_debug.h su_md5.c su_uniqueid.c \
+	su_bm.c su_osx_runloop.c
+ at COREFOUNDATION_TRUE@am__objects_1 = su_osx_runloop.lo
+am_libsu_la_OBJECTS = su.lo su_errno.lo su_addrinfo.lo su_alloc.lo \
+	su_alloc_lock.lo su_strdup.lo su_sprintf.lo su_strlst.lo \
+	su_vector.lo su_time.lo su_time0.lo su_wait.lo su_root.lo \
+	su_timer.lo su_port.lo su_localinfo.lo su_os_nw.lo \
+	su_taglist.lo su_tag.lo su_tag_io.lo su_log.lo \
+	su_global_log.lo su_default_log.lo su_md5.lo su_uniqueid.lo \
+	su_bm.lo $(am__objects_1)
+libsu_la_OBJECTS = $(am_libsu_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" \
+	"$(DESTDIR)$(include_sofiadir)" \
+	"$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+ at COREFOUNDATION_TRUE@am__EXEEXT_1 = torture_su_root_osx$(EXEEXT) \
+ at COREFOUNDATION_TRUE@	test_su_osx$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+addrinfo_SOURCES = addrinfo.c
+addrinfo_OBJECTS = addrinfo.$(OBJEXT)
+addrinfo_LDADD = $(LDADD)
+addrinfo_DEPENDENCIES = libsu.la
+localinfo_SOURCES = localinfo.c
+localinfo_OBJECTS = localinfo.$(OBJEXT)
+localinfo_LDADD = $(LDADD)
+localinfo_DEPENDENCIES = libsu.la
+su_proxy_SOURCES = su_proxy.c
+su_proxy_OBJECTS = su_proxy.$(OBJEXT)
+su_proxy_LDADD = $(LDADD)
+su_proxy_DEPENDENCIES = libsu.la
+test_htable_SOURCES = test_htable.c
+test_htable_OBJECTS = test_htable.$(OBJEXT)
+test_htable_LDADD = $(LDADD)
+test_htable_DEPENDENCIES = libsu.la
+test_memmem_SOURCES = test_memmem.c
+test_memmem_OBJECTS = test_memmem.$(OBJEXT)
+test_memmem_LDADD = $(LDADD)
+test_memmem_DEPENDENCIES = libsu.la
+test_poll_SOURCES = test_poll.c
+test_poll_OBJECTS = test_poll.$(OBJEXT)
+test_poll_LDADD = $(LDADD)
+test_poll_DEPENDENCIES = libsu.la
+test_su_SOURCES = test_su.c
+test_su_OBJECTS = test_su.$(OBJEXT)
+test_su_LDADD = $(LDADD)
+test_su_DEPENDENCIES = libsu.la
+test_su_osx_SOURCES = test_su_osx.c
+test_su_osx_OBJECTS = test_su_osx.$(OBJEXT)
+test_su_osx_LDADD = $(LDADD)
+test_su_osx_DEPENDENCIES = libsu.la
+torture_rbtree_SOURCES = torture_rbtree.c
+torture_rbtree_OBJECTS = torture_rbtree.$(OBJEXT)
+torture_rbtree_LDADD = $(LDADD)
+torture_rbtree_DEPENDENCIES = libsu.la
+torture_su_SOURCES = torture_su.c
+torture_su_OBJECTS = torture_su.$(OBJEXT)
+torture_su_LDADD = $(LDADD)
+torture_su_DEPENDENCIES = libsu.la
+torture_su_alloc_SOURCES = torture_su_alloc.c
+torture_su_alloc_OBJECTS = torture_su_alloc.$(OBJEXT)
+torture_su_alloc_LDADD = $(LDADD)
+torture_su_alloc_DEPENDENCIES = libsu.la
+torture_su_bm_SOURCES = torture_su_bm.c
+torture_su_bm_OBJECTS = torture_su_bm.$(OBJEXT)
+torture_su_bm_LDADD = $(LDADD)
+torture_su_bm_DEPENDENCIES = libsu.la
+torture_su_port_SOURCES = torture_su_port.c
+torture_su_port_OBJECTS = torture_su_port.$(OBJEXT)
+torture_su_port_LDADD = $(LDADD)
+torture_su_port_DEPENDENCIES = libsu.la
+torture_su_root_SOURCES = torture_su_root.c
+torture_su_root_OBJECTS = torture_su_root.$(OBJEXT)
+torture_su_root_LDADD = $(LDADD)
+torture_su_root_DEPENDENCIES = libsu.la
+torture_su_root_osx_SOURCES = torture_su_root_osx.c
+torture_su_root_osx_OBJECTS = torture_su_root_osx.$(OBJEXT)
+torture_su_root_osx_LDADD = $(LDADD)
+torture_su_root_osx_DEPENDENCIES = libsu.la
+torture_su_tag_SOURCES = torture_su_tag.c
+torture_su_tag_OBJECTS = torture_su_tag.$(OBJEXT)
+torture_su_tag_LDADD = $(LDADD)
+torture_su_tag_DEPENDENCIES = libsu.la
+torture_su_time_SOURCES = torture_su_time.c
+torture_su_time_OBJECTS = torture_su_time.$(OBJEXT)
+torture_su_time_LDADD = $(LDADD)
+torture_su_time_DEPENDENCIES = libsu.la
+torture_su_timer_SOURCES = torture_su_timer.c
+torture_su_timer_OBJECTS = torture_su_timer.$(OBJEXT)
+torture_su_timer_LDADD = $(LDADD)
+torture_su_timer_DEPENDENCIES = libsu.la
+dist_pkgdataSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(dist_pkgdata_SCRIPTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libsu_la_SOURCES) $(EXTRA_libsu_la_SOURCES) addrinfo.c \
+	localinfo.c su_proxy.c test_htable.c test_memmem.c test_poll.c \
+	test_su.c test_su_osx.c torture_rbtree.c torture_su.c \
+	torture_su_alloc.c torture_su_bm.c torture_su_port.c \
+	torture_su_root.c torture_su_root_osx.c torture_su_tag.c \
+	torture_su_time.c torture_su_timer.c
+DIST_SOURCES = $(am__libsu_la_SOURCES_DIST) $(EXTRA_libsu_la_SOURCES) \
+	addrinfo.c localinfo.c su_proxy.c test_htable.c test_memmem.c \
+	test_poll.c test_su.c test_su_osx.c torture_rbtree.c \
+	torture_su.c torture_su_alloc.c torture_su_bm.c \
+	torture_su_port.c torture_su_root.c torture_su_root_osx.c \
+	torture_su_tag.c torture_su_time.c torture_su_timer.c
+am__nobase_include_sofia_HEADERS_DIST = sofia-sip/su_types.h \
+	sofia-sip/su.h sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+	sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+	sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+	sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+	sofia-sip/su_time.h sofia-sip/su_tag.h \
+	sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+	sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+	sofia-sip/htable.h sofia-sip/htable2.h sofia-sip/rbtree.h \
+	sofia-sip/su_debug.h sofia-sip/su_log.h sofia-sip/su_config.h \
+	sofia-sip/su_md5.h sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+	sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+	sofia-sip/su_osx_runloop.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+nobase_nodist_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS) \
+	$(nobase_nodist_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+noinst_LTLIBRARIES = libsu.la
+ at COREFOUNDATION_FALSE@OSXSOURCES = 
+ at COREFOUNDATION_TRUE@OSXSOURCES = \
+ at COREFOUNDATION_TRUE@	su_osx_runloop.c
+
+ at COREFOUNDATION_FALSE@OSXHEADERS = 
+ at COREFOUNDATION_TRUE@OSXHEADERS = \
+ at COREFOUNDATION_TRUE@	sofia-sip/su_osx_runloop.h
+
+ at COREFOUNDATION_TRUE@OSXPROGS = \
+ at COREFOUNDATION_TRUE@	torture_su_root_osx test_su_osx
+
+ at COREFOUNDATION_TRUE@OSXTESTS = \
+ at COREFOUNDATION_TRUE@	torture_su_root_osx run_test_su_osx
+
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_su torture_su_port \
+			torture_su_alloc torture_su_time torture_su_tag \
+			test_htable torture_rbtree \
+			test_memmem torture_su_bm \
+			torture_su_root torture_su_timer \
+			run_addrinfo run_localinfo run_test_su \
+			$(OSXTESTS)
+
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = su_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/su_types.h sofia-sip/su.h \
+			sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+			sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+			sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+			sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+			sofia-sip/su_time.h sofia-sip/su_tag.h \
+			sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+			sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+			sofia-sip/htable.h sofia-sip/htable2.h \
+			sofia-sip/rbtree.h sofia-sip/su_debug.h \
+			sofia-sip/su_log.h \
+			sofia-sip/su_config.h sofia-sip/su_md5.h \
+			sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+			sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+			$(OSXHEADERS)
+
+nobase_nodist_include_sofia_HEADERS = sofia-sip/su_configure.h
+libsu_la_SOURCES = \
+	su.c su_errno.c su_addrinfo.c \
+	su_alloc.c su_alloc_lock.c su_strdup.c su_sprintf.c \
+	su_strlst.c su_vector.c \
+	su_time.c su_time0.c \
+	su_wait.c su_root.c su_timer.c su_port.c su_port.h \
+	su_localinfo.c \
+	su_os_nw.c \
+	su_taglist.c su_tag.c su_tag_io.c \
+	su_log.c su_global_log.c su_default_log.c su_module_debug.h \
+	su_md5.c su_uniqueid.c su_bm.c $(OSXSOURCES)
+
+EXTRA_libsu_la_SOURCES = \
+			memmem.c strtoull.c strcasestr.c \
+			memspn.c memcspn.c memccpy.c \
+			inet_ntop.c inet_pton.c getopt.c \
+			su_tag_ref.c
+
+libsu_la_LIBADD = $(REPLACE_LIBADD)
+libsu_la_DEPENDENCIES = $(REPLACE_LIBADD)
+COVERAGE_INPUT = $(libsu_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsu.la
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile su.docs \
+			run_addrinfo run_localinfo run_test_su
+
+dist_pkgdata_SCRIPTS = tag_dll.awk
+
+# ----------------------------------------------------------------------
+# Automake options
+AUTOMAKE_OPTIONS = foreign
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  libsofia-sip-ua/su/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  libsofia-sip-ua/su/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libsu.la: $(libsu_la_OBJECTS) $(libsu_la_DEPENDENCIES) 
+	$(LINK)  $(libsu_la_LDFLAGS) $(libsu_la_OBJECTS) $(libsu_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	     || test -f $$p1 \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+addrinfo$(EXEEXT): $(addrinfo_OBJECTS) $(addrinfo_DEPENDENCIES) 
+	@rm -f addrinfo$(EXEEXT)
+	$(LINK) $(addrinfo_LDFLAGS) $(addrinfo_OBJECTS) $(addrinfo_LDADD) $(LIBS)
+localinfo$(EXEEXT): $(localinfo_OBJECTS) $(localinfo_DEPENDENCIES) 
+	@rm -f localinfo$(EXEEXT)
+	$(LINK) $(localinfo_LDFLAGS) $(localinfo_OBJECTS) $(localinfo_LDADD) $(LIBS)
+su_proxy$(EXEEXT): $(su_proxy_OBJECTS) $(su_proxy_DEPENDENCIES) 
+	@rm -f su_proxy$(EXEEXT)
+	$(LINK) $(su_proxy_LDFLAGS) $(su_proxy_OBJECTS) $(su_proxy_LDADD) $(LIBS)
+test_htable$(EXEEXT): $(test_htable_OBJECTS) $(test_htable_DEPENDENCIES) 
+	@rm -f test_htable$(EXEEXT)
+	$(LINK) $(test_htable_LDFLAGS) $(test_htable_OBJECTS) $(test_htable_LDADD) $(LIBS)
+test_memmem$(EXEEXT): $(test_memmem_OBJECTS) $(test_memmem_DEPENDENCIES) 
+	@rm -f test_memmem$(EXEEXT)
+	$(LINK) $(test_memmem_LDFLAGS) $(test_memmem_OBJECTS) $(test_memmem_LDADD) $(LIBS)
+test_poll$(EXEEXT): $(test_poll_OBJECTS) $(test_poll_DEPENDENCIES) 
+	@rm -f test_poll$(EXEEXT)
+	$(LINK) $(test_poll_LDFLAGS) $(test_poll_OBJECTS) $(test_poll_LDADD) $(LIBS)
+test_su$(EXEEXT): $(test_su_OBJECTS) $(test_su_DEPENDENCIES) 
+	@rm -f test_su$(EXEEXT)
+	$(LINK) $(test_su_LDFLAGS) $(test_su_OBJECTS) $(test_su_LDADD) $(LIBS)
+test_su_osx$(EXEEXT): $(test_su_osx_OBJECTS) $(test_su_osx_DEPENDENCIES) 
+	@rm -f test_su_osx$(EXEEXT)
+	$(LINK) $(test_su_osx_LDFLAGS) $(test_su_osx_OBJECTS) $(test_su_osx_LDADD) $(LIBS)
+torture_rbtree$(EXEEXT): $(torture_rbtree_OBJECTS) $(torture_rbtree_DEPENDENCIES) 
+	@rm -f torture_rbtree$(EXEEXT)
+	$(LINK) $(torture_rbtree_LDFLAGS) $(torture_rbtree_OBJECTS) $(torture_rbtree_LDADD) $(LIBS)
+torture_su$(EXEEXT): $(torture_su_OBJECTS) $(torture_su_DEPENDENCIES) 
+	@rm -f torture_su$(EXEEXT)
+	$(LINK) $(torture_su_LDFLAGS) $(torture_su_OBJECTS) $(torture_su_LDADD) $(LIBS)
+torture_su_alloc$(EXEEXT): $(torture_su_alloc_OBJECTS) $(torture_su_alloc_DEPENDENCIES) 
+	@rm -f torture_su_alloc$(EXEEXT)
+	$(LINK) $(torture_su_alloc_LDFLAGS) $(torture_su_alloc_OBJECTS) $(torture_su_alloc_LDADD) $(LIBS)
+torture_su_bm$(EXEEXT): $(torture_su_bm_OBJECTS) $(torture_su_bm_DEPENDENCIES) 
+	@rm -f torture_su_bm$(EXEEXT)
+	$(LINK) $(torture_su_bm_LDFLAGS) $(torture_su_bm_OBJECTS) $(torture_su_bm_LDADD) $(LIBS)
+torture_su_port$(EXEEXT): $(torture_su_port_OBJECTS) $(torture_su_port_DEPENDENCIES) 
+	@rm -f torture_su_port$(EXEEXT)
+	$(LINK) $(torture_su_port_LDFLAGS) $(torture_su_port_OBJECTS) $(torture_su_port_LDADD) $(LIBS)
+torture_su_root$(EXEEXT): $(torture_su_root_OBJECTS) $(torture_su_root_DEPENDENCIES) 
+	@rm -f torture_su_root$(EXEEXT)
+	$(LINK) $(torture_su_root_LDFLAGS) $(torture_su_root_OBJECTS) $(torture_su_root_LDADD) $(LIBS)
+torture_su_root_osx$(EXEEXT): $(torture_su_root_osx_OBJECTS) $(torture_su_root_osx_DEPENDENCIES) 
+	@rm -f torture_su_root_osx$(EXEEXT)
+	$(LINK) $(torture_su_root_osx_LDFLAGS) $(torture_su_root_osx_OBJECTS) $(torture_su_root_osx_LDADD) $(LIBS)
+torture_su_tag$(EXEEXT): $(torture_su_tag_OBJECTS) $(torture_su_tag_DEPENDENCIES) 
+	@rm -f torture_su_tag$(EXEEXT)
+	$(LINK) $(torture_su_tag_LDFLAGS) $(torture_su_tag_OBJECTS) $(torture_su_tag_LDADD) $(LIBS)
+torture_su_time$(EXEEXT): $(torture_su_time_OBJECTS) $(torture_su_time_DEPENDENCIES) 
+	@rm -f torture_su_time$(EXEEXT)
+	$(LINK) $(torture_su_time_LDFLAGS) $(torture_su_time_OBJECTS) $(torture_su_time_LDADD) $(LIBS)
+torture_su_timer$(EXEEXT): $(torture_su_timer_OBJECTS) $(torture_su_timer_DEPENDENCIES) 
+	@rm -f torture_su_timer$(EXEEXT)
+	$(LINK) $(torture_su_timer_LDFLAGS) $(torture_su_timer_OBJECTS) $(torture_su_timer_LDADD) $(LIBS)
+install-dist_pkgdataSCRIPTS: $(dist_pkgdata_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)"
+	@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  if test -f $$d$$p; then \
+	    f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	    echo " $(dist_pkgdataSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \
+	    $(dist_pkgdataSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-dist_pkgdataSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	  echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \
+	done
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/addrinfo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/getopt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inet_ntop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inet_pton.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/localinfo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memccpy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memcspn.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memmem.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memspn.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/strcasestr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/strtoull.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_addrinfo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_alloc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_alloc_lock.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_bm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_default_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_errno.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_global_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_localinfo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_md5.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_os_nw.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_osx_runloop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_port.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_proxy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_root.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_sprintf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_strdup.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_strlst.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag_io.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_taglist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_time.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_time0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_timer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_uniqueid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_vector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_wait.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_htable.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_memmem.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_poll.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_su.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_su_osx.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_rbtree.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_alloc.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_bm.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_port.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_root.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_root_osx.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_tag.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_time.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_timer.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+install-nobase_nodist_include_sofiaHEADERS: $(nobase_nodist_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_nodist_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_nodist_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_nodist_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_nodist_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_nodist_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(include_sofiadir)" "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdataSCRIPTS \
+	install-nobase_include_sofiaHEADERS \
+	install-nobase_nodist_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgdataSCRIPTS \
+	uninstall-info-am uninstall-nobase_include_sofiaHEADERS \
+	uninstall-nobase_nodist_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-binPROGRAMS install-data \
+	install-data-am install-dist_pkgdataSCRIPTS install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS \
+	install-nobase_nodist_include_sofiaHEADERS install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-binPROGRAMS \
+	uninstall-dist_pkgdataSCRIPTS uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS \
+	uninstall-nobase_nodist_include_sofiaHEADERS
+
+
+sofia-sip/su_configure.h: sofia-sip/su_configure.h.in
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,163 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page addrinfo Resolve network services
+ * 
+ * @section synopsis Synopsis
+ *
+ * <tt>addrinfo [-pcn46] host service</tt>
+ *
+ * @section description Description
+ * 
+ * The @em addrinfo utility will use su_getaddrinfo() to resolve the network
+ * services and print resolved names.
+ *
+ * @section options Options
+ *
+ * The @e addrinfo utility accepts following ccommand line options:
+ * <dl>
+ * <dt>-p</dt>
+ * <dd>use passive open.</dd>
+ * <dt>-c</dt>
+ * <dd>get canonic name.</dd>
+ * <dt>-n</dt>
+ * <dd>use numeric host names.</dd>
+ * <dt>-4</dt>
+ * <dd>IPv4 only.</dd>
+ * <dt>-6</dt>
+ * <dd>IPv6 only (but including mapped IPv4 addresses).</dd>
+ * </dl>
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is @b NO warranty; not even for @b MERCHANTABILITY or <b>FITNESS
+ * FOR A PARTICULAR PURPOSE</b>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su.h"
+
+char const help[] =
+"usage: addrinfo [-pnc46] [domainname]\n"
+"\t-p query for passive open\n"
+"\t-n use numeric host names\n"
+"\t-c ask for canonic names\n"
+"\t-4 IPv4 only\n"
+"\t-6 IPv6 only (but including mapped IPv4 addresses)\n"
+;
+
+int getopt(int argc, char * const argv[], char const *opstring);
+extern int optind;
+
+void usage(void)
+{
+  fputs(help, stderr);
+  exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+#if SU_HAVE_IN6
+  char buffer[INET6_ADDRSTRLEN];
+#else
+  char buffer[20];
+#endif
+  su_addrinfo_t hints[1] = {{ 0 }};
+  su_addrinfo_t *ai, *res = NULL;
+  char const *host, *service;
+  int error;
+
+  for (;;) {
+    switch(getopt(argc, argv, "ndp4c")) {
+    case '4': hints->ai_family = AF_INET; break;
+#if SU_HAVE_IN6
+    case '6': hints->ai_family = AF_INET6; break;
+#endif
+    case 'p': hints->ai_flags |= AI_PASSIVE; break;
+    case 'n': hints->ai_flags |= AI_NUMERICHOST; break;
+    case 'c': hints->ai_flags |= AI_CANONNAME; break;
+
+    case -1:
+      goto main;
+
+    default:
+      usage();
+    }
+  }
+
+ main:
+  if (optind + 1 >= argc)
+    usage();
+
+  service = argv[optind++];
+  host = argv[optind++];
+
+  su_init();
+
+  if ((error = su_getaddrinfo(host, service, hints, &res)) == 0) {
+    for (ai = res; ai; ai = ai->ai_next) {
+      su_sockaddr_t const *su = (su_sockaddr_t const *)ai->ai_addr;
+      unsigned port;
+
+#if SU_HAVE_IN6
+      if (su->su_family != AF_INET6 && su->su_family != AF_INET)
+	continue;
+#else
+      if (su->su_family != AF_INET)
+	continue;
+#endif
+
+      port = ntohs(su->su_port);
+      inet_ntop(ai->ai_family, SU_ADDR(su), buffer, sizeof(buffer));
+      printf("%d@[%s]:%u", ai->ai_protocol, buffer, port);
+
+      if (ai->ai_flags & AI_CANONNAME)
+        printf(" canon=%s", ai->ai_canonname);
+
+      puts("");
+    }
+    su_freeaddrinfo(res);
+  }
+  else {
+    fprintf(stderr, "addrinfo: %s\n", su_gai_strerror(error));
+    error = 1;
+  }
+
+  su_deinit();
+
+  return error;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,177 @@
+/***************************************************************************** 
+ * 
+ *  MODULE NAME : GETOPT.C 
+ * 
+ *  COPYRIGHTS: 
+ *             This module contains code made available by IBM 
+ *             Corporation on an AS IS basis.  Any one receiving the 
+ *             module is considered to be licensed under IBM copyrights 
+ *             to use the IBM-provided source code in any way he or she 
+ *             deems fit, including copying it, compiling it, modifying 
+ *             it, and redistributing it, with or without 
+ *             modifications.  No license under any IBM patents or 
+ *             patent applications is to be implied from this copyright 
+ *             license. 
+ * 
+ *             A user of the module should understand that IBM cannot 
+ *             provide technical support for the module and will not be 
+ *             responsible for any consequences of use of the program. 
+ * 
+ *             Any notices, including this one, are not to be removed 
+ *             from the module without the prior written consent of 
+ *             IBM. 
+ * 
+ *  AUTHOR:   Original author: 
+ *                 G. R. Blair (BOBBLAIR at AUSVM1) 
+ *                 Internet: bobblair at bobblair.austin.ibm.com 
+ * 
+ *            Extensively revised by: 
+ *                 John Q. Walker II, Ph.D. (JOHHQ at RALVM6) 
+ *                 Internet: johnq at ralvm6.vnet.ibm.com 
+ * 
+ *****************************************************************************/ 
+ 
+/****************************************************************************** 
+ * getopt() 
+ * 
+ * The getopt() function is a command line parser.  It returns the next 
+ * option character in argv that matches an option character in opstring. 
+ * 
+ * The argv argument points to an array of argc+1 elements containing argc 
+ * pointers to character strings followed by a null pointer. 
+ * 
+ * The opstring argument points to a string of option characters; if an 
+ * option character is followed by a colon, the option is expected to have 
+ * an argument that may or may not be separated from it by white space. 
+ * The external variable optarg is set to point to the start of the option 
+ * argument on return from getopt(). 
+ * 
+ * The getopt() function places in optind the argv index of the next argument 
+ * to be processed.  The system initializes the external variable optind to 
+ * 1 before the first call to getopt(). 
+ * 
+ * When all options have been processed (that is, up to the first nonoption 
+ * argument), getopt() returns EOF.  The special option "--" may be used to 
+ * delimit the end of the options; EOF will be returned, and "--" will be 
+ * skipped. 
+ * 
+ * The getopt() function returns a question mark (?) when it encounters an 
+ * option character not included in opstring.  This error message can be 
+ * disabled by setting opterr to zero.  Otherwise, it returns the option 
+ * character that was detected. 
+ * 
+ * If the special option "--" is detected, or all options have been 
+ * processed, EOF is returned. 
+ * 
+ * Options are marked by either a minus sign (-) or a slash (/). 
+ * 
+ * No errors are defined. 
+ *****************************************************************************/ 
+ 
+#include <stdio.h>                  /* for EOF */ 
+#include <string.h>                 /* for strchr() */ 
+ 
+ 
+/* static (global) variables that are specified as exported by getopt() */ 
+char *optarg = NULL;    /* pointer to the start of the option argument  */ 
+int   optind = 1;       /* number of the next argv[] to be evaluated    */ 
+int   opterr = 1;       /* non-zero if a question mark should be returned 
+                           when a non-valid option character is detected */ 
+ 
+/* handle possible future character set concerns by putting this in a macro */ 
+#define _next_char(string)  (char)(*(string+1)) 
+ 
+int getopt(int argc, char *argv[], char *opstring) 
+{ 
+    static char *pIndexPosition = NULL; /* place inside current argv string */ 
+    char *pArgString = NULL;        /* where to start from next */ 
+    char *pOptString;               /* the string in our program */ 
+ 
+ 
+    if (pIndexPosition != NULL) { 
+        /* we last left off inside an argv string */ 
+        if (*(++pIndexPosition)) { 
+            /* there is more to come in the most recent argv */ 
+            pArgString = pIndexPosition; 
+        } 
+    } 
+ 
+    if (pArgString == NULL) { 
+        /* we didn't leave off in the middle of an argv string */ 
+        if (optind >= argc) { 
+            /* more command-line arguments than the argument count */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all command-line arguments */ 
+        } 
+ 
+        /*--------------------------------------------------------------------- 
+         * If the next argv[] is not an option, there can be no more options. 
+         *-------------------------------------------------------------------*/ 
+        pArgString = argv[optind++]; /* set this to the next argument ptr */ 
+ 
+        if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ 
+            ('-' != *pArgString)) { 
+            --optind;               /* point to current arg once we're done */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all the command-line flags */ 
+        } 
+ 
+        /* check for special end-of-flags markers */ 
+        if ((strcmp(pArgString, "-") == 0) || 
+            (strcmp(pArgString, "--") == 0)) { 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* encountered the special flag */ 
+        } 
+ 
+        pArgString++;               /* look past the / or - */ 
+    } 
+ 
+    if (':' == *pArgString) {       /* is it a colon? */ 
+        /*--------------------------------------------------------------------- 
+         * Rare case: if opterr is non-zero, return a question mark; 
+         * otherwise, just return the colon we're on. 
+         *-------------------------------------------------------------------*/ 
+        return (opterr ? (int)'?' : (int)':'); 
+    } 
+    else if ((pOptString = strchr(opstring, *pArgString)) == 0) { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line wasn't any good. 
+         *-------------------------------------------------------------------*/ 
+        optarg = NULL;              /* no argument follows the option */ 
+        pIndexPosition = NULL;      /* not in the middle of anything */ 
+        return (opterr ? (int)'?' : (int)*pArgString); 
+    } 
+    else { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line matches one we expect to see 
+         *-------------------------------------------------------------------*/ 
+        if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ 
+            /* It is a colon.  Look for an argument string. */ 
+            if ('\0' != _next_char(pArgString)) {  /* argument in this argv? */ 
+                optarg = &pArgString[1];   /* Yes, it is */ 
+            } 
+            else { 
+                /*------------------------------------------------------------- 
+                 * The argument string must be in the next argv. 
+                 * But, what if there is none (bad input from the user)? 
+                 * In that case, return the letter, and optarg as NULL. 
+                 *-----------------------------------------------------------*/ 
+                if (optind < argc) 
+                    optarg = argv[optind++]; 
+                else { 
+                    optarg = NULL; 
+                    return (opterr ? (int)'?' : (int)*pArgString); 
+                } 
+            } 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+        } 
+        else { 
+            /* it's not a colon, so just return the letter */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = pArgString;    /* point to the letter we're on */ 
+        } 
+        return (int)*pArgString;    /* return the letter that matched */ 
+    } 
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,183 @@
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+
+#include "sofia-sip/su.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
+#if HAVE_SIN6
+static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
+#endif
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *	convert a network format address to presentation format.
+ * return:
+ *	pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *	Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, void const *src, char *dst, size_t size)
+{
+
+	switch (af) {
+	case AF_INET:
+		return inet_ntop4(src, dst, size);
+#if HAVE_SIN6
+	case AF_INET6:
+		return inet_ntop6(src, dst, size);
+#endif
+	default:
+		su_seterrno(EAFNOSUPPORT);
+		return NULL;
+	}
+	/* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *	format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ *	`dst' (as a const)
+ * notes:
+ *	(1) uses no statics
+ *	(2) takes a unsigned char* not an in_addr as input
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+	static const char fmt[] = "%u.%u.%u.%u";
+	char tmp[sizeof "255.255.255.255"];
+
+	if (snprintf(tmp, sizeof tmp, fmt,
+		     src[0], src[1], src[2], src[3]) >= size) {
+		su_seterrno(ENOSPC);
+		return NULL;
+	}
+
+	return strcpy(dst, tmp);
+}
+
+#if HAVE_SIN6
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *	convert IPv6 binary address into presentation (printable) format
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(unsigned char const *src, char *dst, size_t size)
+{
+	/*
+	 * Note that int32_t and int16_t need only be "at least" large enough
+	 * to contain a value of the specified size.  On some systems, like
+	 * Crays, there is no such thing as an integer variable with 16 bits.
+	 * Keep this in mind if you think this function should have been coded
+	 * to use pointer overlays.  All the world's not a VAX.
+	 */
+	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+	struct { int base, len; } best = { -1 , 0 }, cur = { -1, 0 };
+	unsigned int words[8];
+	int i;
+
+	/*
+	 * Preprocess:
+	 *	Copy the input (bytewise) array into a wordwise array.
+	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
+	 */
+	for (i = 0; i < 16; i += 2)
+		words[i / 2] = (src[i] << 8) | (src[i + 1]);
+	best.base = -1;
+	cur.base = -1;
+	for (i = 0; i < 8; i++) {
+		if (words[i] == 0) {
+			if (cur.base == -1)
+				cur.base = i, cur.len = 1;
+			else
+				cur.len++;
+		} else {
+			if (cur.base != -1) {
+				if (best.base == -1 || cur.len > best.len)
+					best = cur;
+				cur.base = -1;
+			}
+		}
+	}
+	if (cur.base != -1) {
+		if (best.base == -1 || cur.len > best.len)
+			best = cur;
+	}
+	if (best.base != -1 && best.len < 2)
+		best.base = -1;
+
+	/*
+	 * Format the result.
+	 */
+	tp = tmp;
+	for (i = 0; i < 8; i++) {
+		/* Are we inside the best run of 0x00's? */
+		if (best.base != -1 && i >= best.base &&
+		    i < (best.base + best.len)) {
+			if (i == best.base)
+				*tp++ = ':';
+			continue;
+		}
+		/* Are we following an initial run of 0x00s or any real hex? */
+		if (i != 0)
+			*tp++ = ':';
+		/* Is this address an encapsulated IPv4? */
+		if (i == 6 && best.base == 0 &&
+		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+				return (NULL);
+			tp += strlen(tp);
+			break;
+		}
+		tp += sprintf(tp, "%x", words[i]);
+	}
+	/* Was it a trailing run of 0x00's? */
+	if (best.base != -1 && (best.base + best.len) == 8)
+		*tp++ = ':';
+	*tp++ = '\0';
+
+	/*
+	 * Check for overflow, copy, and we're done.
+	 */
+	if ((size_t)(tp - tmp) >= size) {
+		su_seterrno(ENOSPC);
+		return NULL;
+	}
+
+	return strcpy(dst, tmp);
+}
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sofia-sip/su.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int	inet_pton4(const char *src, unsigned char *dst);
+#if HAVE_SIN6
+static int	inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ *	convert from presentation format (which usually means ASCII printable)
+ *	to network format (which is usually some kind of binary format).
+ * return:
+ *	1 if the address was valid for the specified address family
+ *	0 if the address wasn't valid (`dst' is untouched in this case)
+ *	-1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *	Paul Vixie, 1996.
+ */
+int
+inet_pton(int af, const char * src, void * dst)
+{
+	switch (af) {
+	case AF_INET:
+		return (inet_pton4(src, dst));
+#if HAVE_SIN6
+	case AF_INET6:
+		return (inet_pton6(src, dst));
+#endif
+	default:
+		su_seterrno(EAFNOSUPPORT);
+		return (-1);
+	}
+	/* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *	like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *	1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *	does not touch `dst' unless it's returning 1.
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+	int saw_digit, octets, ch;
+	unsigned char tmp[4], *tp;
+
+	saw_digit = 0;
+	octets = 0;
+	*(tp = tmp) = 0;
+	while ((ch = *src++) != '\0') {
+		if ('0' <= ch && ch <= '9') {
+			unsigned octet = *tp * 10 + ch - '0';
+
+			if (saw_digit && *tp == 0)
+				return (0);
+			if (octet > 255)
+				return (0);
+			*tp = octet;
+			if (!saw_digit) {
+				if (++octets > 4)
+					return (0);
+				saw_digit = 1;
+			}
+		} else if (ch == '.' && saw_digit) {
+			if (octets == 4)
+				return (0);
+			*++tp = 0;
+			saw_digit = 0;
+		} else
+			return (0);
+	}
+	if (octets < 4)
+		return (0);
+	memcpy(dst, tmp, 4);
+	return (1);
+}
+
+#if HAVE_SIN6
+
+/* int
+ * inet_pton6(src, dst)
+ *	convert presentation level address to network order binary form.
+ * return:
+ *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *	(1) does not touch `dst' unless it's returning 1.
+ *	(2) :: in a full address is silently ignored.
+ * credit:
+ *	inspired by Mark Andrews.
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+	uint8_t tmp[16], *tp, *endp, *colonp;
+	const char *curtok;
+	int ch, saw_xdigit;
+	unsigned val;
+
+	memset((tp = tmp), '\0', sizeof tmp);
+	endp = tp + sizeof tmp;
+	colonp = NULL;
+	/* Leading :: requires some special handling. */
+	if (*src == ':')
+		if (*++src != ':')
+			return (0);
+	curtok = src;
+	saw_xdigit = 0;
+	val = 0;
+	while ((ch = *src++) != '\0') {
+		if (ch == ':') {
+			curtok = src;
+			if (!saw_xdigit) {
+				if (colonp)
+					return (0);
+				colonp = tp;
+				continue;
+			} else if (*src == '\0') {
+				return (0);
+			}
+			if (tp + 2 > endp)
+				return (0);
+			*tp++ = (unsigned char) (val >> 8) & 0xff;
+			*tp++ = (unsigned char) val & 0xff;
+			saw_xdigit = 0;
+			val = 0;
+			continue;
+		}
+		if (ch == '.' && ((tp + 4) <= endp) &&
+		    inet_pton4(curtok, tp) > 0) {
+			tp += 4;
+			saw_xdigit = 0;
+			break;	/* '\0' was seen by inet_pton4(). */
+		}
+
+		if ('0' <= ch && ch <= '9')
+			ch = ch - '0';
+		else if ('A' <= ch && ch <= 'F')
+			ch = ch - 'A' + 10;
+		else if ('a' <= ch && ch <= 'f')
+			ch = ch - 'a' + 10;
+		else
+			return (0);
+		val <<= 4;
+		val |= ch;
+		if (val > 0xffff)
+			return (0);
+		saw_xdigit = 1;
+	}
+	if (saw_xdigit) {
+		if (tp + 2 > endp)
+			return (0);
+		*tp++ = (unsigned char) (val >> 8) & 0xff;
+		*tp++ = (unsigned char) val & 0xff;
+	}
+	if (colonp != NULL) {
+		/*
+		 * Since some memmove()'s erroneously fail to handle
+		 * overlapping regions, we'll do the shift by hand.
+		 */
+		const int n = tp - colonp;
+		int i;
+
+		if (tp == endp)
+			return (0);
+		for (i = 1; i <= n; i++) {
+			endp[- i] = colonp[n - i];
+			colonp[n - i] = 0;
+		}
+		tp = endp;
+	}
+	if (tp != endp)
+		return 0;
+	memcpy(dst, tmp, sizeof tmp);
+	return 1;
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page localinfo list local network addresses
+ * 
+ * @section synopsis Synopsis
+ *
+ * <tt>localinfo [-imdn46gslh] [domainname]</tt>
+ *
+ * @section description Description
+ * 
+ * The @em localinfo utility will obtain the local network addresses
+ * and print them.
+ *
+ * @section options Options
+ *
+ * The @e localinfo utility accepts following command line options:
+ * <dl>
+ * <dt>-i</dt>
+ * <dd>include interface name.</dd>
+ * <dt>-m</dt>
+ * <dd>map IPv4 addresses.</dd>
+ * <dt>-d</dt>
+ * <dd>require a reverse DNS entry.</dd>
+ * <dt>-n</dt>
+ * <dd>use numeric host names.</dd>
+ * <dt>-4</dt>
+ * <dd>IPv4 only.</dd>
+ * <dt>-6</dt>
+ * <dd>IPv6 only (but including mapped IPv4 addresses).</dd>
+ * <dt>-g</dt>
+ * <dd>Global addresses.</dd>
+ * <dt>-s</dt>
+ * <dd>Site-level addresses.</dd>
+ * <dt>-l</dt>
+ * <dd>Link-level addresses.</dd>
+ * <dt>-h</dt>
+ * <dd>Host-internal addresses.</dd>
+ * </dl>
+ *
+ * @section examples Examples
+ *
+ * You want to find out local IPv6 addresses: 
+ * @code
+ * $ localinfo -6
+ * @endcode
+ * You want to find out to link-local addresses
+ * @code
+ * $ localinfo -l -n
+ * @endcode
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is @b NO warranty; not even for @b MERCHANTABILITY or <b>FITNESS
+ * FOR A PARTICULAR PURPOSE</b>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_localinfo.h"
+#include "su_module_debug.h"
+
+char const help[] =
+"usage: localinfo [-imdn46gslh] [domainname]\n"
+"\t-i include interface name\n"
+"\t-m map IPv4 addresses\n"
+"\t-d require DNS entry\n"
+"\t-n use numeric host names\n"
+"\t-4 IPv4 only\n"
+"\t-6 IPv6 only (but including mapped IPv4 addresses)\n"
+"\t-g Global addresses\n"
+"\t-s Site-level addresses\n"
+"\t-l Link-level addresses\n"
+"\t-h Host-internal addresses\n";
+
+int getopt(int argc, char * const argv[], char const *opstring);
+extern int optind;
+
+void usage(int returncode)
+{
+  fputs(help, stderr);
+  exit(returncode);
+}
+
+int main(int argc, char *argv[])
+{
+  char buffer[SU_ADDRSIZE];
+  su_localinfo_t hints[1] = {{ LI_CANONNAME }};
+  su_localinfo_t *li, *res = NULL;
+  int error;
+  int ifindex = 0;
+
+  if (argv[1] && strcmp(argv[1], "--help") == 0)
+    usage(0);
+
+  for (;;) {
+    switch(getopt(argc, argv, "iImdn46gslh")) {
+
+    case 'I': ifindex = 1; break;
+    case 'i': hints->li_flags |= LI_IFNAME; ifindex = 1; break;
+    case 'm': hints->li_flags |= LI_V4MAPPED; break;
+    case '4': hints->li_family = AF_INET; break;
+#if SU_HAVE_IN6
+    case '6': hints->li_family = AF_INET6; break;
+#endif
+    case 'd': hints->li_flags |= LI_NAMEREQD; break;
+    case 'n': hints->li_flags |= LI_NUMERIC; break;
+    case 'g': hints->li_scope |= LI_SCOPE_GLOBAL; break;
+    case 's': hints->li_scope |= LI_SCOPE_SITE; break;
+    case 'l': hints->li_scope |= LI_SCOPE_LINK; break;
+    case 'h': hints->li_scope |= LI_SCOPE_HOST; break;
+
+    case -1:
+      goto main;
+
+    default:
+      usage(1);
+    }
+  }
+
+ main:
+  if (optind < argc)
+    hints->li_canonname = argv[optind++];
+
+  if (optind < argc)
+    usage(1);
+
+  su_init();
+
+  if ((error = su_getlocalinfo(hints, &res)) == 0) {
+    for (li = res; li; li = li->li_next) {
+      if (li->li_flags & LI_NUMERIC) {
+        fputs(li->li_canonname, stdout);
+      }
+      else {
+        inet_ntop(li->li_family, SU_ADDR(li->li_addr), 
+		  buffer, sizeof(buffer));
+        printf("%s maddr=[%s]", li->li_canonname, buffer);
+      }
+      if (li->li_scope & LI_SCOPE_GLOBAL)
+	fputs(" scope=global", stdout);
+      else if (li->li_scope & LI_SCOPE_SITE)
+	fputs(" scope=site", stdout);
+      else if (li->li_scope & LI_SCOPE_LINK)
+	fputs(" scope=link", stdout);
+      else if (li->li_scope & LI_SCOPE_HOST)
+	fputs(" scope=host", stdout);
+      if (ifindex) {
+	if (li->li_ifname)
+	  printf(" if[%d]=%s", li->li_index, li->li_ifname);
+	else
+	  printf(" if[%d]", li->li_index);
+      }
+      puts("");
+    }
+    su_freelocalinfo(res);
+  }
+  else {
+    fprintf(stderr, "localinfo: %s\n", su_gli_strerror(error));
+    error = 1;
+  }
+
+  su_deinit();
+
+  return error;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memccpy.c
+ * @brief The memccpy() replacement function.
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Nov 17 17:45:51 EET 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Copy memory until @a c is found.
+ *
+ * Copies no more than @a n bytes from memory area @a src to memory area @a
+ * dest, stopping after the character @a c is copied and found.
+ *
+ * @param dest       pointer to destination area
+ * @param src        pointer to source area
+ * @param c          terminating byte
+ * @param n          size of destination area
+ *
+ * @return
+ * Returns a pointer to the next character in @a dest after @a c, 
+ * or NULL if @a c was not found in the first @a n characters of @a src.
+ */
+void *memccpy(void *dest, const void *src, int c, size_t n)
+{
+  char *d;
+  char const *s;
+
+  if (!src || !dest)
+    return dest;
+
+  for (d = dest, s = src; n-- > 0;) {
+    if (c == (*d++ = *s++))
+      return d;
+  }
+
+  return NULL;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memcspn.c
+ * @brief The memcspn() replacement function.
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Nov 17 17:45:51 EET 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Search memory for bytes not in a given set.
+ *
+ * The memcspn() function calculates the length of the memory area @a mem
+ * which consists entirely of bytes not in @a reject.
+ *
+ * @param mem        pointer to memory area
+ * @param memlen     size of @a mem in bytes
+ * @param reject     pointer to table containing bytes to reject
+ * @param rejectlen  size of @a reject table
+ *
+ * @return
+ * The memspn() function returns the number of bytes in the memory area @a
+ * which consists entirely of bytes not in @a reject.
+ * @par 
+ * If @a rejectlen is 0, or @a reject is NULL, it returns @a memlen, size of
+ * the memory area.
+ */
+size_t memcspn(const void *mem, size_t memlen,
+	       const void *reject, size_t rejectlen)
+{
+  size_t i;
+
+  unsigned char const *m = mem, *r = reject;
+
+  char rejected[UCHAR_MAX + 1];
+
+  if (rejectlen == 0 || reject == 0)
+    return memlen;
+
+  if (mem == NULL || memlen == 0)
+    return 0;
+
+  memset(rejected, 0, sizeof rejected);
+
+  for (i = 0; i < rejectlen; i++)
+    rejected[r[i]] = 1;
+
+  for (i = 0; i < memlen; i++)
+    if (rejected[m[i]])
+      break;
+
+  return i;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memmem.c
+ * @brief Backup implementation of memmem()
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Sat Apr 12 19:32:33 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+/* Naive implementation of memmem() */
+void *memmem(const void *haystack, size_t haystacklen,
+	     const void *needle, size_t needlelen)
+{
+  size_t i;
+  char const *hs = haystack;
+
+  if (needlelen == 0)
+    return (void *)haystack;
+
+  if (needlelen > haystacklen || haystack == NULL || needle == NULL)
+    return NULL;
+
+  for (i = 0; i <= haystacklen - needlelen; i++) {
+    if (memcmp(hs + i, needle, needlelen) == 0)
+      return (void *)(hs + i);
+  }
+
+  return NULL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memspn.c
+ * The memspn() replacement function.
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Sat Apr 12 19:32:33 2003 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Scan memory for a set of bytes.
+ *
+ * The memspn() function calculates the length of the memory area @a mem
+ * which consists entirely of bytes in @a accept.
+ *
+ * @param mem        pointer to memory area
+ * @param memlen     size of @a mem in bytes
+ * @param accept     pointer to table containing bytes to accept
+ * @param acceptlen  size of @a accept table
+ *
+ * @return
+ * The memspn() function returns the number of bbytes in the memory area @a
+ * which consists entirely of bytes in @a accept.
+ */
+size_t memspn(const void *mem, size_t memlen,
+	      const void *accept, size_t acceptlen)
+{
+  size_t i;
+
+  unsigned char const *m = mem, *a = accept;
+
+  char accepted[UCHAR_MAX + 1];
+
+  if (mem == NULL || memlen == 0 || acceptlen == 0 || accept == NULL)
+    return 0;
+
+  memset(accepted, 0, sizeof accepted);
+
+  for (i = 0; i < acceptlen; i++)
+    accepted[a[i]] = 1;
+
+  for (i = 0; i < memlen; i++)
+    if (!accepted[m[i]])
+      break;
+
+  return i;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+#! /bin/sh
+# Test addrinfo with -n and echo port on 127.0.0.1
+./addrinfo -n echo 127.0.0.1

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+#! /bin/sh
+# Test localinfo with -n flag
+./localinfo -n | sed 's:^: :'

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+#! /bin/bash
+
+rc=0
+
+if $VALGRIND ./test_su ; then
+    echo PASS: multithread test_su
+else
+    echo FAIL: multithread test_su failed
+    rc=1
+fi
+
+if $VALGRIND ./test_su -s ; then
+    echo PASS: singlethread test_su
+else
+    echo FAIL: singlethread test_su failed
+    rc=1
+fi
+
+exit $rc

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,258 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTABLE_H
+/** Defined when <sofia-sip/htable.h> has been included. */
+#define HTABLE_H
+
+/**@ingroup su_htable
+ * @file sofia-sip/htable.h
+ *
+ * Hash tables templates.
+ *
+ * This file contain a hash table template for C.  The hash tables are
+ * resizeable, and they usually contain pointers to entries.  The
+ * declaration for template datatypes is instantiated with macro
+ * HTABLE_DECLARE().  The prototypes for hashing functions are instantiated
+ * with macro HTABLE_PROTOS().  The implementation is instantiated with
+ * macro HTABLE_BODIES().
+ *
+ * The hash table template is most efficient when the hash value is
+ * precalculated and stored in each entry.  The hash "function" given to the
+ * HTABLE_BODIES() would then be something like macro
+ * @code
+ * #define HTABLE_ENTRY_HASH(e) ((e)->e_hash_value)
+ * @endcode
+ *
+ * When a entry with new identical hash key is added to the table, it can be
+ * either @e inserted (before any other entry with same key value) or
+ * @e appended.
+ * 
+ * Example code can be found from <htable_test.c>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Sep 25 17:42:40 2001 ppessi
+ */
+
+typedef unsigned long hash_value_t;
+
+/** Minimum size of hash table */
+#define HTABLE_MIN_SIZE 31
+
+/** Declare hash table structure type.
+ * 
+ * The macro HTABLE_DECLARE() expands to a declaration for hash table
+ * structure.  The its typedef will be <em>prefix</em><code>_t</code>, the
+ * field names start withb @a pr.  The entry type is @a entry_t.
+ *
+ * @param prefix  hash table type and function prefix
+ * @param pr      hash table field prefix
+ * @param entry_t entry type
+ */
+#define HTABLE_DECLARE(prefix, pr, entry_t)		\
+  HTABLE_DECLARE_WITH(prefix, pr, entry_t, unsigned, hash_value_t)
+
+#define HTABLE_DECLARE_WITH(prefix, pr, entry_t, size_t, hash_value_t)	\
+  typedef struct prefix##_s {						\
+    size_t pr##_size;							\
+    size_t pr##_used;							\
+    entry_t**pr##_table; /**< Hash table itself */			\
+  } prefix##_t
+
+#ifndef HTABLE_SCOPE
+/** Default scope for hash table functions. */
+#define HTABLE_SCOPE static inline
+#endif
+
+/** Prototypes for hash table
+ *
+ * The macro HTABLE_PROTOS() expands to the prototypes of hash table
+ * functions.  The function and type names start with @a prefix, the field
+ * names start with @a pr.  The entry type is @a entry_t.
+ *
+ * @param prefix  hash table type and function prefix
+ * @param pr      hash table field prefix
+ * @param entry_t entry type
+ */
+#define HTABLE_PROTOS(prefix, pr, entry_t) \
+  HTABLE_PROTOS_WITH(prefix, pr, entry_t, unsigned, hash_value_t)
+
+#define HTABLE_PROTOS_WITH(prefix, pr, entry_t, size_t, hash_value_t)	\
+HTABLE_SCOPE int prefix##_resize(su_home_t *, prefix##_t pr[1], size_t); \
+HTABLE_SCOPE int prefix##_is_full(prefix##_t const *); \
+HTABLE_SCOPE entry_t **prefix##_hash(prefix##_t const *, hash_value_t hv); \
+HTABLE_SCOPE entry_t **prefix##_next(prefix##_t const *, entry_t * const *ee); \
+HTABLE_SCOPE void prefix##_append(prefix##_t *pr, entry_t const *e); \
+HTABLE_SCOPE void prefix##_insert(prefix##_t *pr, entry_t const *e); \
+HTABLE_SCOPE void prefix##_remove(prefix##_t *, entry_t const *e)
+
+/** Hash table implementation.
+ *
+ * The macro HTABLE_BODIES() expands the hash table functions.  The function
+ * and type names start with @a prefix, the field names start with @a pr.
+ * The entry type is @a entry_t.  The function (or macro) name returning
+ * hash value of each entry is given as @a hfun.
+ *
+ * @param prefix  hash table type and function prefix
+ * @param pr      hash table field prefix
+ * @param entry_t entry type
+ * @param hfun    function or macro returning hash value of entry
+ */
+#define HTABLE_BODIES(prefix, pr, entry_t, hfun) \
+  HTABLE_BODIES_WITH(prefix, pr, entry_t, hfun, unsigned, hash_value_t)
+
+#define HTABLE_BODIES_WITH(prefix, pr, entry_t, hfun, size_t, hash_value_t) \
+/** Reallocate new hash table */ \
+HTABLE_SCOPE \
+int prefix##_resize(su_home_t *home, \
+                    prefix##_t pr[], \
+		    size_t new_size) \
+{ \
+  entry_t **new_hash; \
+  entry_t **old_hash = pr->pr##_table; \
+  size_t old_size; \
+  size_t i, j, i0; \
+  unsigned again = 0; \
+  size_t used = 0, collisions = 0; \
+\
+  if (new_size == 0) \
+    new_size = 2 * pr->pr##_size + 1; \
+  if (new_size < HTABLE_MIN_SIZE) \
+    new_size = HTABLE_MIN_SIZE; \
+\
+  if (!(new_hash = su_zalloc(home, sizeof(*new_hash) * new_size))) \
+    return -1; \
+\
+  old_size = pr->pr##_size; \
+\
+  do for (j = 0; j < old_size; j++) { \
+    if (!old_hash[j]) \
+      continue; \
+\
+    if (again < 2 && hfun(old_hash[j]) % old_size > j) { \
+      /* Wrapped, leave entry for second pass */ \
+      again = 1; continue; \
+    } \
+\
+    i0 = hfun(old_hash[j]) % new_size; \
+\
+    for (i = i0; new_hash[i]; i = (i + 1) % new_size, assert(i != i0)) \
+      collisions++; \
+\
+    new_hash[i] = old_hash[j], old_hash[j] = NULL; \
+    used++; \
+  } \
+  while (again++ == 1); \
+\
+  pr->pr##_table = new_hash, pr->pr##_size = new_size; \
+\
+  assert(pr->pr##_used == used); \
+\
+  return 0; \
+} \
+\
+HTABLE_SCOPE \
+int prefix##_is_full(prefix##_t const *pr) \
+{ \
+  return pr->pr##_table == NULL || 3 * pr->pr##_used > 2 * pr->pr##_size; \
+} \
+\
+HTABLE_SCOPE \
+entry_t **prefix##_hash(prefix##_t const *pr, hash_value_t hv) \
+{ \
+  return pr->pr##_table + hv % pr->pr##_size; \
+} \
+\
+HTABLE_SCOPE \
+entry_t **prefix##_next(prefix##_t const *pr, entry_t * const *ee) \
+{ \
+  if (++ee < pr->pr##_table + pr->pr##_size && ee >= pr->pr##_table) \
+    return (entry_t **)ee; \
+  else \
+    return pr->pr##_table; \
+}  \
+\
+HTABLE_SCOPE \
+void prefix##_append(prefix##_t *pr, entry_t const *e) \
+{ \
+  entry_t **ee; \
+\
+  pr->pr##_used++; \
+  for (ee = prefix##_hash(pr, hfun(e)); *ee; ee = prefix##_next(pr, ee)) \
+   ; \
+  *ee = (entry_t *)e; \
+} \
+\
+HTABLE_SCOPE \
+void prefix##_insert(prefix##_t *pr, entry_t const *e) \
+{ \
+  entry_t *e0, **ee; \
+\
+  pr->pr##_used++; \
+  /* Insert entry into hash table (before other entries with same hash) */ \
+  for (ee = prefix##_hash(pr, hfun(e));  \
+       (e0 = *ee); \
+       ee = prefix##_next(pr, ee)) \
+    *ee = (entry_t *)e, e = e0; \
+  *ee = (entry_t *)e; \
+} \
+\
+HTABLE_SCOPE \
+void prefix##_remove(prefix##_t *pr, entry_t const *e) \
+{ \
+  size_t i, j, k; \
+  size_t size = pr->pr##_size; \
+  entry_t **htable = pr->pr##_table; \
+\
+  if (!e) return; \
+\
+  /* Search for entry */ \
+  for (i = hfun(e) % size; htable[i]; i = (i + 1) % size) \
+    if (e == htable[i]) \
+      break; \
+\
+  /* Entry is not in table? */ \
+  assert(htable[i]); if (!e) return; \
+\
+  /* Move table entries towards their primary place  */ \
+  for (j = (i + 1) % size; htable[j]; j = (j + 1) % size) { \
+    /* k is primary place for entry */ \
+    k = hfun(htable[j]) % size; \
+    if (k == j)			/* entry is in its primary place? */ \
+      continue; \
+    /* primary place is between i and j - do not move this to i */ \
+    if (j > i ? (i < k && k < j) : (i < k || k < j)) \
+      continue; \
+\
+    htable[i] = htable[j], i = j; \
+  } \
+\
+  pr->pr##_used--; \
+\
+  htable[i] = NULL; \
+} \
+extern int prefix##_dummy
+
+#endif /** !defined(HTABLE_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,266 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTABLE2_H
+/** Defined when <sofia-sip/htable2.h> has been included. */
+#define HTABLE2_H 
+
+/**@file sofia-sip/htable2.h
+ *
+ * Hash tables templates, take 2.
+ *
+ * Note: this version can handle structures as entries, and it can be used
+ * without <su_alloc.h>.
+ * 
+ * This file contain a hash table template for C.  The hash tables are
+ * resizeable, and they usually contain pointers to entries.  The
+ * declaration for template datatypes is instantiated with macro
+ * HTABLE2_DECLARE().  The prototypes for hashing functions are instantiated
+ * with macro HTABLE2_PROTOS().  The implementation is instantiated with
+ * macro HTABLE2_BODIES().
+ *
+ * The hash table template is most efficient when the hash value is
+ * precalculated and stored in each entry.  The hash "function" given to the
+ * HTABLE2_BODIES() would then be something like macro
+ * @code
+ * #define HTABLE2_ENTRY_HASH(e) ((e).e_hash_value)
+ * @endcode
+ *
+ * When a entry with new identical hash key is added to the table, it can be
+ * either @e inserted (before any other entry with same key value) or
+ * @e appended.
+ * 
+ * Example code can be found from <htable_test.c>.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Sep 25 17:42:40 2001 ppessi
+ *
+ */
+
+typedef unsigned long hash_value_t;
+
+/** Minimum size of hash table */
+#define HTABLE2_MIN_SIZE 31
+
+/** Declare hash table structure type.
+ * 
+ * The macro HTABLE2_DECLARE() expands to a declaration for hash table
+ * structure.  The its typedef will be <em>prefix</em><code>_t</code>, the
+ * field names start with @a pr.  The entry type is @a entrytype.
+ *
+ * @param sname     name of struct
+ * @param prefix    hash table type and function prefix
+ * @param pr        hash table field prefix
+ * @param entrytype entry type
+ */
+#define HTABLE2_DECLARE(sname, prefix, pr, entrytype)	\
+struct sname { \
+  unsigned pr##size; \
+  unsigned pr##used; \
+  entrytype *pr##table; /**< Hash table itself */ \
+}
+
+#ifndef HTABLE2_SCOPE
+/** Default scope for hash table functions. */
+#define HTABLE2_SCOPE static inline
+#endif
+
+/** Prototypes for hash table
+ *
+ * The macro HTABLE2_PROTOS() expands to the prototypes of hash table
+ * functions.  The function and type names start with @a prefix, the field
+ * names start with @a pr.  The entry type is @a entrytype.
+
+ * @param type      hash table typedef
+ * @param prefix    function prefix
+ * @param pr        hash table field prefix
+ * @param entrytype entry type
+ */
+#define HTABLE2_PROTOS(type, prefix, pr, entrytype)			\
+HTABLE2_SCOPE int prefix##_resize(void *a, type pr[1], unsigned); \
+HTABLE2_SCOPE int prefix##_is_full(type const *); \
+HTABLE2_SCOPE entrytype *prefix##_hash(type const *, hash_value_t hv); \
+HTABLE2_SCOPE entrytype *prefix##_next(type const *, entrytype *ee); \
+HTABLE2_SCOPE void prefix##_append(type *pr, entrytype e); \
+HTABLE2_SCOPE void prefix##_insert(type *pr, entrytype e); \
+HTABLE2_SCOPE int prefix##_remove(type *, entrytype const e)
+
+/** Hash table implementation.
+ *
+ * The macro HTABLE2_BODIES() expands the hash table functions.  The function
+ * and type names start with @a prefix, the field names start with @a pr.
+ * The entry type is @a entrytype.  The function (or macro) name returning
+ * hash value of each entry is given as @a hfun.
+ *
+ * @param type      hash table type
+ * @param prefix    function prefix for hash table 
+ * @param pr        field prefix for hash table 
+ * @param entrytype type of entry element
+ * @param hfun      function or macro returning hash value of entry
+ * @param is_used   function or macro returning true if entry is occupied
+ * @param reclaim   function or macro zeroing entry
+ * @param is_equal  equality test
+ * @param halloc    function allocating or freeing memory
+ */
+#define HTABLE2_BODIES(type, prefix, pr, entrytype,			\
+		       hfun, is_used, reclaim, is_equal, halloc)	\
+/** Reallocate new hash table */ \
+HTABLE2_SCOPE \
+int prefix##_resize(void *realloc_arg, \
+                    type pr[1], \
+		    unsigned new_size) \
+{ \
+  entrytype *new_hash; \
+  entrytype *old_hash = pr->pr##table; \
+  unsigned old_size; \
+  unsigned i, j, i0; \
+  unsigned again = 0, used = 0, collisions = 0; \
+\
+  (void)realloc_arg; \
+\
+  if (new_size == 0) \
+    new_size = 2 * pr->pr##size + 1; \
+  if (new_size < HTABLE2_MIN_SIZE) \
+    new_size = HTABLE2_MIN_SIZE; \
+\
+  if (!(new_hash = halloc(realloc_arg, NULL, sizeof(*new_hash) * new_size))) \
+    return -1; \
+\
+  memset(new_hash, 0, sizeof(*new_hash) * new_size); \
+  old_size = pr->pr##size; \
+\
+  do for (j = 0; j < old_size; j++) { \
+    if (!is_used(old_hash[j])) \
+      continue; \
+\
+    if (again < 2 && hfun(old_hash[j]) % old_size > j) { \
+      /* Wrapped, leave entry for second pass */ \
+      again = 1; continue; \
+    } \
+\
+    i0 = hfun(old_hash[j]) % new_size; \
+\
+    for (i = i0; is_used(new_hash[i]); \
+         i = (i + 1) % new_size, assert(i != i0)) \
+      collisions++; \
+\
+    new_hash[i] = old_hash[j]; reclaim(&old_hash[j]); \
+    used++; \
+  } \
+  while (again++ == 1); \
+\
+  pr->pr##table = new_hash, pr->pr##size = new_size; \
+\
+  if (old_hash) old_hash = halloc(realloc_arg, old_hash, 0);	\
+\
+  assert(pr->pr##used == used);\
+\
+  return 0; \
+} \
+\
+HTABLE2_SCOPE \
+int prefix##_is_full(type const *pr) \
+{ \
+  return pr->pr##table == NULL || 3 * pr->pr##used > 2 * pr->pr##size; \
+} \
+\
+HTABLE2_SCOPE \
+entrytype *prefix##_hash(type const *pr, hash_value_t hv) \
+{ \
+  return pr->pr##table + hv % pr->pr##size; \
+} \
+\
+HTABLE2_SCOPE \
+entrytype *prefix##_next(type const *pr, entrytype *ee) \
+{ \
+  if (++ee < pr->pr##table + pr->pr##size && ee >= pr->pr##table) \
+    return ee; \
+  else \
+    return pr->pr##table; \
+}  \
+\
+HTABLE2_SCOPE \
+void prefix##_append(type *pr, entrytype e) \
+{ \
+  entrytype *ee; \
+\
+  pr->pr##used++; \
+  for (ee = prefix##_hash(pr, hfun(e)); \
+       is_used(*ee); \
+       ee = prefix##_next(pr, ee)) \
+   ; \
+  *ee = e; \
+} \
+\
+HTABLE2_SCOPE \
+void prefix##_insert(type *pr, entrytype e) \
+{ \
+  entrytype e0; \
+  entrytype *ee; \
+\
+  pr->pr##used++; \
+  /* Insert entry into hash table (before other entries with same hash) */ \
+  for (ee = prefix##_hash(pr, hfun(e));  \
+       is_used((*ee)); \
+       ee = prefix##_next(pr, ee)) \
+    *ee = e, e = e0; \
+  *ee = e; \
+} \
+\
+HTABLE2_SCOPE \
+int prefix##_remove(type *pr, entrytype const e) \
+{ \
+  unsigned i, j, k, size = pr->pr##size; \
+  entrytype *htable = pr->pr##table; \
+\
+  /* Search for entry */ \
+  for (i = hfun(e) % size; is_used(htable[i]); i = (i + 1) % size) \
+    if (is_equal(e, htable[i])) \
+      break; \
+\
+  assert(is_used(htable[i])); if (!is_used(htable[i])) return -1; \
+\
+  /* Move table entries towards their primary place  */ \
+  for (j = (i + 1) % size; is_used(htable[j]); j = (j + 1) % size) { \
+    /* k is primary place for entry */ \
+    k = hfun(htable[j]) % size; \
+    if (k == j)			/* entry is in its primary place? */ \
+      continue; \
+    /* primary place is between i and j - do not move this to i */ \
+    if (j > i ? (i < k && k < j) : (i < k || k < j)) \
+      continue; \
+\
+    htable[i] = htable[j], i = j; \
+  } \
+\
+  pr->pr##used--; \
+\
+  reclaim(&htable[i]); \
+\
+  return 0; \
+} \
+extern int const prefix##_dummy
+
+#endif /** !defined(HTABLE2_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,673 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef RBTREE_H
+/** Defined when <sofia-sip/rbtree.h> has been included. */
+#define RBTREE_H 
+
+/**@file sofia-sip/rbtree.h
+ *
+ * Red-black tree.
+ *
+ * This file contain a red-black-tree template for C. The red-black-tree is
+ * a balanced binary tree containing structures as nodes. 
+ *
+ * The prototypes for red-black-tree functions are declared with macro
+ * RBTREE_PROTOS(). The implementation is instantiated with macro
+ * RBTREE_BODIES().
+ *
+ * When a entry with new identical key is added to the tree, it can be
+ * either @e inserted (replacing other node with same key value) or @e
+ * appended.
+ * 
+ * Example code can be found from <rbtree_test.c>.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Sep  7 19:45:11 EEST 2004 ppessi
+ *
+ */
+
+#if DOCUMENTATION_ONLY
+/** Type used for rbtree nodes. */
+typedef struct node Type;
+#endif
+
+  /*               x                c
+   *              / \              / \
+   * Convert     a   c    into    x   d
+   *                / \          / \
+   *               b   d        a   b
+   */
+
+#define RBTREE_LEFT_ROTATE(prefix, Type, left, right, parent)	\
+static inline \
+void prefix ## _left_rotate(Type **top, Type *x)   \
+{						   \
+  Type *c = right(x), *dad = parent(x); assert(c); \
+  						   \
+  if ((right(x) = left(c)))			   \
+    parent(right(x)) = x;			   \
+						   \
+  if (!(parent(c) = dad))			   \
+    *top = c;					   \
+  else if (left(dad) == x)			   \
+    left(dad) = c;				   \
+  else						   \
+    assert(right(dad) == x), right(dad) = c;	   \
+						   \
+  left(c) = x;					   \
+  parent(x) = c;				   \
+} \
+extern int const prefix##_dummy 
+
+  /*               x                c
+   *              / \              / \
+   * Convert     c   f    into    a   x
+   *            / \                  / \
+   *           a   d                d   f
+   */
+
+#define RBTREE_RIGHT_ROTATE(prefix, Type, left, right, parent)	\
+static inline \
+void prefix ## _right_rotate(Type **top, Type *x)	\
+{							\
+  Type *c = left(x), *dad = parent(x); assert(c);	\
+							\
+  if ((left(x) = right(c)))				\
+    parent(left(x)) = x;				\
+							\
+  if (!(parent(c) = dad))				\
+    *top = c;						\
+  else if (right(dad) == x)				\
+    right(dad) = c;					\
+  else							\
+    assert(left(dad) == x), left(dad) = c;		\
+							\
+  right(c) = x;						\
+  parent(x) = c;					\
+} \
+extern int const prefix##_dummy
+
+#define RBTREE_BALANCE_INSERT1(prefix, Type, left, right, parent, IS_RED, SET_RED, IS_BLACK, SET_BLACK)				\
+static inline								\
+void prefix ## _balance_insert(Type **top, Type *node)			\
+{									\
+  Type *dad, *uncle, *granddad;						\
+} \
+extern int const prefix##_dummy
+
+
+/* Balance Red-Black binary tree after inserting node @a n.
+ *
+ * The function red_black_balance_insert() balances a red-black tree after
+ * insertion.
+ *
+ * RED(node) - set node as red
+ */
+#define RBTREE_BALANCE_INSERT(prefix, Type, left, right, parent, IS_RED, SET_RED, IS_BLACK, SET_BLACK)				\
+static inline								\
+void prefix ## _balance_insert(Type **top, Type *node)			\
+{									\
+  Type *dad, *uncle, *granddad;						\
+									\
+  SET_RED(node);							\
+									\
+  for (dad = parent(node); node != *top && IS_RED(dad); dad = parent(node)) { \
+    /* Repeat until we are parent or we have a black dad */		\
+    granddad = parent(dad); assert(granddad);				\
+    if (dad == left(granddad)) {					\
+      uncle = right(granddad);						\
+      if (IS_RED(uncle)) {						\
+	SET_BLACK(dad); SET_BLACK(uncle); SET_RED(granddad);		\
+	node = granddad;						\
+      } else {								\
+	if (node == right(dad)) {					\
+	  prefix##_left_rotate(top, node = dad);			\
+	  dad = parent(node); assert(dad);				\
+	  granddad = parent(dad); assert(granddad);			\
+	}								\
+	SET_BLACK(dad);							\
+	SET_RED(granddad);						\
+	prefix##_right_rotate(top, granddad);				\
+      }									\
+    } else { assert(dad == right(granddad));				\
+      uncle = left(granddad);						\
+      if (IS_RED(uncle)) {						\
+	SET_BLACK(dad); SET_BLACK(uncle); SET_RED(granddad);		\
+	node = granddad;						\
+      } else {								\
+	if (node == left(dad)) {					\
+	  prefix##_right_rotate(top, node = dad);			\
+	  dad = parent(node); assert(dad);				\
+	  granddad = parent(dad); assert(granddad);			\
+	}								\
+	SET_BLACK(dad);							\
+	SET_RED(granddad);						\
+	prefix##_left_rotate(top, granddad);				\
+      }									\
+    }									\
+  }									\
+									\
+  assert(*top);								\
+									\
+  SET_BLACK((*top));							\
+} \
+extern int const prefix##_dummy
+
+#define RBTREE_BALANCE_DELETE(prefix, Type, left, right, parent,	\
+			      IS_RED, SET_RED, IS_BLACK, SET_BLACK,	\
+                              COPY_COLOR)				\
+static inline								\
+void prefix##_balance_delete(Type **top, Type *node)			\
+{									\
+  Type *dad, *brother;							\
+									\
+  for (dad = parent(node); node != *top && IS_RED(dad); dad = parent(node)) { \
+    if (node == left(dad)) {						\
+      brother = right(dad);						\
+									\
+      if (!brother) {							\
+	node = dad;							\
+	continue;							\
+      }									\
+									\
+      assert(IS_BLACK(brother));					\
+									\
+      if (IS_BLACK(left(brother)) && IS_BLACK(right(brother))) {	\
+	SET_RED(brother);						\
+	node = dad;							\
+	continue;							\
+      }									\
+									\
+      if (IS_BLACK(right(brother))) {					\
+	SET_RED(brother);						\
+	SET_BLACK(left(brother));					\
+	prefix##_right_rotate(top, brother);				\
+	brother = right(dad);						\
+      }									\
+									\
+      COPY_COLOR(brother, dad);						\
+      SET_BLACK(dad);							\
+      if (right(brother))						\
+	SET_BLACK(right(brother));					\
+      prefix##_left_rotate(top, dad);					\
+      node = *top;							\
+      break;								\
+    } else {								\
+      assert(node == right(dad));					\
+									\
+      brother = left(dad);						\
+									\
+      if (!brother) {							\
+	node = dad;							\
+	continue;							\
+      }									\
+									\
+      assert(IS_BLACK(brother));					\
+									\
+      if (IS_BLACK(left(brother)) && IS_BLACK(right(brother))) {	\
+	SET_RED(brother);						\
+	node = dad;							\
+	continue;							\
+      }									\
+									\
+      if (IS_BLACK(left(brother))) {					\
+	SET_BLACK(right(brother));					\
+	SET_RED(brother);						\
+	prefix##_left_rotate(top, brother);				\
+	brother = left(dad);						\
+      }									\
+									\
+      COPY_COLOR(brother, parent(node));				\
+      SET_BLACK(parent(node));						\
+      if (left(brother))						\
+	SET_BLACK(left(brother));					\
+      prefix##_right_rotate(top, dad);					\
+      node = *top;							\
+      break;								\
+    }									\
+  }									\
+									\
+  SET_BLACK(node);							\
+}  \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/**Insert a @a node into the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be inserted
+ * @param return_old return value parameter for matching node 
+ *                   already in the @a tree
+ *
+ * @retval 0 if node was inserted
+ * @retval -1 if there already was an matching node 
+ *            and return_old is NULL.
+ */
+int rbtree_insert(Type **tree, Type *node, Type **return_old);
+#endif
+
+/* Insert node into tree. */
+#define RBTREE_INSERT(SCOPE, prefix, Type, left, right, parent,		\
+		      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	\
+		      CMP, REMOVE, INSERT)				\
+SCOPE									\
+int prefix ## _insert(Type **const tree,				\
+	 	      Type * const node,				\
+		      Type **return_old)				\
+{									\
+  Type *old, *dad, **slot;						\
+									\
+  if (tree == NULL || node == NULL) return -1;				\
+									\
+  for (slot = tree, old = *slot, dad = NULL; old; old = *slot) {	\
+    int result = CMP(node, old);					\
+    if (result < 0)							\
+      dad = old, slot = &(left(old));					\
+    else if (result > 0)						\
+      dad = old, slot = &(right(old));					\
+    else								\
+      break;								\
+  }									\
+									\
+  if (old == node)							\
+    old = NULL;								\
+  else if (old) {							\
+    if (!return_old) return -1;						\
+									\
+    if ((left(node) = left(old)))					\
+      parent(left(node)) = node;					\
+    if ((right(node) = right(old)))					\
+      parent(right(node)) = node;					\
+									\
+    if (!(parent(node) = parent(old)))					\
+      *tree = node;							\
+    else if (left(parent(node)) == old)					\
+      left(parent(node)) = node;					\
+    else assert(right(parent(node)) == old),				\
+      right(parent(node)) = node;					\
+									\
+    COPY_COLOR(node, old);						\
+									\
+    REMOVE(old);							\
+									\
+  } else {								\
+    *slot = node;							\
+    parent(node) = dad;							\
+									\
+    if (tree != slot) {							\
+      prefix##_balance_insert(tree, node);				\
+    } else {								\
+      SET_BLACK(node);							\
+    }									\
+  }									\
+									\
+  INSERT(node);								\
+									\
+  if (return_old)							\
+    *return_old = old;							\
+									\
+  return 0;								\
+}  \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Append @a a node into the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be appended
+ *
+ * @retval 0 when successful (always)
+ */
+int rbtree_append(Type ** tree,
+		  Type *  node);
+#endif
+
+/* Define function appending a node into the tree */
+#define RBTREE_APPEND(SCOPE, prefix, Type, left, right, parent,		\
+		      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	\
+		      CMP, REMOVE, INSERT)				\
+SCOPE									\
+int prefix ## _append(Type **const tree,				\
+	 	      Type * const node)				\
+{									\
+  Type *old, *dad, **slot;						\
+									\
+  if (tree == NULL || node == NULL) return -1;				\
+									\
+  for (slot = tree, old = *slot, dad = NULL; old; old = *slot) {	\
+    if (old == node)							\
+      return 0;								\
+    if (CMP(node, old) < 0)						\
+      dad = old, slot = &(left(old));					\
+    else								\
+      dad = old, slot = &(right(old));					\
+  }									\
+									\
+  *slot = node;								\
+  parent(node) = dad;							\
+									\
+  if (tree != slot) {							\
+    prefix##_balance_insert(tree, node);				\
+  } else {								\
+    SET_BLACK(node);							\
+  }									\
+									\
+  INSERT(node);								\
+									\
+  return 0;								\
+}  \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Remove a @a node from the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be appended
+ */
+void rbtree_remove(Type **tree, Type *node);				
+#endif
+
+#define RBTREE_REMOVE(SCOPE, prefix, Type, left, right, parent,		\
+		      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+		      REMOVE, INSERT)					\
+SCOPE									\
+void prefix##_remove(Type **top, Type *node)				\
+{									\
+  Type *kid, *dad;							\
+  int need_to_balance;							\
+									\
+  if (top == NULL || node == NULL)					\
+    return;								\
+									\
+  /* Make sure that node is in tree */					\
+  for (dad = node; dad; dad = parent(dad))				\
+    if (dad == *top)							\
+      break;								\
+									\
+  if (!dad) return;							\
+									\
+  /* Find a successor node with a free branch */			\
+  if (!left(node) || !right(node))					\
+    dad = node;								\
+  else for (dad = right(node); left(dad); dad = left(dad))		\
+    ;									\
+  /* Dad has a free branch => kid is dad's only child */		\
+  kid = left(dad) ? left(dad) : right(dad);				\
+									\
+  /* Remove dad from tree */						\
+  if (!(parent(dad)))							\
+    *top = kid;								\
+  else if (left(parent(dad)) == dad)					\
+    left(parent(dad)) = kid;						\
+  else assert(right(parent(dad)) == dad),				\
+    right(parent(dad)) = kid;						\
+  if (kid)								\
+    parent(kid) = parent(dad);						\
+									\
+  need_to_balance = kid && IS_BLACK(dad);				\
+									\
+  /* Put dad in place of node */					\
+  if (node != dad) {							\
+    if (!(parent(dad) = parent(node)))					\
+      *top = dad;							\
+    else if (left(parent(dad)) == node)					\
+      left(parent(dad)) = dad;						\
+    else assert(right(parent(dad)) == node),				\
+      right(parent(dad)) = dad;						\
+									\
+    COPY_COLOR(dad, node);						\
+									\
+    if ((left(dad) = left(node)))					\
+      parent(left(dad)) = dad;						\
+									\
+    if ((right(dad) = right(node)))					\
+      parent(right(dad)) = dad;						\
+  }									\
+									\
+  REMOVE(node);								\
+  SET_RED(node);							\
+									\
+  if (need_to_balance)							\
+    prefix##_balance_delete(top, kid);					\
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return inorder successor of node @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to successor, or NULL if @a node was last.
+ */
+Type *rbtree_succ(Type const *node);
+#endif
+
+/* Define function returning inorder successor of node @a node. */
+#define RBTREE_SUCC(SCOPE, prefix, Type, left, right, parent)	\
+SCOPE Type *prefix##_succ(Type const *node)				\
+{									\
+  Type const *dad;							\
+									\
+  if (right(node)) {							\
+    for (node = right(node); left(node); node = left(node))		\
+      ;									\
+    return (Type *)node;						\
+  }									\
+									\
+  for (dad = parent(node); dad && node == right(dad); dad = parent(node)) \
+    node = dad;								\
+									\
+  return (Type *)dad;							\
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return inorder precedessor of node @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to precedessor, or NULL if @a node was first.
+ */
+Type *rbtree_prec(Type const *node);
+#endif
+
+/* Define function returning inorder precedessor of node @a node. */
+#define RBTREE_PREC(SCOPE, prefix, Type, left, right, parent)	\
+  SCOPE Type *prefix##_prec(Type const *node)				\
+{									\
+  Type const *dad;							\
+									\
+  if (left(node)) {							\
+    for (node = left(node); right(node); node = right(node))		\
+      ;									\
+    return (Type *)node;						\
+  }									\
+									\
+  for (dad = parent(node); dad && node == left(dad); dad = parent(node)) \
+    node = dad;								\
+									\
+  return (Type *)dad;							\
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return first node in the tree to which @a node belongs to.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to first node.
+ */
+Type *rbtree_first(Type const *node);
+#endif
+
+/* Define function returning first node in tree @a node. */
+#define RBTREE_FIRST(SCOPE, prefix, Type, left, right, parent)	\
+SCOPE Type *prefix##_first(Type const *node)    \
+{						\
+  while (node && left(node))			\
+    node = left(node);				\
+						\
+  return (Type *)node;				\
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return last node in the tree to which @a node belongs to.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to last node.
+ */
+Type *rbtree_last(Type const *node);
+#endif
+
+/* Define function returning last node in tree @a node. */
+#define RBTREE_LAST(SCOPE, prefix, Type, left, right, parent)	\
+SCOPE Type *prefix##_last(Type const *node)	\
+{						\
+  while (node && right(node))			\
+    node = right(node);				\
+						\
+  return (Type *)node;				\
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return height of the tree below @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Height of the tree.
+ */
+int rbtree_height(Type const *node);
+#endif
+
+/* Define function returning height of the tree from the @a node. */
+#define RBTREE_HEIGHT(SCOPE, prefix, Type, getleft, getright, getparent)	\
+SCOPE int prefix##_height(Type const *node)			\
+{								\
+  int left, right;						\
+								\
+  if (!node)							\
+    return 0;							\
+								\
+  left = getleft(node) ? prefix##_height(getleft(node)) : 0;	\
+  right = getright(node) ? prefix##_height(getright(node)) : 0;	\
+								\
+  if (left > right)						\
+    return left + 1;						\
+  else								\
+    return right + 1;						\
+} \
+extern int const prefix##_dummy
+
+/** Define prototypes for red-black tree functions. @HIDE 
+ *
+ * @param SCOPE function scope (e.g., static inline)
+ * @param prefix function prefix (e.g., rbtree)
+ * @param Type node type
+ *
+ * @par Example
+ * @code
+ * RBTREE_PROTOS(static inline, rbtree, struct node);
+ * @endcode
+ */
+#define RBTREE_PROTOS(SCOPE, prefix, Type)				\
+  SCOPE int prefix ## _insert(Type **, Type *, Type **return_old);	\
+  SCOPE int prefix ## _append(Type **, Type *);				\
+  SCOPE void prefix ## _remove(Type **, Type *);			\
+  SCOPE Type *prefix ## _succ(Type const *);				\
+  SCOPE Type *prefix ## _prec(Type const *);				\
+  SCOPE Type *prefix ## _first(Type const *);				\
+  SCOPE Type *prefix ## _last(Type const *);				\
+  SCOPE int prefix ## _height(Type const *)
+
+/** Define bodies for red-black tree functions. @HIDE 
+ *
+ * @param SCOPE function scope (e.g., static inline)
+ * @param prefix function prefix (e.g., rbtree)
+ * @param Type node type
+ * @param left accessor of left node 
+ * @param right accessor of right node
+ * @param parent accessor of parent node
+ * @param IS_RED predicate testing if node is red
+ * @param SET_RED setter marking node as red
+ * @param IS_BLACK predicate testing if node is black
+ * @param SET_BLACK setter marking node as black
+ * @param COPY_COLOR method copying color from node to another
+ * @param CMP method comparing two nodes
+ * @param INSERT setter marking node as inserted to the tree
+ * @param REMOVE method marking node as removed and possibly deleting node
+ * 
+ * @par Example
+ *
+ * @code
+ * #define LEFT(node) ((node)->left)
+ * #define RIGHT(node) ((node)->right)
+ * #define PARENT(node) ((node)->parent)
+ * #define SET_RED(node) ((node)->black = 0)
+ * #define SET_BLACK(node) ((node)->black = 1)
+ * #define CMP(a, b) ((a)->value - (b)->value)
+ * #define IS_RED(node) ((node) && (node)->black == 0)
+ * #define IS_BLACK(node) (!(node) || (node)->black == 1)
+ * #define COPY_COLOR(dst, src) ((dst)->black = (src)->black)
+ * #define INSERT(node) ((node)->inserted = 1)
+ * #define REMOVE(node) ((node)->left = (node)->right = (node)->parent = NULL, \
+ *                       (node)->inserted = 0)
+ * 
+ * RBTREE_BODIES(static inline, rbtree, struct node,
+ *               LEFT, RIGHT, PARENT,
+ *               IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+ *               CMP, INSERT, REMOVE);
+ * @endcode
+ */
+#define RBTREE_BODIES(SCOPE, prefix, Type,				\
+		      left, right, parent,				\
+		      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+		      CMP, INSERT, REMOVE)				\
+  RBTREE_LEFT_ROTATE(prefix, Type, left, right, parent);		\
+  RBTREE_RIGHT_ROTATE(prefix, Type, left, right, parent);		\
+  RBTREE_BALANCE_INSERT(prefix, Type, left, right, parent,		\
+			IS_RED, SET_RED, IS_BLACK, SET_BLACK);		\
+  RBTREE_BALANCE_DELETE(prefix, Type, left, right, parent,		\
+			IS_RED, SET_RED, IS_BLACK, SET_BLACK,		\
+			COPY_COLOR);					\
+  RBTREE_INSERT(SCOPE, prefix, Type, left, right, parent,		\
+		IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	\
+		CMP, REMOVE, INSERT);					\
+  RBTREE_APPEND(SCOPE, prefix, Type, left, right, parent,		\
+		IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	\
+		CMP, REMOVE, INSERT);					\
+  RBTREE_REMOVE(SCOPE, prefix, Type, left, right, parent,		\
+		IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	\
+		REMOVE, INSERT);					\
+  RBTREE_SUCC(SCOPE, prefix, Type, left, right, parent);		\
+  RBTREE_PREC(SCOPE, prefix, Type, left, right, parent);		\
+  RBTREE_FIRST(SCOPE, prefix, Type, left, right, parent);		\
+  RBTREE_LAST(SCOPE, prefix, Type, left, right, parent);		\
+  RBTREE_HEIGHT(SCOPE, prefix, Type, left, right, parent)
+
+#endif /* !define(RBTREE_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,476 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_H
+/** Defined when <sofia-sip/su.h> has been included. */
+#define SU_H
+/**@ingroup su_socket 
+ * @file sofia-sip/su.h Socket and network address interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+#ifndef SU_ERRNO_H
+#include <sofia-sip/su_errno.h>
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if SU_HAVE_BSDSOCK		/* Unix-compatible includes */
+#include <errno.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#if SU_HAVE_WINSOCK		/* Windows includes */
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+
+#  if defined(IPPROTO_IPV6)
+/* IPv6 defined in ws2tcpip.h */
+#  elif SU_HAVE_IN6 
+#    include <tpipv6.h>		/* From "IPv6 Tech Preview"  */
+#  else
+#    error Winsock with IPv6 support required
+#  endif
+
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* Constant definitions */
+
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+enum {
+  /** Invalid socket descriptor, error from socket() or accept() */ 
+  INVALID_SOCKET = -1,
+#define INVALID_SOCKET ((su_socket_t)INVALID_SOCKET)
+  /** Error from other socket calls */
+  SOCKET_ERROR = -1,
+#define SOCKET_ERROR SOCKET_ERROR
+  /** Return code for a successful call */
+  su_success = 0, 
+  /** Return code for an unsuccessful call */
+  su_failure = -1
+};
+#elif SU_HAVE_WINSOCK
+enum { 
+  su_success = 0, 
+  su_failure = 0xffffffffUL 
+};
+
+#define MSG_NOSIGNAL (0)
+
+#endif
+
+/**@HI Maximum size of host name. */
+#define SU_MAXHOST (1025)
+/**@HI Maximum size of service name. */
+#define SU_MAXSERV (25)
+
+/**@HI Maximum size of address in text format. */
+#define SU_ADDRSIZE (48)
+/**@HI Maximum size of port number in text format. */
+#define SU_SERVSIZE (16)
+
+#define SU_SUCCESS su_success
+#define SU_FAILURE su_failure
+
+/* ---------------------------------------------------------------------- */
+/* Type definitions */
+
+/** Socket descriptor type. */
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+typedef int su_socket_t;
+#elif SU_HAVE_WINSOCK
+typedef SOCKET su_socket_t;
+#endif
+
+#if !SU_HAVE_SOCKADDR_STORAGE
+/*
+ * RFC 2553: protocol-independent placeholder for socket addresses
+ */
+#define _SS_MAXSIZE	128
+#define _SS_ALIGNSIZE	(sizeof(int64_t))
+#define _SS_PAD1SIZE	(_SS_ALIGNSIZE - sizeof(u_char) * 2)
+#define _SS_PAD2SIZE	(_SS_MAXSIZE - sizeof(u_char) * 2 - \
+				_SS_PAD1SIZE - _SS_ALIGNSIZE)
+
+struct sockaddr_storage {
+#if SU_HAVE_SOCKADDR_SA_LEN
+	unsigned char ss_len;		/* address length */
+	unsigned char ss_family;	/* address family */
+#else
+	unsigned short ss_family;	/* address family */
+#endif
+	char	__ss_pad1[_SS_PAD1SIZE];
+	int64_t __ss_align;	/* force desired structure storage alignment */
+	char	__ss_pad2[_SS_PAD2SIZE];
+};
+#endif
+
+/** Common socket address structure. */
+union su_sockaddr_u {
+#ifdef DOCUMENTATION_ONLY
+  uint8_t             su_len;         /**< Length of structure */
+  uint8_t             su_family;      /**< Address family. */
+  uint16_t            su_port;        /**< Port number. */
+#else
+  short               su_dummy;	      /**< Dummy member to initialize */
+#if SU_HAVE_SOCKADDR_SA_LEN
+#define               su_len          su_sa.sa_len
+#define               su_family       su_sa.sa_family
+#else
+#define               su_len          su_array[0]
+  short               su_family;
+#endif
+#define               su_port         su_sin.sin_port  
+#endif
+
+  char                su_array[32];   /**< Presented as chars */
+  uint16_t            su_array16[16]; /**< Presented as 16-bit ints */
+  uint32_t            su_array32[8];  /**< Presented as 32-bit ints */
+  struct sockaddr     su_sa;          /**< Address in struct sockaddr format */
+  struct sockaddr_in  su_sin;         /**< Address in IPv4 format */
+#if SU_HAVE_IN6
+  struct sockaddr_in6 su_sin6;        /**< Address in IPv6 format */
+#endif
+#ifdef DOCUMENTATION_ONLY
+  uint32_t            su_scope_id;    /**< Scope ID. */
+#else
+#define               su_scope_id     su_array32[6]
+#endif
+};
+
+typedef union su_sockaddr_u su_sockaddr_t;
+
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+/**Type of @a siv_len field in #su_iovec_t.
+ *
+ * The @a siv_len field in #su_iovec_t has different types in with POSIX
+ * (size_t) and WINSOCK2 (u_long). Truncate the iovec element size to
+ * #SU_IOVECLEN_MAX, if needed, and cast using #su_ioveclen_t.
+ *
+ * @sa #su_iovec_t, #SU_IOVECLEN_MAX
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef size_t su_ioveclen_t;
+
+/** I/O vector for scatter-gather I/O.
+ *
+ * This is the I/O vector element used with su_vsend() and su_vrecv(). It is
+ * defined like struct iovec with POSIX sockets:
+ * @code
+ * struct iovec {
+ *    void *iov_base;	// Pointer to data.
+ *    size_t iov_len;	// Length of data.
+ * };
+ * @endcode
+ *
+ * When using WINSOCK sockets it is defined as
+ * <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
+ * WSABUF</a>:
+ * @code
+ * typedef struct __WSABUF {
+ *   u_long len;
+ *   char FAR* buf;
+ * } WSABUF, *LPWSABUF;
+ * @endcode
+ *
+ * @note Ordering of the fields is reversed on Windows. Do not initialize this
+ * structure with static initializer, but assign both fields separately.
+ *
+ * For historical reasons, the structure is known as #msg_iovec_t in @msg
+ * module.
+ *
+ * @sa #su_iovec_t, #su_ioveclen_t, SU_IOVECLEN_MAX, su_vsend(), su_vrecv(), 
+ * #msg_iovec_t, msg_iovec(), msg_recv_iovec(), 
+ * @c struct @c iovec defined in <sys/uio.h>, writev(2), readv(2),
+ * sendmsg(), recvmsg(),
+ * <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
+ * WSABUF of WinSock2</a>
+ */
+typedef struct su_iovec_s {
+  void  *siv_base;		/**< Pointer to buffer. */
+  su_ioveclen_t siv_len;		/**< Size of buffer.  */
+} su_iovec_t;
+
+/** Maximum size of buffer in a single su_iovec_t element. 
+ * @sa #su_ioveclen_t, #su_iovec_t
+ *
+ * @since New in @VERSION_1_12_2.
+ * @HIDE
+ */
+#define SU_IOVECLEN_MAX SIZE_MAX
+#endif
+
+#if SU_HAVE_WINSOCK
+typedef u_long su_ioveclen_t;
+
+/* This is same as WSABUF */
+typedef struct su_iovec_s {
+  su_ioveclen_t  siv_len;
+  void   *siv_base;
+} su_iovec_t;
+
+#define SU_IOVECLEN_MAX ULONG_MAX
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Socket compatibility functions */
+
+SOFIAPUBFUN int su_init(void);
+SOFIAPUBFUN void su_deinit(void);
+
+/** Create an endpoint for communication. */
+SOFIAPUBFUN su_socket_t su_socket(int af, int sock, int proto);
+/** Close an socket descriptor. */
+SOFIAPUBFUN int su_close(su_socket_t s);
+/** Control socket. */
+SOFIAPUBFUN int su_ioctl(su_socket_t s, int request, ...);
+
+/** Checks if the @a errcode indicates that the socket call failed because
+ * it would have blocked.
+ *
+ * Defined as macro with POSIX sockets.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN int su_is_blocking(int errcode);
+
+/** Set/reset blocking option. */ 
+SOFIAPUBFUN int su_setblocking(su_socket_t s, int blocking);
+/** Set/reset address reusing option. */
+SOFIAPUBFUN int su_setreuseaddr(su_socket_t s, int reuse);
+/** Get the error code associated with the socket. */
+SOFIAPUBFUN int su_soerror(su_socket_t s);
+/** Get size of message available in socket. */
+SOFIAPUBFUN issize_t su_getmsgsize(su_socket_t s);
+
+/** Scatter-gather send. */
+SOFIAPUBFUN
+issize_t su_vsend(su_socket_t, su_iovec_t const iov[], isize_t len, int flags,
+		  su_sockaddr_t const *su, socklen_t sulen);
+/** Scatter-gather receive. */
+SOFIAPUBFUN
+issize_t su_vrecv(su_socket_t, su_iovec_t iov[], isize_t len, int flags,
+		  su_sockaddr_t *su, socklen_t *sulen);
+/** Return local IP address */
+SOFIAPUBFUN int su_getlocalip(su_sockaddr_t *sin);
+
+#if SU_HAVE_BSDSOCK
+#define su_ioctl  ioctl
+/*
+ * Note: before 1.12.2, there was su_isblocking() which did not take argument
+ * and which was missing from WINSOCK 
+ */
+#define su_is_blocking(e) \
+  ((e) == EINPROGRESS || (e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif
+
+#if SU_HAVE_WINSOCK
+SOFIAPUBFUN int inet_pton(int af, char const *src, void *dst);
+SOFIAPUBFUN const char *inet_ntop(int af, void const *src,
+				  char *dst, size_t size);
+SOFIAPUBFUN ssize_t 
+  su_send(su_socket_t s, void *buffer, size_t length, int flags),
+  su_sendto(su_socket_t s, void *buffer, size_t length, int flags,
+	    su_sockaddr_t const *to, socklen_t tolen),
+  su_recv(su_socket_t s, void *buffer, size_t length, int flags),
+  su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
+	      su_sockaddr_t *from, socklen_t *fromlen);
+
+static __inline
+uint16_t su_ntohs(uint16_t s)
+{
+  return (uint16_t)(((s & 255) << 8) | ((s & 0xff00) >> 8));
+}
+
+static __inline
+uint32_t su_ntohl(uint32_t l)
+{
+  return ((l & 0xff) << 24) | ((l & 0xff00) << 8)
+       | ((l & 0xff0000) >> 8) | ((l & 0xff000000U) >> 24);
+}
+
+#define ntohs su_ntohs
+#define htons su_ntohs
+#define ntohl su_ntohl
+#define htonl su_ntohl
+
+#else
+#define su_send(s,b,l,f) send((s),(b),(l),(f))
+#define su_sendto(s,b,l,f,a,L) sendto((s),(b),(l),(f),(void const*)(a),(L))
+#define su_recv(s,b,l,f) recv((s),(b),(l),(f))
+#define su_recvfrom(s,b,l,f,a,L) recvfrom((s),(b),(l),(f),(void *)(a),(L))
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Other compatibility stuff */
+
+#if SU_HAVE_WINSOCK
+#define getuid() (0x505)
+#endif
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP (132)
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Address manipulation macros */
+
+/**@HI Get pointer to address field.
+ *
+ * The macro SU_ADDR() returns pointer to the address field (sin_data,
+ * sin_addr or sin_addr6, depending on the address family).
+ */
+#if SU_HAVE_IN6
+#define SU_ADDR(su) \
+  ((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
+  ((su)->su_family == AF_INET6 ? (void *)&(su)->su_sin6.sin6_addr : \
+  (void *)&(su)->su_sa.sa_data))
+#else
+#define SU_ADDR(su) \
+  ((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
+  (void *)&(su)->su_sa.sa_data)
+#endif
+
+/**@HI Get length of address field.
+ *
+ * The macro SU_ADDRLEN() returns length of the address field (sin_data,
+ * sin_addr or sin_addr6, depending on the address family).
+ */
+#if SU_HAVE_IN6
+#define SU_ADDRLEN(su)					\
+  ((su)->su_family == AF_INET				\
+   ? (socklen_t)sizeof((su)->su_sin.sin_addr) :		\
+   ((su)->su_family == AF_INET6				\
+    ? (socklen_t)sizeof((su)->su_sin6.sin6_addr)	\
+    : (socklen_t)sizeof((su)->su_sa.sa_data)))
+#else
+#define SU_ADDRLEN(su)					\
+  ((su)->su_family == AF_INET				\
+   ? (socklen_t)sizeof((su)->su_sin.sin_addr)		\
+   : (socklen_t)sizeof((su)->su_sa.sa_data))
+#endif
+
+/**@HI Test if su_sockaddr_t is INADDR_ANY or IN6ADDR_ANY. */
+#if SU_HAVE_IN6
+#define SU_HAS_INADDR_ANY(su) \
+  ((su)->su_family == AF_INET \
+   ? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) \
+   : ((su)->su_family == AF_INET6 \
+      ? (memcmp(&(su)->su_sin6.sin6_addr, su_in6addr_any(), \
+		sizeof(*su_in6addr_any())) == 0) : 0))
+#else
+#define SU_HAS_INADDR_ANY(su) \
+  ((su)->su_family == AF_INET \
+  ? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) : 0)
+#endif
+
+#define SU_SOCKADDR_INADDR_ANY(su) SU_HAS_INADDR_ANY(su)
+
+/**@HI Calculate correct size of su_sockaddr_t structure. */ 
+#if SU_HAVE_IN6
+#define SU_SOCKADDR_SIZE(su) \
+  ((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin)	  \
+	       : ((su)->su_family == AF_INET6 ? sizeof((su)->su_sin6)	\
+		  : sizeof(*su))))
+#else
+#define SU_SOCKADDR_SIZE(su) \
+  ((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin)	\
+	       : sizeof(*su)))
+#endif
+#define su_sockaddr_size SU_SOCKADDR_SIZE
+
+#if SU_HAVE_IN6
+#if SU_HAVE_BSDSOCK
+#define su_in6addr_any()         (&in6addr_any)
+#define su_in6addr_loopback()    (&in6addr_loopback)
+#define SU_IN6ADDR_ANY_INIT      IN6ADDR_ANY_INIT
+#define SU_IN6ADDR_LOOPBACK_INIT IN6ADDR_LOOPBACK_INIT
+#endif
+#if SU_HAVE_WINSOCK || DOCUMENTATION_ONLY
+SOFIAPUBVAR const struct in_addr6 *su_in6addr_any(void);
+SOFIAPUBVAR const struct in_addr6 *su_in6addr_loopback(void);
+#define SU_IN6ADDR_ANY_INIT      { 0 }
+#define SU_IN6ADDR_LOOPBACK_INIT { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }
+#endif
+#endif /* SU_HAVE_IN6 */
+
+#define SU_IN6_IS_ADDR_V4MAPPED(a) \
+  (((uint32_t const *) (a))[0] == 0 &&			      \
+   ((uint32_t const *) (a))[1] == 0 &&			      \
+   ((uint32_t const *) (a))[2] == htonl(0xffff))
+
+#define SU_IN6_IS_ADDR_V4COMPAT(a)			      \
+  (((uint32_t const *)(a))[0] == 0 &&			      \
+   ((uint32_t const *)(a))[1] == 0 &&			      \
+   ((uint32_t const *)(a))[2] == 0 &&			      \
+   ((uint32_t const *)(a))[3] != htonl(1) &&		      \
+   ((uint32_t const *)(a))[3] != htonl(0))
+
+SOFIAPUBFUN int su_cmp_sockaddr(su_sockaddr_t const *a,
+				su_sockaddr_t const *b);
+SOFIAPUBFUN int su_match_sockaddr(su_sockaddr_t const *a,
+				  su_sockaddr_t const *b);
+SOFIAPUBFUN void su_canonize_sockaddr(su_sockaddr_t *su);
+
+#if SU_HAVE_IN6
+#define SU_CANONIZE_SOCKADDR(su) \
+  ((su)->su_family == AF_INET6 ? su_canonize_sockaddr(su) : (void)0)
+#else
+#define SU_CANONIZE_SOCKADDR(su) \
+  ((void)0)
+#endif
+
+SOFIA_END_DECLS
+
+#ifndef SU_ADDRINFO_H
+#include <sofia-sip/su_addrinfo.h>
+#endif
+
+#endif /* !defined(SU_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SU_ADDRINFO_H
+/* Defined when <sofia-sip/su_addrinfo.h> has been included */
+#define SU_ADDRINFO_H
+/**@ingroup su_socket 
+ *
+ * @file sofia-sip/su_addrinfo.h Network address and service translation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Nov 30 17:07:04 EET 2005 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if !SU_HAVE_ADDRINFO
+/*
+ * Error return codes from getaddrinfo()
+ */
+#ifndef EAI_ADDRFAMILY
+#define	EAI_ADDRFAMILY	 1	/* address family for hostname not supported */
+#define	EAI_AGAIN	 2	/* temporary failure in name resolution */
+#define	EAI_BADFLAGS	 3	/* invalid value for ai_flags */
+#define	EAI_FAIL	 4	/* non-recoverable failure in name resolution */
+#define	EAI_FAMILY	 5	/* ai_family not supported */
+#define	EAI_MEMORY	 6	/* memory allocation failure */
+#define	EAI_NODATA	 7	/* no address associated with hostname */
+#define	EAI_NONAME	 8	/* hostname nor servname provided, or not known */
+#define	EAI_SERVICE	 9	/* servname not supported for ai_socktype */
+#define	EAI_SOCKTYPE	10	/* ai_socktype not supported */
+#define	EAI_SYSTEM	11	/* system error returned in errno */
+#define EAI_BADHINTS	12
+#define EAI_PROTOCOL	13
+#define EAI_MAX		14
+#endif
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#ifndef AI_PASSIVE
+#define	AI_PASSIVE	0x00000001 /* get address to use bind() */
+#define	AI_CANONNAME	0x00000002 /* fill ai_canonname */
+#define	AI_NUMERICHOST	0x00000004 /* prevent name resolution */
+/* valid flags for addrinfo */
+#define	AI_MASK		(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+
+#define	AI_ALL		0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
+#define	AI_V4MAPPED_CFG	0x00000200 /* accept IPv4-mapped if kernel supports */
+#define	AI_ADDRCONFIG	0x00000400 /* only if any address is assigned */
+#define	AI_V4MAPPED	0x00000800 /* accept IPv4-mapped IPv6 address */
+/* special recommended flags for getipnodebyname */
+#define	AI_DEFAULT	(AI_V4MAPPED_CFG | AI_ADDRCONFIG)
+#endif
+
+/*
+ * Constants for getnameinfo()
+ */
+#ifndef NI_MAXHOST
+#define	NI_MAXHOST	1025
+#define	NI_MAXSERV	32
+#endif
+
+/*
+ * Flag values for getnameinfo()
+ */
+#ifndef NI_NOFQDN
+#define	NI_NOFQDN	0x00000001
+#define	NI_NUMERICHOST	0x00000002
+#define	NI_NAMEREQD	0x00000004
+#define	NI_NUMERICSERV	0x00000008
+#define	NI_DGRAM	0x00000010
+#endif
+
+struct addrinfo {
+	int	ai_flags;	/* AI_PASSIVE, AI_CANONNAME */
+	int	ai_family;	/* PF_xxx */
+	int	ai_socktype;	/* SOCK_xxx */
+	int	ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+	size_t	ai_addrlen;	/* length of ai_addr */
+	char	*ai_canonname;	/* canonical name for hostname */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next structure in linked list */
+};
+#endif	/* SU_WITH_GETADDRINFO */
+
+#ifndef EAI_BADHINTS     
+#define EAI_BADHINTS	10012
+#endif
+#ifndef EAI_PROTOCOL  
+#define EAI_PROTOCOL	10013
+#endif
+
+#ifndef AI_MASK
+#define	AI_MASK		(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+#endif
+
+/** RFC 1576 address info structure. */
+typedef struct addrinfo su_addrinfo_t;
+
+/** Translate address and service. */
+SOFIAPUBFUN
+int su_getaddrinfo(char const *node, char const *service,
+		   su_addrinfo_t const *hints,
+		   su_addrinfo_t **res);
+/** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */
+SOFIAPUBFUN void su_freeaddrinfo(su_addrinfo_t *res);
+
+/** Return string describing address translation error. */
+SOFIAPUBFUN char const *su_gai_strerror(int errcode);
+
+union su_sockaddr_u;
+
+SOFIAPUBFUN
+int su_getnameinfo(const union su_sockaddr_u *su, size_t sulen,
+		   char *host, size_t hostlen,
+		   char *serv, size_t servlen,
+		   int flags);
+
+SOFIA_END_DECLS
+
+#endif	/* !defined(SU_ADDRINFO_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ALLOC_H  /** Defined when <sofia-sip/su_alloc.h> has been included. */
+#define SU_ALLOC_H
+
+/**@ingroup su_alloc
+ *
+ * @file sofia-sip/su_alloc.h Home-based memory management interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Aug 19 01:12:25 1999 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+#include <stdarg.h>
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_HOME_T
+#define SU_HOME_T struct su_home_s
+#endif
+
+/** Memory home type. */
+typedef SU_HOME_T su_home_t;
+typedef struct su_block_s su_block_t;
+
+/** Thread-locking function. @internal */
+typedef struct su_alock su_alock_t;
+
+/** Memory home structure */
+struct su_home_s { 
+  int         suh_size;
+  su_block_t *suh_blocks;
+  su_alock_t *suh_lock;
+};
+
+#define SU_HOME_INIT(obj) { 0, NULL, NULL }
+
+SU_DLL void *su_home_new(isize_t size)
+     __attribute__((__malloc__));
+SU_DLL void *su_home_ref(su_home_t const *);
+SU_DLL int su_home_unref(su_home_t *);
+
+SU_DLL size_t su_home_refcount(su_home_t *home);
+
+SU_DLL int su_home_destructor(su_home_t *, void (*)(void *));
+
+SU_DLL int su_home_desctructor(su_home_t *, void (*)(void *));
+#ifndef su_home_desctructor
+/* This has typo in before 1.12.4 */
+#define su_home_desctructor(home, destructor) \
+        su_home_destructor((home), (destructor))
+#endif
+
+SU_DLL void *su_home_clone(su_home_t *parent, isize_t size)
+     __attribute__((__malloc__));
+
+SU_DLL int  su_home_init(su_home_t *h);
+
+SU_DLL void su_home_deinit(su_home_t *h);
+
+SU_DLL void su_home_preload(su_home_t *h, isize_t n, isize_t size);
+
+SU_DLL su_home_t *su_home_auto(void *area, isize_t size);
+
+#define SU_HOME_AUTO_SIZE(n)				\
+  (((n) + ((sizeof(su_home_t) + 7) & (size_t)~8) +	\
+    ((3 * sizeof (void *) + 4 * sizeof(unsigned) +	\
+      7 * (sizeof (long) + sizeof(void *)) + 7) & (size_t)~8)) 	\
+    / sizeof(su_home_t))
+
+SU_DLL int su_home_move(su_home_t *dst, su_home_t *src);
+
+SU_DLL int su_home_threadsafe(su_home_t *home);
+
+SU_DLL int su_home_has_parent(su_home_t const *home);
+
+SU_DLL void su_home_check(su_home_t const *home);
+
+SU_DLL int su_home_mutex_lock(su_home_t *home);
+
+SU_DLL int su_home_mutex_unlock(su_home_t *home);
+
+SU_DLL void *su_alloc(su_home_t *h, isize_t size)
+     __attribute__((__malloc__));
+SU_DLL void *su_zalloc(su_home_t *h, isize_t size)
+     __attribute__((__malloc__));
+SU_DLL void *su_salloc(su_home_t *h, isize_t size)
+     __attribute__((__malloc__));
+SU_DLL void *su_realloc(su_home_t *h, void *data, isize_t size)
+     __attribute__((__malloc__));
+SU_DLL int su_in_home(su_home_t *h, void const *data);
+
+SU_DLL char *su_strdup(su_home_t *home, char const *s)
+     __attribute__((__malloc__));
+SU_DLL char *su_strcat(su_home_t *home, char const *s1, char const *s2)
+     __attribute__((__malloc__));
+SU_DLL char *su_strndup(su_home_t *home, char const *s, isize_t n)
+     __attribute__((__malloc__));
+
+SU_DLL char *su_strcat_all(su_home_t *home, ...)
+     __attribute__((__malloc__));
+
+SU_DLL char *su_sprintf(su_home_t *home, char const *fmt, ...)
+     __attribute__ ((__malloc__, __format__ (printf, 2, 3)));
+
+SU_DLL char *su_vsprintf(su_home_t *home, char const *fmt, va_list ap)
+     __attribute__((__malloc__));
+
+/* free an independent block */
+SU_DLL void su_free(su_home_t *h, void *);		
+
+/** Check if a memory home is threadsafe */
+SU_DLL int su_home_is_threadsafe(su_home_t const *home);
+
+/* ---------------------------------------------------------------------- */
+/* Deprecated */
+
+SU_DLL su_home_t *su_home_create(void)
+     __attribute__((__malloc__));
+SU_DLL void su_home_destroy(su_home_t *h);
+
+#define su_home_zap(h) su_home_unref((h))
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_ALLOC_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ALLOC_STAT_H
+/** Defined when <sofia-sip/su_alloc_stat.h> has been included. */
+#define SU_ALLOC_STAT_H 
+
+/**@ingroup su_alloc
+ *
+ * @file sofia-sip/su_alloc_stat.h Home-based memory management statistics
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Apr  9 10:24:05 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_home_stat_t su_home_stat_t;
+
+SU_DLL void su_home_init_stats(su_home_t *h);
+SU_DLL void su_home_get_stats(su_home_t *, int include_clones, 
+			      su_home_stat_t *stats, isize_t statssize);
+
+SU_DLL void su_home_stat_add(su_home_stat_t *total, 
+			     su_home_stat_t const *hs);
+
+struct su_home_stat_t
+{
+  int      hs_size;
+  usize_t hs_clones;		/**< Number of clones */
+  usize_t hs_rehash;		/**< Number of (re)allocations of hash table. */
+  usize_t hs_blocksize; 	/**< Current size of hash table */
+
+  struct {
+    unsigned hsp_size;		/**< Size of preload area */
+    unsigned hsp_used;		/**< Number of bytes used from preload */
+  } hs_preload;
+
+  struct {
+    uint64_t hsa_number;
+    uint64_t hsa_bytes;
+    uint64_t hsa_rbytes;
+    uint64_t hsa_maxrbytes;
+    uint64_t hsa_preload;	/**< Number of allocations from preload area */
+  } hs_allocs;
+
+  struct {
+    uint64_t hsf_number;
+    uint64_t hsf_bytes;
+    uint64_t hsf_rbytes;
+    uint64_t hsf_preload;	/**< Number of free()s from preload area */
+  } hs_frees;
+
+  struct {
+    uint64_t hsb_number;
+    uint64_t hsb_bytes;
+    uint64_t hsb_rbytes;
+  } hs_blocks;
+};
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_ALLOC_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_BM_H
+/** Defined when <sofia-sip/su_bm.h> has been included. */
+#define SU_BM_H
+
+/**
+ * @file sofia-sip/su_bm.h
+ * @brief Boyer-Moore search algorithm
+ *  
+ * @author Pekka.Pessi at nokia.com
+ * 
+ * @date Created: Mon Apr 11 17:03:13 2005 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct bw_fwd_table bm_fwd_table_t;
+
+SOFIAPUBFUN bm_fwd_table_t *bm_memmem_study(char const *needle, size_t nlen);
+
+SOFIAPUBFUN char const* bm_memmem(char const *haystack, size_t hlen,
+				  char const *needle, size_t nlen,
+				  bm_fwd_table_t *fwd);
+
+SOFIAPUBFUN bm_fwd_table_t *bm_memcasemem_study(char const *needle, size_t);
+
+SOFIAPUBFUN char const* bm_memcasemem(char const *haystack, size_t hlen,
+				      char const *needle, size_t nlen,
+				      bm_fwd_table_t *fwd);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_MEMMEM_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_CONFIG_H
+/** Defined when <sofia-sip/su_config.h> has been included. */
+#define SU_CONFIG_H
+/**@file sofia-sip/su_config.h 
+ * 
+ * @b su library configuration
+ * 
+ * This file includes an appropriate <su_configure*.h> include file.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include <sofia-sip/su_configure.h>
+
+#if defined(__GNUC__)
+/* Special attributes for GNU C */
+#if __GNUC__ < 3 && (!defined(__GNUC_MINOR__) || __GNUC_MINOR__ < 96)
+#define __malloc__		/* avoid spurious warnigns */
+#endif
+#elif !defined(__attribute__)
+#  define __attribute__(x) 
+#endif
+
+/* C++ linkage needs to know that types and declarations are C, not C++.  */
+#if defined(__cplusplus)
+/** Begin declarations in Sofia header files */
+# define SOFIA_BEGIN_DECLS	extern "C" {
+/** End declarations in Sofia header files */
+# define SOFIA_END_DECLS	}
+#else
+# define SOFIA_BEGIN_DECLS
+# define SOFIA_END_DECLS
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Macros required by Win32 linkage */
+
+/** SOFIAPUBFUN declares an exported function */
+#define SOFIAPUBFUN
+/** SOFIAPUBVAR declares an exported variable */
+#define SOFIAPUBVAR extern
+/** SOFIACALL declares the calling convention for exported functions */
+#define SOFIACALL
+
+/* Win32 linkage */
+
+/* Windows platform with MS/Borland/Cygwin/MinGW32 compiler */
+#if defined(_WIN32) && \
+  (defined(_MSC_VER) || defined(__BORLANDC__) ||  \
+   defined(__CYGWIN__) || defined(__MINGW32__))
+  #undef SOFIACALL
+  #define SOFIACALL __cdecl
+
+  #if defined(LIBSOFIA_SIP_UA_STATIC)
+  #else
+    #undef SOFIAPUBFUN
+    #undef SOFIAPUBVAR
+    #if defined(IN_LIBSOFIA_SIP_UA)
+      #define SOFIAPUBFUN __declspec(dllexport)
+      #define SOFIAPUBVAR __declspec(dllexport)
+    #else
+      #define SOFIAPUBFUN __declspec(dllimport)
+      #define SOFIAPUBVAR __declspec(dllimport) extern
+    #endif
+  #endif
+
+  #if !defined _REENTRANT
+    #define _REENTRANT
+  #endif
+#endif
+
+#define BNF_DLL   SOFIAPUBFUN
+#define HTTP_DLL  SOFIAPUBFUN
+#define IPT_DLL   SOFIAPUBFUN
+#define AUTH_DLL  SOFIAPUBFUN
+#define MSG_DLL   SOFIAPUBFUN
+#define NEA_DLL   SOFIAPUBFUN
+#define NTA_DLL   SOFIAPUBFUN
+#define NTH_DLL   SOFIAPUBFUN
+#define SDP_DLL   SOFIAPUBFUN
+#define SIP_DLL   SOFIAPUBFUN
+#define SU_DLL    SOFIAPUBFUN
+#define TPORT_DLL SOFIAPUBFUN
+#define URL_DLL   SOFIAPUBFUN
+#define MSG_TEST_DLL SOFIAPUBFUN
+
+#endif /* SU_CONFIG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_CONFIGURE_H
+/** Defined when <sofia-sip/su_configure.h> has been included. */
+#define SU_CONFIGURE_H 
+
+/**@file sofia-sip/su_configure.h
+ *
+ * Autoconf configuration for SU library.
+ *
+ * The file <su_configure.h> is automatically generated by autoconf.
+ *
+ * The file <su_configure.h> contains configuration information for
+ * programs using @b su library.  The configuration for su library itself is
+ * in "config.h".
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Mon Aug 21 20:32:25 2000 ppessi
+ */
+
+/** Define as 1 if you have <stdint.h> */
+#undef SU_HAVE_STDINT
+/** Define as 1 if you have <inttypes.h> */
+#undef SU_HAVE_INTTYPES
+/** Define as 1 if you have <sys/types.h> */
+#undef SU_HAVE_SYS_TYPES
+
+/** Define as 1 if you have BSD socket interface */
+#undef SU_HAVE_BSDSOCK
+/** Define as 1 if you have pthreads library */
+#undef SU_HAVE_PTHREADS
+/** Define as 1 if you have poll() */
+#undef SU_HAVE_POLL
+/** Define as 1 if you have IPv6 structures, macros and constants */
+#undef SU_HAVE_IN6
+
+/** Define as 1 if you have sa_len field in struct sockaddr */
+#undef SU_HAVE_SOCKADDR_SA_LEN
+
+/** Define as 1 if you have struct sockaddr_storage */
+#undef SU_HAVE_SOCKADDR_STORAGE
+
+/** Define as 1 if you have struct addrinfo. */
+#undef SU_HAVE_ADDRINFO
+
+/** Define as 1 if you have Winsock interface */
+#undef SU_HAVE_WINSOCK
+
+/** Define as 1 if you have Winsock2 interface */
+#undef SU_HAVE_WINSOCK2     	
+
+/** Define as 1 if you have OSX CoreFoundation interface */
+#undef SU_HAVE_OSX_CF_API
+
+/** Define as 1 if you have inline functions */
+#undef SU_HAVE_INLINE
+/** Define as suitable declarator inline functions */
+#undef SU_INLINE
+/** Define as suitable declarator static inline functions */
+#undef su_inline
+
+/** Define this as 1 if we can use tags directly from stack. */
+#undef SU_HAVE_TAGSTACK 
+
+/* These are valid only for GCC */
+
+#define SU_S64_C(i) (SU_S64_T)(i ## LL)
+#define SU_U64_C(i) (SU_U64_T)(i ## ULL)
+#define SU_S32_C(i) (SU_S32_T)(i ## L)
+#define SU_U32_C(i) (SU_U32_T)(i ## UL)
+#define SU_S16_C(i) (SU_S16_T)(i)
+#define SU_U16_C(i) (SU_U16_T)(i ## U)
+#define SU_S8_C(i)  (SU_S8_T)(i)
+#define SU_U8_C(i)  (SU_U8_T)(i ## U)
+
+/** Define this as ssize_t. */
+#undef SOFIA_SSIZE_T
+
+/** Define this as size_t
+    (int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_ISIZE_T
+
+/** Maximum value of isize_t */
+#undef ISIZE_MAX
+
+/** Define this as ssize_t
+    (int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_ISSIZE_T
+
+/** Maximum value of issize_t */
+#undef ISSIZE_MAX
+
+/** Define this as size_t
+    (unsigned int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_USIZE_T
+
+/** Maximum value of usize_t */
+#undef USIZE_MAX
+
+/**On Solaris define this in order to get POSIX extensions. */
+#undef __EXTENSIONS__
+
+/** Define this in order to get GNU extensions. */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#endif /* SU_CONFIGURE_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,209 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_DEBUG_H
+/** Defined when <sofia-sip/su_debug.h> has been included */
+#define SU_DEBUG_H 
+
+/**@ingroup su_log
+ * @file sofia-sip/su_debug.h
+ * @brief SU debugging macros
+ *
+ * The logging levels and macros to use are defined as follows:
+ *  - SU_DEBUG_0()  fatal errors, panic 
+ *  - SU_DEBUG_1()  critical errors, minimal progress at subsystem level
+ *  - SU_DEBUG_2()  non-critical errors
+ *  - SU_DEBUG_3()  warnings, progress messages
+ *  - SU_DEBUG_5()  signaling protocol actions (incoming packets, etc.)
+ *  - SU_DEBUG_7()  media protocol actions (incoming packets, etc.)
+ *  - SU_DEBUG_9()  entering/exiting functions, very verbatim progress
+ *
+ * These macros are used to log with module-specific levels. The SU_LOG
+ * macro is redefined with a pointer to a module-specific #su_log_t
+ * structure, e.g., "iptsec_debug.h".
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Feb  8 10:06:33 2000 ppessi
+ *
+ * @sa @ref debug_logs, su_llog(), su_vllog(), #su_log_t, 
+ */
+
+#ifndef SU_LOG_H
+#include <sofia-sip/su_log.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_DEBUG_MAX
+/** The maximum debugging level. */
+#define SU_DEBUG_MAX 9
+#endif
+
+#define SU_LOG_LEVEL \
+((SU_LOG != NULL && SU_LOG->log_init) == 0 ? 9 : \
+((SU_LOG != NULL && SU_LOG->log_init > 1) ? \
+  SU_LOG->log_level : su_log_default->log_level))
+
+#if SU_DEBUG_MAX >= 0
+#ifndef SU_LOG
+#define SU_LOG       (su_log_default)
+#else
+SOFIAPUBVAR su_log_t SU_LOG[];
+#endif
+
+#define SU_DEBUG_DEF(level) \
+  static SU_INLINE void su_debug_##level(char const *fmt, ...) \
+    __attribute__ ((__format__ (printf, 1, 2))); \
+  void su_debug_##level(char const *fmt, ...) \
+    { va_list ap; va_start(ap, fmt); su_vllog(SU_LOG, level, fmt, ap); va_end(ap); }
+
+SU_DEBUG_DEF(0)
+/** Log messages at level 0.
+ *
+ * Fatal errors and panic messages should be logged at level 0. 
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_0(x) (SU_LOG_LEVEL >= 0 ? (su_debug_0 x) : (void)0)
+
+/** Log C library errors. */
+#define SU_LERROR(s) (su_llog(SU_LOG, 1, "%s: %s\n", (s), strerror(errno)))
+/** Log socket errors. */
+#define SU_LSERROR(s) \
+  (su_llog(SU_LOG, 1, "%s: %s\n", (s), su_strerror(su_errno())))
+#else
+#define SU_DEBUG_0(x) ((void)0)
+#define SU_LERROR(s)  ((void)0)
+#define SU_LSERROR(s) ((void)0)
+#endif
+
+#if SU_DEBUG_MAX >= 1
+SU_DEBUG_DEF(1)
+/**Log messages at level 1.
+ *
+ * Critical errors and minimal progress at subsystem level should be logged
+ * at level 1.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_1(x) (SU_LOG_LEVEL >= 1 ? (su_debug_1 x) : (void)0)
+#else
+#define SU_DEBUG_1(x) (void)1
+#endif
+
+#if SU_DEBUG_MAX >= 2
+SU_DEBUG_DEF(2)
+/**Log messages at level 2. 
+ *
+ * Non-critical errors should be logged at level 2.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_2(x) (SU_LOG_LEVEL >= 2 ? (su_debug_2 x) : (void)0)
+#else
+#define SU_DEBUG_2(x) (void)2
+#endif
+
+#if SU_DEBUG_MAX >= 3
+SU_DEBUG_DEF(3)
+/** Log messages at level 3.
+ *
+ * Warnings and progress messages should be logged at level 3.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_3(x) (SU_LOG_LEVEL >= 3 ? (su_debug_3 x) : (void)0)
+#else
+#define SU_DEBUG_3(x) (void)3
+#endif
+
+#if SU_DEBUG_MAX >= 4
+SU_DEBUG_DEF(4)
+/** Log messages at level 4. */
+#define SU_DEBUG_4(x) (SU_LOG_LEVEL >= 4 ? (su_debug_4 x) : (void)0)
+#else
+#define SU_DEBUG_4(x) (void)4
+#endif
+
+#if SU_DEBUG_MAX >= 5
+SU_DEBUG_DEF(5)
+/** Log messages at level 5.
+ *
+ * Signaling protocol actions (incoming packets, etc.) should be logged
+ * at level 5.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_5(x) (SU_LOG_LEVEL >= 5 ? (su_debug_5 x) : (void)0)
+#else
+#define SU_DEBUG_5(x) (void)5
+#endif
+
+#if SU_DEBUG_MAX >= 6
+SU_DEBUG_DEF(6)
+/** Log messages at level 6. */
+#define SU_DEBUG_6(x) (SU_LOG_LEVEL >= 6 ? (su_debug_6 x) : (void)0)
+#else
+#define SU_DEBUG_6(x) (void)6
+#endif
+
+#if SU_DEBUG_MAX >= 7
+SU_DEBUG_DEF(7)
+/** Log messages at level 7.
+ *
+ * Media protocol actions (incoming packets, etc) should be logged at level 7. 
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_7(x) (SU_LOG_LEVEL >= 7 ? (su_debug_7 x) : (void)0)
+#else
+#define SU_DEBUG_7(x) (void)7
+#endif
+
+#if SU_DEBUG_MAX >= 8
+SU_DEBUG_DEF(8)
+/** Log messages at level 8. */
+#define SU_DEBUG_8(x) (SU_LOG_LEVEL >= 8 ? (su_debug_8 x) : (void)0)
+#else
+#define SU_DEBUG_8(x) (void)8
+#endif
+
+#if SU_DEBUG_MAX >= 9
+SU_DEBUG_DEF(9)
+/** Log messages at level 9.
+ *
+ * Entering/exiting functions, very verbatim progress should be logged at
+ * level 9.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_9(x) (SU_LOG_LEVEL >= 9 ? (su_debug_9 x) : (void)0)
+#else
+#define SU_DEBUG_9(x) (void)9
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_DEBUG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,243 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ERRNO_H
+/** Defined when <sofia-sip/su_errno.h> has been included. */
+#define SU_ERRNO_H
+
+/**@file sofia-sip/su_errno.h Errno handling
+ *
+ * Source-code compatibility with Windows (having separate errno for
+ * socket library and C libraries).
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Dec 22 18:16:06 EET 2005 pessi
+ */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+
+#include <errno.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Return string describing su error code. */
+SOFIAPUBFUN char const *su_strerror(int e);
+
+/** The latest su error. */
+SOFIAPUBFUN int su_errno(void);
+
+/** Set the su error. */
+SOFIAPUBFUN int su_seterrno(int);
+
+#if !SU_HAVE_WINSOCK
+#define su_errno() (errno)
+#define su_seterrno(n) ((errno = (n)), -1)
+#endif
+
+#if defined(__APPLE_CC__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef EBADMSG
+#define EBADMSG EFAULT
+#endif
+#ifndef EPROTO
+#define EPROTO EPROTOTYPE
+#endif
+#ifndef EBADMSG
+#define EBADMSG EFAULT
+#endif
+#endif
+
+#if defined(_WIN32)
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK  (10035) /* WSAEWOULDBLOCK */
+#endif
+
+#ifndef EINPROGRESS
+#define EINPROGRESS  (10036) /* WSAEINPROGRESS */
+#endif
+
+#ifndef EALREADY
+#define EALREADY (10037) /* WSAEALREADY */
+#endif
+
+#ifndef ENOTSOCK
+#define ENOTSOCK (10038) /* WSAENOTSOCK */
+#endif
+
+#ifndef EDESTADDRREQ
+#define EDESTADDRREQ (10039) /* WSAEDESTADDRREQ */
+#endif
+
+#ifndef EMSGSIZE
+#define EMSGSIZE (10040) /* WSAEMSGSIZE */
+#endif
+
+#ifndef EPROTOTYPE
+#define EPROTOTYPE (10041) /* WSAEPROTOTYPE */
+#endif
+
+#ifndef ENOPROTOOPT
+#define ENOPROTOOPT (10042) /* WSAENOPROTOOPT */
+#endif
+
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT (10043) /* WSAEPROTONOSUPPORT */
+#endif
+
+#ifndef ESOCKTNOSUPPORT
+#define ESOCKTNOSUPPORT (10044) /* WSAESOCKTNOSUPPORT */
+#endif
+
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP (10045) /* WSAEOPNOTSUPP */
+#endif
+
+#ifndef EPFNOSUPPORT
+#define EPFNOSUPPORT (10046) /* WSAEPFNOSUPPORT */
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT (10047) /* WSAEAFNOSUPPORT */
+#endif
+
+#ifndef EADDRINUSE
+#define EADDRINUSE (10048) /* WSAEADDRINUSE */
+#endif
+
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL (10049) /* WSAEADDRNOTAVAIL */
+#endif
+
+#ifndef ENETDOWN
+#define ENETDOWN (10050) /* WSAENETDOWN */
+#endif
+
+#ifndef ENETUNREACH
+#define ENETUNREACH (10051) /* WSAENETUNREACH */
+#endif
+
+#ifndef ENETRESET
+#define ENETRESET (10052) /* WSAENETRESET */
+#endif
+
+#ifndef ECONNABORTED
+#define ECONNABORTED (10053) /* WSAECONNABORTED */
+#endif
+
+#ifndef ECONNRESET
+#define ECONNRESET (10054) /* WSAECONNRESET */
+#endif
+
+#ifndef ENOBUFS
+#define ENOBUFS (10055) /* WSAENOBUFS */
+#endif
+
+#ifndef EISCONN
+#define EISCONN (10056) /* WSAEISCONN */
+#endif
+
+#ifndef ENOTCONN
+#define ENOTCONN (10057) /* WSAENOTCONN */
+#endif
+
+#ifndef ESHUTDOWN
+#define ESHUTDOWN (10058) /* WSAESHUTDOWN */
+#endif
+
+#ifndef ETOOMANYREFS
+#define ETOOMANYREFS (10059) /* WSAETOOMANYREFS */
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT (10060) /* WSAETIMEDOUT */
+#endif
+
+#ifndef ECONNREFUSED
+#define ECONNREFUSED (10061) /* WSAECONNREFUSED */
+#endif
+
+#ifndef ELOOP
+#define ELOOP (10062) /* WSAELOOP */
+#endif
+
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG (10063) /* WSAENAMETOOLONG */
+#endif
+
+#ifndef EHOSTDOWN
+#define EHOSTDOWN (10064) /* WSAEHOSTDOWN */
+#endif
+
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH (10065) /* WSAEHOSTUNREACH */
+#endif
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY (10066) /* WSAENOTEMPTY */
+#endif
+
+#ifndef EPROCLIM
+#define EPROCLIM (10067) /* WSAEPROCLIM */
+#endif
+
+#ifndef EUSERS
+#define EUSERS (10068) /* WSAEUSERS */
+#endif
+
+#ifndef EDQUOT
+#define EDQUOT (10069) /* WSAEDQUOT */
+#endif
+
+#ifndef ESTALE
+#define ESTALE (10070) /* WSAESTALE */
+#endif
+
+#ifndef EREMOTE
+#define EREMOTE (10071) /* WSAEREMOTE */
+#endif
+
+#ifndef EBADMSG
+#  if defined(WSABADMSG)
+#    define EBADMSG (WSAEBADMSG)
+#  else
+#    define EBADMSG (20005)
+#  endif
+#endif
+
+#ifndef EPROTO
+#  if defined(WSAEPROTO)
+#    define EPROTO WSAEPROTO
+#  else
+#    define EPROTO (20006)
+#  endif
+#endif
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_LOCALINFO_H
+/** Defined when <sofia-sip/su_localinfo.h> has been included. */
+#define SU_LOCALINFO_H 
+
+
+/**@ingroup su_socket
+ * @file sofia-sip/su_localinfo.h  Interface for obtaining local addresses.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Aug 10 18:58:01 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Local address info structure. */
+typedef struct su_localinfo_s su_localinfo_t;
+
+/** Local address info structure. */
+struct su_localinfo_s {
+  /**Bitwise or of flags: 
+   * #LI_V4MAPPED, #LI_CANONNAME, #LI_NAMEREQD, 
+   * #LI_NUMERIC, #LI_DOWN, #LI_IFNAME */
+  int li_flags;
+  int li_family;		/**< Address family. */
+  int li_index;			/**< Network interface index. */
+  int li_scope;			/**< Address scope. */
+  socklen_t li_addrlen;		/**< Length of li_addr. */
+  su_sockaddr_t *li_addr;	/**< Binary address. */
+  char *li_canonname;		/**< Canonical name for address. */
+  su_localinfo_t *li_next;	/**< Next structure in linked list. */
+  char *li_ifname;		/**< Network interface name. */
+};
+
+/** Flags for su_getlocalinfo() - li_flags */
+enum {
+  /** IPv4 addresses will be mapped as IPv6 */
+  LI_V4MAPPED     = 1,
+  /** Get domain name corresponding to the local address */
+  LI_CANONNAME    = 2,
+  /** Do not return addresses not in DNS. Implies LI_CANONNAME. */
+  LI_NAMEREQD     = 6,
+  /** Instead of domain name, use numeric form */
+  LI_NUMERIC      = 8,
+  /** Include interfaces even if they are down (new in @VERSION_1_12_2). */
+  LI_DOWN         = 16,
+  /** Get interface name */
+  LI_IFNAME       = 256
+};
+
+/** Localinfo scope - li_scope */
+enum {
+  LI_SCOPE_HOST   = 0x10,	/**< Host-local address, valid within host. */
+  LI_SCOPE_LINK   = 0x20,	/**< Link-local address. */
+  LI_SCOPE_SITE   = 0x40,	/**< Site-local address. */
+  LI_SCOPE_GLOBAL = 0x80	/**< Global address. */
+};
+
+/** Localinfo error codes. */
+enum {
+  ELI_NOADDRESS  = -1,		/**< No matching address. */
+  ELI_MEMORY     = -2,		/**< Memory allocation error. */
+  ELI_FAMILY     = -3,		/**< Unknown address family. */
+  ELI_RESOLVER   = -4,		/**< Error when resolving address. */
+  ELI_SYSTEM     = -5,		/**< System error. */
+  ELI_BADHINTS   = -6,		/**< Invalid value for hints. */
+  ELI_NOERROR    = 0		/**< No error. */
+};
+
+/** Request local address information */
+SOFIAPUBFUN int su_getlocalinfo(su_localinfo_t const *hints,
+				su_localinfo_t **res);
+/** Free local address information */
+SOFIAPUBFUN void su_freelocalinfo(su_localinfo_t *);
+/** Describe su_localinfo errors. */
+SOFIAPUBFUN char const *su_gli_strerror(int error);
+/** Copy a localinfo structure */
+SOFIAPUBFUN su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0);
+
+/** Return the scope of address in the sockaddr structure */
+SOFIAPUBFUN int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_LOCALINFO_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log 
+ * @file sofia-sip/su_log.h   SU logging interface
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Feb 22 18:09:02 2001 ppessi
+ *
+ */
+
+#ifndef SU_LOG_T
+/** Defined when the type #su_log_t has been defined. */
+#define SU_LOG_T
+/** Type of log structure. */
+typedef struct su_log_s su_log_t;
+#endif
+
+#ifndef SU_LOG_H_NEED_SU_LOG_T
+
+#ifndef SU_LOG_H
+/** Defined when <sofia-sip/su_log.h> has been included. */
+#define SU_LOG_H
+
+#include <stdarg.h>
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Prototype for logging function */
+typedef void (su_logger_f)(void *stream, char const *fmt, va_list ap);
+
+/** Log object. */
+struct su_log_s {
+  int          log_size;
+  char const  *log_name;
+  char const  *log_env;
+  unsigned     log_default;
+  unsigned     log_level;
+  int          log_init;
+
+  su_logger_f *log_logger;
+  void        *log_stream;
+};
+
+enum { SU_LOG_MAX = 9 };
+
+/** Initialize a su_log_t structure */
+#define SU_LOG_INIT(name, env, level) \
+  { sizeof(su_log_t), name, env, level, SU_LOG_MAX, 0, NULL, NULL, }
+
+SOFIAPUBFUN void su_log(char const *fmt, ...)
+  __attribute__ ((__format__ (printf, 1, 2)));
+
+SOFIAPUBFUN void su_llog(su_log_t *log, unsigned level, char const *fmt, ...)
+  __attribute__ ((__format__ (printf, 3, 4)));
+SOFIAPUBFUN void su_vllog(su_log_t *log, unsigned level, 
+			  char const *fmt, va_list ap);
+SOFIAPUBFUN void su_log_redirect(su_log_t *log, su_logger_f *f, void *stream);
+SOFIAPUBFUN void su_log_set_level(su_log_t *log, unsigned level);
+SOFIAPUBFUN void su_log_soft_set_level(su_log_t *log, unsigned level);
+SOFIAPUBFUN void su_log_init(su_log_t *log);
+
+SOFIAPUBVAR su_log_t su_log_default[];
+SOFIAPUBVAR su_log_t su_log_global[];
+
+/** Log the latest su error message */
+SOFIAPUBFUN void su_perror(char const *s);
+
+/** Log the su error message. */
+SOFIAPUBFUN void su_perror2(char const *s, int errcode);
+
+SOFIA_END_DECLS
+
+#endif
+
+#endif /* !defined(SU_LOG_H_NEED_SU_LOG_T) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_MD5_H /**  Defined when su_md5.h has been included. */
+#define SU_MD5_H
+
+/**@defgroup su_md5 MD5 Digest
+ *
+ * The MD5 message digest algorithm is described in RFC 1321 by R. Rivest,
+ * 1992.  The algorithm takes as input a octet string of arbitrary length
+ * and generates a 128-bit hash value, "message digest" from the message
+ * contents.
+ *
+ * While some message collisions (different messages with same MD5 digest)
+ * has been generated, using collisions in an actual attack is much harder
+ * and MD5 can be considered as cryptographically strong.
+ */
+
+/** @file sofia-sip/su_md5.h MD5 digest interface.
+ *
+ * @author <Pekka.Pessi at nokia.com>
+ */ 
+
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** MD5 context. */
+typedef struct su_md5_t {
+  uint32_t buf[4];
+  uint32_t bits[2];
+  uint8_t  in[64];
+} su_md5_t;
+
+#define SU_MD5_DIGEST_SIZE 16
+
+SOFIAPUBFUN void su_md5_init(su_md5_t *context);
+SOFIAPUBFUN void su_md5_deinit(su_md5_t *context);
+SOFIAPUBFUN void su_md5_update(su_md5_t *context,
+			       void const *buf, usize_t len);
+SOFIAPUBFUN void su_md5_strupdate(su_md5_t *ctx, char const *s);
+SOFIAPUBFUN void su_md5_str0update(su_md5_t *ctx, char const *s);
+
+SOFIAPUBFUN void su_md5_iupdate(su_md5_t *context,
+				void const *buf, usize_t len);
+SOFIAPUBFUN void su_md5_striupdate(su_md5_t *ctx, char const *s);
+SOFIAPUBFUN void su_md5_stri0update(su_md5_t *ctx, char const *s);
+
+SOFIAPUBFUN void su_md5_digest(su_md5_t const *ctx,
+			       uint8_t digest[SU_MD5_DIGEST_SIZE]);
+SOFIAPUBFUN void su_md5_hexdigest(su_md5_t const *ctx,
+				  char digest[2 * SU_MD5_DIGEST_SIZE + 1]);
+
+#define SU_MD5_STRUPDATE(ctx, s) \
+ ((s) ? su_md5_update(ctx, (s), strlen(s)) : (void)0)
+#define SU_MD5_STR0UPDATE(ctx, s) \
+ su_md5_update(ctx, (s) ? (s) : "", (s) ? strlen(s) + 1 : 1)
+#define SU_MD5_STRIUPDATE(ctx, s) \
+  ((s) ? su_md5_iupdate(ctx, (s), strlen(s)) : (void)0)
+#define SU_MD5_STRI0UPDATE(ctx, s) \
+  su_md5_iupdate(ctx, (s) ? (s) : "", (s) ? strlen(s) : 1)
+
+SOFIA_END_DECLS
+
+#endif /* !defined(MD5_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_OS_NW_H
+/** Defined when <sofia-sip/su_os_nw.h> has been included. */
+#define SU_OS_NW_H
+
+/**@ingroup su_os_nw
+ * @file sofia-sip/su_os_nw.h Network change events.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 15 09:05:18 EEST 2006  martti.mela at nokia.com
+ *
+ * @since Experimental in @VERSION_1_12_2.
+ * Note that this is expected to change in future releases.
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_H
+#include "sofia-sip/su.h"
+#endif
+
+#ifndef SU_TIME_H
+#include "sofia-sip/su_time.h"
+#endif
+
+#ifndef SU_ALLOC_H
+#include "sofia-sip/su_alloc.h"
+#endif
+
+#ifndef SU_WAIT_H
+#include "sofia-sip/su_wait.h"
+#endif
+
+#if SU_HAVE_POLL
+#include <sys/poll.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* network-changed callback */
+
+#ifndef SU_NETWORK_CHANGED_MAGIC_T
+/**Default type of application context for network_changed function.
+ *
+ * Application may define the typedef ::su_network_changed_magic_t to appropriate type
+ * by defining macro #SU_NETWORK_CHANGED_MAGIC_T before including <su_os_nw.h>, for
+ * example,
+ * @code
+ * #define SU_NETWORK_CHANGED_MAGIC_T struct context
+ * #include <su_os_nw.h>
+ * @endcode
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define SU_NETWORK_CHANGED_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_network_changed_magic_t to appropriate type
+ * by defining macro #SU_NETWORK_CHANGED_MAGIC_T before including <su_os_nw.h>, for
+ * example,
+ * @code
+ * #define SU_NETWORK_CHANGED_MAGIC_T struct context
+ * #include <su_os_nw.h>
+ * @endcode
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SU_NETWORK_CHANGED_MAGIC_T su_network_changed_magic_t;
+
+typedef struct su_network_changed_s su_network_changed_t;
+
+/** Function prototype for network-changed callback . 
+ *
+ * 
+ * @since New in @VERSION_1_12_2.
+ */
+typedef void (su_network_changed_f)(su_network_changed_magic_t *, su_root_t *);
+
+
+/* ---------------------------------------------------------------------- */
+/* Functions */
+
+/* Network-changed */
+SOFIAPUBFUN su_network_changed_t *
+su_root_add_network_changed(su_home_t *home,
+			    su_root_t *root, 
+			    su_network_changed_f *, 
+			    su_network_changed_magic_t *);
+SOFIAPUBFUN int su_root_remove_network_changed(su_network_changed_t *);
+
+SOFIA_END_DECLS
+
+#endif /* SU_OS_NW_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_OSX_RUNLOOP_H
+/** Defined when <sofia-sip/su_osx_runloop.h> has been included. */
+#define SU_OSX_RUNLOOP_H
+
+/**
+ * @file sofia-sip/su_osx_runloop.h
+ * @brief OSX Run Loop integration.
+ * 
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *  
+ * @date Created: Fri Sep 22 16:49:51 EEST 2006 mela
+ * 
+ * @NEW_1_12_4.
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#include <CoreFoundation/CoreFoundation.h>
+
+SOFIA_BEGIN_DECLS
+
+su_root_t *su_root_osx_runloop_create(su_root_magic_t *) __attribute__((__malloc__));
+void       su_root_osx_prepare_run(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_OSX_RUNLOOP_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_STRLST_H  /** Defined when <sofia-sip/su_strlst.h> has been included. */
+#define SU_STRLST_H
+/**@ingroup su_strlst
+ * @file sofia-sip/su_strlst.h String lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri May  3 09:13:22 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_strlst_s su_strlst_t;
+
+/** Create a string list. */
+SU_DLL su_strlst_t *su_strlst_create(su_home_t *home)
+     __attribute__((__malloc__));
+/** Destroy a string list. */
+SU_DLL void su_strlst_destroy(su_strlst_t *);
+
+SU_DLL su_strlst_t *su_strlst_create_with(su_home_t *, char const *, ...)
+     __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_create_with_dup(su_home_t *, char const *, ...)
+     __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_vcreate_with(su_home_t *,
+					   char const *,
+					   va_list va)
+     __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *,
+					       char const *, 
+					       va_list va)
+     __attribute__((__malloc__));
+
+/** Shallow copy a string list. */
+SU_DLL su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig);
+
+/** Deep copy a string list. */
+SU_DLL su_strlst_t *su_strlst_dup(su_home_t *home, su_strlst_t const *orig);
+
+/** Duplicate and append a string to list. */
+SU_DLL char *su_strlst_dup_append(su_strlst_t *, char const *str);
+
+/** Append a string to list. */
+SU_DLL char const *su_strlst_append(su_strlst_t *, char const *str);
+
+/** Append a formatted string to the list. */
+SU_DLL char const *su_slprintf(su_strlst_t *self, char const *fmt, ...);
+
+/** Append a formatted string to the list. */
+SU_DLL char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap);
+
+/** Get a numbered item from list. */
+SU_DLL char const *su_strlst_item(su_strlst_t const *, usize_t i);
+
+/** Set a numbered item to list */
+SU_DLL char const *su_strlst_set_item(su_strlst_t *self, usize_t i, 
+				      char const *s);
+
+/** Remove a numbered item from list. */
+SU_DLL char const *su_strlst_remove(su_strlst_t *, usize_t i);
+
+/** Concatenate list of strings to one string. */
+SU_DLL char *su_strlst_join(su_strlst_t *s, su_home_t *home, 
+			     char const *sep)
+     __attribute__((__malloc__));
+
+/** Split a string. */
+SU_DLL su_strlst_t *su_strlst_split(su_home_t *, char *s, char const *sep)
+     __attribute__((__malloc__));
+
+/** Duplicate and split a string. */
+SU_DLL su_strlst_t *su_strlst_dup_split(su_home_t *, char const *s, 
+					char const *sep)
+     __attribute__((__malloc__));
+
+/** Get number of items in list. */
+SU_DLL usize_t su_strlst_len(su_strlst_t const *l);
+
+#if SU_HAVE_INLINE
+static inline
+su_home_t *su_strlst_home(su_strlst_t *s)
+{
+  return (su_home_t *)s;
+}
+#else
+#define su_strlst_home(s) ((su_home_t *)(s))
+#endif
+
+/** Get a string array from list. */
+SU_DLL char const **su_strlst_get_array(su_strlst_t *self)
+     __attribute__((__malloc__));
+
+/** Free a string array */
+SU_DLL void su_strlst_free_array(su_strlst_t *self, char const * array[]);
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_STRLST_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_H
+/** Defined when <sofia-sip/su_tag.h> has been included. */
+#define SU_TAG_H
+
+/**@SU_TAG
+ * @file sofia-sip/su_tag.h  Object-oriented tags and tag list interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <stdarg.h>
+#include <stddef.h> /* ANSI C: size_t */
+
+SOFIA_BEGIN_DECLS
+
+/** Tag item type */
+typedef struct tag_type_s const *tag_type_t;
+/** Tag item value */
+typedef intptr_t                 tag_value_t;
+
+/** Tag list signature */
+#define TAG_LIST tag_type_t tag, tag_value_t value, ...
+
+/** Tag item. */
+typedef struct {
+  tag_type_t   t_tag;		/**< Tag */
+  tag_value_t  t_value;		/**< Value */
+} tagi_t;
+
+/** Tag type class */
+typedef struct tag_class_s const tag_class_t;
+
+struct tag_type_s {
+  char const    *tt_ns;
+  char const 	*tt_name;
+  tag_class_t   *tt_class;
+  tag_value_t    tt_magic;
+};
+
+/** Definition of tag type. */
+typedef struct tag_type_s const tag_typedef_t[1];
+
+/** End of tag list */
+SOFIAPUBVAR tag_typedef_t tag_null;
+
+/** Ignore tag item. */
+SOFIAPUBVAR tag_typedef_t tag_skip;
+
+/** Jump to another tag list */
+SOFIAPUBVAR tag_typedef_t tag_next;
+
+/** Any tag accepted when filtering. */
+SOFIAPUBVAR tag_typedef_t tag_any;
+
+/** Filter tag using function as argument. 
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBVAR tag_typedef_t tag_filter;
+
+/** Prototype for filtering function used with TAG_FILTER(). 
+ * @since New in @VERSION_1_12_2.
+ */
+typedef int tag_filter_f(tagi_t const *filter, tagi_t const *dest);
+
+/** @HI Initialize a tag item marking the end of list. Equivalent to TAG_END(). */
+#define TAG_NULL()  (tag_type_t)0, (tag_value_t)0
+
+/** @HI Initialize a tag item marking the end of list. Equivalent to TAG_NULL(). */
+#define TAG_END()   (tag_type_t)0, (tag_value_t)0
+
+/** @HI Initialize an empty tag item. */
+#define TAG_SKIP(x)    tag_skip, (tag_value_t)(x)
+
+/** @HI Initialize a tag item pointing to another tag list at @a next. */
+#define TAG_NEXT(next) tag_next, (tag_value_t)(next)
+
+/** @HI Initialize a filter tag item accepting any item. */
+#define TAG_ANY()   tag_any,  (tag_value_t)0
+
+/** @HI Initialize a @a item if condition is true; 
+ * otherwise, initialize an empty tag item. */
+#define TAG_IF(condition, item) !(condition) ? tag_skip : item
+
+/** @HI Initialize a filter tag item accepting any item. 
+ * @since New in @VERSION_1_12_2.
+ */
+#define TAG_FILTER(function)  tag_filter, tag_filter_v(function)
+
+/** Convert tag item to a string  */
+SOFIAPUBFUN int t_snprintf(tagi_t const *t, char b[], size_t size);
+
+/** Convert string to a tag value */
+SOFIAPUBFUN int t_scan(tag_type_t tt, su_home_t *home, char const *s, 
+		       tag_value_t *return_value);
+
+/* Tagarg functions */
+SOFIAPUBFUN tagi_t *tl_tlist(su_home_t *, tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN size_t tl_tmove(tagi_t *dst, size_t, tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_gets(tagi_t const lst[], tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_tgets(tagi_t lst[], tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN tagi_t *tl_tfilter(su_home_t *, tagi_t const lst[], 
+			       tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_tremove(tagi_t lst[], tag_type_t, tag_value_t, ...);
+
+/* Low-level taglist manipulation functions */
+SOFIAPUBFUN size_t tl_len(tagi_t const lst[]);
+SOFIAPUBFUN size_t tl_xtra(tagi_t const lst[], size_t offset);
+SOFIAPUBFUN tagi_t *tl_next(tagi_t const *lst);
+SOFIAPUBFUN tagi_t *tl_move(tagi_t *dst, tagi_t const src[]);
+SOFIAPUBFUN tagi_t *tl_dup(tagi_t dst[], tagi_t const lst[], void **bb);
+SOFIAPUBFUN tagi_t *tl_adup(su_home_t *, tagi_t const lst[]);
+SOFIAPUBFUN void tl_free(tagi_t list[]);
+
+SOFIAPUBFUN tagi_t *tl_find(tagi_t const lst[], tag_type_t tt);
+SOFIAPUBFUN tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt);
+SOFIAPUBFUN tagi_t *tl_filter(tagi_t *, tagi_t const filter[],
+			      tagi_t const lst[], void **b);
+SOFIAPUBFUN tagi_t *tl_afilter(su_home_t *, tagi_t const filter[],
+			       tagi_t const lst[]);
+
+SOFIAPUBFUN tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[], 
+				      tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN size_t  tl_vlen(va_list ap);
+SOFIAPUBFUN tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap);
+SOFIAPUBFUN tagi_t *tl_vlist(va_list ap);
+SOFIAPUBFUN tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap);
+SOFIAPUBFUN void    tl_vfree(tagi_t *t);
+
+/** Align to pointer size */
+#define SU_ALIGN(x) \
+((sizeof(void *) - ((intptr_t)(x) & (sizeof(void *) - 1))) & (sizeof(void *) - 1))
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t tag_int_v(int v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_int_vr(int *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_uint_v(unsigned v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_uint_vr(unsigned *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_usize_v(usize_t v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_usize_vr(usize_t *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_size_v(size_t v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_size_vr(size_t *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_bool_v(int v) { return v != 0; }
+su_inline tag_value_t tag_bool_vr(int *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_ptr_v(void *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_ptr_vr(void *vp, void *v)
+  { (void)v; return(tag_value_t)vp; }
+su_inline tag_value_t tag_cptr_v(void const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_cptr_vr(void *vp, void const *v) 
+  { (void)v; return(tag_value_t)vp; }
+su_inline tag_value_t tag_cstr_v(char const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_cstr_vr(char const**vp) {return(tag_value_t)vp;}
+su_inline tag_value_t tag_str_v(char const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_str_vr(char const **vp) {return(tag_value_t)vp;}
+#if __cplusplus
+extern "C++" {
+  static inline tag_value_t tag_ptr_v(void const *v)
+  { return (tag_value_t)v; }
+  static inline tag_value_t tag_ptr_vr(void *vp, void const *p) 
+  { return(tag_value_t)vp; }
+  static inline tag_value_t tag_str_v(char *v) { return (tag_value_t)v; }
+  static inline tag_value_t tag_str_vr(char **vp) {return(tag_value_t)vp;}
+}
+#endif
+su_inline tag_value_t tag_filter_v(tag_filter_f *v) {return(tag_value_t)v;}
+#else
+#define tag_int_v(v)   (tag_value_t)(v)
+#define tag_int_vr(v)  (tag_value_t)(v)
+#define tag_uint_v(v)  (tag_value_t)(v)
+#define tag_uint_vr(v) (tag_value_t)(v)
+#define tag_bool_v(v)  (tag_value_t)(v != 0)
+#define tag_bool_vr(v) (tag_value_t)(v)
+#define tag_ptr_v(v)   (tag_value_t)(v)
+#define tag_ptr_vr(v,x) (tag_value_t)(v)
+#define tag_cstr_v(v)  (tag_value_t)(v)
+#define tag_cstr_vr(v) (tag_value_t)(v)
+#define tag_str_v(v)   (tag_value_t)(v)
+#define tag_str_vr(v)  (tag_value_t)(v)
+#define tag_filter_v(v) (tag_value_t)(v)
+#endif
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SU_TAG_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_CLASS_H
+/** Defined when <sofia-sip/su_tag_class.h> has been included. */
+#define SU_TAG_CLASS_H 
+
+/**@SU_TAG
+ * @file  su_tag_class.h
+ * @brief Tag class interface for object-oriented tags 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Feb 21 00:49:41 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* Macros for defining tag classes */
+
+#ifndef TAG_NAMESPACE
+/** Default namespace for tags */
+#define TAG_NAMESPACE ""
+#endif
+
+#define TAG_TYPEDEF(t, type) \
+  {{ TAG_NAMESPACE, #t, type ## _tag_class }}
+
+#define INTTAG_TYPEDEF(t)      TAG_TYPEDEF(t, int)
+#define UINTTAG_TYPEDEF(t)     TAG_TYPEDEF(t, uint)
+#define USIZETAG_TYPEDEF(t)    TAG_TYPEDEF(t, usize)
+#define SIZETAG_TYPEDEF(t)     TAG_TYPEDEF(t, size)
+#define BOOLTAG_TYPEDEF(t)     TAG_TYPEDEF(t, bool)
+#define PTRTAG_TYPEDEF(t)      TAG_TYPEDEF(t, ptr)
+#define SOCKETTAG_TYPEDEF(t)   TAG_TYPEDEF(t, socket)
+#define CSTRTAG_TYPEDEF(t)     TAG_TYPEDEF(t, cstr)
+#define STRTAG_TYPEDEF(t)      TAG_TYPEDEF(t, str)
+#define NSTAG_TYPEDEF(t)       TAG_TYPEDEF(t, ns)
+
+struct tag_class_s {
+  int             tc_size;
+  tagi_t const *(*tc_next)(tagi_t const *t);
+  size_t        (*tc_len)(tagi_t const *t);
+  tagi_t       *(*tc_move)(tagi_t *dst, tagi_t const *src);
+  size_t        (*tc_xtra)(tagi_t const *t, size_t offset);
+  tagi_t       *(*tc_dup)(tagi_t *dst, tagi_t const *src, void **b);
+  tagi_t       *(*tc_free)(tagi_t *t);
+  tagi_t const *(*tc_find)(tag_type_t t, tagi_t const lst[]);
+  int           (*tc_snprintf)(tagi_t const *t, char b[], size_t size);
+  tagi_t       *(*tc_filter)(tagi_t *dst, tagi_t const f[], tagi_t const *src,
+			     void **bb);
+  int           (*tc_ref_set)(tag_type_t tt, void *ref, tagi_t const value[]);
+  int           (*tc_scan)(tag_type_t tt, su_home_t *home,
+			   char const *str,
+			   tag_value_t *return_value);
+};
+
+SOFIAPUBVAR tag_class_t end_tag_class[];
+SOFIAPUBVAR tag_class_t int_tag_class[];
+SOFIAPUBVAR tag_class_t uint_tag_class[];
+SOFIAPUBVAR tag_class_t usize_tag_class[];
+SOFIAPUBVAR tag_class_t size_tag_class[];
+SOFIAPUBVAR tag_class_t bool_tag_class[];
+SOFIAPUBVAR tag_class_t ptr_tag_class[];
+SOFIAPUBVAR tag_class_t socket_tag_class[];
+SOFIAPUBVAR tag_class_t cstr_tag_class[];
+SOFIAPUBVAR tag_class_t str_tag_class[];
+SOFIAPUBVAR tag_class_t ns_tag_class[];
+
+#define REFTAG_TYPEDEF(tag) \
+  {{ TAG_NAMESPACE, #tag "_ref", ref_tag_class, (tag_value_t)tag }}
+
+SOFIAPUBVAR tag_class_t ref_tag_class[];
+
+SOFIAPUBFUN int t_ptr_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_ptr_scan(tag_type_t, su_home_t *, char const *,
+			   tag_value_t *return_value);
+
+SOFIAPUBFUN int t_bool_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_bool_scan(tag_type_t, su_home_t *, char const *,
+			    tag_value_t *return_value);
+
+SOFIAPUBFUN int t_int_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_int_scan(tag_type_t, su_home_t *, char const *,
+			   tag_value_t *return_value);
+
+SOFIAPUBFUN int t_uint_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_uint_scan(tag_type_t, su_home_t *, char const *,
+			    tag_value_t *return_value);
+
+SOFIAPUBFUN tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **b);
+SOFIAPUBFUN size_t t_str_xtra(tagi_t const *t, size_t offset);
+SOFIAPUBFUN int t_str_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_str_scan(tag_type_t, su_home_t *, char const *,
+			   tag_value_t *return_value);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAG_CLASS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_INLINE_H
+/** Defined when <sofia-sip/su_tag_inline.h> has been included */
+#define SU_TAG_INLINE_H 
+/**@SU_TAG
+ * @file sofia-sip/su_tag_inline.h
+ * Inline functions for object tags and tag lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define tt_next     tt_class->tc_next
+#define tt_len      tt_class->tc_len
+#define tt_move     tt_class->tc_move
+#define tt_xtra     tt_class->tc_xtra
+#define tt_dup      tt_class->tc_dup
+#define tt_free     tt_class->tc_free
+#define tt_find     tt_class->tc_find
+#define tt_snprintf tt_class->tc_snprintf
+#define tt_filter   tt_class->tc_filter
+
+#define TAG_TYPE_OF(t) ((t) && (t)->t_tag ? (t)->t_tag : tag_null)
+
+/** Check if the tag item is last in current list */
+static inline int t_end(tagi_t const *t)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+
+  /* XXX - virtualize this */
+
+  return tt == tag_null || tt == tag_next;
+}
+
+static inline tagi_t const *t_next(tagi_t const *t)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+
+  if (tt->tt_next) 
+    return tt->tt_next(t);
+  else
+    return t + 1;
+}
+
+static inline tagi_t *t_move(tagi_t *dst, tagi_t const *src)
+{
+  tag_type_t tt = TAG_TYPE_OF(src);
+
+  if (tt->tt_move) 
+    return tt->tt_move(dst, src);
+
+  *dst = *src;
+  return dst + 1;
+}
+
+static inline size_t t_xtra(tagi_t const *t, size_t offset)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+
+  if (tt->tt_xtra) 
+    return tt->tt_xtra(t, offset);
+
+  return 0;
+}
+
+static inline tagi_t *t_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  tag_type_t tt = TAG_TYPE_OF(src);
+
+  if (tt->tt_dup) 
+    return tt->tt_dup(dst, src, bb);
+
+  *dst = *src;
+  return dst + 1;
+}
+
+static inline tagi_t const *t_find(tag_type_t tt, tagi_t const *lst)
+{
+  if (!tt)
+    return NULL;
+
+  if (tt->tt_find) 
+    return tt->tt_find(tt, lst);
+
+  for (; lst; lst = t_next(lst)) {
+    if (tt == lst->t_tag)
+      return lst;
+  }
+
+  return NULL;
+}
+
+static inline tagi_t *t_free(tagi_t *t)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+
+  if (tt->tt_free) 
+    return tt->tt_free(t);
+  else if (tt->tt_next)
+    return (tagi_t *)tt->tt_next(t);
+  else
+    return t + 1;
+}
+
+static inline size_t t_len(tagi_t const *t)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+
+  if (tt->tt_len) 
+    return tt->tt_len(t);
+
+  return sizeof(*t);
+}
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAG_INLINE_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_IO_H
+/** Defined when <sofia-sip/su_tag_io.h> has been included */
+#define SU_TAG_IO_H 
+
+/**@SU_TAG
+ * @file sofia-sip/su_tag_io.h
+ * @brief I/O interface for tag lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Feb 21 12:10:06 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+#include <stdio.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN void tl_print(FILE *f, char const *title, tagi_t const lst[]);
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t tag_socket_v(su_socket_t v) {
+  return (tag_value_t)v;
+}
+su_inline tag_value_t tag_socket_vr(su_socket_t *vp) { 
+  return (tag_value_t)vp; 
+}
+#else
+#define tag_socket_v(v)   (tag_value_t)(v)
+#define tag_socket_vr(v)  (tag_value_t)(v)
+#endif
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAGARG_H
+/** Defined when <sofia-sip/su_tagarg.h> has been included. */
+#define SU_TAGARG_H
+
+/**@SU_TAG 
+ * @file sofia-sip/su_tagarg.h  Tagged argument lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/**@page tagarg Tagarg Functions
+ *
+ * A @em tagarg function may be called with a varying number of tagged
+ * arguments.  The include file <su_tagarg.h> declares a type ta_list and
+ * defines four macros (ta_start(), ta_args(), ta_tags() and ta_end()) for
+ * accessing the argument list.
+ *
+ * An example of prototype of a a @em tagarg function is as follows:
+ * @code
+ * int tag_print(FILE *f, tag_type_t tag, tag_value_t value, ...);
+ * @endcode
+ *
+ * Such a function could be called as follows:
+ * @code
+ *   tag_print(stdout, 
+ *             TAG_STRING("a is"), TAG_INT(a), 
+ *             TAG_STRING("b is"), URLTAG_URL(b),
+ *             TAG_IF(c, TAG_STRING("and c is true")),
+ *             TAG_END());
+ * @endcode
+ *
+ * @note 
+ * The tagged argument list @b must be terminated by a TAG_END(),
+ * TAG_NULL() or TAG_NEXT().
+ */
+
+/**Object for accessing tagged argument lists.
+ *
+ * The called function must declare an object of type ta_list which is
+ * used by the macros ta_start(), ta_args(), ta_tags(), and ta_end().
+ *
+ * If a tagged list is not finished with TAG_END(), TAG_NULL(), or
+ * TAG_NEXT() items, random errors may occur.
+ *
+ * @hideinitializer
+ */
+typedef struct {
+  tagi_t  tl[2];
+  va_list ap;
+} ta_list;
+
+/**Macro initializing a ta_list object.
+ *
+ * The ta_start() macro initializes @a ta for subsequent use by ta_args(),
+ * ta_tags() and ta_end(), and must be called first.
+ *
+ * The parameters @a t and @a v are the names of the @c tag and @c value in
+ * the first tag list item before the variable argument list (...).
+ *
+ * The ta_start() macro returns no value.
+ *
+ * @hideinitializer
+ */
+#if SU_HAVE_TAGSTACK
+/* All arguments are saved into stack (left-to-right) */
+#define ta_start(ta, t, v)						\
+   do {									\
+    tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v);	\
+    va_start((ta).ap, (v));						\
+    while ((ta_start__tag) == tag_next && (ta_start__value) != 0) {	\
+      ta_start__tag = ((tagi_t *)ta_start__value)->t_tag;		\
+      if (ta_start__tag == tag_null || ta_start__tag == NULL)		\
+	break;								\
+      if (ta_start__tag == tag_next) {					\
+	ta_start__value = ((tagi_t *)ta_start__value)->t_value; }	\
+      else {								\
+	ta_start__tag = tag_next;					\
+	break;								\
+      }									\
+    }									\
+    (ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value;	\
+    if (ta_start__tag != NULL &&					\
+	ta_start__tag != tag_null &&					\
+	ta_start__tag != tag_next) {					\
+      (ta).tl[1].t_tag = tag_next;					\
+      (ta).tl[1].t_value = (tag_value_t)(&(v) + 1);			\
+    } else {								\
+      (ta).tl[1].t_tag = 0; (ta).tl[1].t_value = (tag_value_t)0;	\
+    }									\
+  } while(0)
+#else
+/* Tagged arguments are in registers - copy all of them. */
+#define ta_start(ta, t, v)						\
+   do {									\
+    tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v);	\
+    va_start((ta).ap, (v));						\
+    while ((ta_start__tag) == tag_next && (ta_start__value) != 0) {	\
+      ta_start__tag = ((tagi_t *)ta_start__value)->t_tag;		\
+      if (ta_start__tag == tag_null || ta_start__tag == NULL)		\
+	break;								\
+      if (ta_start__tag == tag_next) {					\
+	ta_start__value = ((tagi_t *)ta_start__value)->t_value;		\
+      } else {								\
+	ta_start__tag = tag_next;					\
+	break;								\
+      }									\
+    }									\
+    (ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value;	\
+    if (ta_start__tag != NULL &&					\
+	ta_start__tag != tag_null &&					\
+	ta_start__tag != tag_next) {					\
+      (ta).tl[1].t_tag = tag_next;					\
+      (ta).tl[1].t_value = (tag_value_t)tl_vlist((ta).ap);		\
+    } else {								\
+      (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0;	\
+    }									\
+  } while(0)
+#endif
+
+/**Macro accessing tagged argument list.
+ *
+ * The ta_args() returns a pointer to tag list containing the arguments.
+ *
+ * @hideinitializer
+ */
+#define ta_args(ta) (ta).tl
+
+/**Macro passing tagged argument list as an argument to another function.
+ *
+ * The ta_tags() macro expands to an tag list that can be given as arguments
+ * to a function taking an variable tag item list as an argument.
+ *
+ * @hideinitializer
+ */
+#define ta_tags(ta) \
+  (ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).tl[1].t_value
+
+/**Handle return from function with tagged argument list
+ * 
+ * The ta_end() macro handles return from function whose tagged argument
+ * list was initialized by ta_start().
+ *
+ * The ta_end() macro returns no value.
+ *
+ * @hideinitializer
+ */
+#if SU_HAVE_TAGSTACK
+#define ta_end(ta) (va_end((ta).ap), (ta).tl->t_tag = NULL, 0)
+#else
+#define ta_end(ta)					   \
+  ((((ta).tl[1].t_value) ?				   \
+    (tl_vfree((tagi_t *)((ta).tl[1].t_value))) : (void)0), \
+   (ta).tl[1].t_value = 0, va_end((ta).ap), 0)
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAGARG_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TIME_H
+/** Defined when <sofia-sip/su_time.h> has been included. */
+#define SU_TIME_H
+/**@ingroup su_time
+ * @file sofia-sip/su_time.h 
+ * @brief Time types and functions.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Time in seconds and microsecondcs. 
+ *
+ * The structure su_time_t contains time in seconds and microseconds since
+ * epoch (January 1, 1900).
+ */
+struct su_time_s { 
+  unsigned long tv_sec;		/**< Seconds */
+  unsigned long tv_usec;	/**< Microseconds  */
+};
+/** Time in seconds and microsecondcs. */
+typedef struct su_time_s su_time_t;
+
+/** Time difference in microseconds. 
+ * 
+ * The type su_duration_t is used to present small time differences (24
+ * days), usually calculated between two su_time_t timestamps.  Note that
+ * the su_duration_t is signed.
+ */
+typedef long su_duration_t;
+
+enum { 
+  /** Maximum duration in milliseconds. */
+  SU_DURATION_MAX = 0x7fffffffL 
+};
+#define SU_DURATION_MAX SU_DURATION_MAX
+
+/** NTP timestamp. 
+ * 
+ * NTP timestamp is defined as microseconds since epoch (1-Jan-1900) 
+ * with 64-bit resolution.
+ */
+typedef uint64_t su_ntp_t;
+
+/** Represent NTP consttant */
+#define SU_NTP_C(x) SU_U64_C(x)
+
+#define SU_TIME_CMP(t1, t2) su_time_cmp(t1, t2)
+
+/** Seconds from 1.1.1900 to 1.1.1970. @NEW_1_12_4 */
+#define SU_TIME_EPOCH 2208988800UL 
+
+SOFIAPUBFUN su_time_t su_now(void);
+SOFIAPUBFUN void su_time(su_time_t *tv);
+SOFIAPUBFUN long su_time_cmp(su_time_t const t1, su_time_t const t2);
+SOFIAPUBFUN double su_time_diff(su_time_t const t1, su_time_t const t2);
+SOFIAPUBFUN su_duration_t su_duration(su_time_t const t1, su_time_t const t2);
+
+SOFIAPUBFUN su_time_t su_time_add(su_time_t t, su_duration_t dur);
+SOFIAPUBFUN su_time_t su_time_dadd(su_time_t t, double dur);
+
+SOFIAPUBFUN int su_time_print(char *s, int n, su_time_t const *tv);
+
+#define SU_SEC_TO_DURATION(sec) ((su_duration_t)(1000 * (sec)))
+
+SOFIAPUBFUN su_ntp_t su_ntp_now(void);
+SOFIAPUBFUN uint32_t su_ntp_sec(void);
+SOFIAPUBFUN uint32_t su_ntp_hi(su_ntp_t);
+SOFIAPUBFUN uint32_t su_ntp_lo(su_ntp_t);
+SOFIAPUBFUN uint32_t su_ntp_mw(su_ntp_t ntp);
+
+#if !SU_HAVE_INLINE
+SOFIAPUBFUN uint32_t su_ntp_fraq(su_time_t t);
+SOFIAPUBFUN uint32_t su_time_ms(su_time_t t);
+#else
+static SU_INLINE
+/** Middle 32 bit of NTP timestamp. */
+uint32_t su_ntp_fraq(su_time_t t)
+{
+  /*
+   * Multiply usec by 0.065536 (ie. 2**16 / 1E6)
+   * 
+   * Utilize fact that 0.065536 == 1024 / 15625
+   */
+  return (t.tv_sec << 16) + (1024 * t.tv_usec + 7812) / 15625;
+}
+
+static SU_INLINE
+/** Time as milliseconds. */
+uint32_t su_time_ms(su_time_t t)
+{
+  return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000;
+}
+#endif
+
+SOFIAPUBFUN su_ntp_t su_ntp_hilo(uint32_t hi, uint32_t lo);
+
+SOFIAPUBFUN uint64_t su_counter(void);
+
+SOFIAPUBFUN uint64_t su_nanocounter(void);
+
+SOFIAPUBFUN uint32_t su_random();
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TIME_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TYPES_H
+/** Defined when <sofia-sip/su_types.h> has been included */
+#define SU_TYPES_H
+/**@file sofia-sip/su_types.h Basic integer types for @b su library.
+ *
+ * This include file provides <stdint.h> or <inttypes.h> types.
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+
+#if SU_HAVE_STDINT
+#include <stdint.h>
+#elif SU_HAVE_INTTYPES
+#include <inttypes.h>
+#endif
+
+#if SU_HAVE_SYS_TYPES
+#include <sys/types.h>
+#endif
+
+#include <stddef.h>
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_STDINT || SU_HAVE_INTTYPES
+#define SU_S64_T int64_t
+#define SU_U64_T uint64_t
+#define SU_S32_T int32_t
+#define SU_U32_T uint32_t
+#define SU_S16_T int16_t
+#define SU_U16_T uint16_t
+#define SU_S8_T  int8_t
+#define SU_U8_T  uint8_t
+#define SU_LEAST64_T int_least64_t
+#define SU_LEAST32_T int_least32_t
+#define SU_LEAST16_T int_least16_t
+#define SU_LEAST8_T int_least8_t
+#endif
+
+#if DOXYGEN_ONLY || (!SU_HAVE_STDINT && !SU_HAVE_INTTYPES && SU_HAVE_WIN32)
+
+/* Use macros defined in <su_configure_win32.h> */
+
+#ifndef _INTPTR_T_DEFINED
+/** Integer type large enough to store pointers */
+typedef SU_INTPTR_T intptr_t;
+#endif
+#ifndef _UINTPTR_T_DEFINED
+/** Unsigned integer type large enough to store pointers */
+typedef unsigned SU_INTPTR_T uintptr_t;
+#endif
+
+/** 64-bit unsigned integer */ 
+typedef SU_U64_T uint64_t;
+/** 64-bit signed integer */   
+typedef SU_S64_T int64_t;
+/** 32-bit unsigned integer */ 
+typedef SU_U32_T uint32_t;
+/** 32-bit signed integer */   
+typedef SU_S32_T int32_t;
+/** 16-bit unsigned integer */ 
+typedef SU_U16_T uint16_t;
+/** 16-bit signed integer */   
+typedef SU_S16_T int16_t;
+/** 8-bit unsigned integer */  
+typedef SU_U8_T  uint8_t;
+/** 8-bit signed integer */    
+typedef SU_S8_T  int8_t;
+
+/** At least 64-bit integer */
+typedef SU_LEAST64_T int_least64_t;
+/** At least 32-bit integer */
+typedef SU_LEAST32_T int_least32_t;
+/** At least 16-bit integer */
+typedef SU_LEAST16_T int_least16_t;
+/** At least 8-bit integer */
+typedef SU_LEAST8_T int_least8_t;
+#endif
+
+#if !SU_HAVE_STDINT && !SU_HAVE_INTTYPES && !SU_HAVE_WIN32
+#error "no integer types available."
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* size_t types for binary compatibility */
+
+#ifdef SOFIA_SSIZE_T
+/** POSIX type used for a count of bytes or an error indication. */
+typedef SOFIA_SSIZE_T ssize_t;
+#endif
+
+#ifdef SOFIA_ISIZE_T
+/** Compatibility type. 
+ *
+ * sofia-sip <= 1.12.1 often used int for count of bytes. 
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as int, otherwise as size_t. Note that int is signed and size_t is
+ * unsigned.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_ISIZE_T isize_t;
+#else
+typedef size_t isize_t;
+#endif
+
+#ifdef SOFIA_ISSIZE_T
+/**Compatibility type. 
+ *
+ * sofia-sip <= 1.12.1 used int for count of bytes. 
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as int, otherwise as ssize_t. (-1 is used for error indication).
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_ISSIZE_T issize_t;
+#else
+typedef ssize_t issize_t;
+#endif
+
+#ifdef SOFIA_USIZE_T
+/**Compatibility type. 
+ *
+ * sofia-sip <= 1.12.1 sometimes used unsigned int for count of bytes. 
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as unsigned int, otherwise as size_t.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_USIZE_T usize_t;
+#else
+typedef size_t usize_t;
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_TYPES_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_UNIQUEID_H
+/** Defined when <sofia-sip/su_uniqueid.h> has been included. */
+#define SU_UNIQUEID_H 
+
+
+/**@ingroup su_uniqueid
+ * @file sofia-sip/su_uniqueid.h
+ *
+ * Functions to handle GloballyUniqueIDs.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Globally unique identifier type. */
+typedef union GloballyUniqueIdentifier { 
+  unsigned char id[16]; 
+  struct {
+    uint32_t  time_low;
+    uint16_t  time_mid;
+    uint16_t  time_high_and_version;
+    uint8_t   clock_seq_hi_and_reserved;
+    uint8_t   clock_seq_low;
+    uint8_t   node[6];
+  } s;
+} su_guid_t;
+
+/** Return node identifier */
+SOFIAPUBFUN size_t su_node_identifier(void *address, size_t addrlen);
+
+/** Generate a GUID 
+ * 
+ * The function guid_generate() generates a new globally unique identifier
+ * for an IP telephony call.  The guid follows the structure specified in
+ * the ITU-T recommendation H.225.0 v2.  The guid is usable also in SIP
+ * @b Call-ID header.
+ *
+ * @param guid [out] pointer to structure for new call identifier
+ */
+SOFIAPUBFUN void su_guid_generate(su_guid_t *guid);
+
+/** Print guid.
+ *
+ * The function guid_sprintf() formats the IP telephony call identifier
+ * according the human-readable format specified in the ITU-T recommendation
+ * H.225.0 v2.  The printed identifier can be used as a SIP @b Call-ID if
+ * the colons in IEEE MAC address are replaced with '-', '+' or other
+ * character allowed in SIP @e token.
+ * 
+ * @param buf  [out] buffer to store the formatted globally unique identifier
+ * @param len  [in] size of buffer @a buf (should be at least guid_strlen bytes)
+ * @param guid [in] pointer to structure containing globally unique identifier
+ * 
+ * @retval 
+ * The function guid_sprintf() returns length of the formatted
+ * globally unique identifier excluding the final NUL.
+ */
+SOFIAPUBFUN isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *guid);
+
+enum { 
+  /** Length of guid in hex format */ 
+  su_guid_strlen = 8 + 5 + 5 + 5 + 13
+};
+
+/** Random integer in range [lb, ub] (inclusive).
+ *
+ * The function randint() generates a pseudo-random integer in the range
+ * [ln, ub] (inclusive).
+ *
+ * @param lb [in] lower bound
+ * @param ub [in] upper bound
+ *
+ * @return 
+* The function randint() returns a pseudo-random integer.
+ */
+SOFIAPUBFUN int su_randint(int lb, int ub);
+
+/** Fill memory with random values.
+ *
+ * The function randmem() fills the given memory range with pseudo-random data.
+ *
+ * @param mem [out] pointer to the beginning of the memory area to be filled
+ * @param siz [in] size fo the memory area in bytes
+ */
+SOFIAPUBFUN void *su_randmem(void *mem, size_t siz);
+
+/** Generate a random 32-bit integer. */
+SOFIAPUBFUN uint32_t su_random();
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_VECTOR_H
+/** Defined when <sofia-sip/su_vector.h> has been included. */
+#define SU_VECTOR_H
+
+/**@file sofia-sip/su_vector.h
+ * @brief Vector interface
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Fri Sep 27 14:31:15 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_vector_s su_vector_t;
+typedef void (* su_free_func_t) (void *data);
+
+/** Create a vector. */
+SU_DLL su_vector_t *su_vector_create(su_home_t *home, su_free_func_t free_f)
+     __attribute__((__malloc__));
+
+/** Destroy a vector. */
+SU_DLL void su_vector_destroy(su_vector_t *);
+
+/** Insert an item to vector. */
+SU_DLL int su_vector_insert(su_vector_t *vector, usize_t index, void *item);
+
+SU_DLL int su_vector_remove(su_vector_t *vector, usize_t index);
+
+/** Append a item to vector. */
+SU_DLL int su_vector_append(su_vector_t *, void *item);
+
+/** Get a numbered item from vector. */
+SU_DLL void *su_vector_item(su_vector_t const *, usize_t i);
+
+/** Get number of items in vector. */
+SU_DLL usize_t su_vector_len(su_vector_t const *l);
+
+SU_DLL int su_vector_empty(su_vector_t *vector);
+SU_DLL int su_vector_is_empty(su_vector_t const *vector);
+
+#if SU_HAVE_INLINE
+static inline
+su_home_t *su_vector_home(su_vector_t *s)
+{
+  return (su_home_t *)s;
+}
+#else
+#define su_vector_home(s) ((su_home_t *)(s))
+#endif
+
+/** Get an array of pointers from the vector. */
+SU_DLL void **su_vector_get_array(su_vector_t *)
+     __attribute__((__malloc__));
+
+/** Free the array */
+SU_DLL void su_vector_free_array(su_vector_t *, void *array[]);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_VECTOR_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,477 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_WAIT_H
+/** Defined when <sofia-sip/su_wait.h> has been included. */
+#define SU_WAIT_H
+
+/**@ingroup su_wait
+ * @file sofia-sip/su_wait.h Syncronization and threading interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_H
+#include "sofia-sip/su.h"
+#endif
+
+#ifndef SU_TIME_H
+#include "sofia-sip/su_time.h"
+#endif
+#if SU_HAVE_POLL
+#include <sys/poll.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* Constants */
+
+#if SU_HAVE_POLL || DOCUMENTATION_ONLY
+/** Compare wait object. @HI */
+#define SU_WAIT_CMP(x, y) \
+ (((x).fd - (y).fd) ? ((x).fd - (y).fd) : ((x).events - (y).events))
+
+/** Incoming data is available on socket. @HI */
+#define SU_WAIT_IN      (POLLIN)
+/** Data can be sent on socket. @HI */
+#define SU_WAIT_OUT     (POLLOUT)
+/** Socket is connected. @HI */
+#define SU_WAIT_CONNECT (POLLOUT)
+/** An error occurred on socket. @HI */
+#define SU_WAIT_ERR     (POLLERR)
+/** The socket connection was closed. @HI */
+#define SU_WAIT_HUP     (POLLHUP)
+/** A listening socket accepted a new connection. @HI */
+#define SU_WAIT_ACCEPT  (POLLIN)
+
+/** No timeout for su_wait(). */
+#define SU_WAIT_FOREVER (-1)
+/** The return value of su_wait() if timeout occurred. */
+#define SU_WAIT_TIMEOUT (-2)
+
+/** Initializer for a wait object. @HI */
+#define SU_WAIT_INIT    { INVALID_SOCKET, 0, 0 }
+
+/** Maximum number of sources supported by su_wait() */
+#define SU_WAIT_MAX    (0x7fffffff)
+
+#elif SU_HAVE_WINSOCK
+
+#define SU_WAIT_CMP(x, y) ((intptr_t)(x) - (intptr_t)(y))
+
+#define SU_WAIT_IN      (FD_READ)
+#define SU_WAIT_OUT     (FD_WRITE)
+#define SU_WAIT_CONNECT (FD_CONNECT)
+#define SU_WAIT_ERR     (0)	/* let's get it on */
+#define SU_WAIT_HUP     (FD_CLOSE)
+#define SU_WAIT_ACCEPT  (FD_ACCEPT)
+
+#define SU_WAIT_FOREVER (WSA_INFINITE)
+#define SU_WAIT_TIMEOUT (WSA_WAIT_TIMEOUT)
+
+#define SU_WAIT_INIT    NULL
+
+#define SU_WAIT_MAX    (64)
+
+#else
+#define SU_WAIT_CMP(x, y) 
+#define SU_WAIT_IN      
+#define SU_WAIT_OUT     
+#define SU_WAIT_ERR     
+#define SU_WAIT_HUP     
+#define SU_WAIT_ACCEPT  
+#define SU_WAIT_FOREVER 
+#define SU_WAIT_TIMEOUT 
+
+#define SU_WAIT_INIT
+
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Types */
+
+#if 0
+typedef struct _pollfd {
+  su_socket_t fd;           /* file descriptor */
+  short events;     /* requested events */
+  short revents;    /* returned events */
+} su_wait_t;
+#elif SU_HAVE_POLL
+typedef struct pollfd su_wait_t;
+#elif SU_HAVE_WINSOCK
+typedef HANDLE su_wait_t;
+#else
+/** Wait object. */
+typedef struct os_specific su_wait_t;
+#endif
+
+/* Used by AD */
+typedef int su_success_t;
+
+/* ---------------------------------------------------------------------- */
+
+/** <a href="#su_root_t">Root object</a> type. */
+typedef struct su_root_s su_root_t;
+
+#ifndef SU_ROOT_MAGIC_T
+/**Default type of application context for <a href="#su_root_t">su_root_t</a>.
+ *
+ * Application may define the typedef ::su_root_magic_t to appropriate type
+ * by defining macro SU_ROOT_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_ROOT_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_ROOT_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_root_magic_t to appropriate type
+ * by defining macro SU_ROOT_MAGIC_T () before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_ROOT_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_ROOT_MAGIC_T su_root_magic_t;
+
+#ifndef SU_WAKEUP_ARG_T
+/**Default type of @link ::su_wakeup_f wakeup function @endlink 
+ * @link ::su_wakeup_arg_t argument type @endlink.  
+ *
+ * The application can define the typedef ::su_wakeup_arg_t by defining
+ * the SU_WAKEUP_ARG_T () before including <su_wait.h>, for example,
+ * @code
+ * #define SU_WAKEUP_ARG_T struct transport
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_WAKEUP_ARG_T void
+#endif
+
+/** @link ::su_wakeup_f Wakeup callback @endlink argument type. 
+ *
+ * The application can define the typedef ::su_wakeup_arg_t by defining
+ * the SU_WAKEUP_ARG_T () before including <su_wait.h>, for example,
+ * @code
+ * #define SU_WAKEUP_ARG_T struct transport
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_WAKEUP_ARG_T su_wakeup_arg_t;
+
+/** Wakeup callback function prototype. 
+ *
+ * Whenever a registered wait object receives an event, the @link
+ * ::su_wakeup_f callback function @endlink is invoked.
+ */
+typedef int (*su_wakeup_f)(su_root_magic_t *,
+			   su_wait_t *,
+			   su_wakeup_arg_t *arg);
+
+enum { 
+  su_pri_normal,		/**< Normal priority */
+  su_pri_first,			/**< Elevated priority */
+  su_pri_realtime		/**< Real-time priority */
+};
+
+struct _GSource;
+
+/** Hint for number of registered fds in su_root */
+SOFIAPUBVAR int su_root_size_hint;
+
+/* ---------------------------------------------------------------------- */
+/* Pre-poll callback */
+
+#ifndef SU_PREPOLL_MAGIC_T
+/**Default type of application context for prepoll function.
+ *
+ * Application may define the typedef ::su_prepoll_magic_t to appropriate type
+ * by defining macro #SU_PREPOLL_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_PREPOLL_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_PREPOLL_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_prepoll_magic_t to appropriate type
+ * by defining macro #SU_PREPOLL_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_PREPOLL_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_PREPOLL_MAGIC_T su_prepoll_magic_t;
+
+
+/** Pre-poll callback function prototype. 
+ *
+ * 
+ */
+typedef void su_prepoll_f(su_prepoll_magic_t *, su_root_t *);
+
+/* ---------------------------------------------------------------------- */
+
+/* Timers */
+#ifdef SU_TIMER_T
+#error SU_TIMER_T defined
+#endif
+
+#ifndef SU_TIMER_ARG_T
+/** Default type of timer expiration callback function argument type.
+ * Application may define this to appropriate type before including
+ * <su_wait.h>. */
+#define SU_TIMER_ARG_T void 
+#endif
+
+/** Timer object type. */
+typedef struct su_timer_s su_timer_t;
+
+/** Timer callback argument type. */
+typedef SU_TIMER_ARG_T su_timer_arg_t;
+
+/** Timeout function type. */
+typedef void (*su_timer_f)(su_root_magic_t *magic, 
+			   su_timer_t *t,
+			   su_timer_arg_t *arg);
+
+/* ---------------------------------------------------------------------- */
+
+/* Tasks */
+
+/** Port type. */
+typedef struct su_port_s su_port_t;
+
+typedef struct { su_port_t *sut_port; su_root_t *sut_root; } _su_task_t;
+
+/** Task reference type. */
+typedef _su_task_t su_task_r[1];
+
+/** Initializer for a task reference. @HI */
+#define SU_TASK_R_INIT  {{ NULL, NULL }}
+
+/* This must be used instead of su_task_r as return value type. */
+typedef _su_task_t const *_su_task_r;
+
+/* ---------------------------------------------------------------------- */
+
+/* Messages */
+#ifndef SU_MSG_ARG_T
+/** Default type of su_msg_t message data.  Application may define this to
+ * appropriate type before including <su_wait.h>.
+ */
+#define SU_MSG_ARG_T void 
+#endif
+
+/** Message argument type. */
+typedef SU_MSG_ARG_T su_msg_arg_t;
+
+/** Message type. */
+typedef struct su_msg_s su_msg_t;
+
+/** Message reference type. */
+typedef su_msg_t *su_msg_r[1];
+
+/** Contstant reference to su_msg */
+typedef su_msg_t * const su_msg_cr[1];
+
+/** Initializer for a message reference. @HI */
+#define SU_MSG_R_INIT   { NULL }
+
+/** Message delivery function type. */
+typedef void (*su_msg_f)(su_root_magic_t *magic, 
+			 su_msg_r msg,
+			 su_msg_arg_t *arg);
+
+/* ---------------------------------------------------------------------- */
+
+/* Clones */
+#ifndef SU_CLONE_T
+#define SU_CLONE_T struct su_clone_s
+#endif
+
+/** Clone reference. */
+typedef SU_CLONE_T *su_clone_r[1];
+
+/** Clone reference initializer. */
+#define SU_CLONE_R_INIT  {NULL}
+
+/** Clone initialization function type. */
+typedef int (*su_root_init_f)(su_root_t *, su_root_magic_t *);
+
+/** Clone finalization function type. */
+typedef void (*su_root_deinit_f)(su_root_t *, su_root_magic_t *);
+
+/* ---------------------------------------------------------------------- */
+/* Functions */
+
+/* Wait */
+SOFIAPUBFUN void su_wait_init(su_wait_t dst[1]);
+SOFIAPUBFUN int su_wait_create(su_wait_t *dst, su_socket_t s, int events);
+SOFIAPUBFUN int su_wait_destroy(su_wait_t *dst);
+SOFIAPUBFUN int su_wait(su_wait_t waits[], unsigned n, su_duration_t timeout);
+SOFIAPUBFUN int su_wait_events(su_wait_t *wait, su_socket_t s);
+SOFIAPUBFUN int su_wait_mask(su_wait_t *dst, su_socket_t s, int events);
+
+#if SU_HAVE_POLL
+static inline
+su_socket_t su_wait_socket(su_wait_t *wait)
+{
+  return wait->fd;
+}
+#endif
+
+/* Root */
+SOFIAPUBFUN su_root_t *su_root_create(su_root_magic_t *magic)
+  __attribute__((__malloc__));
+SOFIAPUBFUN void su_root_destroy(su_root_t*);
+SOFIAPUBFUN int su_root_set_magic(su_root_t *self, su_root_magic_t *magic);
+SOFIAPUBFUN su_root_magic_t *su_root_magic(su_root_t *root);
+SOFIAPUBFUN int su_root_register(su_root_t*, su_wait_t *, 
+				 su_wakeup_f, su_wakeup_arg_t *,
+				 int priority);
+/* This is slow. Deprecated. */
+SOFIAPUBFUN int su_root_unregister(su_root_t*, su_wait_t *, 
+				   su_wakeup_f, su_wakeup_arg_t*);
+SOFIAPUBFUN int su_root_deregister(su_root_t*, int);
+SOFIAPUBFUN int su_root_eventmask(su_root_t *, 
+				  int index, int socket, int events);
+SOFIAPUBFUN su_duration_t su_root_step(su_root_t *root, su_duration_t timeout);
+SOFIAPUBFUN su_duration_t su_root_sleep(su_root_t *root, su_duration_t);
+SOFIAPUBFUN int su_root_multishot(su_root_t *root, int multishot);
+SOFIAPUBFUN void su_root_run(su_root_t *root);
+SOFIAPUBFUN void su_root_break(su_root_t *root);
+SOFIAPUBFUN _su_task_r su_root_task(su_root_t const *root);
+SOFIAPUBFUN _su_task_r su_root_parent(su_root_t const *root);
+
+SOFIAPUBFUN int su_root_add_prepoll(su_root_t *root, 
+				    su_prepoll_f *, 
+				    su_prepoll_magic_t *);
+SOFIAPUBFUN int su_root_remove_prepoll(su_root_t *root);
+
+SOFIAPUBFUN struct _GSource *su_root_gsource(su_root_t *self);
+
+SOFIAPUBFUN int su_root_yield(su_root_t *root);
+
+/* Timers */
+SOFIAPUBFUN su_timer_t *su_timer_create(su_task_r const, su_duration_t msec)
+     __attribute__((__malloc__));
+SOFIAPUBFUN void su_timer_destroy(su_timer_t *);
+SOFIAPUBFUN int su_timer_set(su_timer_t *, su_timer_f, su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_set_interval(su_timer_t *t, su_timer_f,
+				      su_timer_arg_t *, su_duration_t);
+SOFIAPUBFUN int su_timer_set_at(su_timer_t *, su_timer_f,
+				su_timer_arg_t *, su_time_t);
+SOFIAPUBFUN int su_timer_run(su_timer_t *, su_timer_f, su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_set_for_ever(su_timer_t *, su_timer_f, 
+				      su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_reset(su_timer_t *);
+
+SOFIAPUBFUN su_root_t *su_timer_root(su_timer_t const *);
+
+SOFIAPUBFUN int su_timer_expire(su_timer_t ** const, 
+				su_duration_t *tout,
+				su_time_t now);
+
+/* Tasks */
+
+/** NULL task. */
+SOFIAPUBVAR su_task_r const su_task_null;
+
+SOFIAPUBFUN _su_task_r su_task_init(su_task_r task);
+SOFIAPUBFUN void su_task_deinit(su_task_r task);
+
+SOFIAPUBFUN void su_task_copy(su_task_r dst, su_task_r const src);
+SOFIAPUBFUN void su_task_move(su_task_r dst, su_task_r src);
+SOFIAPUBFUN int su_task_cmp(su_task_r const, su_task_r const);
+SOFIAPUBFUN int su_task_is_running(su_task_r const);
+
+SOFIAPUBFUN su_root_t *su_task_root(su_task_r const self);
+SOFIAPUBFUN su_timer_t **su_task_timers(su_task_r const self);
+
+SOFIAPUBFUN int su_task_execute(su_task_r const task,
+				int (*function)(void *), void *arg,
+				int *return_value);
+
+/* Messages */
+SOFIAPUBFUN int su_msg_create(su_msg_r msg,
+			      su_task_r const to, su_task_r const from, 
+			      su_msg_f wakeup, isize_t size);
+SOFIAPUBFUN int su_msg_report(su_msg_r msg, su_msg_f report);
+SOFIAPUBFUN int su_msg_reply(su_msg_r reply, su_msg_r const msg,
+			     su_msg_f wakeup, isize_t size);
+SOFIAPUBFUN void su_msg_destroy(su_msg_r msg);
+SOFIAPUBFUN void su_msg_save(su_msg_r msg, su_msg_r msg0);
+SOFIAPUBFUN void su_msg_remove_refs(su_msg_cr msg);
+SOFIAPUBFUN su_msg_arg_t *su_msg_data(su_msg_cr msg);
+SOFIAPUBFUN isize_t su_msg_size(su_msg_cr msg);
+SOFIAPUBFUN _su_task_r su_msg_from(su_msg_cr msg);
+SOFIAPUBFUN _su_task_r su_msg_to(su_msg_cr msg);
+SOFIAPUBFUN int su_msg_send(su_msg_r msg);
+
+/** Does reference contain a message? */
+#if SU_HAVE_INLINE
+static SU_INLINE
+int su_msg_is_non_null(su_msg_cr msg)
+{
+  return msg && *msg != NULL;
+}
+#else
+#define su_msg_is_non_null(msg) ((msg) && (*(msg)) != NULL)
+#endif
+
+/* Clones */
+SOFIAPUBFUN int su_root_threading(su_root_t *self, int enable);
+SOFIAPUBFUN int su_clone_start(su_root_t *root, 
+			       su_clone_r,
+			       su_root_magic_t *magic,
+			       su_root_init_f, 
+			       su_root_deinit_f);
+SOFIAPUBFUN _su_task_r su_clone_task(su_clone_r);
+SOFIAPUBFUN void su_clone_forget(su_clone_r);
+SOFIAPUBFUN void su_clone_stop(su_clone_r);
+SOFIAPUBFUN void su_clone_wait(su_root_t *root, su_clone_r clone);
+
+SOFIAPUBFUN int su_clone_pause(su_clone_r);
+SOFIAPUBFUN int su_clone_resume(su_clone_r);
+
+SOFIA_END_DECLS
+
+#endif /* SU_WAIT_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,355 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/tstdef.h Macros for unit tests
+ *
+ * The macros defined here can be used by unit test programs. When a test
+ * fails, the TEST macros print the offending file name and line number. 
+ * They use format that is accepted by Emacs and other fine editors so you
+ * can directly go to the source code of the failed test with next-error.
+ * 
+ * @note There is no protection agains multiple inclusion. 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Aug 22 13:53:24 2001 ppessi
+ *
+ * @par Example Program
+ *
+ * You should define the macro TSTFLAGS to a int variable possibly
+ * containing a flag #tst_verbatim. As a convention, the int variable should
+ * be set when your test program is run with @c -v or @c --verbatim command
+ * line option. If the (TSTFLAGS & tst_verbatim) is true, the test macros
+ * log the test before executing it and the result of successful tests, too.
+ *
+ * You should typedef longlong to integer type at least 64 bit wide before
+ * including <sofia-sip/tstdef.h>, too.
+ * 
+ * As an example, we provide a test program making sure that inet_ntop() and
+ * inet_pton() behave as expected and that we can create UDP/IPv4 sockets
+ * with @b su library:
+ *
+ * @code
+ * #include "config.h"
+ * 
+ * #include <stdio.h>
+ * #include <limits.h>
+ * 
+ * #include <sofia-sip/su.h>
+ * 
+ * #define TSTFLAGS tstflags
+ *
+ * #include <stdlib.h>
+ * #include <sofia-sip/tstdef.h>
+ *
+ * static int tstflags = 0;
+ * 
+ * void usage(void)
+ * {
+ *   fprintf(stderr, "usage: %s [-v|--verbatim]\n", name);
+ *   exit(2);
+ * }
+ * 
+ * static int socket_test(void);
+ * 
+ * int main(int argc, char *argv[])
+ * {
+ *   int retval = 0, i;
+ * 
+ *   for (i = 1; argv[i]; i++) {
+ *     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
+ *       tstflags |= tst_verbatim;
+ *     else
+ *       usage();
+ *   }
+ * 
+ *   retval |= socket_test(); fflush(stdout);
+ * 
+ *   return retval;
+ * }
+ * 
+ * double max_bandwidth()
+ *
+ * int socket_test(void)
+ * {
+ *   su_socket_t s;
+ *   char buf[64];
+ *   unsigned long localhost = htonl(0x7f000001);
+ *   unsigned long addr;
+ *
+ *   BEGIN();
+ * 
+ *   // Check inet_ntop() return value (Tests equality of integral values)
+ *   TEST(inet_ntop(AF_INET, &localhost, buf, sizeof buf), buf);
+ * 
+ *   // Check inet_ntop() result (Tests equality of strings)
+ *   TEST_S(buf, "127.0.0.1");
+ * 
+ *   // Check inet_pton() argument validation (Tests equality of ints)
+ *   TEST(inet_pton(0, buf, &addr), -1);
+ * 
+ *   // Check inet_pton() return value (Tests for true value (non-zero))
+ *   TEST_1(inet_pton(AF_INET, buf, &addr) > 0);
+ * 
+ *   // Check inet_pton() result (Tests equality of memory areas)
+ *   TEST_M(&addr, &localhost, sizeof(addr));
+ *
+ *   // Test to create UDP socket (Test for true value)
+ *   TEST_1((s = su_socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+ *
+ *   // Check max bandwidth
+ *   TEST_D(max_bandwidth(), DBL_MAX);
+ *
+ *   END();
+ * }
+ * @endcode
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if HAVE_FUNC
+#define TSTNAME name, __func__, "() "
+#elif HAVE_FUNCTION
+#define TSTNAME name, __FUNCTION__, "() "
+#else
+#define TSTNAME name, "", ""
+#endif
+
+enum {
+  /** If (TSTFLAGS & tst_verbatim) is non-zero, be verbatim. */
+  tst_verbatim = 1,
+  /** If (TSTFLAGS & tst_abort) is non-zero, abort() when failed. */
+  tst_abort = 2,
+};
+
+#ifndef TSTFLAGS
+#error <TSTFLAGS is not defined>
+#endif
+
+#ifdef TSTFLAGS
+/** Begin a test function. @HIDE */
+#define BEGIN() BEGIN_(TSTFLAGS); { extern int tstdef_dummy
+/** End a test function. @HIDE */
+#define END() (void) tstdef_dummy; } END_(TSTFLAGS)
+/**Test that @a suite returns a nonzero value.
+ * @deprecated Use TEST_1() 
+ * @HIDE */
+#define TEST0(suite) TEST_1_(TSTFLAGS, suite)
+/** Test that @a suite returns a nonzero value. @HIDE */
+#define TEST_1(suite) TEST_1_(TSTFLAGS, suite)
+/** Test a void suite. @HIDE */
+#define TEST_VOID(suite) TEST_VOID_(TSTFLAGS, suite)
+/** Test that @a suite is equal to @a expected. @HIDE */
+#define TEST(suite, expected) TEST_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same pointer as @a expected. @HIDE */
+#define TEST_P(suite, expected) TEST_P_(TSTFLAGS, suite, expected)
+/** Test that 64-bit @a suite is equal to @a expect. @HIDE */
+#define TEST64(suite, expected) TEST64_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same double as @a expected. @HIDE */
+#define TEST_D(suite, expected) TEST_D_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same string as @a expected. @HIDE */
+#define TEST_S(suite, expected) TEST_S_(TSTFLAGS, suite, expected)
+/** Test that @a suite is results as identical memory as @a expected. @HIDE */
+#define TEST_M(suite, expected, len) TEST_M_(TSTFLAGS, suite, expected, len)
+/** Test that @a suite has same size as @a expected. @HIDE */
+#define TEST_SIZE(suite, expected) TEST_SIZE_(TSTFLAGS, suite, expected)
+
+#else
+/* Deprecated */
+#define TEST0(flags, suite) TEST_1_(flags, suite)
+#define TEST_1(flags, suite) TEST_1_(flags, suite)
+#define TEST_VOID(flags, suite) TEST_VOID_(flags, suite)
+#define TEST(flags, suite, expect) TEST_(flags, suite, expect)
+#define TEST64(flags, suite, expect) TEST64_(flags, suite, expect)
+#define TEST_S(flags, suite, expect) TEST_S_(flags, suite, expect)
+#define BEGIN(flags) BEGIN_(flags) { extern int tstdef_dummy
+#define END(flags) (void) tstdef_dummy;  } END_(flags) 
+#endif
+
+#define TEST_FAILED(flags) \
+  ((flags) & tst_abort) ? abort() : (void)0; return 1
+
+/** @HIDE */
+#define TEST_1_(flags, suite) do { \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s\n", TSTNAME, #suite); \
+    fflush(stdout); } \
+  if ((suite)) { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: (%s)\n", TSTNAME, #suite); break ; } \
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: (%s)\n", \
+          __FILE__, __LINE__, TSTNAME, #suite); fflush(stderr); \
+  TEST_FAILED(flags); }						\
+  while(0)
+
+/** @HIDE */
+#define TEST_VOID_(flags, suite) do { \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s\n", TSTNAME, #suite); \
+    fflush(stdout); } \
+  (suite); } while(0)
+
+/** @HIDE */
+#define TEST_(flags, suite, expect) do {				\
+    uintptr_t _value, _expect;						\
+    if (flags & tst_verbatim) {						\
+      printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect);	\
+      fflush(stdout); }							\
+    _value = (uintptr_t)(suite);					\
+    _expect = (uintptr_t)(expect);					\
+    if (_value == _expect) {						\
+      if (flags & tst_verbatim)						\
+	printf("%s: %s%sok: %s == %s \n",				\
+	       TSTNAME, #suite, #expect);				\
+      break;								\
+    }									\
+    fprintf(stderr, "%s:%u: %s %s%sFAILED: "				\
+	    "%s != %s or "MOD_ZU" != "MOD_ZU"\n",			\
+	    __FILE__, __LINE__, TSTNAME,				\
+	    #suite, #expect, (size_t)_value, (size_t)_expect);		\
+    fflush(stderr);							\
+    TEST_FAILED(flags);							\
+  } while(0)
+
+/** @HIDE */
+#define TEST_P_(flags, suite, expect) do {				\
+    void const * _value, * _expect;					\
+  if (flags & tst_verbatim) {						\
+    printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect);	\
+    fflush(stdout); }							\
+  if ((_value = (suite)) == (_expect = (expect))) {			\
+    if (flags & tst_verbatim)						\
+      printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect);	\
+    break;								\
+  }									\
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %p != %p\n",	\
+	  __FILE__, __LINE__, TSTNAME,					\
+	  #suite, #expect, _value, _expect); fflush(stderr);		\
+  TEST_FAILED(flags);							\
+  } while(0)
+
+/** @HIDE */
+#define TEST_SIZE_(flags, suite, expect) do {	\
+  size_t _value, _expect; \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+    fflush(stdout); } \
+  if ((_value = (size_t)(suite)) == \
+      (_expect = (size_t)(expect))) \
+  { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or "MOD_ZU" != "MOD_ZU"\n", \
+	 __FILE__, __LINE__, TSTNAME, \
+	  #suite, #expect, _value, _expect); fflush(stderr);		\
+  TEST_FAILED(flags);							\
+  } while(0)
+
+
+/** @HIDE */
+#define TEST64_(flags, suite, expect) do { \
+  uint64_t _value, _expect; \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+    fflush(stdout); } \
+  if ((_value = (uint64_t)(suite)) == (_expect = (uint64_t)(expect))) \
+  { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or "LLU" != "LLU"\n", \
+	 __FILE__, __LINE__, TSTNAME, \
+	  #suite, #expect, (unsigned longlong)_value,	\
+	 (unsigned longlong)_expect); fflush(stderr);	\
+  TEST_FAILED(flags);					\
+  } while(0)
+
+/** @HIDE */
+#define TEST_D_(flags, suite, expect) do { \
+  double _value, _expect; \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+    fflush(stdout); } \
+  if ((_value = (double)(suite)) == (_expect = (double)(expect))) \
+  { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %g != %g\n", \
+	 __FILE__, __LINE__, TSTNAME, \
+         #suite, #expect, _value, _expect); fflush(stderr); \
+  TEST_FAILED(flags);					    \
+  } while(0)
+
+/** @HIDE */
+#define TEST_S_(flags, suite, expect) do { \
+  char const * _value, * _expect; \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s is %s\n", TSTNAME, #suite, #expect); \
+    fflush(stdout); } \
+  _value = (suite); \
+  _expect = (expect); \
+  if (((_value == NULL || _expect == NULL) && _value == _expect) || \
+      (_value != NULL && _expect != NULL && strcmp(_value, _expect) == 0)) \
+  { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect);break;}\
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %s%s%s != \"%s\"\n", \
+	 __FILE__, __LINE__, TSTNAME, \
+	  #suite, #expect, \
+	  _value ? "\"" : "", _value ? _value : "NULL", _value ? "\"" : "", \
+	  _expect); fflush(stderr);					\
+  TEST_FAILED(flags);							\
+  } while(0)
+
+/** @HIDE */
+#define TEST_M_(flags, suite, expect, len) do { \
+  void const * _value, * _expect; \
+  int _len; \
+  if (flags & tst_verbatim) { \
+    printf("%s: %s%stesting %s is %s\n", TSTNAME, #suite, #expect); \
+    fflush(stdout); } \
+  _value = (suite); \
+  _expect = (expect); \
+  _len = (len); \
+  if (((_value == NULL || _expect == NULL) && _value == _expect) || \
+      memcmp(_value, _expect, _len) == 0) \
+  { if (flags & tst_verbatim) \
+  printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect);break;}\
+  fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s "\
+                  "or \"%.*s\" != \"%.*s\"\n", \
+	 __FILE__, __LINE__, TSTNAME, \
+	  #suite, #expect, _len, (char *)_value, _len, (char *)_expect); \
+  fflush(stderr);							\
+  TEST_FAILED(flags);							\
+  } while(0)
+
+/** @HIDE */
+#define BEGIN_(flags) \
+  if (flags & tst_verbatim) printf("%s: %s%sstarting\n", TSTNAME)
+
+/** @HIDE */
+#define END_(flags) \
+  if (flags & tst_verbatim) \
+    printf("%s: %s%sfinished fully successful\n", TSTNAME); \
+  return 0
+
+SOFIA_END_DECLS

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file strcasestr.c
+ * @brief Backup implementation of strcasestr()
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stddef.h>
+
+/* Naive implementation of strcasestr() */
+char *strcasestr(const char *haystack,
+		 const char *needle)
+{
+  unsigned char lcn, ucn;
+  unsigned i;
+
+  if (haystack == NULL || needle == NULL)
+    return NULL;
+
+  lcn = ucn = needle[0];
+  if (isupper(lcn))
+    lcn = tolower(lcn);
+  else if (islower(ucn))
+    ucn = toupper(ucn);
+
+  if (lcn == 0)
+    return (char *)haystack;
+
+  while (haystack[0] != 0) {
+    if (lcn == haystack[0] || ucn == haystack[0]) {
+      for (i = 1; ; i++) {
+	char n = needle[i], h = haystack[i];
+	if (n == 0)
+	  return (char *)haystack;
+	if (h == 0)
+	  return NULL;
+	if (isupper(n)) n = tolower(n);
+	if (isupper(h)) h = tolower(h);
+	if (n != h)
+	  break;
+      }
+    }
+    haystack++;
+  } 
+
+  return NULL;		/* Not found */
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,286 @@
+/* 
+ * strtoull.c --
+ *
+ *	Source code for the "strtoull" library procedure.
+ *
+ * Copyright (c) 1988 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+The following license.terms for information on usage and redistribution
+of this individual file, and for a DISCLAIMER OF ALL WARRANTIES.
+ 
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties.  The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license. 
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+/*
+ * The table below is used to convert from ASCII digits to a
+ * numerical equivalent.  It maps from '0' through 'z' to integers
+ * (100 for non-digit characters).
+ */
+
+static char cvtIn[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,		/* '0' - '9' */
+    100, 100, 100, 100, 100, 100, 100,		/* punctuation */
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'A' - 'Z' */
+    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+    30, 31, 32, 33, 34, 35,
+    100, 100, 100, 100, 100, 100,		/* punctuation */
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'a' - 'z' */
+    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+    30, 31, 32, 33, 34, 35};
+
+
+/**Convert an ASCII string into an unsigned long long integer.
+ *
+ * @param[in]  string  String of ASCII digits, possibly preceded by white
+ *                     space. For bases greater than 10, either lower- or
+ *                     upper-case digits may be used.
+ *
+ * @param[out] endPtr  Where to store address of terminating character, or
+ *                     NULL.
+ *
+ * @param[in] base     Base for conversion. Must be less than 37. If 0, then
+ *                     the base is chosen from the leading characters of
+ *                     string: "0x" means hex, "0" means octal, anything
+ *                     else means decimal.
+ *
+ * @return
+ * The integer equivalent of string. If @a endPtr is non-NULL, then pointer
+ * to the character after the last one that was part of the integer is
+ * stored to @a *endPtr.
+ *
+ * If string doesn't contain a valid integer value, then zero is
+ * returned and *endPtr is set to original value of @a string.
+ */
+
+unsigned longlong
+strtoull(const char *string, char **endPtr, int base)
+{
+    register const char *p;
+    register unsigned longlong result = 0;
+    register unsigned digit;
+    register unsigned longlong shifted;
+    int anyDigits = 0, negative = 0;
+
+    /*
+     * Skip any leading blanks.
+     */
+
+    p = string;
+    while (isspace(*p)) {	/* INTL: locale-dependent */
+	p += 1;
+    }
+
+    /*
+     * Check for a sign.
+     */
+
+    if (*p == '-') {
+	p += 1;
+	negative = 1;
+    } else {
+	if (*p == '+') {
+	    p += 1;
+	}
+    }
+
+    /*
+     * If no base was provided, pick one from the leading characters
+     * of the string.
+     */
+    
+    if (base == 0) {
+	if (*p == '0') {
+	    p += 1;
+	    if (*p == 'x' || *p == 'X') {
+		p += 1;
+		base = 16;
+	    } else {
+
+		/*
+		 * Must set anyDigits here, otherwise "0" produces a
+		 * "no digits" error.
+		 */
+
+		anyDigits = 1;
+		base = 8;
+	    }
+	} else {
+	    base = 10;
+	}
+    } else if (base == 16) {
+
+	/*
+	 * Skip a leading "0x" from hex numbers.
+	 */
+
+	if ((p[0] == '0') && (p[1] == 'x' || *p == 'X')) {
+	    p += 2;
+	}
+    }
+
+    /*
+     * Sorry this code is so messy, but speed seems important.  Do
+     * different things for base 8, 10, 16, and other.
+     */
+
+    if (base == 8) {
+	for ( ; ; p += 1) {
+	    digit = *p - '0';
+	    if (digit > 7) {
+		break;
+	    }
+	    shifted = result << 3;
+	    if ((shifted >> 3) != result) {
+		goto overflow;
+	    }
+	    result = shifted + digit;
+	    if ( result < shifted ) {
+		goto overflow;
+	    }
+	    anyDigits = 1;
+	}
+    } else if (base == 10) {
+	for ( ; ; p += 1) {
+	    digit = *p - '0';
+	    if (digit > 9) {
+		break;
+	    }
+	    shifted = 10 * result;
+	    if ((shifted / 10) != result) {
+		goto overflow;
+	    }
+	    result = shifted + digit;
+	    if ( result < shifted ) {
+		goto overflow;
+	    }
+	    anyDigits = 1;
+	}
+    } else if (base == 16) {
+	for ( ; ; p += 1) {
+	    digit = *p - '0';
+	    if (digit > ('z' - '0')) {
+		break;
+	    }
+	    digit = cvtIn[digit];
+	    if (digit > 15) {
+		break;
+	    }
+	    shifted = result << 4;
+	    if ((shifted >> 4) != result) {
+		goto overflow;
+	    }
+	    result = shifted + digit;
+	    if ( result < shifted ) {
+		goto overflow;
+	    }
+	    anyDigits = 1;
+	}
+    } else if ( base >= 2 && base <= 36 ) {
+	for ( ; ; p += 1) {
+	    digit = *p - '0';
+	    if (digit > ('z' - '0')) {
+		break;
+	    }
+	    digit = cvtIn[digit];
+	    if (digit >= (unsigned) base) {
+		break;
+	    }
+	    shifted = result * base;
+	    if ((shifted/base) != result) {
+		goto overflow;
+	    }
+	    result = shifted + digit;
+	    if ( result < shifted ) {
+		goto overflow;
+	    }
+	    anyDigits = 1;
+	}
+    }
+
+    /*
+     * Negate if we found a '-' earlier.
+     */
+
+    if (negative) {
+		result = (unsigned longlong)(-((longlong)result));
+    }
+
+    if (endPtr != 0) {
+    /*
+     * See if there were any digits at all.
+     */
+        if (!anyDigits) {
+    	    p = string;
+        }
+	*endPtr = (char *) p;
+    }
+
+    return result;
+
+    /*
+     * On overflow generate the right output
+     */
+
+ overflow:
+    errno = ERANGE;
+    if (endPtr != 0) {
+	for ( ; ; p += 1) {
+	    digit = *p - '0';
+	    if (digit > ('z' - '0')) {
+		break;
+	    }
+	    digit = cvtIn[digit];
+	    if (digit >= (unsigned) base) {
+		break;
+	    }
+	}
+	*endPtr = (char *) p;
+    }
+
+    return (unsigned longlong)-1;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,443 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_socket
+ * @CFILE su.c OS-independent socket functions
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h" 
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_alloc.h"
+
+#if !SU_HAVE_BSDSOCK && !SU_HAVE_WINSOCK
+#error Bad configuration
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC (1)
+#endif
+
+int su_socket_close_on_exec = 0;
+
+/** Create an endpoint for communication. */
+su_socket_t su_socket(int af, int socktype, int proto)
+{
+  su_socket_t s = socket(af, socktype, proto);
+#if SU_HAVE_BSDSOCK
+  if (s != INVALID_SOCKET && su_socket_close_on_exec) {
+    fcntl(s, F_SETFD, FD_CLOEXEC); /* Close on exec */
+  }
+#endif
+  return s;
+}
+
+#if SU_HAVE_BSDSOCK
+int su_init(void)
+{
+  su_home_threadsafe(NULL);
+
+  signal(SIGPIPE, SIG_IGN);	/* we want to get EPIPE instead */
+
+  su_log_init(su_log_default);
+  su_log_init(su_log_global);
+
+  return 0;
+}
+
+void su_deinit(void)
+{
+}
+
+/** Close an socket descriptor. */
+int su_close(su_socket_t s)
+{
+  return close(s);
+}
+
+int su_setblocking(su_socket_t s, int blocking)
+{
+  int mode = fcntl(s, F_GETFL, 0);
+
+  if (mode < 0)
+     return -1;
+
+  if (blocking) 
+    mode &= ~(O_NDELAY | O_NONBLOCK);
+  else
+    mode |= O_NDELAY | O_NONBLOCK;
+
+  return fcntl(s, F_SETFL, mode);
+}
+#endif
+
+#if SU_HAVE_WINSOCK
+int su_init(void)
+{
+  WORD	wVersionRequested;
+  WSADATA	wsaData;
+
+  wVersionRequested = MAKEWORD(2, 0);
+
+  if (WSAStartup(wVersionRequested, &wsaData) !=0) {
+    return -1;
+  }
+
+  su_log_init(su_log_default);
+
+  su_log_init(su_log_global);
+
+  return 0;
+}
+
+void su_deinit(void)
+{
+  WSACleanup();
+}
+
+/** Close an socket descriptor. */
+int su_close(su_socket_t s)
+{
+  return closesocket(s);
+}
+
+/** Control socket. */
+int su_ioctl(su_socket_t s, int request, ...)
+{
+  int retval;
+  void *argp;
+  va_list va;
+  va_start(va, request);
+  argp = va_arg(va, void *);
+  retval = ioctlsocket(s, request, argp);
+  va_end(va);
+  return retval;
+}
+
+int su_is_blocking(int errcode)
+{
+  return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS;
+}
+
+int su_setblocking(su_socket_t s, int blocking)
+{
+  unsigned long nonBlock = !blocking;
+  
+  return ioctlsocket(s, FIONBIO, &nonBlock);
+}
+
+
+#endif /* SU_HAVE_WINSOCK */
+
+int su_soerror(su_socket_t s)
+{
+  int error = 0;
+  socklen_t errorlen = sizeof(error);
+
+  getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&error, &errorlen);
+
+  return error;
+}
+
+int su_setreuseaddr(su_socket_t s, int reuse)
+{
+  return setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 
+		    (void *)&reuse, (socklen_t)sizeof(reuse));
+}
+
+
+#if HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#if SU_HAVE_WINSOCK
+issize_t su_getmsgsize(su_socket_t s)
+{
+  unsigned long n = (unsigned long)-1;
+  if (ioctlsocket(s, FIONREAD, &n) == -1)
+    return -1;
+  return (issize_t)n;
+}
+#else
+issize_t su_getmsgsize(su_socket_t s)
+{
+  int n = -1;
+  if (su_ioctl(s, FIONREAD, &n) == -1)
+    return -1;
+  return (issize_t)n;
+}
+#endif
+
+#if SU_HAVE_WINSOCK && SU_HAVE_IN6
+/** Return a pointer to the in6addr_any. */
+struct in_addr6 const *su_in6addr_any(void)
+{
+  static const struct in_addr6 a = SU_IN6ADDR_ANY_INIT;
+  return &a;
+}
+
+/** Return a pointer to IPv6 loopback address */
+struct in_addr6 const *su_in6addr_loopback(void)
+{
+  static const struct in_addr6 a = SU_IN6ADDR_LOOPBACK_INIT;
+  return &a;
+}
+#endif
+
+#if SU_HAVE_WINSOCK
+
+ssize_t su_send(su_socket_t s, void *buffer, size_t length, int flags)
+{
+  if (length > INT_MAX)
+    length = INT_MAX;
+  return (ssize_t)send(s, buffer, (int)length, flags);
+}
+
+ssize_t su_sendto(su_socket_t s, void *buffer, size_t length, int flags,
+		   su_sockaddr_t const *to, socklen_t tolen)
+{
+  if (length > INT_MAX)
+    length = INT_MAX;
+  return (ssize_t)sendto(s, buffer, (int)length, flags,
+			 &to->su_sa, (int) tolen);
+}
+
+ssize_t su_recv(su_socket_t s, void *buffer, size_t length, int flags)
+{
+  if (length > INT_MAX)
+    length = INT_MAX;
+
+  return (ssize_t)recv(s, buffer, (int)length, flags);
+}
+
+ssize_t su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
+		    su_sockaddr_t *from, socklen_t *fromlen)
+{
+  int retval, ilen;
+
+  if (fromlen)
+    ilen = *fromlen;
+
+  if (length > INT_MAX)
+    length = INT_MAX;
+
+  retval = recvfrom(s, buffer, (int)length, flags, 
+		    &from->su_sa, fromlen ? &ilen : NULL);
+
+  if (fromlen)
+    *fromlen = ilen;
+
+  return (ssize_t)retval;
+}
+
+/** Scatter/gather send */
+issize_t su_vsend(su_socket_t s,
+		  su_iovec_t const iov[], isize_t iovlen, int flags,
+		  su_sockaddr_t const *su, socklen_t sulen)
+{
+  int ret;
+  DWORD bytes_sent = (DWORD)su_failure;
+  
+  ret = WSASendTo(s,
+		  (LPWSABUF)iov,
+		  (DWORD)iovlen,
+		  &bytes_sent,
+		  flags,
+		  &su->su_sa,
+		  sulen,
+		  NULL,
+		  NULL);
+  if (ret < 0)
+    return (issize_t)ret;
+  else
+    return (issize_t)bytes_sent;
+}
+
+
+/** Scatter/gather recv */
+issize_t su_vrecv(su_socket_t s, su_iovec_t iov[], isize_t iovlen, int flags,
+		  su_sockaddr_t *su, socklen_t *sulen)
+{
+  int ret;
+  DWORD bytes_recv = (DWORD)su_failure;
+  DWORD dflags = flags;
+  int fromlen = sulen ? *sulen : 0;
+
+  ret =  WSARecvFrom(s,
+		     (LPWSABUF)iov,
+		     (DWORD)iovlen,
+		     &bytes_recv,
+		     &dflags,
+		     &su->su_sa,
+		     sulen ? &fromlen : NULL,
+		     NULL,
+		     NULL);
+
+  if (sulen) *sulen = fromlen;
+
+  if (ret < 0)
+    return (issize_t)ret;
+  else
+    return (issize_t)bytes_recv;
+}
+
+
+#else
+
+issize_t su_vsend(su_socket_t s,
+		  su_iovec_t const iov[], isize_t iovlen, int flags,
+		  su_sockaddr_t const *su, socklen_t sulen)
+{
+  struct msghdr hdr[1] = {{0}};
+
+  hdr->msg_name = (void *)su;
+  hdr->msg_namelen = sulen;
+  hdr->msg_iov = (struct iovec *)iov;
+  hdr->msg_iovlen = iovlen;
+
+  return sendmsg(s, hdr, flags);
+}
+
+issize_t su_vrecv(su_socket_t s, su_iovec_t iov[], isize_t iovlen, int flags,
+		  su_sockaddr_t *su, socklen_t *sulen)
+{
+  struct msghdr hdr[1] = {{0}};
+  issize_t retval;
+
+  hdr->msg_name = (void *)su;
+  if (su && sulen)
+    hdr->msg_namelen = *sulen;
+  hdr->msg_iov = (struct iovec *)iov;
+  hdr->msg_iovlen = iovlen;
+
+  retval = recvmsg(s, hdr, flags);
+
+  if (su && sulen)
+    *sulen = hdr->msg_namelen;
+
+  return retval;
+}
+
+#endif
+
+/** Compare two socket addresses */
+int su_cmp_sockaddr(su_sockaddr_t const *a, su_sockaddr_t const *b)
+{
+  int rv;
+
+  /* Check that a and b are non-NULL */
+  if ((rv = (a != NULL) - (b != NULL)) || a == NULL /* && b == NULL */)
+    return rv;
+
+  if ((rv = a->su_family - b->su_family))
+    return rv;
+  
+  if (a->su_family == AF_INET)
+    rv = memcmp(&a->su_sin.sin_addr, &b->su_sin.sin_addr, 
+		sizeof(struct in_addr));
+#if SU_HAVE_IN6
+  else if (a->su_family == AF_INET6)
+    rv = memcmp(&a->su_sin6.sin6_addr, &b->su_sin6.sin6_addr, 
+		sizeof(struct in6_addr));
+#endif
+  else
+    rv = memcmp(a, b, sizeof(struct sockaddr));
+
+  if (rv)
+    return rv;
+  
+  return a->su_port - b->su_port;
+}
+
+/** Check if socket address b match with a.
+ *
+ * The function su_match_sockaddr() returns true if the socket address @a b
+ * matches with the socket address @a a. This happens if either all the
+ * interesting fields are identical: address family, port number, address,
+ * and scope ID (in case of IPv6) or that the @a a contains a wildcard
+ * (zero) in their place.
+ */
+int su_match_sockaddr(su_sockaddr_t const *a, su_sockaddr_t const *b)
+{
+  /* Check that a and b are non-NULL */
+  if (a == NULL)
+    return 1;
+  if (b == NULL)
+    return 0;
+
+  if (a->su_family != 0 && a->su_family != b->su_family)
+    return 0;
+
+  if (a->su_family == 0 || SU_SOCKADDR_INADDR_ANY(a))
+    ;
+  else if (a->su_family == AF_INET) {
+    if (memcmp(&a->su_sin.sin_addr, &b->su_sin.sin_addr, 
+	       sizeof(struct in_addr)))
+      return 0;
+  }
+#if SU_HAVE_IN6
+  else if (a->su_family == AF_INET6) {
+    if (a->su_scope_id != 0 && a->su_scope_id != b->su_scope_id)
+      return 0;
+    if (memcmp(&a->su_sin6.sin6_addr, &b->su_sin6.sin6_addr, 
+	       sizeof(struct in6_addr)))
+      return 0;
+  }
+#endif
+  else if (memcmp(a, b, sizeof(struct sockaddr)))
+    return 0;
+
+  if (a->su_port == 0)
+    return 1;
+  
+  return a->su_port == b->su_port;
+}
+
+/** Convert mapped/compat address to IPv4 address */
+void su_canonize_sockaddr(su_sockaddr_t *su)
+{
+#if SU_HAVE_IN6
+  if (su->su_family != AF_INET6)
+    return;
+
+  if (!IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) &&
+      !IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))
+    return;
+  
+  su->su_family = AF_INET;
+  su->su_array32[1] = su->su_array32[5];
+  su->su_array32[2] = 0; 
+  su->su_array32[3] = 0;
+#endif
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1352 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "su" - OS Services and Utilities
+ *
+ * @section su_meta Module Information
+ *
+ * The @b su module contains a simple, portable socket/timing/synchronizing
+ * library developed for Sofia communications software.
+ * 
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @STATUS @SofiaSIP Core library
+ * 
+ * @LICENSE LGPL
+ *
+ * @section su_overview Overview
+ *
+ * The @b su module provides following interfaces for application programs:
+ *
+ * - su_types.h - integral types
+ * - su.h - @ref su_socket 
+ *   - su_localinfo.h - get list of local IP addresses
+ * - su_wait.h - @ref su_wait 
+ * - su_time.h - @ref su_time
+ * - su_alloc.h - @ref su_alloc
+ * - su_log.h - @ref su_log
+ * - su_tag.h - @ref su_tag
+ * - su_md5.h - @ref su_md5
+ * - su_uniqueid.h - @ref su_uniqueid 
+ *
+ * The @b su library also contains some collection datatypes:
+ * - htable.h - @ref su_htable
+ * - rbtree.h - balanced red-black trees
+ * - su_strlst.h - @ref su_strlst
+ * - su_vector.h - @ref su_vector
+ *
+ * There are also some convenience macros for unit test programs:
+ * - tstdef.h - macros for unit tests
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ *
+ * @par SU Debug Log
+ *
+ * The debugging output from @b su module is controlled by #su_log_global
+ * log object. The environment variable #SU_DEBUG sets the default log
+ * level.
+ */
+
+/**@maindefgroup su OS Utilities
+ *
+ * The "su" module contains OS utilies for Sofia.
+ *
+ * The @b su is a simple, portable socket/timing/synchronizing library
+ * developed for Sofia communications software. Currently, interface to
+ * it consists of following parts:
+ *
+ * - <a href=su_types_h.html>su_types</a> - basic integer types
+ * - <a href=group_su_socket.html>su_socket</a> - socket functions
+ * - <a href=group_su_wait.html>su_wait</a> - synchronization functions
+ * - <a href=group_su_time.html>su_time</a> - time functions
+ * - <a href=group_su_alloc.html>su_alloc</a> - memory management functions
+ * - <a href=group_su_log.html>su_log</a> - generic logging functions
+ * - <a href=group_su_tag.html>su_tag</a> - tag list function
+ * - <a href=group_su_md5.html>su_md5</a> - MD5 hashing 
+ */
+
+/**@defgroup su_programs Shell Programs
+ * 
+ * The @b su module provides few shell utilities:
+ * - @ref localinfo (localinfo.c)
+ * - @ref addrinfo (addrinfo.c) 
+ */
+
+/**@defgroup su_socket Socket Functions
+ *
+ *  @brief The <su.h> contains the portable socket functions. 
+ *
+ *  The <su.h> contains following functions, macros, and types:
+ *    - su_init(): initializes sockets
+ *    - su_deinit(): deinitializes sockets
+ *    - su_socket(): creates a socket
+ *    - su_close(): closes a socket
+ *    - su_ioctl(): ioctl to a socket
+ *    - su_setreuseaddr(): set/reset reusing the addresses/ports for a socket
+ *    - su_setblocking(): enables/disables blocking
+ *    - su_isblocking(): checks if the previous call failed because it 
+ *  	would have blocked
+ *    - su_errno(): the latest socket error
+ *    - su_perror(): prints the latest socket error message to stderr
+ *    - su_strerror(): returns the given socket error message
+ *    - su_perror2(): prints the  given socket error message to stderr
+ *    - su_soerror(): returns the error code associated with the socket
+ *    - su_getmsgsize(): return the number of bytes that can be recv()ed from
+ *  	a socket
+ *    - su_getlocalip(): return an IP address belonging to the local host
+ *    - su_vsend(): scatter-gather send
+ *    - su_vrecv(): scatter-gather receive
+ *    - #su_iovec_t: structure holding scatter-gather IO vector
+ */
+
+/**@defgroup su_htable Hash tables
+ *
+ * Hash tables.
+ *
+ * The hash table interface and implementation is defined in
+ * <sofia-sip/htable.h>. Example code and tests for the implementation is in
+ * test_htable.c.
+ */
+
+
+/* <a name="su_wallclock"></a>
+ * <h3>Function @c su_wallclock() - get current time</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_time.h&gt;
+ * 
+ * void su_wallclock(su_time_t *tv);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * Fills the @a tv with the current NTP timestamp.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c tv      <td>pointer to the timeval object
+ * </table>
+ * </blockquote>
+ * 
+ * <a name="su_now"></a>
+ * <h3>Function @c su_now() - get current time</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_time.h&gt;
+ * 
+ * su_time_t su_now(void);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * Return the current NTP timestamp.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The structure containing the current NTP timestamp.
+ * </blockquote>
+ * 
+ * <a name="su_time_print"></a>
+ * <h3>Function @c su_time_print() - print an NTP timestamp</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_time.h&gt;
+ * 
+ * int su_time_print(char *s, int n, su_time_t const *tv);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ *  This function prints an NTP timestamp as a decimal number to the
+ *  given buffer.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c char *s            <td>pointer to buffer
+ *   <tr><td>@c int n              <td>buffer size
+ *   <tr><td>@c su_time_t const tv <td>pointer to the timeval object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The number of characters printed, excluding the final NUL.
+ * </blockquote>
+ * 
+ * <a name="su_duration"></a>
+ * <h3>Function @c su_duration() - return time difference in milliseconds</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_time.h&gt;
+ * 
+ * su_duration_t su_duration(su_time_t t1, su_time_t t2);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * Calculates the duration in milliseconds from @a t2 to @a t1 in milliseconds. If the difference is bigger
+ * than @c SU_MAX_DURATION, return @c SU_MAX_DURATION instead.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t1      <td>after time
+ *   <tr><td>@c t2      <td>before time
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The duration in milliseconds between the two times.
+ * </blockquote>
+ * 
+ * <a name="su_alloc.h"></a>
+ * <h1>&lt;su_alloc.h&gt;</h1>
+ * 
+ * This section describes memory management functions.
+ * 
+ * 
+ * The
+ * @c su_alloc library provides convenience functions for
+ * memory management. The library defines an object @c su_home_t for
+ * collecting multiple memory allocations under one handle.
+ * 
+ * <ul>
+ *   - Function @c su_home_create()
+ *       - create an su_home_t object
+ * 
+ *   - Function @c su_home_destroy()
+ *       - free a home object
+ * 
+ *   - Function @c su_alloc()
+ *       - allocate a memory block
+ * 
+ *   - Function @c su_zalloc()
+ *       - allocate and zero a memory block
+ * 
+ *   - Function @c su_salloc()
+ *       - allocate a structure
+ * 
+ *   - Function @c su_free()
+ *       - free a memory block
+ * 
+ * </ul>
+ * 
+ * 
+ * The functions for implementing objects derived from @c su_home_t
+ * are as follows:
+ * <ul>
+ *   - Function @c su_home_init()
+ *       - initialize an @c su_home_t object
+ * 
+ *   - Function @c su_home_deinit()
+ *        - free memory blocks from home
+ * 
+ * </ul>
+ * 
+ * <a name="su_home_create"></a>
+ * <h3>Function @c su_home_create() - create an su_home_t object</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * su_home_t *su_home_create(void);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_create() creates a home object used to
+ * collect multiple memory allocations under one handle, so that they can be
+ * freed by calling <dfn>su_home_destroy()</dfn>.
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to an @c su_home_t object, or
+ * @c NULL upon an error.
+ * </blockquote>
+ * 
+ * <a name="su_home_destroy"></a>
+ * <h3>Function @c su_home_destroy() - free a home object</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void su_home_destroy(su_home_t *h);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_destroy() frees a home object, and all
+ * memory blocks associated with it.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ * 
+ * <a name="su_alloc"></a>
+ * <h3>Function @c su_alloc() - allocate a memory block</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void *su_alloc(su_home_t *h, int  n);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_alloc() allocates a memory block of a given size.
+ * 
+ * 
+ * If @a h is @c NULL, this function behaves exactly like
+ * @c malloc().
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ *   <tr><td>@c int n      <td>size of the memory block to be allocated
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ * 
+ * <a name="su_zalloc"></a>
+ * <h3>Function @c su_zalloc() - allocate and zero a memory block</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void *su_zalloc(su_home_t *h, int  n)
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_zalloc() allocates a memory block with a given
+ * size and zeroes the allocated block.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ *   <tr><td>@c int n      <td>size of the memory block to be allocated
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ * 
+ * <a name="su_salloc"></a>
+ * <h3>Function @c su_salloc() - allocate a structure</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void *su_salloc(su_home_t *h, int  s);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function su_salloc() allocates a structure with a given size,
+ * zeros it, and initializes the size field to the given size.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ *   <tr><td>@c int n      <td>size of the structure to be allocated
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ * 
+ * <a name="su_free"></a>
+ * <h3>Function @c su_free() - free a memory block</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void su_free(su_home_t *h, void *vb);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_free() frees a single memory block.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h  <td>pointer to a home object
+ *   <tr><td>@c void      *vb <td>pointer to the memory block to be freed
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * </blockquote>
+ * 
+ * <a name="su_home_init"></a>
+ * <h3>Function @c su_home_init() - initialize an @c su_home_t object</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * int su_home_init(su_home_t *h);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_init() initializes an object derived from
+ * @c su_home_t. It checks that the @a suh_size field is valid.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The function @c su_home_init() returns @c 0 when
+ * successful, or @c -1 upon an error.
+ * </blockquote>
+ * 
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_home_t.</strong>
+ * </blockquote>
+ * 
+ * <a name="su_home_deinit"></a>
+ * <h3>Function @c su_home_deinit() - free memory blocks from home </h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_alloc.h&gt;
+ * 
+ * void su_home_deinit(su_home_t *h);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_deinit() frees the memory blocks
+ * associated with the home object.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_home_t.</strong>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_wait.h"></a>
+ * <h1>&lt;su_wait.h&gt;</h1>
+ * 
+ * This section describes synchronization functionality.
+ * The @c su_wait library provides portable synchronization
+ * primitives needed for running communication software.
+ * 
+ * Synchronization means that the program can stop waiting for events,
+ * set callback functions for events, schedule timers, and set callback
+ * functions for timers. In other words, it is an OS-independent
+ * @c poll()/@c select()/@c WaitForMultipleObjects()
+ * interface, spiced up with timer interface.
+ * 
+ * The library provides three kinds of objects: root
+ * objects (@c su_root_t), wait objects
+ * (@c su_wait_t), and timer objects
+ * (@c su_timer_t).
+ * 
+ * <a name="wait"></a>
+ * <h2>Wait Objects</h2>
+ * 
+ * 
+ *   Wait objects are used to signal I/O events to the process.
+ *   The events are as follows:
+ * 
+ * <dl>
+ *   <dt>SU_WAIT_IN
+ *   <dd>incoming data is available
+ * 
+ *   <dt>SU_WAIT_OUT
+ *   <dd>data can be output
+ * 
+ *   <dt>SU_WAIT_ERR
+ *   <dd>an error occurred
+ * 
+ *   <dt>SU_WAIT_HUP
+ *   <dd>the socket connection was closed
+ * 
+ *   <dt>SU_WAIT_ACCEPT
+ *   <dd>a listening socket accepted a new connection attempt
+ * </dl>
+ * 
+ * 
+ *   It is possible to combine several events with |, binary or operator.
+ * 
+ * 
+ *   Public API contains functions as follows:
+ * <ul>
+ *   - su_wait_create()
+ *   - su_wait_destroy()
+ *   - su_wait()
+ *   - su_wait_events()
+ * </ul>
+ * 
+ * 
+ *   In Unix, the wait object is @c struct poll. The structure contains a file
+ *   handle, a mask describing expected events, and a mask containing the
+ *   occurred events after calling @c poll(), ie. @c su_wait().
+ * 
+ * 
+ *   In Windows, the wait object is a @c HANDLE (a descriptor of a Windows
+ *   kernel entity).
+ * 
+ * 
+ * <a name="su_wait_create"></a>
+ * <h3>Function @c su_wait_create()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_wait_create(su_wait_t *newwait, su_socket_t socket, int events)</pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * 
+ * <blockquote>
+ * @c Su_wait_create() creates a new wait object for a
+ * @a socket with given @a events.  The new wait object is
+ * assigned to the @a newwait parameter.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * 
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c newwait<td>the newly created wait object
+ *   <tr><td>@c socket <td>socket descriptor
+ *   <tr><td>@c events <td>mask for events that can signal this wait object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * 
+ * <blockquote>
+ * 0 if the call was successful, -1 otherwise.
+ * </blockquote>
+ * 
+ * <a name="su_wait_destroy"></a>
+ * <h3>Function @c su_wait_destroy()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre> #include &lt;su_wait.h&gt;
+ * 
+ * int su_wait_destroy(su_wait_t *waitobj);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>Destroy a wait object.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * 
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c waitobj <td>pointer to wait object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * 
+ * <blockquote>
+ * 0 when successful, -1 upon an error.
+ * </blockquote>
+ * 
+ * <a name="su_wait"></a>
+ * <h3>Function @c su_wait()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_wait(su_wait_t waits[], unsigned n, long timeout);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  Block until a event specified by wait objects or a timeout occurs.
+ * 
+ * 
+ *   In Unix, this is poll.
+ * 
+ * 
+ *   In Windows, this is WSAWaitForMultipleEvents
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c waits   <td>array of wait objects
+ *   <tr><td>@c n       <td>number of wait objects in array waits
+ *   <tr><td>@c timeout <td>timeout in milliseocnds
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ *   Index of the signaled wait object, if any, SU_WAIT_TIMEOUT if timeout
+ *   occurred, and -1 upon an error.
+ * </blockquote>
+ * 
+ * <a name="su_wait_events"></a>
+ * <h3>Function @c su_wait_events()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_wait_events(su_wait_t *waitobj, su_socket_t s);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  Return an mask describing events occurred.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c waitobj  <td>pointer to wait object
+ *   <tr><td>@c s        <td>socket
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  Binary mask describing the events.
+ * </blockquote>
+ * 
+ * <a name="su_wait_mask"></a>
+ * <h3>Function @c su_wait_mask()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_wait_mask(su_wait_t *waitobj, su_socket_t s, int events);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>
+ *   Sets the mask describing events that can signal the wait object.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c waitobj  <td>pointer to wait object
+ *   <tr><td>@c s        <td>socket
+ *   <tr><td>@c events   <td>new event mask
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ *   0 when successful, -1 upon an error.
+ * </blockquote>
+ * 
+ * <a name="root"></a>
+ * <h2>Root objects</h2>
+ * 
+ * 
+ *    Root object is a structure containing a list of wait objects,
+ *    associated callback functions, and arguments to these functions.
+ *    It can also contain a list of timers, and a magic cookie (a pointer
+ *    defined by root object user.)
+ * 
+ * 
+ *    The public API contains following functions:
+ * <ul>
+ *   - su_root_create()
+ *   - su_root_destroy()
+ *   - su_root_magic()
+ *   - su_root_register()
+ *   - su_root_unregister()
+ *   - su_root_run()
+ *   - su_root_break()
+ *   - su_root_step()
+ * </ul>
+ * 
+ * These functions are intended for implementing su_root API:
+ * <ul>
+ *   - su_root_init()
+ *   - su_root_deinit()
+ *   - su_root_query()
+ *   - su_root_event()
+ * </ul>
+ * 
+ * <a name="su_root_create"></a>
+ * <h3>Function @c su_root_create()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * su_root_t *su_root_create(su_root_magic_t *magic);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Allocate and initialize an instance of su_root_t
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c magic    <td>pointer to user data
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  A pointer to allocated su_root_t instance, NULL on error.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_destroy"></a>
+ * <h3>Function @c su_root_destroy()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * void su_root_destroy(su_root_t *root);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize and free an instance of su_root_t
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root    <td>pointer to a root structure
+ * </table>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_magic"></a>
+ * <h3>Function @c su_root_magic()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * su_root_magic_t *su_root_magic(su_root_t *root);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Return the user data pointer that was given input to su_root_create() or
+ * 
+ *  su_root_init().
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to a root object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  A pointer to user data
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_register"></a>
+ * <h3>Function @c su_root_register()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_root_register(su_root_t *root,
+ * 		     su_wait_t *waits,
+ * 		     su_wakeup_f callback,
+ * 		     su_wakeup_arg_t arg,
+ * 		     int priority);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Register a su_wait_t object. The wait object, a callback function and
+ * 
+ *  a argument is stored to the root object. The callback function is called,
+ *  when the wait object is signaled.
+ * 
+ *  Please note if identical wait objects are inserted, only first one is
+ *  ever signalled.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ *   <tr><td>@c waits    <td>pointer to wait object
+ *   <tr><td>@c callback <td>callback function pointer
+ *   <tr><td>@c arg      <td>argument given to callback function when it is invoked
+ *   <tr><td>@c priority <td>relative priority of the wait object
+ *              (0 is normal, 1 important, 2 realtime)
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  Index of the wait object, or -1 upon an error.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_unregister"></a>
+ * <h3>Function @c su_root_unregister()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_root_unregister(su_root_t *root,
+ * 		       su_wait_t *wait,
+ * 		       su_wakeup_f callback,
+ * 		       su_wakeup_arg_t arg);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> UnRegisters a su_wait_t object. The wait object, a callback function and
+ * 
+ *  a argument are removed from the root object. The callback function is called,
+ *  when the wait object is signaled.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ *   <tr><td>@c waits    <td>pointer to wait object
+ *   <tr><td>@c callback <td>callback function pointer (may be NULL)
+ *   <tr><td>@c arg      <td>argument given to callback function when it
+ *                                 is invoked (may be NULL)
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  Index of the wait object, or -1 upon an error.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_run"></a>
+ * <h3>Function @c su_root_run()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * void su_root_run(su_root_t *root);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  This function waits for wait objects and the timers associated with
+ *   the root object.  When any wait object is signaled or timer is
+ *   expired, it invokes the callbacks, and returns waiting.
+ * 
+ * 
+ *   This function returns when su_root_break() is called from a callback.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ * </table>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_break"></a>
+ * <h3>Function @c su_root_break()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * void su_root_break(su_root_t *root);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  If this function is used to terminate execution of su_root_run(). It
+ * 
+ *   can be called from a callback function.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ * </table>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_step"></a>
+ * <h3>Function @c su_root_step()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * su_duration_t su_root_step(su_root_t *root, su_duration_t tout);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  This function waits for wait objects and the timers associated with
+ *   the @a root object.  When any wait object is signaled or timer is
+ *   expired, it invokes the callbacks, and returns.
+ * 
+ * 
+ *   This function returns when a callback has been invoked or @a tout
+ *   milliseconds is elapsed.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ *   <tr><td>@c tout     <td>timeout in milliseconds
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ *   Milliseconds to the next invocation of timer, or SU_WAIT_FOREVER if
+ *   there are no active timers.
+ * </blockquote>
+ * 
+ * <a name="timer"></a>
+ * <h2>Timer objects</h2>
+ * 
+ * Timers are used to schedule some task to be executed at given time or
+ * after a default interval. The default interval is specified when the
+ * timer is created. We call timer activation "setting the timer", and
+ * deactivation "resetting the timer" (as in SDL). When the given time has
+ * arrived or the default interval has elapsed, the timer expires and
+ * it is ready for execution.
+ * 
+ * These functions are available for handling timers:
+ * 
+ * - su_timer_create()
+ *   - su_timer_destroy()
+ *   - su_timer_set()
+ *   - su_timer_set_at()
+ *   - su_timer_reset()
+ *   - su_timer_run()
+ * 
+ * <a name="su_timer_create"></a>
+ * <h3>Function @c su_timer_create()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * su_timer_t *su_timer_create(su_root_t *root, su_duration_t msec);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * 
+ * <blockquote>
+ * Allocate and initialize an instance of su_timer_t.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *  <tr><td>@c root   <td>the root object with which the timer will be associated
+ *  <tr><td>@c msec   <td>the default duration of the timer
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  A pointer to allocated timer instance, NULL on error.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_timer_destroy"></a>
+ * <h3>Function @c su_timer_destroy()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * void su_timer_destroy(su_timer_t *t);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize and free an instance of su_timer_t.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t      <td>pointer to the timer object
+ * </table>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_timer_set"></a>
+ * <h3>Function @c su_timer_set()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_timer_set(su_timer_t *t,
+ * 		 su_timer_f wakeup,
+ * 		 su_wakeup_arg_t arg);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Sets the given timer to expire after the default duration.
+ * 
+ * The timer must have an default duration.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t      <td>pointer to the timer object
+ *   <tr><td>@c wakeup <td>pointer to the wakeup function
+ *   <tr><td>@c arg    <td>argument given to the wakeup function
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  0 if successful, -1 otherwise.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_timer_set_at"></a>
+ * <h3>Function @c su_timer_set_at()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_timer_set_at(su_timer_t *t,
+ * 		    su_timer_f wakeup,
+ * 		    su_wakeup_arg_t arg,
+ * 		    su_time_t when);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Sets the timer to expire at given time.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t      <td>pointer to the timer object
+ *   <tr><td>@c wakeup <td>pointer to the wakeup function
+ *   <tr><td>@c arg    <td>argument given to the wakeup function
+ *   <tr><td>@c when   <td>time structure defining the wakeup time
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  0 if successful, -1 otherwise.
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_timer_reset"></a>
+ * <h3>Function @c su_timer_reset()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * int su_timer_reset(su_timer_t *t);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  Resets the given timer.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t      <td>pointer to the timer object
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  0 if successful, -1 otherwise.
+ * </blockquote>
+ * 
+ * <a name="su_timer_run"></a>
+ * <h3>Function @c su_timer_run()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * 
+ * su_duration_t su_timer_run(su_timer_t ** const t0, su_duration_t tout);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  Expires and executes expired timers in queue.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c t0     <td>pointer to the timer queue
+ *   <tr><td>@c tout   <td>timeout in milliseconds
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>
+ *  The duration in milliseconds before the next timer expires, or timeout (2**31 - 1
+ *  ms), whichever is shorter.
+ * </blockquote>
+ * 
+ * <!--
+ * Root object is used for synchronizing. There must be one root object per
+ * thread. There are two alternative ways for creating a root object. If you
+ * are just using su_root_t, and don't want to <a
+ * href="#inherit_su_root_t">inherit from it</a>, you can use
+ * @c su_create().
+ * -->
+ * 
+ * <a name="su_wait_internal.h"></a>
+ * <h1>&lt;su_wait_internal.h&gt;</h1>
+ * 
+ * 
+ * This section contains the internal functions, that is, functions used to
+ * implement objects in @c &lt;su_wait.h&gt;.
+ * 
+ * <a name="su_root_init"></a>
+ * <h3>Function @c su_root_init()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * #include &lt;su_wait_internal.h&gt;
+ * 
+ * int su_root_init(su_root_t *root, su_root_magic_t *magic);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * 
+ * <blockquote>
+ * 
+ * Initialize an instance of @c su_root_t. The caller should allocate
+ * the memory required for su_root_t, and set the sur_size to the size of the
+ * allocated structure.
+ * 
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * 
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root    <td>pointer to a uninitialized root structure
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  0 when call was successful, -1 otherwise.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Note</h4>
+ * <blockquote>
+ * <strong>This is an internal function, and it is intended for implementing
+ * the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_deinit"></a>
+ * <h3>Function @c su_root_deinit()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * #include &lt;su_wait_internal.h&gt;
+ * 
+ * void su_root_deinit(su_root_t *root);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize an instance of su_root_t
+ * </blockquote>
+ * 
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root    <td>pointer to a root structure
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Note</h4>
+ * <blockquote>  <strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ * 
+ * <a name="su_root_query"></a>
+ * <h3>Function @c su_root_query()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * #include &lt;su_wait_internal.h&gt;
+ * 
+ * unsigned su_root_query(su_root_t *root, su_wait_t *waits, unsigned n_waits);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote> Copies the su_wait_t objects from the root. The number of wait objects
+ * 
+ *  can be found out by calling su_root_query() with n_waits as zero.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c waits    <td>pointer to array to which wait objects are copied
+ *   <tr><td>@c root     <td>pointer to root object
+ *   <tr><td>@c n_waits  <td>number of wait objects fitting in array waits
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Return Value</h4>
+ * <blockquote>  Number of wait objects, or 0 upon an error.
+ * </blockquote>
+ * 
+ * 
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ * 
+ * 
+ * <a name="su_root_event"></a>
+ * <h3>Function @c su_root_event()</h3>
+ * 
+ * <h4>Synopsis</h4>
+ * 
+ * <blockquote><pre>
+ * #include &lt;su_wait.h&gt;
+ * #include &lt;su_wait_internal.h&gt;
+ * 
+ * void su_root_event(su_root_t *root, su_wait_t *waitobj);
+ * </pre></blockquote>
+ * 
+ * <h4>Description</h4>
+ * <blockquote>  Invokes the callback function associated with the wait object.
+ * 
+ * 
+ *   If waitobj is NULL, check if a wait object associated with root is
+ *   signaled, and its callback is invoked.
+ * </blockquote>
+ * 
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ *   <tr><td>@c root     <td>pointer to root object
+ *   <tr><td>@c waitobj    <td>pointer to wait object, or NULL
+ * </table>
+ * </blockquote>
+ * 
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ * 
+ */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,956 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_addrinfo.h>
+#include <sofia-sip/su.h>
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET          127
+#endif
+
+#ifndef IN_EXPERIMENTAL
+#define IN_EXPERIMENTAL(a)      ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#endif
+
+#if !HAVE_GETADDRINFO
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/*
+ * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
+ *
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked.
+ * - Return values.  There are nonstandard return values defined and used
+ *   in the source code.  This is because RFC2133 is silent about which error
+ *   code must be returned for which situation.
+ * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
+ */
+
+#if defined(__KAME__) && defined(INET6)
+# define FAITH
+#endif
+
+#define SUCCESS 0
+#define GAI_ANY 0
+#define YES 1
+#define NO  0
+
+#undef SU_HAVE_IN6
+
+#ifdef FAITH
+static int translate = NO;
+static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
+#endif
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+
+};
+static const char in_loopback[] = { 127, 0, 0, 1 }; 
+static const char in6_loopback[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+struct sockinet {
+	u_char	si_len;
+	u_char	si_family;
+	u_short	si_port;
+};
+
+static struct gai_afd {
+	int a_af;
+	int a_addrlen;
+	int a_socklen;
+	int a_off;
+	const char *a_addrany;
+	const char *a_loopback;	
+} gai_afdl [] = {
+#if SU_HAVE_IN6
+#define N_INET6 0
+	{PF_INET6, sizeof(struct in6_addr),
+	 sizeof(struct sockaddr_in6),
+	 offsetof(struct sockaddr_in6, sin6_addr),
+	 in6_addrany, in6_loopback},
+#define N_INET  1
+#else
+#define N_INET  0
+#endif
+	{PF_INET, sizeof(struct in_addr),
+	 sizeof(struct sockaddr_in),
+	 offsetof(struct sockaddr_in, sin_addr),
+	 in_addrany, in_loopback},
+	{0, 0, 0, 0, NULL, NULL},
+};
+
+#if SU_HAVE_IN6
+#define PTON_MAX	16
+#else
+#define PTON_MAX	4
+#endif
+
+#if SU_HAVE_IN6 && !defined(s6_addr8)
+#  define s6_addr8 s6_addr
+#endif
+
+#if !SU_HAVE_IN6
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+#else
+extern int h_errno;
+#endif
+#endif
+
+static int get_name(const char *, struct gai_afd *,
+		    struct addrinfo **, char *, struct addrinfo *,
+		    int);
+static int get_addr(const char *, int, struct addrinfo **,
+		    struct addrinfo *, int);
+static int str_isnumber(const char *);
+	
+#define GET_CANONNAME(ai, str) \
+if (pai->ai_flags & AI_CANONNAME) {\
+	if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
+		strcpy((ai)->ai_canonname, (str));\
+	} else {\
+		error = EAI_MEMORY;\
+		goto free;\
+	}\
+}
+
+#if SU_HAVE_SOCKADDR_SA_LEN
+#define GET_AI(ai, gai_afd, addr, port) {\
+	char *p;\
+	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
+					      ((gai_afd)->a_socklen)))\
+	    == NULL) goto free;\
+	memcpy(ai, pai, sizeof(struct addrinfo));\
+	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
+	memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
+	(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
+	(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
+	((struct sockinet *)(ai)->ai_addr)->si_port = port;\
+	p = (char *)((ai)->ai_addr);\
+	memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
+}
+#else
+#define GET_AI(ai, gai_afd, addr, port) {\
+	char *p;\
+	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
+					      ((gai_afd)->a_socklen)))\
+	    == NULL) goto free;\
+	memcpy(ai, pai, sizeof(struct addrinfo));\
+	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
+	memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
+	(ai)->ai_addrlen = (gai_afd)->a_socklen; \
+	(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
+	((struct sockinet *)(ai)->ai_addr)->si_port = port;\
+	p = (char *)((ai)->ai_addr);\
+	memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
+}
+#endif
+
+#define ERR(err) { error = (err); goto bad; }
+
+static int
+str_isnumber(p)
+	const char *p;
+{
+	char *q = (char *)p;
+	while (*q) {
+		if (! isdigit(*q))
+			return NO;
+		q++;
+	}
+	return YES;
+}
+
+static
+int
+getaddrinfo(hostname, servname, hints, res)
+	const char *hostname, *servname;
+	const struct addrinfo *hints;
+	struct addrinfo **res;
+{
+	struct addrinfo sentinel;
+	struct addrinfo *top = NULL;
+	struct addrinfo *cur;
+	int i, error = 0;
+	char pton[PTON_MAX];
+	struct addrinfo ai;
+	struct addrinfo *pai;
+	u_short port;
+
+#ifdef FAITH
+	static int firsttime = 1;
+
+	if (firsttime) {
+		/* translator hack */
+		{
+			char *q = getenv("GAI");
+			if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
+				translate = YES;
+		}
+		firsttime = 0;
+	}
+#endif
+
+	/* initialize file static vars */
+	sentinel.ai_next = NULL;
+	cur = &sentinel;
+	pai = &ai;
+	pai->ai_flags = 0;
+	pai->ai_family = PF_UNSPEC;
+	pai->ai_socktype = GAI_ANY;
+	pai->ai_protocol = GAI_ANY;
+	pai->ai_addrlen = 0;
+	pai->ai_canonname = NULL;
+	pai->ai_addr = NULL;
+	pai->ai_next = NULL;
+	port = GAI_ANY;
+	
+	if (hostname == NULL && servname == NULL)
+		return EAI_NONAME;
+	if (hints) {
+		/* error check for hints */
+		if (hints->ai_addrlen || hints->ai_canonname ||
+		    hints->ai_addr || hints->ai_next)
+			ERR(EAI_BADHINTS); /* xxx */
+		if (hints->ai_flags & ~AI_MASK)
+			ERR(EAI_BADFLAGS);
+		switch (hints->ai_family) {
+		case PF_UNSPEC:
+		case PF_INET:
+#if SU_HAVE_IN6
+		case PF_INET6:
+#endif
+			break;
+		default:
+			ERR(EAI_FAMILY);
+		}
+		memcpy(pai, hints, sizeof(*pai));
+		switch (pai->ai_socktype) {
+		case GAI_ANY:
+			switch (pai->ai_protocol) {
+			case GAI_ANY:
+				break;
+			case IPPROTO_UDP:
+				pai->ai_socktype = SOCK_DGRAM;
+				break;
+			case IPPROTO_TCP:
+				pai->ai_socktype = SOCK_STREAM;
+				break;
+#if HAVE_SCTP
+			case IPPROTO_SCTP:
+				pai->ai_socktype = SOCK_STREAM;
+				break;
+#endif
+			default:
+				pai->ai_socktype = SOCK_RAW;
+				break;
+			}
+			break;
+		case SOCK_RAW:
+			break;
+		case SOCK_DGRAM:
+			if (pai->ai_protocol != IPPROTO_UDP &&
+#if HAVE_SCTP
+			    pai->ai_protocol != IPPROTO_SCTP &&
+#endif
+			    pai->ai_protocol != GAI_ANY)
+				ERR(EAI_BADHINTS);	/*xxx*/
+			if (pai->ai_protocol == GAI_ANY)
+				pai->ai_protocol = IPPROTO_UDP;
+			break;
+		case SOCK_STREAM:
+			if (pai->ai_protocol != IPPROTO_TCP &&
+#if HAVE_SCTP
+			    pai->ai_protocol != IPPROTO_SCTP &&
+#endif
+			    pai->ai_protocol != GAI_ANY)
+				ERR(EAI_BADHINTS);	/*xxx*/
+			if (pai->ai_protocol == GAI_ANY)
+				pai->ai_protocol = IPPROTO_TCP;
+			break;
+#if HAVE_SCTP
+		case SOCK_SEQPACKET:
+			if (pai->ai_protocol != IPPROTO_SCTP &&
+			    pai->ai_protocol != GAI_ANY)
+				ERR(EAI_BADHINTS);	/*xxx*/
+
+			if (pai->ai_protocol == GAI_ANY)
+				pai->ai_protocol = IPPROTO_SCTP;
+			break;
+#endif
+		default:
+			ERR(EAI_SOCKTYPE);
+			break;
+		}
+	}
+
+	/*
+	 * service port
+	 */
+	if (servname) {
+		if (str_isnumber(servname)) {
+			if (pai->ai_socktype == GAI_ANY) {
+				/* caller accept *GAI_ANY* socktype */
+				pai->ai_socktype = SOCK_DGRAM;
+				pai->ai_protocol = IPPROTO_UDP;
+			}
+			port = htons(atoi(servname));
+		} else {
+			struct servent *sp;
+			char *proto;
+
+			proto = NULL;
+			switch (pai->ai_socktype) {
+			case GAI_ANY:
+				proto = NULL;
+				break;
+			case SOCK_DGRAM:
+				proto = "udp";
+				break;
+			case SOCK_STREAM:
+				proto = "tcp";
+				break;
+			default:
+				fprintf(stderr, "panic!\n");
+				break;
+			}
+			if ((sp = getservbyname(servname, proto)) == NULL)
+				ERR(EAI_SERVICE);
+			port = sp->s_port;
+			if (pai->ai_socktype == GAI_ANY) {
+				if (strcmp(sp->s_proto, "udp") == 0) {
+					pai->ai_socktype = SOCK_DGRAM;
+					pai->ai_protocol = IPPROTO_UDP;
+				} else if (strcmp(sp->s_proto, "tcp") == 0) {
+					pai->ai_socktype = SOCK_STREAM;
+					pai->ai_protocol = IPPROTO_TCP;
+#if HAVE_SCTP
+				} else if (strcmp(sp->s_proto, "sctp") == 0) {
+					pai->ai_socktype = SOCK_STREAM;
+					pai->ai_protocol = IPPROTO_SCTP;
+#endif
+				} else
+					ERR(EAI_PROTOCOL);	/*xxx*/
+			}
+		}
+	}
+	
+	/*
+	 * hostname == NULL.
+	 * passive socket -> anyaddr (0.0.0.0 or ::)
+	 * non-passive socket -> localhost (127.0.0.1 or ::1)
+	 */
+	if (hostname == NULL) {
+		struct gai_afd *gai_afd;
+
+		for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
+			if (!(pai->ai_family == PF_UNSPEC
+			   || pai->ai_family == gai_afd->a_af)) {
+				continue;
+			}
+
+			if (pai->ai_flags & AI_PASSIVE) {
+				GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
+				/* xxx meaningless?
+				 * GET_CANONNAME(cur->ai_next, "anyaddr");
+				 */
+			} else {
+				GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
+					port);
+				/* xxx meaningless?
+				 * GET_CANONNAME(cur->ai_next, "localhost");
+				 */
+			}
+			cur = cur->ai_next;
+		}
+		top = sentinel.ai_next;
+		if (top)
+			goto good;
+		else
+			ERR(EAI_FAMILY);
+	}
+	
+	/* hostname as numeric name */
+	for (i = 0; gai_afdl[i].a_af; i++) {
+		if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
+			u_long v4a;
+			u_char pfx;
+
+			switch (gai_afdl[i].a_af) {
+			case AF_INET:
+				v4a = ((struct in_addr *)pton)->s_addr;
+				if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+					pai->ai_flags &= ~AI_CANONNAME;
+				v4a >>= IN_CLASSA_NSHIFT;
+				if (v4a == 0 || v4a == IN_LOOPBACKNET)
+					pai->ai_flags &= ~AI_CANONNAME;
+				break;
+#if SU_HAVE_IN6
+			case AF_INET6:
+				pfx = ((struct in6_addr *)pton)->s6_addr8[0];
+				if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+					pai->ai_flags &= ~AI_CANONNAME;
+				break;
+#endif
+			}
+			
+			if (pai->ai_family == gai_afdl[i].a_af ||
+			    pai->ai_family == PF_UNSPEC) {
+				if (! (pai->ai_flags & AI_CANONNAME)) {
+					GET_AI(top, &gai_afdl[i], pton, port);
+					goto good;
+				}
+				/*
+				 * if AI_CANONNAME and if reverse lookup
+				 * fail, return ai anyway to pacify
+				 * calling application.
+				 *
+				 * XXX getaddrinfo() is a name->address
+				 * translation function, and it looks strange
+				 * that we do addr->name translation here.
+				 */
+				get_name(pton, &gai_afdl[i], &top, pton, pai, port);
+				goto good;
+			} else 
+				ERR(EAI_FAMILY);	/*xxx*/
+		}
+	}
+
+	if (pai->ai_flags & AI_NUMERICHOST)
+		ERR(EAI_NONAME);
+
+	/* hostname as alphabetical name */
+	error = get_addr(hostname, pai->ai_family, &top, pai, port);
+	if (error == 0) {
+		if (top) {
+ good:
+			*res = top;
+			return SUCCESS;
+		} else
+			error = EAI_FAIL;
+	}
+ free:
+	if (top)
+		freeaddrinfo(top);
+ bad:
+	*res = NULL;
+	return error;
+}
+
+static int
+get_name(addr, gai_afd, res, numaddr, pai, port0)
+	const char *addr;
+	struct gai_afd *gai_afd;
+	struct addrinfo **res;
+	char *numaddr;
+	struct addrinfo *pai;
+	int port0;
+{
+	u_short port = port0 & 0xffff;
+	struct hostent *hp;
+	struct addrinfo *cur;
+	int error = 0, h_error;
+	
+#if SU_HAVE_IN6
+	hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
+#else
+	hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
+#endif
+	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+		GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
+		GET_CANONNAME(cur, hp->h_name);
+	} else
+		GET_AI(cur, gai_afd, numaddr, port);
+	
+#if SU_HAVE_IN6
+	if (hp)
+		freehostent(hp);
+#endif
+	*res = cur;
+	return SUCCESS;
+ free:
+	if (cur)
+		freeaddrinfo(cur);
+#if SU_HAVE_IN6
+	if (hp)
+		freehostent(hp);
+#endif
+ /* bad: */
+	*res = NULL;
+	return error;
+}
+
+static int
+get_addr(hostname, af, res, pai, port0)
+	const char *hostname;
+	int af;
+	struct addrinfo **res;
+	struct addrinfo *pai;
+	int port0;
+{
+	u_short port = port0 & 0xffff;
+	struct addrinfo sentinel;
+	struct hostent *hp;
+	struct addrinfo *top, *cur;
+	struct gai_afd *gai_afd;
+	int i, error = 0, h_error;
+	char *ap;
+
+	top = NULL;
+	sentinel.ai_next = NULL;
+	cur = &sentinel;
+#if SU_HAVE_IN6
+	if (af == AF_UNSPEC) {
+		hp = getipnodebyname(hostname, AF_INET6,
+				AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
+	} else
+		hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
+#else
+	hp = gethostbyname(hostname);
+	h_error = h_errno;
+#endif
+	if (hp == NULL) {
+		switch (h_error) {
+		case HOST_NOT_FOUND:
+		case NO_DATA:
+			error = EAI_NODATA;
+			break;
+		case TRY_AGAIN:
+			error = EAI_AGAIN;
+			break;
+		case NO_RECOVERY:
+		default:
+			error = EAI_FAIL;
+			break;
+		}
+		goto bad;
+	}
+
+	if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+	    (hp->h_addr_list[0] == NULL))
+		ERR(EAI_FAIL);
+	
+	for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
+		switch (af) {
+#if SU_HAVE_IN6
+		case AF_INET6:
+			gai_afd = &gai_afdl[N_INET6];
+			break;
+#endif
+#ifndef INET6
+		default:	/* AF_UNSPEC */
+#endif
+		case AF_INET:
+			gai_afd = &gai_afdl[N_INET];
+			break;
+#if SU_HAVE_IN6
+		default:	/* AF_UNSPEC */
+			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+				ap += sizeof(struct in6_addr) -
+					sizeof(struct in_addr);
+				gai_afd = &gai_afdl[N_INET];
+			} else
+				gai_afd = &gai_afdl[N_INET6];
+			break;
+#endif
+		}
+#ifdef FAITH
+		if (translate && gai_afd->a_af == AF_INET) {
+			struct in6_addr *in6;
+
+			GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
+			in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
+			memcpy(&in6->s6_addr32[0], &faith_prefix,
+			    sizeof(struct in6_addr) - sizeof(struct in_addr));
+			memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
+		} else
+#endif /* FAITH */
+		GET_AI(cur->ai_next, gai_afd, ap, port);
+		if (cur == &sentinel) {
+			top = cur->ai_next;
+			GET_CANONNAME(top, hp->h_name);
+		}
+		cur = cur->ai_next;
+	}
+#if SU_HAVE_IN6
+	freehostent(hp);
+#endif
+	*res = top;
+	return SUCCESS;
+ free:
+	if (top)
+		freeaddrinfo(top);
+#if SU_HAVE_IN6
+	if (hp)
+		freehostent(hp);
+#endif
+ bad:
+	*res = NULL;
+	return error;
+}
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values.  There seems to be no standard for return value (RFC2133)
+ *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+#define SUCCESS 0
+#define YES 1
+#define NO  0
+
+static struct gni_afd {
+	int a_af;
+	int a_addrlen;
+	int a_socklen;
+	int a_off;
+} gni_afdl [] = {
+#if SU_HAVE_IN6
+	{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+		offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+		offsetof(struct sockaddr_in, sin_addr)},
+	{0, 0, 0},
+};
+
+struct gni_sockinet {
+	u_char	si_len;
+	u_char	si_family;
+	u_short	si_port;
+};
+
+#define ENI_NOSOCKET 	EAI_FAIL
+#define ENI_NOSERVNAME	EAI_NONAME
+#define ENI_NOHOSTNAME	EAI_NONAME
+#define ENI_MEMORY	EAI_MEMORY
+#define ENI_SYSTEM	EAI_SYSTEM
+#define ENI_FAMILY	EAI_FAMILY
+#define ENI_SALEN	EAI_MEMORY
+
+static
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+	const struct sockaddr *sa;
+	size_t salen;
+	char *host;
+	size_t hostlen;
+	char *serv;
+	size_t servlen;
+	int flags;
+{
+	struct gni_afd *gni_afd;
+	struct servent *sp;
+	struct hostent *hp;
+	u_short port;
+	int family, len, i;
+	char *addr, *p;
+	u_long v4a;
+	u_char pfx;
+	int h_error;
+	char numserv[512];
+	char numaddr[512];
+
+	if (sa == NULL)
+		return ENI_NOSOCKET;
+
+#if SU_HAVE_SOCKADDR_SA_LEN
+	len = sa->sa_len;
+	if (len != salen) return ENI_SALEN;
+#else
+	len = salen;
+#endif
+	
+	family = sa->sa_family;
+	for (i = 0; gni_afdl[i].a_af; i++)
+		if (gni_afdl[i].a_af == family) {
+			gni_afd = &gni_afdl[i];
+			goto found;
+		}
+	return ENI_FAMILY;
+	
+ found:
+	if (len != gni_afd->a_socklen) return ENI_SALEN;
+	
+	port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
+	addr = (char *)sa + gni_afd->a_off;
+
+	if (serv == NULL || servlen == 0) {
+		/* what we should do? */
+	} else if (flags & NI_NUMERICSERV) {
+		snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+		if (strlen(numserv) > servlen)
+			return ENI_MEMORY;
+		strcpy(serv, numserv);
+	} else {
+		sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
+		if (sp) {
+			if (strlen(sp->s_name) > servlen)
+				return ENI_MEMORY;
+			strcpy(serv, sp->s_name);
+		} else
+			return ENI_NOSERVNAME;
+	}
+
+	switch (sa->sa_family) {
+	case AF_INET:
+		v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+		if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+			flags |= NI_NUMERICHOST;
+		v4a >>= IN_CLASSA_NSHIFT;
+		if (v4a == 0 || v4a == IN_LOOPBACKNET)
+			flags |= NI_NUMERICHOST;			
+		break;
+#if SU_HAVE_IN6
+	case AF_INET6:
+		pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
+		if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+			flags |= NI_NUMERICHOST;
+		break;
+#endif
+	}
+	if (host == NULL || hostlen == 0) {
+		/* what should we do? */
+	} else if (flags & NI_NUMERICHOST) {
+		if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
+		    == NULL)
+			return ENI_SYSTEM;
+		if (strlen(numaddr) > hostlen)
+			return ENI_MEMORY;
+		strcpy(host, numaddr);
+	} else {
+#if SU_HAVE_IN6
+		hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
+#else
+		hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af);
+		h_error = h_errno;
+#endif
+
+		if (hp) {
+			if (flags & NI_NOFQDN) {
+				p = strchr(hp->h_name, '.');
+				if (p) *p = '\0';
+			}
+			if (strlen(hp->h_name) > hostlen) {
+#if SU_HAVE_IN6
+				freehostent(hp);
+#endif
+				return ENI_MEMORY;
+			}
+			strcpy(host, hp->h_name);
+#if SU_HAVE_IN6
+			freehostent(hp);
+#endif
+		} else {
+			if (flags & NI_NAMEREQD)
+				return ENI_NOHOSTNAME;
+			if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
+			    == NULL)
+				return ENI_NOHOSTNAME;
+			if (strlen(numaddr) > hostlen)
+				return ENI_MEMORY;
+			strcpy(host, numaddr);
+		}
+	}
+	return SUCCESS;
+}
+
+#endif	/* !HAVE_GETNAMEINFO */
+
+#if !HAVE_FREEADDRINFO
+static 
+void
+freeaddrinfo(ai)
+	struct addrinfo *ai;
+{
+	struct addrinfo *next;
+
+	do {
+		next = ai->ai_next;
+		if (ai->ai_canonname)
+			free(ai->ai_canonname);
+		/* no need to free(ai->ai_addr) */
+		free(ai);
+	} while ((ai = next) != NULL);
+}
+#endif
+
+#if !HAVE_GAI_STRERROR
+static 
+char *
+gai_strerror(ecode)
+	int ecode;
+{
+  switch (ecode) {
+  case 0: 
+    return "success.";
+#if defined(EAI_ADDRFAMILY)
+  case EAI_ADDRFAMILY:
+    return "address family for hostname not supported.";
+#endif
+#if defined(EAI_AGAIN)
+  case EAI_AGAIN:
+    return "temporary failure in name resolution.";
+#endif
+#if defined(EAI_BADFLAGS)
+  case EAI_BADFLAGS:
+    return "invalid value for ai_flags.";
+#endif
+#if defined(EAI_FAIL)
+  case EAI_FAIL:
+    return "non-recoverable failure in name resolution.";
+#endif
+#if defined(EAI_FAMILY)
+  case EAI_FAMILY:
+    return "ai_family not supported.";
+#endif
+#if defined(EAI_MEMORY)
+  case EAI_MEMORY:
+    return "memory allocation failure.";
+#endif
+#if defined(EAI_NODATA)
+  case EAI_NODATA:
+    return "no address associated with hostname.";
+#endif
+#if defined(EAI_NONAME)
+  case EAI_NONAME:
+    return "hostname nor servname provided, or not known.";
+#endif
+#if defined(EAI_SERVICE)
+  case EAI_SERVICE:
+    return "servname not supported for ai_socktype.";
+#endif
+#if defined(EAI_SOCKTYPE)
+  case EAI_SOCKTYPE:
+    return "ai_socktype not supported.";
+#endif
+#if defined(EAI_SYSTEM)
+  case EAI_SYSTEM:
+    return "system error returned in errno.";
+#endif
+#if defined(EAI_BADHINTS)
+  case EAI_BADHINTS:
+    return "invalid value for hints.";
+#endif
+#if defined(EAI_PROTOCOL)
+  case EAI_PROTOCOL:
+    return "resolved protocol is unknown.";
+#endif
+  default:
+    return "unknown error.";
+  }
+}
+#endif
+
+
+/** Translate address and service.
+ *
+ * This is a getaddrinfo() supporting SCTP and other exotic protocols.
+ */
+int su_getaddrinfo(char const *node, char const *service,
+		   su_addrinfo_t const *hints,
+		   su_addrinfo_t **res)
+{
+#if HAVE_SCTP
+  if (res && hints && hints->ai_protocol == IPPROTO_SCTP) {
+    su_addrinfo_t *ai, system_hints[1];
+    int retval, socktype;
+
+    socktype = hints->ai_socktype;
+    
+    if (!(socktype == 0 ||
+	  socktype == SOCK_SEQPACKET ||
+	  socktype == SOCK_STREAM ||
+	  socktype == SOCK_DGRAM))
+      return EAI_SOCKTYPE;
+
+    *system_hints = *hints;
+    system_hints->ai_protocol = IPPROTO_TCP;
+    system_hints->ai_socktype = SOCK_STREAM;
+
+    retval = getaddrinfo(node, service, system_hints, res);
+    if (retval)
+      return retval;
+
+    if (socktype == 0)
+      socktype = SOCK_STREAM;
+
+    for (ai = *res; ai; ai = ai->ai_next) {
+      ai->ai_protocol = IPPROTO_SCTP;
+      ai->ai_socktype = socktype;
+    }
+
+    return 0;
+  }
+#endif
+
+  return getaddrinfo(node, service, hints, res);
+}
+
+/** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */
+void su_freeaddrinfo(su_addrinfo_t *res)
+{
+  freeaddrinfo(res);
+}
+
+/** Return string describing address translation error. */
+char const *su_gai_strerror(int errcode)
+{
+	return (char const *)gai_strerror(errcode);
+}
+
+/** Resolve socket address into hostname and service name.
+ *
+ * @note
+ * This function uses now @RFC2133 prototype. The @RFC3493 redefines the
+ * prototype as well as ai_addrlen to use socklen_t instead of size_t.
+ * If your application allocates more than 2 gigabytes for resolving the
+ * hostname, you probably lose.
+ */
+int
+su_getnameinfo(const su_sockaddr_t *su, size_t sulen,
+	       char *return_host, size_t hostlen,
+	       char *return_serv, size_t servlen,
+	       int flags)
+{
+  return getnameinfo(&su->su_sa, (socklen_t)sulen,
+		     return_host, (socklen_t)hostlen, 
+		     return_serv, (socklen_t)servlen, 
+		     flags);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1583 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ * @CFILE su_alloc.c  Home-based memory management.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ * 
+ * @date Created: Thu Aug 19 01:12:25 1999 ppessi
+ */
+
+#include "config.h"
+
+/**@defgroup su_alloc Memory Management Tutorial
+ *
+ * This page gives a short overview of home-based memory management used
+ * with Sofia. Such home-based memory management is useful when a lot of
+ * memory blocks are allocated for given task. The allocations are done via
+ * the @e memory @e home, which keeps a reference to each block. When the
+ * memory home is then freed, it will free all blocks to which it has
+ * reference.
+ *
+ * Typically, there is a @e home @e object which contains a su_home_t
+ * structure in the beginning of the object (sort of inheritance from
+ * su_home_t):
+ * @code
+ * struct context {
+ *   su_home_t ctx_home[1];
+ *   other_t  *ctx_stuff;
+ *   ...
+ * }
+ * @endcode
+ * 
+ * A new home memory pool can be created with su_home_new():
+ * @code
+ * struct context *ctx = su_home_new(sizeof (struct context));
+ * @endcode
+ *
+ * It is also possible to create a secondary memory pool that can be
+ * released separately:
+ *
+ * @code
+ * struct context *ctx = su_home_clone(tophome, sizeof (struct context));
+ * @endcode
+ *
+ * Note that the tophome has a reference to @a ctx structure; whenever
+ * tophome is freed, the @a ctx is also freed.
+ * 
+ * You can also create an independent home object by passing NULL as @a
+ * tophome argument. This is identical to the call to su_home_new().
+ *
+ * The memory allocations using @a ctx proceed then as follows:
+ * @code
+ *    zeroblock = su_zalloc(ctx->ctx_home, sizeof (*zeroblock));
+ * @endcode
+ *
+ * The home memory pool - the home object and all the memory blocks
+ * allocated using it - are freed when su_home_unref() is called:
+ *
+ * @code
+ *    su_home_unref(ctx->ctx_home).
+ * @endcode
+ *
+ * @note For historical reasons, su_home_unref() is also known as
+ * su_home_zap().
+ *
+ * As you might have guessed, it is also possible to use reference counting
+ * with home objects. The function su_home_ref() increases the reference
+ * count, su_home_unref() decreases. A newly allocated home object has
+ * reference count of 1.
+ *
+ * @note Please note that while it is possible to create new references to
+ * secondary home objects which have a parent home, the secondary home
+ * objects will always be destroyed when the parent home is destroyed even
+ * if there are other references left to them.
+ *
+ * The memory blocks in a cloned home object are freed when the object with
+ * home itself is freed:
+ * @code
+ *    su_free(tophome, ctx);
+ * @endcode
+ * 
+ * @note
+ *
+ * The su_home_destroy() function is deprecated as it does not free the home
+ * object itself.
+ *
+ * The function su_home_init() initializes a home object with infinite
+ * reference count. It must be deinitialized with su_home_deinit().
+ *
+ * @section su_home_destructor_usage Destructors
+ *
+ * It is possible to give a destructor function to a home object. The
+ * destructor releases other resources associated with the home object
+ * besides memory. The destructor function will be called when the reference
+ * count of home reaches zero (upon calling su_home_unref()) or the home
+ * object is otherwise deinitialized (calling su_home_deinit() on
+ * objects allocated from stack).
+ *
+ * @section su_home_move_example Combining Allocations
+ *
+ * In some cases, an operation that makes multiple memory allocations may
+ * fail, making those allocations redundant. If the allocations are made
+ * through a temporary home, they can be conveniently freed by calling
+ * su_home_deinit(), for instance. If, however, the operation is successful,
+ * and one wants to keep the allocations, the allocations can be combined
+ * into an existing home with su_home_move(). For example,
+ * @code
+ * int example(su_home_t *home, ...) 
+ * {
+ *   su_home_t temphome[1] = { SU_HOME_INIT(temphome) };
+ *   
+ *   ... do lot of allocations with temphome ...
+ *  
+ *   if (success) 
+ *     su_home_move(home, temphome);
+ *   su_home_deinit(temphome);
+ *
+ *   return success;
+ * }
+ * @endcode
+ *
+ * Note that the @a temphome is deinitialized in every case, but when
+ * operation is successful, the allocations are moved from @a temphome to @a
+ * home.
+ *
+ * @section su_alloc_threadsafe Threadsafe Operation
+ *
+ * If multiple threads need to access same home object, it must be marked as
+ * @c threadsafe by calling su_home_threadsafe() with the home pointer as
+ * argument. The threadsafeness is not inherited by clones.
+ *
+ * The threadsafe home objects can be locked and unlocked with
+ * su_home_mutex_lock() and su_home_mutex_unlock().
+ *
+ * @section su_alloc_preloading Preloading a Memory Home
+ *
+ * In some situations there is quite heavy overhead when using the global
+ * heap allocator. The overhead caused by the large number of small
+ * allocations can be reduced by using su_home_preload(): it allocates or
+ * preloads some a memory to home to be used as a kind of private heap. The
+ * preloaded memory area is then used to satisfy small enough allocations.
+ * For instance, the SIP parser typically preloads some 2K of memory when it
+ * starts to parse the message.
+ *
+ * @section su_alloc_stack Using Stack
+ *
+ * In some situation, it is sensible to use memory allocated from stack for
+ * some operations. The su_home_auto() function can be used for that
+ * purpose. The memory area from stack is used to satisfy the allocations as
+ * far as possible; if it is not enough, allocation is made from heap.
+ *
+ * The word @e auto refers to the automatic scope; however, the home object
+ * initialized with su_home_auto() must be explicitly deinitialized with
+ * su_home_deinit() when the program exits the scope where the stack frame
+ * used in su_home_auto() was allocate.
+ * 
+ */
+
+#include <sofia-sip/su_config.h>
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_alloc_stat.h"
+#include "sofia-sip/su_errno.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+
+#include <assert.h>
+
+void (*su_home_locker)(void *mutex);
+void (*su_home_unlocker)(void *mutex);
+
+void (*su_home_mutex_locker)(void *mutex);
+void (*su_home_mutex_unlocker)(void *mutex);
+
+#define MEMLOCK(h)   \
+  (((h) && (h)->suh_lock ? su_home_locker((h)->suh_lock) : (void)0), (h)->suh_blocks)
+#define UNLOCK(h) (((h) && (h)->suh_lock ? su_home_unlocker((h)->suh_lock) : (void)0), NULL)
+
+#ifdef NDEBUG
+#define MEMCHECK 0
+#define MEMCHECK_EXTRA 0
+#elif !defined(MEMCHECK)
+/* Default settings for valgrinding */
+#define MEMCHECK 1
+#define MEMCHECK_EXTRA 0
+#elif !defined(MEMCHECK_EXTRA)
+#define MEMCHECK_EXTRA sizeof (size_t)
+#endif
+
+enum { 
+  SUB_N = 31,			/**< Initial size */
+  SUB_N_AUTO = 7,		/**< Initial size for autohome */
+  SUB_P = 29			/**< Secondary probe.
+				 * Secondary probe must be relative prime 
+				 * with all sub_n values */
+};		
+
+#define ALIGNMENT (8)
+#define ALIGN(n) (size_t)(((n) + (ALIGNMENT - 1)) & (size_t)~(ALIGNMENT - 1))
+#define SIZEBITS (sizeof (size_t) * 8 - 1)
+
+typedef struct {
+  size_t   sua_size:SIZEBITS;	/**< Size of the block */
+  unsigned sua_home:1;		/**< Is this another home? */
+  unsigned :0;
+  void    *sua_data;		/**< Data pointer */
+} su_alloc_t;
+
+struct su_block_s {
+  su_home_t  *sub_parent;	/**< Parent home */
+  char       *sub_preload;	/**< Preload area */
+  su_home_stat_t *sub_stats;	/**< Statistics.. */
+  void      (*sub_destructor)(void *); /**< Destructor function */
+  size_t      sub_ref;		/**< Reference count */
+#define REF_MAX SIZE_MAX
+  size_t      sub_used;		/**< Number of blocks allocated */
+  size_t      sub_n;		/**< Size of hash table  */
+
+  unsigned    sub_prsize:16;	/**< Preload size */
+  unsigned    sub_prused:16;	/**< Used from preload */
+  unsigned    sub_auto:1;	/**< struct su_block_s is from stack! */
+  unsigned    sub_preauto:1;	/**< Preload is from stack! */
+  unsigned    sub_auto_all:1;	/**< Everything is from stack! */
+  unsigned :0;
+
+  su_alloc_t  sub_nodes[SUB_N];	/**< Pointers to data/lower blocks */
+};
+
+static void su_home_check_blocks(su_block_t const *b);
+
+static void su_home_stats_alloc(su_block_t *, void *p, void *preload,
+				size_t size, int zero);
+static void su_home_stats_free(su_block_t *sub, void *p, void *preload,
+			       size_t size);
+
+static void _su_home_deinit(su_home_t *home);
+
+#define SU_ALLOC_STATS 1
+
+#if SU_ALLOC_STATS
+size_t count_su_block_find, count_su_block_find_loop;
+size_t size_su_block_find, used_su_block_find;
+size_t max_size_su_block_find, max_used_su_block_find;
+size_t su_block_find_collision, su_block_find_collision_used, 
+  su_block_find_collision_size;
+#endif
+
+static inline su_alloc_t *su_block_find(su_block_t *b, void const *p)
+{
+  size_t h, h0, probe;
+
+#if SU_ALLOC_STATS  
+  size_t collision = 0;
+
+  count_su_block_find++;
+  size_su_block_find += b->sub_n;
+  used_su_block_find += b->sub_used;
+  if (b->sub_n > max_size_su_block_find)
+    max_size_su_block_find = b->sub_n;
+  if (b->sub_used > max_used_su_block_find)
+    max_used_su_block_find = b->sub_used;
+#endif
+
+  assert(p != NULL);
+
+  h = h0 = (size_t)((uintptr_t)p % b->sub_n);
+
+  probe = (b->sub_n > SUB_P) ? SUB_P : 1;
+
+  do {
+    if (b->sub_nodes[h].sua_data == p)
+      return &b->sub_nodes[h];
+    h += probe;
+    if (h >= b->sub_n)
+      h -= b->sub_n;
+#if SU_ALLOC_STATS
+    if (++collision > su_block_find_collision)
+      su_block_find_collision = collision, 
+	su_block_find_collision_used = b->sub_used,
+	su_block_find_collision_size = b->sub_n;
+    count_su_block_find_loop++;
+#endif
+  } while (h != h0);
+
+  return NULL;
+}
+
+static inline su_alloc_t *su_block_add(su_block_t *b, void *p)
+{
+  size_t h, probe;
+
+  assert(p != NULL);
+
+  h = (size_t)((uintptr_t)p % b->sub_n);
+
+  probe = (b->sub_n > SUB_P) ? SUB_P : 1;
+
+  while (b->sub_nodes[h].sua_data) {
+    h += probe;
+    if (h >= b->sub_n)
+      h -= b->sub_n;
+  }
+
+  b->sub_used++;
+  b->sub_nodes[h].sua_data = p;
+
+  return &b->sub_nodes[h];
+}
+
+static inline int su_is_preloaded(su_block_t const *sub, char *data)
+{
+  return
+    sub->sub_preload && 
+    sub->sub_preload <= data && 
+    sub->sub_preload + sub->sub_prsize > data;
+}
+
+static inline int su_alloc_check(su_block_t const *sub, su_alloc_t const *sua)
+{
+#if MEMCHECK_EXTRA
+  size_t size, term;
+  assert(sua);
+  if (sua) {
+    size = sua->sua_size;
+    memcpy(&term, (char *)sua->sua_data + size, sizeof (term));
+    assert(size - term == 0);
+    return size - term == 0;
+  }
+  else
+    return 0;
+#endif
+  return sua != NULL;
+}
+
+/** Allocate the block hash table.
+ *
+ * The function su_hash_alloc() allocates a block hash table of @a n
+ * elements.
+ *
+ * @param home  pointer to home object
+ * @param n     number of buckets in hash table
+ *
+ * @return
+ *   This function returns a pointer to the allocated hash table or
+ *   NULL if an error occurred.
+ */
+static inline su_block_t *su_hash_alloc(size_t n)
+{
+  su_block_t *b = calloc(1, offsetof(su_block_t, sub_nodes[n]));
+
+  if (b)
+    b->sub_n = n;
+
+  return b;
+}
+
+enum sub_zero { do_malloc, do_calloc, do_clone };
+
+/** Allocate a memory block.
+ *
+ * Precondition: locked home
+ *
+ * @param home home to allocate
+ * @param sub  block structure used to allocate
+ * @param size
+ * @param zero if true, zero allocated block;
+ *             if > 1, allocate a subhome
+ *
+ */
+static 
+void *sub_alloc(su_home_t *home, 
+		su_block_t *sub,
+		size_t size,
+		enum sub_zero zero)
+{
+  void *data, *preload = NULL;
+  
+  assert (size < (1UL << SIZEBITS));
+
+  if (sub == NULL || 3 * sub->sub_used > 2 * sub->sub_n) {
+    /* Resize the hash table */
+    size_t i, n, n2, used;
+    su_block_t *b2;
+
+    if (sub)
+      n = home->suh_blocks->sub_n, n2 = 4 * n + 3, used = sub->sub_used;
+    else
+      n = 0, n2 = SUB_N, used = 0;
+
+#if 0
+    printf("su_alloc(home = %p): realloc block hash of size %d\n", home, n2);
+#endif
+
+    if (!(b2 = su_hash_alloc(n2)))
+      return NULL;
+
+    for (i = 0; i < n; i++) {
+      if (sub->sub_nodes[i].sua_data)
+	su_block_add(b2, sub->sub_nodes[i].sua_data)[0] = sub->sub_nodes[i];
+    }
+
+    if (sub) {
+      b2->sub_parent = sub->sub_parent;
+      b2->sub_ref = sub->sub_ref;
+      b2->sub_preload = sub->sub_preload;
+      b2->sub_prsize = sub->sub_prsize;
+      b2->sub_prused = sub->sub_prused;
+      b2->sub_preauto = sub->sub_preauto;
+      b2->sub_destructor = sub->sub_destructor;
+      /* auto_all is not copied! */
+      b2->sub_stats = sub->sub_stats;
+    }
+
+    home->suh_blocks = b2;
+
+    if (sub && !sub->sub_auto)
+      free(sub);
+    sub = b2;
+  }
+
+  if (size && sub && zero < do_clone &&
+      sub->sub_preload && size <= sub->sub_prsize) {
+    /* Use preloaded memory */
+    size_t prused = sub->sub_prused + size + MEMCHECK_EXTRA; 
+    prused = ALIGN(prused);
+    if (prused <= sub->sub_prsize) {
+      preload = (char *)sub->sub_preload + sub->sub_prused;
+      sub->sub_prused = (unsigned)prused;
+    }
+  }
+
+  if (preload && zero)
+    data = memset(preload, 0, size);
+  else if (preload)
+    data = preload;
+  else if (zero)
+    data = calloc(1, size + MEMCHECK_EXTRA);
+  else
+    data = malloc(size + MEMCHECK_EXTRA);
+
+  if (data) {
+    su_alloc_t *sua;
+
+#if MEMCHECK_EXTRA
+    size_t term = 0 - size;
+    memcpy((char *)data + size, &term, sizeof (term));
+#endif
+
+    if (!preload)
+      sub->sub_auto_all = 0;
+
+    if (zero == do_clone) {
+      /* Prepare cloned home */ 
+      su_home_t *subhome = data;
+
+      assert(preload == 0);
+
+      subhome->suh_blocks = su_hash_alloc(SUB_N);
+      if (!subhome->suh_blocks) 
+	return (void)free(data), NULL;
+
+      subhome->suh_size = (unsigned)size;
+      subhome->suh_blocks->sub_parent = home;
+      subhome->suh_blocks->sub_ref = 1;
+    }
+
+    /* OK, add the block to the hash table. */
+
+    sua = su_block_add(sub, data); assert(sua);
+    sua->sua_size = size;
+    sua->sua_home = zero > 1;
+
+    if (sub->sub_stats)
+      su_home_stats_alloc(sub, data, preload, size, zero);
+  }
+
+  return data;
+}
+
+/**Create a new su_home_t object.
+ *
+ * Create a home object used to collect multiple memory allocations under
+ * one handle. The memory allocations made using this home object is freed
+ * either when this home is destroyed. 
+ *
+ * The maximum @a size of a home object is INT_MAX (2 gigabytes).
+ *
+ * @param size    size of home object
+ *
+ * The memory home object allocated with su_home_new() can be reclaimed with
+ * su_home_unref().
+ *
+ * @return
+ * This function returns a pointer to an su_home_t object, or NULL upon
+ * an error.
+ */
+void *su_home_new(isize_t size)
+{
+  su_home_t *home;
+
+  assert(size >= sizeof (*home));
+
+  if (size < sizeof (*home))
+    return (errno = EINVAL), NULL;
+  else if (size > INT_MAX)
+    return (errno = ENOMEM), NULL;
+
+  home = calloc(1, size);
+  if (home) {
+    home->suh_size = (int)size;
+    home->suh_blocks = su_hash_alloc(SUB_N);
+    if (home->suh_blocks)
+      home->suh_blocks->sub_ref = 1;
+    else
+      free(home), home = NULL;
+  }
+
+  return home;
+}
+
+/** Create a new reference to a home object. */
+void *su_home_ref(su_home_t const *home)
+{
+  if (home) {
+    su_block_t *sub = MEMLOCK(home);
+
+    if (sub == NULL || sub->sub_ref == 0) {
+      assert(sub && sub->sub_ref != 0);
+      UNLOCK(home);
+      return NULL;
+    }
+    
+    if (sub->sub_ref != REF_MAX)
+      sub->sub_ref++;
+    UNLOCK(home);
+  }
+  else
+    su_seterrno(EFAULT);
+
+  return (void *)home;
+}
+
+/** Set destructor function.
+ *
+ * The destructor function is called after the reference count of a
+ * #su_home_t object reaches zero or a home object is deinitialized, but
+ * before any of the memory areas within the home object are freed.
+ *
+ * @since New in @VERSION_1_12_4.
+ * Earlier versions had su_home_desctructor() (spelling).
+ */
+int su_home_destructor(su_home_t *home, void (*destructor)(void *))
+{
+  int retval = -1;
+
+  if (home) {
+    su_block_t *sub = MEMLOCK(home);
+    if (sub && sub->sub_destructor == NULL) {
+      sub->sub_destructor = destructor;
+      retval = 0;
+    }
+    UNLOCK(home);
+  }
+  else
+    su_seterrno(EFAULT);
+
+  return retval;
+}
+
+#undef su_home_desctructor
+
+/** Set destructor function.
+ *
+ * @deprecated The su_home_destructor() was added in @VERSION_1_12_4. The
+ * su_home_desctructor() is now defined as a macro expanding as
+ * su_home_destructor(). If you want to compile an application as binary
+ * compatible with earlier versions, you have to define su_home_desctructor
+ * as itself, e.g.,
+ * @code
+ * #define su_home_desctructor su_home_desctructor
+ * #include <sofia-sip/su_alloc.h>
+ * @endcode
+ */
+int su_home_desctructor(su_home_t *home, void (*destructor)(void *))
+{
+  return su_home_destructor(home, destructor);
+}
+
+/**Unreference a su_home_t object.
+ *
+ * The function su_home_unref() decrements the reference count on a home
+ * object and destroys and frees it and the memory allocations using it.
+ *
+ * @param home memory pool object to be unreferences
+ *
+ * The function return values is 
+ *
+ * @retval 1 if object was freed
+ * @retval 0 if object is still alive
+ */
+int su_home_unref(su_home_t *home)
+{
+  su_block_t *sub;
+
+  if (home == NULL)
+    return 0;
+
+  sub = MEMLOCK(home);
+
+  if (sub == NULL) {
+    /* Xyzzy */
+    return 0;
+  }
+  else if (sub->sub_ref == REF_MAX) {
+    UNLOCK(home);
+    return 0;
+  }
+  else if (--sub->sub_ref > 0) {
+    UNLOCK(home);
+    return 0;
+  }
+  else if (sub->sub_parent) {
+    su_home_t *parent = sub->sub_parent;
+    UNLOCK(home);
+    su_free(parent, home);
+    return 1;
+  }
+  else {
+    _su_home_deinit(home);
+    free(home);
+    /* UNLOCK(home); */
+    return 1;
+  }
+}
+
+/** Return reference count of home. */
+size_t su_home_refcount(su_home_t *home)
+{
+  size_t count = 0;
+
+  if (home) {
+    su_block_t *sub = MEMLOCK(home);
+
+    if (sub)
+      count = sub->sub_ref;
+
+    UNLOCK(home);
+  }
+
+  return count;
+}
+
+/**Clone a su_home_t object.
+ *
+ * Clone a secondary home object used to collect multiple memoryf
+ * allocations under one handle. The memory is freed either when the cloned
+ * home is destroyed or when the parent home is destroyed.
+ *
+ * An independent
+ * home object is created if NULL is passed as @a parent argument.
+ *
+ * @param parent  a parent object (may be NULL)
+ * @param size    size of home object
+ *
+ * The memory home object allocated with su_home_clone() can be freed with
+ * su_home_unref().
+ *
+ * @return
+ * This function returns a pointer to an su_home_t object, or NULL upon
+ * an error.
+ */
+void *su_home_clone(su_home_t *parent, isize_t size)
+{
+  su_home_t *home;
+
+  assert(size >= sizeof (*home));
+
+  if (size < sizeof (*home))
+    return (void)(errno = EINVAL), NULL;
+  else if (size > INT_MAX)
+    return (void)(errno = ENOMEM), NULL;
+
+  if (parent) {
+    su_block_t *sub = MEMLOCK(parent);
+    home = sub_alloc(parent, sub, size, 2);
+    UNLOCK(parent);
+  }
+  else {
+    home = su_home_new(size);
+  }
+
+  return home;
+}
+
+/** Return true if home is a clone. */
+int su_home_has_parent(su_home_t const *home)
+{
+  return home && !home->suh_lock && 
+    home->suh_blocks && home->suh_blocks->sub_parent;
+}
+
+/** Allocate a memory block.
+ *
+ * The function su_alloc() allocates a memory block of a given @a size.
+ *
+ * If @a home is NULL, this function behaves exactly like malloc().
+ *
+ * @param home  pointer to home object
+ * @param size  size of the memory block to be allocated
+ *
+ * @return
+ * This function returns a pointer to the allocated memory block or
+ * NULL if an error occurred.
+ */
+void *su_alloc(su_home_t *home, isize_t size)
+{
+  void *data;
+
+  if (home) {
+    data = sub_alloc(home, MEMLOCK(home), size, 0);
+    UNLOCK(home);
+  }
+  else
+    data = malloc(size);
+
+  return data;
+}
+
+/**Free a memory block.
+ *
+ * The function su_free() frees a single memory block. The @a home must be
+ * the owner of the memory block (usually the memory home used to allocate
+ * the memory block, or NULL if no home was used).
+ *
+ * @param home  pointer to home object
+ * @param data  pointer to the memory block to be freed
+ */
+void su_free(su_home_t *home, void *data)
+{
+  if (home && data) {
+    su_alloc_t *allocation;
+    su_block_t *sub = MEMLOCK(home);
+
+    assert(sub);
+    allocation = su_block_find(sub, data);
+    assert(allocation);
+
+    if (su_alloc_check(sub, allocation)) {
+      void *preloaded = NULL;
+
+      /* Is this preloaded data? */
+      if (su_is_preloaded(sub, data))
+	preloaded = data;
+
+      if (sub->sub_stats)
+	su_home_stats_free(sub, data, preloaded, allocation->sua_size);
+
+      if (allocation->sua_home) {
+	su_home_t *subhome = data;
+	su_block_t *sub = MEMLOCK(subhome);
+
+	assert(sub->sub_ref != REF_MAX);
+	/* assert(sub->sub_ref > 0); */
+
+	sub->sub_ref = 0;	/* Zap all references */
+
+	_su_home_deinit(subhome);
+      }
+
+#if MEMCHECK != 0
+      memset(data, 0xaa, allocation->sua_size);
+#endif
+
+      memset(allocation, 0, sizeof (*allocation));
+      sub->sub_used--;
+
+      if (preloaded)
+	data = NULL;
+    }
+
+    UNLOCK(home);
+  }
+
+  free(data);
+}
+
+/** Check home consistency.
+ *
+ * The function su_home_check() ensures that the home structure and all
+ * memory blocks allocated through it are consistent.  It can be used to
+ * catch memory allocation and usage errors.
+ *
+ * @param home Pointer to a memory home.
+ */
+void su_home_check(su_home_t const *home)
+{
+#if MEMCHECK != 0
+  su_block_t const *b = MEMLOCK(home);
+
+  su_home_check_blocks(b);
+
+  UNLOCK(home);
+#endif
+}
+
+/** Check home blocks. */
+static
+void su_home_check_blocks(su_block_t const *b)
+{
+#if MEMCHECK != 0
+  if (b) {
+    size_t i, used;
+    assert(b->sub_used <= b->sub_n);
+
+    for (i = 0, used = 0; i < b->sub_n; i++)
+      if (b->sub_nodes[i].sua_data) {
+	su_alloc_check(b, &b->sub_nodes[i]), used++;
+	if (b->sub_nodes[i].sua_home)
+	  su_home_check((su_home_t *)b->sub_nodes[i].sua_data);
+      }
+
+    assert(used == b->sub_used);
+  }
+#endif
+}
+
+/**
+ * Create an su_home_t object.
+ *
+ * The function su_home_create() creates a home object.  A home object is
+ * used to collect multiple memory allocations, so that they all can be
+ * freed by calling su_home_unref().
+ *
+ * @return This function returns a pointer to an @c su_home_t object, or @c
+ * NULL upon an error. 
+ */
+su_home_t *su_home_create(void)
+{
+  return su_home_new(sizeof(su_home_t));
+}
+
+/** Deinitialize a home object
+ *
+ * The function su_home_destroy() frees all memory blocks associated with a
+ * home object. Note that the home object is not freed.
+ *
+ * @param home pointer to a home object
+ *
+ * @deprecated
+ * su_home_destroy() is included for backwards compatibility only. Use
+ * su_home_unref() instead of su_home_destroy().
+ */
+void su_home_destroy(su_home_t *home)
+{
+  su_home_deinit(home);
+  /* XXX - home itself is not destroyed */
+}
+
+/** Initialize an su_home_t struct.
+ *
+ * The function su_home_init() initializes an su_home_t structure. It can be
+ * used when the home structure is allocated from stack.
+ *
+ * @param home pointer to home object
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ *
+ * @sa SU_HOME_INIT(), su_home_deinit(), su_home_new(), su_home_clone()
+ */
+int su_home_init(su_home_t *home)
+{
+  if (home == NULL)
+    return -1;
+
+  home->suh_blocks = su_hash_alloc(SUB_N);
+
+  return 0;
+}
+
+/** Internal deinitialization */
+static
+void _su_home_deinit(su_home_t *home)
+{
+  if (home->suh_blocks) {
+    size_t i;
+    su_block_t *b;
+
+     if (home->suh_blocks->sub_destructor) {
+      void (*destructor)(void *) = home->suh_blocks->sub_destructor;
+      home->suh_blocks->sub_destructor = NULL;
+      destructor(home);
+    }
+
+    b = home->suh_blocks;
+
+    su_home_check_blocks(b);
+
+    for (i = 0; i < b->sub_n; i++) {
+      if (b->sub_nodes[i].sua_data) {
+	if (b->sub_nodes[i].sua_home) {
+	  su_home_t *subhome = b->sub_nodes[i].sua_data;
+	  su_block_t *subb = MEMLOCK(subhome);
+
+	  assert(subb); assert(subb->sub_ref >= 1);
+#if 0
+	  if (subb->sub_ref > 0)
+	    SU_DEBUG_7(("su_home_unref: subhome %p with destructor %p has still %u refs\n",
+			subhome, subb->sub_destructor, subb->sub_ref));
+#endif
+	  subb->sub_ref = 0;	/* zap them all */
+	  _su_home_deinit(subhome);
+	}
+	else if (su_is_preloaded(b, b->sub_nodes[i].sua_data))
+	  continue;
+	free(b->sub_nodes[i].sua_data);
+      }
+    }
+
+    if (b->sub_preload && !b->sub_preauto)
+      free(b->sub_preload);
+    if (b->sub_stats)
+      free(b->sub_stats);
+    if (!b->sub_auto)
+      free(b);
+
+    home->suh_blocks = NULL;
+  }
+
+  home->suh_lock = NULL;
+}
+
+/** Free memory blocks allocated through home.
+ *
+ * The function @c su_home_deinit() frees the memory blocks associated with
+ * the home object allocated otherwise. It does not free the home object
+ * itself. Use su_home_unref() to free the home object.
+ *
+ * @param home pointer to home object
+ *
+ * @sa su_home_init()
+ */
+void su_home_deinit(su_home_t *home)
+{
+  if (MEMLOCK(home)) {
+    assert(home->suh_blocks && home->suh_blocks->sub_ref == 0);
+    _su_home_deinit(home);
+    /* UNLOCK(home); */
+  }
+}
+
+/**Move allocations from a su_home_t object to another.
+ *
+ * The function su_home_move() moves allocations made through the @a src
+ * home object under the @a dst home object. It is handy, for example, if an
+ * operation allocates some number of blocks that should be freed upon an
+ * error. It uses a temporary home and moves the blocks from temporary to a
+ * proper home when successful, but frees the temporary home upon an error.
+ *
+ * If @a src has destructor, it is called before starting to move.
+ *
+ * @param dst destination home
+ * @param src source home
+ *
+ * @retval 0 if succesful
+ * @retval -1 upon an error
+ */
+int su_home_move(su_home_t *dst, su_home_t *src)
+{
+  size_t i, n, n2, used;
+  su_block_t *s, *d, *d2;
+
+  if (src == NULL || dst == src)
+    return 0;
+
+  if (dst) {
+    s = MEMLOCK(src); d = MEMLOCK(dst);
+
+    if (s && s->sub_n) {
+
+      if (s->sub_destructor) {
+	void (*destructor)(void *) = s->sub_destructor;
+	s->sub_destructor = NULL;
+	destructor(src);
+      }
+
+      if (d) 
+	used = s->sub_used + d->sub_used;
+      else
+	used = s->sub_used;
+
+      if ((used && d == NULL) || 3 * used > 2 * d->sub_n) {
+	if (d)
+	  for (n = n2 = d->sub_n; 3 * used > 2 * n2; n2 = 4 * n2 + 3)
+	    ;
+	else
+	  n = 0, n2 = s->sub_n;
+
+	if (!(d2 = su_hash_alloc(n2))) {
+	  UNLOCK(dst); UNLOCK(src);
+	  return -1;
+	}
+
+	dst->suh_blocks = d2;
+
+      	for (i = 0; i < n; i++)
+	  if (d->sub_nodes[i].sua_data) 
+	    su_block_add(d2, d->sub_nodes[i].sua_data)[0] = d->sub_nodes[i];
+
+	if (d) {
+	  d2->sub_parent = d->sub_parent;
+	  d2->sub_ref = d->sub_ref;
+	  d2->sub_preload = d->sub_preload;
+	  d2->sub_prsize = d->sub_prsize;
+	  d2->sub_prused = d->sub_prused;
+	  d2->sub_preauto = d->sub_preauto;
+	  d2->sub_stats = d->sub_stats;
+	}
+
+	if (d && !d->sub_auto)
+	  free(d);
+
+	d = d2;
+      }
+
+      if ((n = s->sub_n)) {
+	for (i = 0; i < n; i++)
+	  if (s->sub_nodes[i].sua_data) {
+	    su_block_add(d, s->sub_nodes[i].sua_data)[0] = s->sub_nodes[i];
+	  }
+
+	s->sub_used = 0;
+
+	memset(s->sub_nodes, 0, n * sizeof (s->sub_nodes[0]));
+      }
+
+      if (s->sub_stats) {
+      }
+    }
+
+    UNLOCK(dst); UNLOCK(src);
+  }
+  else {
+    s = MEMLOCK(src); 
+
+    if (s && s->sub_used) {
+      s->sub_used = 0;
+      memset(s->sub_nodes, 0, s->sub_n * sizeof (s->sub_nodes[0]));
+    }
+
+    UNLOCK(src);
+  }
+
+  return 0;
+}
+
+/** Preload a memory home.
+ *
+ * The function su_home_preload() preloads a memory home.
+ */
+void su_home_preload(su_home_t *home, isize_t n, isize_t isize)
+{
+  su_block_t *sub;
+
+  if (home == NULL)
+    return;
+
+  if (home->suh_blocks == NULL) 
+    su_home_init(home);
+
+  sub = MEMLOCK(home);
+  if (!sub->sub_preload) {
+    size_t size;
+    void *preload;
+
+    size = n * ALIGN(isize);
+    if (size > 65535)		/* We have 16 bits... */
+      size = 65535 & (ALIGNMENT - 1);
+
+    preload = malloc(size);
+
+    home->suh_blocks->sub_preload = preload;
+    home->suh_blocks->sub_prsize = (unsigned)size;
+  }
+  UNLOCK(home);
+}
+
+/** Preload a memory home from stack.
+ *
+ * The function su_home_auto() initalizes a memory home using an area
+ * allocated from stack. Poor mans alloca().
+ */
+su_home_t *su_home_auto(void *area, isize_t size)
+{
+  su_home_t *home;
+  su_block_t *sub;
+  size_t homesize = ALIGN(sizeof *home);
+  size_t subsize = ALIGN(offsetof(su_block_t, sub_nodes[SUB_N_AUTO]));
+  size_t prepsize;
+
+  char *p = area;
+
+  prepsize = homesize + subsize + (ALIGN((intptr_t)p) - (intptr_t)p);
+
+  if (area == NULL || size < prepsize)
+    return NULL;
+
+  if (size > INT_MAX)
+    size = INT_MAX;
+
+  home = memset(p, 0, homesize);
+  home->suh_size = (int)size;
+
+  sub = memset(p + homesize, 0, subsize);
+  home->suh_blocks = sub;
+
+  if (size > prepsize + 65535)
+    size = prepsize + 65535;
+
+  sub->sub_n = SUB_N_AUTO;
+  sub->sub_preload = p + prepsize;
+  sub->sub_prsize = (unsigned)(size - prepsize);
+  sub->sub_preauto = 1;
+  sub->sub_auto = 1;
+  sub->sub_auto_all = 1;
+
+  return home;
+}
+
+
+/** Reallocate a memory block.
+ *
+ *   The function su_realloc() allocates a memory block of @a size bytes.
+ *   It copies the old block contents to the new block and frees the old
+ *   block.
+ *
+ *   If @a home is NULL, this function behaves exactly like realloc().
+ *
+ *   @param home  pointer to memory pool object
+ *   @param data  pointer to old memory block
+ *   @param size  size of the memory block to be allocated
+ *   
+ * @return
+ *   This function returns a pointer to the allocated memory block or
+ *   NULL if an error occurred.
+ */
+void *su_realloc(su_home_t *home, void *data, isize_t size)
+{
+  void *ndata;
+  su_alloc_t *sua;
+  su_block_t *sub;
+  size_t p;
+  size_t term = 0 - size;
+
+  if (!home) 
+    return realloc(data, size);
+
+  if (size == 0) {
+    if (data)
+      su_free(home, data);
+    return NULL;
+  }
+
+  sub = MEMLOCK(home);
+  if (!data) {
+    data = sub_alloc(home, sub, size, 0);
+    UNLOCK(home);
+    return data;
+  }
+
+  sua = su_block_find(sub, data);
+
+  if (!su_alloc_check(sub, sua))
+    return UNLOCK(home);
+  
+  assert(!sua->sua_home);
+  if (sua->sua_home)
+    return UNLOCK(home);
+  
+  if (!su_is_preloaded(sub, data)) {
+    ndata = realloc(data, size + MEMCHECK_EXTRA);
+    if (ndata) {
+      if (sub->sub_stats) {
+	su_home_stats_free(sub, data, 0, sua->sua_size);
+	su_home_stats_alloc(sub, data, 0, size, 1);
+      }
+
+#if MEMCHECK_EXTRA
+      memcpy((char *)ndata + size, &term, sizeof (term));
+#else
+      (void)term;
+#endif
+      memset(sua, 0, sizeof *sua);
+      sub->sub_used--;
+      su_block_add(sub, ndata)->sua_size = size;
+    }
+    UNLOCK(home);
+
+    return ndata;
+  }
+
+  p = (char *)data - home->suh_blocks->sub_preload;
+  p += sua->sua_size + MEMCHECK_EXTRA;
+  p = ALIGN(p);
+
+  if (p == sub->sub_prused) {
+    size_t p2 = (char *)data - sub->sub_preload + size + MEMCHECK_EXTRA;
+    p2 = ALIGN(p2);
+    if (p2 <= sub->sub_prsize) {
+      /* Extend/reduce existing preload */
+      if (sub->sub_stats) {
+	su_home_stats_free(sub, data, data, sua->sua_size);
+	su_home_stats_alloc(sub, data, data, size, 0);
+      }
+
+      sub->sub_prused = (unsigned)p2;
+      sua->sua_size = size;
+
+#if MEMCHECK_EXTRA
+      memcpy((char *)data + size, &term, sizeof (term));
+#endif
+      UNLOCK(home);
+      return data;
+    }
+  }
+  else if (size < sua->sua_size) {
+    /* Reduce existing preload */
+    if (sub->sub_stats) {
+      su_home_stats_free(sub, data, data, sua->sua_size);
+      su_home_stats_alloc(sub, data, data, size, 0);
+    }
+#if MEMCHECK_EXTRA
+    memcpy((char *)data + size, &term, sizeof (term));
+#endif
+    sua->sua_size = size;
+    UNLOCK(home);
+    return data;
+  }
+
+  ndata = malloc(size + MEMCHECK_EXTRA);
+
+  if (ndata) {
+    if (p == sub->sub_prused) {
+      /* Free preload */
+      sub->sub_prused = (char *)data - home->suh_blocks->sub_preload;
+      if (sub->sub_stats)
+	su_home_stats_free(sub, data, data, sua->sua_size);
+    }
+    
+    memcpy(ndata, data, sua->sua_size < size ? sua->sua_size : size);
+#if MEMCHECK_EXTRA
+    memcpy((char *)ndata + size, &term, sizeof (term));
+#endif
+
+    if (sub->sub_stats)
+      su_home_stats_alloc(sub, data, 0, size, 1);
+
+    memset(sua, 0, sizeof *sua); sub->sub_used--;
+
+    su_block_add(sub, ndata)->sua_size = size;
+  }
+
+  UNLOCK(home);
+
+  return ndata;
+}
+
+
+/**Check if a memory block has been allocated from the @a home.
+ *
+ * Check if the given memory block has been allocated from the home.
+ *
+ * @param home pointer to memory pool object
+ * @param memory ponter to memory block
+ *
+ * @retval 1 if @a memory has been allocated from @a home.
+ * @retval 0 otherwise
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+int su_in_home(su_home_t *home, void const *memory)
+{
+  su_alloc_t *sua;
+  su_block_t *sub;
+  int retval = 0;
+
+  if (!home || !memory)
+    return 0;
+
+  sub = MEMLOCK(home);
+
+  if (sub) {
+    sua = su_block_find(sub, memory);
+
+    retval = su_alloc_check(sub, sua);
+
+    UNLOCK(home);
+  }
+  
+  return retval;
+}
+
+
+/**Allocate and zero a memory block.
+ *
+ * The function su_zalloc() allocates a memory block with a given size from
+ * given memory home @a home and zeroes the allocated block.
+ *
+ *  @param home  pointer to memory pool object
+ *  @param size  size of the memory block
+ *
+ * @note The memory home pointer @a home may be @c NULL. In that case, the
+ * allocated memory block is not associated with any memory home, and it
+ * must be freed by calling su_free() or free().
+ *
+ * @return
+ * The function su_zalloc() returns a pointer to the allocated memory block,
+ * or NULL upon an error.
+ */
+void *su_zalloc(su_home_t *home, isize_t size)
+{
+  void *data;
+
+  assert (size >= 0);
+
+  if (home) {
+    data = sub_alloc(home, MEMLOCK(home), size, 1);
+    UNLOCK(home);
+  }
+  else
+    data = calloc(1, size);
+
+  return data;
+}
+
+/** Allocate a structure
+ *
+ * The function su_salloc() allocates a structure with a given size, zeros
+ * it, and initializes the size field to the given size.  The size field
+ * is the first in the structure. It has type of int. 
+ *
+ * @param home  pointer to memory pool object
+ * @param size  size of the structure
+ *
+ * @par Example
+ * The structure is defined and allocated as follows:
+ * @code
+ *   struct test {
+ *     int   tst_size;
+ *     char *tst_name;
+ *     void *tst_ptr[3];
+ *   };
+ * 
+ *   struct test *t;
+ *   ...
+ *   t = su_salloc(home, sizeof (*t)); 
+ *   assert(t && t->t_size == sizeof (*t));
+ *   
+ * @endcode
+ * After calling su_salloc() we get a pointer t to a struct test,
+ * initialized to zero except the tst_size field, which is initialized to
+ * sizeof (*t).
+ *
+ * @return A pointer to the allocated structure, or NULL upon an error.
+ */
+void *su_salloc(su_home_t *home, isize_t size)
+{
+  struct { int size; } *retval;
+
+  if (size < sizeof (*retval))
+    size = sizeof (*retval);
+
+  if (size > INT_MAX)
+    return (void)(errno = ENOMEM), NULL;
+
+  if (home) {
+    retval = sub_alloc(home, MEMLOCK(home), size, 1);
+    UNLOCK(home);
+  }
+  else
+    retval = calloc(1, size);
+
+  if (retval)
+    retval->size = (int)size;
+
+  return retval;
+}
+
+/** Check if a memory home is threadsafe */
+int su_home_is_threadsafe(su_home_t const *home)
+{
+  return home && home->suh_lock;
+}
+
+/** Obtain exclusive lock on home (if home is threadsafe). */
+int su_home_mutex_lock(su_home_t *home)
+{
+  if (home == NULL)
+    return su_seterrno(EFAULT);
+
+  if (home->suh_lock) {
+    su_home_ref(home);
+    su_home_mutex_locker(home->suh_lock);
+  }
+  else if (home->suh_blocks) {
+    if (!su_home_ref(home))
+      return -1;
+  }
+
+  return 0;
+}
+
+/** Release exclusive lock on home (if home is threadsafe) */
+int su_home_mutex_unlock(su_home_t *home)
+{
+  if (home == NULL)
+    return su_seterrno(EFAULT);
+
+  if (home->suh_lock) {
+    su_home_mutex_unlocker(home->suh_lock);
+    su_home_unref(home);
+  }
+  else if (home->suh_blocks) {
+    su_home_unref(home);
+  }
+
+  return 0;
+}
+
+
+/** Initialize statistics structure */
+void su_home_init_stats(su_home_t *home)
+{
+  su_block_t *sub;
+  size_t size;
+
+  if (home == NULL)
+    return;
+
+  sub = home->suh_blocks;
+
+  if (!sub)
+    sub = home->suh_blocks = su_hash_alloc(SUB_N);
+  if (!sub)
+    return;
+
+  if (!sub->sub_stats) {
+    size = sizeof (*sub->sub_stats);
+    sub->sub_stats = malloc(size);
+    if (!sub->sub_stats)
+      return;
+  }
+  else
+    size = sub->sub_stats->hs_size;
+  
+  memset(sub->sub_stats, 0, size);
+  sub->sub_stats->hs_size = (int)size;
+  sub->sub_stats->hs_blocksize = sub->sub_n;
+}
+
+/** Retrieve statistics from memory home.
+ */
+void su_home_get_stats(su_home_t *home, int include_clones, 
+		       su_home_stat_t hs[1],
+		       isize_t size)
+{
+  su_block_t *sub;
+
+  if (hs == NULL || size < (sizeof hs->hs_size))
+    return;
+
+  memset(hs, 0, size);
+
+  sub = MEMLOCK(home);
+
+  if (sub && sub->sub_stats) {
+    int sub_size = sub->sub_stats->hs_size;
+    if (sub_size > (int)size)
+      sub_size = (int)size;
+    sub->sub_stats->hs_preload.hsp_size = sub->sub_prsize;
+    sub->sub_stats->hs_preload.hsp_used = sub->sub_prused;
+    memcpy(hs, sub->sub_stats, sub_size);
+    hs->hs_size = sub_size;
+  }
+
+  UNLOCK(home);
+}
+
+static 
+void su_home_stats_alloc(su_block_t *sub, void *p, void *preload,
+			 size_t size, int zero)
+{
+  su_home_stat_t *hs = sub->sub_stats;
+
+  size_t rsize = ALIGN(size);
+
+  hs->hs_rehash += (sub->sub_n != hs->hs_blocksize);
+  hs->hs_blocksize = sub->sub_n;
+
+  hs->hs_clones += zero > 1;
+
+  if (preload) {
+    hs->hs_allocs.hsa_preload++;
+    return;
+  }
+
+  hs->hs_allocs.hsa_number++;
+  hs->hs_allocs.hsa_bytes += size;
+  hs->hs_allocs.hsa_rbytes += rsize;
+  if (hs->hs_allocs.hsa_rbytes > hs->hs_allocs.hsa_maxrbytes)
+    hs->hs_allocs.hsa_maxrbytes = hs->hs_allocs.hsa_rbytes;
+  
+  hs->hs_blocks.hsb_number++;
+  hs->hs_blocks.hsb_bytes += size;
+  hs->hs_blocks.hsb_rbytes += rsize;
+}
+
+static 
+void su_home_stats_free(su_block_t *sub, void *p, void *preload, size_t size)
+{
+  su_home_stat_t *hs = sub->sub_stats;
+
+  size_t rsize = ALIGN(size);
+
+  if (preload) {
+    hs->hs_frees.hsf_preload++;
+    return;
+  }
+
+  hs->hs_frees.hsf_number++;
+  hs->hs_frees.hsf_bytes += size;
+  hs->hs_frees.hsf_rbytes += rsize;
+
+  hs->hs_blocks.hsb_number--;
+  hs->hs_blocks.hsb_bytes -= size;
+  hs->hs_blocks.hsb_rbytes -= rsize;
+}
+
+void su_home_stat_add(su_home_stat_t total[1], su_home_stat_t const hs[1])
+{
+  total->hs_clones               += hs->hs_clones;
+  total->hs_rehash               += hs->hs_rehash;
+
+  if (total->hs_blocksize < hs->hs_blocksize)
+    total->hs_blocksize = hs->hs_blocksize;
+
+  total->hs_allocs.hsa_number    += hs->hs_allocs.hsa_number;
+  total->hs_allocs.hsa_bytes     += hs->hs_allocs.hsa_bytes;
+  total->hs_allocs.hsa_rbytes    += hs->hs_allocs.hsa_rbytes;
+  total->hs_allocs.hsa_maxrbytes += hs->hs_allocs.hsa_maxrbytes;
+
+  total->hs_frees.hsf_number     += hs->hs_frees.hsf_number;
+  total->hs_frees.hsf_bytes      += hs->hs_frees.hsf_bytes;
+  total->hs_frees.hsf_rbytes     += hs->hs_frees.hsf_rbytes;
+
+  total->hs_blocks.hsb_number    += hs->hs_blocks.hsb_number;
+  total->hs_blocks.hsb_bytes     += hs->hs_blocks.hsb_bytes;
+  total->hs_blocks.hsb_rbytes    += hs->hs_blocks.hsb_rbytes;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ * @CFILE su_alloc_lock.c 
+ * @brief Thread-locking for su_alloc module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri Feb 23 17:38:11 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su.h>
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#include <assert.h>
+
+extern void (*su_home_locker)(void *mutex);
+extern void (*su_home_unlocker)(void *mutex);
+
+extern void (*su_home_mutex_locker)(void *mutex);
+extern void (*su_home_mutex_unlocker)(void *mutex);
+
+/** Mutex */
+static void mutex_locker(void *_mutex)
+{
+  pthread_mutex_t *mutex = _mutex;
+  pthread_mutex_lock(mutex + 1);
+}
+
+static void mutex_unlocker(void *_mutex)
+{
+  pthread_mutex_t *mutex = _mutex;
+  pthread_mutex_unlock(mutex + 1);
+}
+#endif
+
+
+/** Convert su_home_t object to a thread-safe one.
+ *
+ * Convert a memory home object as thread-safe by allocating mutexes and
+ * modifying function pointers in su_alloc.c module.
+
+ * @param home memory home object to be converted thread-safe.
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_home_threadsafe(su_home_t *home)
+{
+  pthread_mutex_t *mutex;
+
+  if (home == NULL)
+    return su_seterrno(EFAULT);
+
+  if (home->suh_lock)		/* Already? */
+    return 0;
+
+#if 0				/* Allow threadsafe subhomes */
+  assert(!su_home_has_parent(home));
+  if (su_home_has_parent(home))
+    return su_seterrno(EINVAL);
+#endif
+
+#if SU_HAVE_PTHREADS
+  if (!su_home_unlocker) {
+    /* Avoid linking pthread library just for memory management */
+    su_home_mutex_locker = mutex_locker;
+    su_home_mutex_unlocker = mutex_unlocker;
+    su_home_locker = (void (*)(void *))pthread_mutex_lock;
+    su_home_unlocker = (void (*)(void *))pthread_mutex_unlock;
+  }
+
+  mutex = su_alloc(home, 2 * sizeof (pthread_mutex_t));
+  assert(mutex);
+  if (mutex) {
+    /* Mutex for memory operations */
+    pthread_mutex_init(mutex, NULL);
+    /* Mutex used for explicit locking */ 
+    pthread_mutex_init(mutex + 1, NULL);
+    home->suh_lock = (void *)mutex;
+    return 0;
+  }
+#else
+  su_seterrno(ENOSYS);
+#endif
+
+  return -1;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,273 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file su_bm.c
+ * @brief Search with Boyer-Moore algorithm
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Apr 11 16:35:16 2005 ppessi
+ * 
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_bm.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef TORTURELOG
+#define TORTURELOG(x) (void)0
+#endif
+
+struct bw_fwd_table { 
+  unsigned char table[UCHAR_MAX + 1];
+};
+
+/** Build forward skip table #bm_fwd_table_t for Boyer-Moore algorithm. */
+static
+bm_fwd_table_t *
+bm_memmem_study0(char const *needle, size_t nlen, bm_fwd_table_t *fwd)
+{
+  size_t i;
+
+  if (nlen >= UCHAR_MAX) {
+    needle += nlen - UCHAR_MAX;
+    nlen = UCHAR_MAX;
+  }
+
+  memset(&fwd->table, (unsigned char)nlen, sizeof fwd->table);
+
+  for (i = 0; i < nlen; i++) {
+    fwd->table[(unsigned short)needle[i]] = (unsigned char)(nlen - i - 1);
+  }
+
+  return fwd;
+}
+
+/** @defgroup su_bm Fast string searching with Boyer-Moore algorithm
+ *
+ * The Boyer-Moore algorithm is used to implement fast substring search. The
+ * algorithm has some overhead caused by filling a table. Substring search
+ * then requires at most 1 / substring-length less string comparisons. On
+ * modern desktop hardware, Boyer-Moore algorithm is seldom faster than the
+ * naive implementation if the searched substring is shorter than the cache
+ * line.
+ *
+ */ 
+
+/**@ingroup su_bm
+ * @typedef struct bw_fwd_table bm_fwd_table_t;
+ *
+ * Forward skip table for Boyer-Moore algorithm.
+ *
+ */
+
+/** Build case-sensitive forward skip table #bm_fwd_table_t 
+ *  for Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+bm_fwd_table_t *
+bm_memmem_study(char const *needle, size_t nlen)
+{
+  bm_fwd_table_t *fwd = malloc(sizeof *fwd);
+
+  if (fwd)
+    bm_memmem_study0(needle, nlen, fwd);
+
+  return fwd;
+}
+
+/** Search for a substring using Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+char const*
+bm_memmem(char const *haystack, size_t hlen,
+	  char const *needle, size_t nlen,
+	  bm_fwd_table_t *fwd)
+{
+  size_t i, j;
+  bm_fwd_table_t fwd0[1];
+
+  if (nlen == 0)
+    return haystack;
+  if (needle == NULL || haystack == NULL || nlen > hlen)
+    return NULL;
+
+  if (nlen == 1) {
+    for (i = 0; i < hlen; i++)
+      if (haystack[i] == needle[0])
+	return haystack + i;
+    return NULL;
+  }
+
+  if (!fwd)
+    fwd = bm_memmem_study0(needle, nlen, fwd0);
+
+  for (i = j = nlen - 1; i < hlen;) {
+    unsigned char h = haystack[i];
+    if (h == needle[j]) {
+      TORTURELOG(("match \"%s\" at %u\nwith  %*s\"%.*s*%s\": %s\n", 
+		  haystack, (unsigned)i, 
+		  (int)(i - j), "", (int)j, needle, needle + j + 1, 
+		  j == 0 ? "match!" : "back by 1"));
+      if (j == 0)
+	return haystack + i;
+      i--, j--;
+    }
+    else {
+      if (fwd->table[h] > nlen - j) {
+	TORTURELOG(("match \"%s\" at %u\n"
+		    "last  %*s\"%.*s*%s\": (by %u)\n", 
+		    haystack, (unsigned)i,
+		    (int)(i - j), "", 
+		    (int)j, needle, needle + j + 1, fwd->table[h]));
+      	i += fwd->table[h];
+      }
+      else {
+	TORTURELOG(("match \"%s\" at %u\n"
+		    "2nd   %*s\"%.*s*%s\": (by %u)\n", 
+		    haystack, (unsigned)i,
+		    (int)(i - j), "", 
+		    (int)j, needle, needle + j + 1, (unsigned)(nlen - j)));
+	i += nlen - j;
+      }
+      j = nlen - 1;
+    }
+  }
+  
+  return NULL;
+}
+
+
+/** Build forward skip table for Boyer-Moore algorithm */
+static
+bm_fwd_table_t *
+bm_memcasemem_study0(char const *needle, size_t nlen, bm_fwd_table_t *fwd)
+{
+  size_t i;
+
+  if (nlen >= UCHAR_MAX) {
+    needle += nlen - UCHAR_MAX;
+    nlen = UCHAR_MAX;
+  }
+
+  for (i = 0; i < UCHAR_MAX; i++)
+    fwd->table[i] = (unsigned char)nlen;
+
+  for (i = 0; i < nlen; i++) {
+    unsigned char n = tolower(needle[i]);
+    fwd->table[n] = (unsigned char)(nlen - i - 1);
+  }
+
+  return fwd;
+}
+
+/** Build case-insensitive forward skip table for Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+bm_fwd_table_t *
+bm_memcasemem_study(char const *needle, size_t nlen)
+{
+  bm_fwd_table_t *fwd = malloc(sizeof *fwd);
+
+  if (fwd)
+    bm_memcasemem_study0(needle, nlen, fwd);
+
+  return fwd;
+}
+
+/** Search for substring using Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+char const*
+bm_memcasemem(char const *haystack, size_t hlen,
+	      char const *needle, size_t nlen,
+	      bm_fwd_table_t *fwd)
+{
+  size_t i, j;
+  bm_fwd_table_t fwd0[1];
+
+  if (nlen == 0)
+    return haystack;
+  if (needle == 0 || haystack == 0 || nlen > hlen)
+    return NULL;
+
+  if (nlen == 1) {
+    for (i = 0; i < hlen; i++)
+      if (haystack[i] == needle[0])
+	return haystack + i;
+    return NULL;
+  }
+
+  if (!fwd) {
+    fwd = bm_memcasemem_study0(needle, nlen, fwd0);
+  }
+
+  for (i = j = nlen - 1; i < hlen;) {
+    unsigned char h = haystack[i], n = needle[j];
+    if (isupper(h)) 
+      h = tolower(h);
+    if (isupper(n))
+      n = tolower(n);
+
+    if (h == n) {
+      TORTURELOG(("match \"%s\" at %u\n"
+		  "with  %*s\"%.*s*%s\": %s\n",
+		  haystack, (unsigned)i,
+		  (int)(i - j), "", (int)j, needle, needle + j + 1, 
+		  j == 0 ? "match!" : "back by 1"));
+      if (j == 0)
+	return haystack + i;
+      i--, j--;
+    }
+    else {
+      if (fwd->table[h] > nlen - j) {
+	TORTURELOG(("match \"%s\" at %u\n"
+		    "last  %*s\"%.*s*%s\": (by %u)\n",
+		    haystack, (unsigned)i,
+		    (int)(i - j), "", (int)j, needle, needle + j + 1, 
+		    fwd->table[h]));
+      	i += fwd->table[h];
+      }
+      else {
+	TORTURELOG(("match \"%s\" at %u\n"
+		    "2nd   %*s\"%.*s*%s\": (by %u)\n", 
+		    haystack, (unsigned)i,
+		    (int)(i - j), "", (int)j, needle, needle + j + 1, 
+		    (unsigned)(nlen - j)));
+	i += nlen - j;
+      }
+      j = nlen - 1;
+    }
+  }
+  
+  return NULL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_default_log.c
+ *
+ * Default debug log object.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 17:30:46 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_debug.h>
+
+/** Log into FILE, by default stderr. */
+static void default_logger(void *stream, char const *fmt, va_list ap)
+{
+  FILE *f = stream ? (FILE *)stream : stderr;
+
+  vfprintf(f, fmt, ap);
+}
+
+/**@var SOFIA_DEBUG
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The SOFIA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ * 
+ * @sa <su_debug.h>, su_log_global
+ */
+extern char const SOFIA_DEBUG[];
+
+#ifdef SU_DEBUG
+#define SOFIA_DEBUG_ SU_DEBUG
+#else
+#define SOFIA_DEBUG_ 3
+#endif
+
+/**Default debug log. 
+ *
+ * If a source module does not define a log object, the output from su_log()
+ * function or SU_DEBUG_X() macros use this log object. Also, if a log
+ * function references log object with NULL pointer, the su_log_default
+ * object is used.
+ *
+ * If output from another log object is not redirected with
+ * su_log_redirect(), the output can be redirected via this log object.
+ *
+ * If the logging level of a log object is not set with su_log_set_level(),
+ * or the environment variable directing its level is not set, the log level
+ * from the #su_log_default object is used.
+ *
+ * The level of #su_log_default is set using SOFIA_DEBUG environment
+ * variable.
+ */
+su_log_t su_log_default[1] = {{ 
+  sizeof(su_log_t), 
+  "sofia",		/* Log name */
+  "SOFIA_DEBUG",	/* Environment variable controlling logging level */
+  SOFIA_DEBUG_,		/* Default level */
+  SU_LOG_MAX,		/* Maximum log level */
+  0,
+  default_logger, 
+  NULL
+}};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE su_errno.c errno compatibility
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Original: Thu Mar 18 19:40:51 1999 pessi
+ * @date Split to su_errno.c: Thu Dec 22 18:37:02 EET 2005 pessi
+ */
+
+#include "config.h" 
+
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su.h>
+
+#include <string.h>
+
+#if SU_HAVE_WINSOCK
+
+#include <stdio.h>
+
+/** Get the latest socket error. */
+int su_errno(void)
+{
+  return WSAGetLastError();
+}
+
+/** Set the socket error. */
+int su_seterrno(int errcode)
+{
+  WSASetLastError(errcode);
+
+  return -1;
+}
+
+const char *su_strerror(int errcode)
+{
+  struct errmsg { int no; const char *msg; };
+  static struct errmsg *msgp;
+  static struct errmsg msgs[] = {
+    { 0, "Success" },
+    { WSAEINTR, "Interrupted system call" },
+    { WSAEBADF, "Bad file descriptor" },
+    { WSAEACCES, "Permission denied" },
+    { WSAEFAULT, "Bad address" },
+    { WSAEINVAL, "Invalid argument" },
+    { WSAEMFILE, "Too many open files" },
+    { WSAEWOULDBLOCK, "Another winsock call while a "
+      "blocking function was in progress" },
+    { WSAEINPROGRESS, "Operation now in progress" },
+    { WSAEALREADY, "Operation already in progress" },
+    { WSAENOTSOCK, "Socket operation on non-socket" },
+    { WSAEDESTADDRREQ, "Destination address required" },
+    { WSAEMSGSIZE, "Message too long" },
+    { WSAEPROTOTYPE, "Protocol wrong type for socket" },
+    { WSAENOPROTOOPT, "Protocol not available" },
+    { WSAEPROTONOSUPPORT, "Protocol not supported" },
+    { WSAESOCKTNOSUPPORT, "Socket type not supported" },
+    { WSAEOPNOTSUPP, "Operation not supported" },
+    { WSAEPFNOSUPPORT, "Protocol family not supported" },
+    { WSAEAFNOSUPPORT, "Address family not supported" },
+    { WSAEADDRINUSE, "Address already in use" },
+    { WSAEADDRNOTAVAIL, "Can't assign requested address" },
+    { WSAENETDOWN, "Network is down" },
+    { WSAENETUNREACH, "Network is unreachable" },
+    { WSAENETRESET, "Network dropped connection on reset" },
+    { WSAECONNABORTED, "Software caused connection abort" },
+    { WSAECONNRESET, "Connection reset by peer" },
+    { WSAENOBUFS, "No buffer space available" },
+    { WSAEISCONN, "Socket is already connected" },
+    { WSAENOTCONN, "Socket is not connected" },
+    { WSAESHUTDOWN, "Can't send after socket shutdown" },
+    { WSAETOOMANYREFS, "Too many references: "
+      "can't splice" },
+    { WSAETIMEDOUT, "Operation timed out" },
+    { WSAECONNREFUSED, "Connection refused" },
+    { WSAELOOP, "Too many levels of symbolic links" },
+    { WSAENAMETOOLONG, "File name too long" },
+    { WSAEHOSTDOWN, "Host is down" },
+    { WSAEHOSTUNREACH, "No route to host" },
+    { WSAENOTEMPTY, "Directory not empty" },
+    { WSAEPROCLIM, "Too many processes" },
+    { WSAEUSERS, "Too many users" },
+    { WSAEDQUOT, "Disc quota exceeded" },
+    { WSAESTALE, "Stale NFS file handle" },
+    { WSAEREMOTE, "Too many levels of remote in path" },
+    { WSASYSNOTREADY, "Network subsystem is unvailable" },
+    { WSAVERNOTSUPPORTED, "WinSock version is not "
+      "supported" },
+    { WSANOTINITIALISED, "Successful WSAStartup() not yet "
+      "performed" },
+    { WSAEDISCON, "Graceful shutdown in progress" },
+    /* Resolver errors */
+    { WSAHOST_NOT_FOUND, "No such host is known" },
+    { WSATRY_AGAIN, "Host not found, or server failed" },
+    { WSANO_RECOVERY, "Unexpected server error "
+      "encountered" },
+    { WSANO_DATA, "Valid name without requested data" },
+    { WSANO_ADDRESS, "No address, look for MX record" },
+    { 0, NULL }
+  };
+  static struct errmsg sofia_msgs[] = {
+    { EBADMSG, "Bad message" },
+    { EPROTO, "Protocol error" },
+    { 0, NULL }
+  };
+  static char buf[64];
+
+  if (errcode < WSABASEERR) 
+    return strerror(errcode);
+
+  if (errcode < 20000)
+    for (msgp = msgs; msgp->msg; msgp++) {
+      if (errcode == msgp->no) {
+	return msgp->msg;
+      }
+    }
+  else
+    for (msgp = sofia_msgs; msgp->msg; msgp++) {
+      if (errcode == msgp->no) {
+	return msgp->msg;
+      }
+    }
+
+  /* This can not overflow, but in other hand, it is not thread-safe */
+  sprintf(buf, "winsock error %d", errcode);
+
+  return buf;
+}
+
+#else
+
+const char *su_strerror(int errcode)
+{
+  return strerror(errcode);
+}
+
+#endif /* SU_HAVE_WINSOCK */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_global_log.c
+ *
+ * Global SU debug log.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Mon May  7 11:08:36 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_debug.h>
+
+/**@var SU_DEBUG
+ *
+ * Environment variable determining the debug log level for @b su module.
+ *
+ * The SU_DEBUG environment variable is used to determine the debug logging
+ * level for @b su module. The default level is 3.
+ * 
+ * @sa <su_debug.h>, su_log_global
+ */
+extern char const SU_DEBUG[];
+
+#ifdef SU_DEBUG
+#define SU_DEBUG_ SU_DEBUG
+#else
+#define SU_DEBUG_ 3
+#endif
+
+/**Debug log for @b su module. 
+ * 
+ * The su_log_global is the log object used by @b su module. The level of
+ * #su_log_global is set using #SU_DEBUG environment variable.
+ */
+su_log_t su_log_global[1] = {{ 
+  sizeof(su_log_t), 
+  "su", 
+  "SU_DEBUG", 
+  SU_DEBUG_, 
+  SU_LOG_MAX,
+  0,
+  NULL, 
+  NULL
+}};

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1537 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_socket
+ * @CFILE su_localinfo.c
+ *
+ * Obtain list of local addresses.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Oct  4 14:09:29 EET 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_localinfo.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#if HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#if HAVE_GETIFADDRS
+
+#define USE_LOCALINFO0 1
+#define localinfo0 bsd_localinfo
+static int bsd_localinfo(su_localinfo_t const *, su_localinfo_t **);
+
+#elif HAVE_IPHLPAPI_H
+
+#include <iphlpapi.h>
+#define USE_LOCALINFO0 1
+#define localinfo0 win_localinfo
+static int win_localinfo(su_localinfo_t const *, su_localinfo_t **);
+
+#else
+
+#undef USE_LOCALINFO0
+static int localinfo4(su_localinfo_t const *, su_localinfo_t **);
+#  if SU_HAVE_IN6
+static int localinfo6(su_localinfo_t const *, su_localinfo_t **);
+#  endif
+
+#endif
+
+static int li_name(su_localinfo_t const*, int, su_sockaddr_t const*, char **);
+static void li_sort(su_localinfo_t *i, su_localinfo_t **rresult);
+static int li_scope4(uint32_t ip4);
+
+/** @brief Request local address information.
+ *
+ * Gather the network interfaces and the addresses corresponding to them,
+ * check if they match to the search criteria specifed by @a hints and
+ * return a list of matching local address information in the @a
+ * return_localinfo. The local address information may include IPv4/IPv6
+ * addresses, interface name, interface index, address scope, and domain
+ * names corresponding to the local addresses.
+ *
+ * @param[in] hints specifies selection criteria
+ * @param[out] return_localinfo   return list of local addresses
+ *
+ * @par Selection criteria - hints
+ *
+ * The selection criteria @a hints is used to select which addresses are
+ * returned and what kind of information is included in the @a res list.
+ *
+ * @par Selection by flags - hints->li_flags
+ *
+ * The @a hints->li_flags contain flags, which can be combined with bit-wise
+ * or.  The currently defined flags are as follows:
+ *
+ * - #LI_V4MAPPED: when returning IPv4 addresses, map them as IPv6
+ *   addresses.  If this flag is specified, IPv4 addresses are returned even
+ *   if @a hints->li_family is set to @c AF_INET6.
+ * - #LI_CANONNAME: return the domain name (DNS PTR) corresponding to the 
+ *   local address in @a li_canonname.
+ * - #LI_NAMEREQD: Do not return addresses not in DNS. 
+ * - #LI_NUMERIC: instead of domain name, return the text presentation of
+ *   the addresss in @a li_canonname.
+ * - #LI_DOWN: include interfaces and their addresses even if the interfaces
+ *   are down. New in @VERSION_1_12_2.
+ * - #LI_IFNAME: return the interface name in @a li_ifname.
+ *
+ * @par Selection by address family - hints->li_family
+ *
+ * The address family can have three values: 0, AF_INET and AF_INET6.  If
+ * address family @a hints->li_family, both IPv4 and IPv6 addresses are
+ * returned.
+ *
+ * @par Selection by interface index - hints->li_index
+ *
+ * If the field @a hints->li_index is non-zero, only the addresses assigned
+ * to the interface with given index are returned.  The list of interface
+ * indices and names can be obtained by the function @c su_if_names().
+ *
+ * @par Selection by interface name - hints->li_ifname
+ *
+ * If the field @a hints->li_ifname is not NULL, only the addresses assigned
+ * to the named interface are returned.  The list of interface names can be
+ * obtained by the function @c su_if_names().
+ *
+ * @par Selection by address scope - hints->li_scope
+ *
+ * If the field @a hints->li_scope is nonzero, only the addresses with
+ * matching scope are returned. The different address scopes can be combined
+ * with bitwise or. They are defined as follows
+ * - #LI_SCOPE_HOST: host-local address, valid within host (::1, 127.0.0.1/8)
+ * - #LI_SCOPE_LINK: link-local address, valid within link 
+ *   (IP6 addresses with prefix fe80::/10, 
+ *    IP4 addresses in net 169.254.0.0/16).
+ * - #LI_SCOPE_SITE: site-local address, addresses valid within organization
+ *   (IPv6 addresses with prefix  fec::/10,
+ *    private IPv4 addresses in nets 10.0.0.0/8, 172.16.0.0/12, 
+ *    and 192.168.0.0/16 as defined in @RFC1918)
+ * - #LI_SCOPE_GLOBAL: global address.
+ *
+ * For instance, setting @a hints->li_scope to @c LI_SCOPE_GLOBAL | @c
+ * LI_SCOPE_SITE, both the @e global and @e site-local addresses are
+ * returned.
+ *
+ * @sa @RFC1918, @RFC4291, su_sockaddr_scope()
+ *
+ * @par Selection by domain name - hints->li_canonname
+ *
+ * If this field is non-null, the domain name (DNS PTR) corresponding to
+ * local IP addresses should match to the name given in this field.
+ *
+ * @return Zero (#ELI_NOERROR) when successful, or negative error code when
+ * failed.
+ * 
+ * @par Diagnostics
+ * Use su_gli_strerror() in order to obtain a string describing the error
+ * code returned by su_getlocalinfo().
+ *
+ */
+int su_getlocalinfo(su_localinfo_t const *hints, 
+		    su_localinfo_t **return_localinfo)
+{
+  int error = 0, ip4 = 0, ip6 = 0;
+  su_localinfo_t *result = NULL, **rr = &result;
+  su_localinfo_t hh[1] = {{ 0 }};
+
+  assert(return_localinfo);
+
+  *return_localinfo = NULL;
+
+  if (hints) {
+    /* Copy hints so that it can be modified */
+    *hh = *hints;
+    if (hh->li_canonname)
+      hh->li_flags |= LI_CANONNAME;
+    if ((hh->li_flags & LI_IFNAME) && hh->li_ifname == NULL)
+      return ELI_BADHINTS;
+  }
+
+  switch (hh->li_family) {
+#if SU_HAVE_IN6
+  case AF_INET6:
+    if (hh->li_flags & LI_V4MAPPED)
+      ip6 = ip4 = 1, hh->li_family = 0;
+    else
+      ip6 = 1;
+    break;
+#endif
+
+  case AF_INET:
+    ip4 = 1;
+    break;
+
+  case 0:
+    ip6 = ip4 = 1;    
+    break;
+
+  default:
+    return -1;
+  }
+
+#if USE_LOCALINFO0 
+  error = localinfo0(hh, rr);
+#else
+
+#  if SU_HAVE_IN6
+  if (ip6) {
+    error = localinfo6(hh, rr);
+    if (error == ELI_NOADDRESS && ip4)
+      error = 0;
+    
+    if (!error) 
+      /* Search end of list */
+      for (; *rr; rr = &(*rr)->li_next)
+	;
+  }
+#  endif
+  if (ip4 && !error) {
+    /* Append IPv4 addresses */
+    error = localinfo4(hh, rr);
+  }
+#endif
+
+  if (!result)
+    error = ELI_NOADDRESS;
+
+  if (!error)
+    li_sort(result, return_localinfo);
+  else
+    su_freelocalinfo(result);
+
+  return error;
+}
+
+/** Free local address information. 
+ *
+ * Free a list of su_localinfo_t structures obtained with su_getlocalinfo()
+ * or su_copylocalinfo() along with socket addresses and strings associated
+ * with them.
+ *
+ * @sa su_getlocalinfo(), su_copylocalinfo(), #su_localinfo_t
+ */
+void su_freelocalinfo(su_localinfo_t *tbf)
+{
+  su_localinfo_t *li;
+
+  for (li = tbf; li; li = tbf) {
+    tbf = li->li_next;
+    if (li->li_canonname)
+      free(li->li_canonname);
+    free(li);
+  }
+}
+
+/** Describe su_localinfo errors. 
+ *
+ * The function su_gli_strerror() returns a string describing the error
+ * condition indicated by the code that was returned by the function
+ * su_getlocalinfo().
+ *
+ * @param error error code returned by su_getlocalinfo()
+ *
+ * @return
+ * A pointer to string describing the error condition.
+ */
+char const *su_gli_strerror(int error)
+{
+  switch (error) {
+  case ELI_NOERROR:   return "No error";
+  case ELI_NOADDRESS: return "No matching address";
+  case ELI_MEMORY:    return "Memory allocation error";
+  case ELI_FAMILY:    return "Unknown address family";
+  case ELI_RESOLVER:  return "Error when resolving address";
+  case ELI_SYSTEM:    return "System error";
+  case ELI_BADHINTS:  return "Invalid value for hints";
+  default:            return "Unknown error";
+  }
+}
+
+/** Duplicate su_localinfo structure.
+ */
+su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0)
+{
+  size_t n;
+  su_localinfo_t *li, *retval = NULL, **lli = &retval;
+
+# define SLEN(s) ((s) ? strlen(s) + 1 : 0)
+
+  for (; li0 ; li0 = li0->li_next) {
+    n = sizeof(*li0) + li0->li_addrlen + SLEN(li0->li_ifname);
+    if (!(li = calloc(1, n))) {
+      su_freelocalinfo(retval);
+      return NULL;
+    }
+    *lli = li;
+    lli = &li->li_next;
+    li->li_flags = li0->li_flags;
+    li->li_family = li0->li_family;
+    li->li_index = li0->li_index;
+    li->li_scope = li0->li_scope;
+    li->li_addrlen = li0->li_addrlen;
+    li->li_addr = memcpy(li + 1, li0->li_addr, li0->li_addrlen);
+
+    if (li0->li_canonname) {
+      if (!(li->li_canonname = malloc(SLEN(li0->li_canonname)))) {
+	su_freelocalinfo(retval);
+	return NULL;
+      }
+      strcpy(li->li_canonname, li0->li_canonname);
+    }
+
+    if (li0->li_ifname)
+      li->li_ifname = strcpy(li->li_addrlen + (char *)li->li_addr, 
+			     li0->li_ifname);
+  }
+
+  return retval;
+}
+
+
+/** Return IPv4 address scope */
+static int 
+li_scope4(uint32_t ip4)
+{
+  ip4 = ntohl(ip4);
+
+  if (0x7f000000 == (ip4 & 0xff000000))
+    return LI_SCOPE_HOST;
+  /* draft-ietf-zeroconf-ipv4-linklocal-02.txt - 169.254/16. */
+  else if (0xa9fe0000 == (ip4 & 0xffff0000))
+    return LI_SCOPE_LINK;
+  /* RFC1918 - 10/8, 172.16/12, 192.168/16. */
+  else if (0x0a000000 == (ip4 & 0xff000000) ||
+	   0xac100000 == (ip4 & 0xfff00000) ||
+	   0xc0a80000 == (ip4 & 0xffff0000))
+    return LI_SCOPE_SITE;
+  else
+    return LI_SCOPE_GLOBAL;
+}
+
+#if SU_HAVE_IN6
+
+#if HAVE_WINSOCK2_H
+#define IN6_IS_ADDR_LOOPBACK SU_IN6_IS_ADDR_LOOPBACK
+static inline int
+IN6_IS_ADDR_LOOPBACK(void const *ip6)
+{
+  uint8_t const *u = ip6;
+
+  return 
+    u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0 && 
+    u[4] == 0 && u[5] == 0 && u[6] == 0 && u[7] == 0 && 
+    u[8] == 0 && u[9] == 0 && u[10] == 0 && u[11] == 0 && 
+    u[12] == 0 && u[13] == 0 && u[14] == 0 && u[15] == 1;
+}
+#endif
+
+/** Return IPv6 address scope */
+static int 
+li_scope6(struct in6_addr const *ip6)
+{
+  if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
+    uint32_t ip4 = *(uint32_t *)(ip6->s6_addr + 12);
+    return li_scope4(ip4);
+  }
+  else if (IN6_IS_ADDR_LOOPBACK(ip6))
+    return LI_SCOPE_HOST;
+  else if (IN6_IS_ADDR_LINKLOCAL(ip6))
+    return LI_SCOPE_LINK;
+  else if (IN6_IS_ADDR_SITELOCAL(ip6))
+    return LI_SCOPE_SITE;
+  else
+    return LI_SCOPE_GLOBAL;
+}
+#endif
+
+/** Return the scope of address in the sockaddr structure */
+int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen)
+{
+  if (sulen >= (sizeof su->su_sin) && su->su_family == AF_INET)
+    return li_scope4(su->su_sin.sin_addr.s_addr);
+
+#if SU_HAVE_IN6
+  if (sulen >= (sizeof su->su_sin6) && su->su_family == AF_INET6)
+    return li_scope6(&su->su_sin6.sin6_addr);
+#endif
+
+  return 0;
+}
+
+#if USE_LOCALINFO0
+
+#elif HAVE_IFCONF
+/** Build a list of local IPv4 addresses and append it to *rresult. */
+static
+int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+  su_localinfo_t *tbf = NULL, **lli = &tbf;
+  su_localinfo_t *li = NULL, *li_first = NULL;
+  su_sockaddr_t *su;
+  int error = ELI_NOADDRESS;
+  char *canonname = NULL;
+  su_socket_t s;
+
+#if SU_HAVE_IN6
+  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;
+#else
+  int const su_xtra = 0;
+#endif
+
+  struct ifconf ifc;
+  int numifs;
+  char *buffer;
+  struct ifreq *ifr, *ifr_next;
+
+  s = su_socket(AF_INET, SOCK_DGRAM, 0);
+  if (s == -1) {
+    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n", 
+		su_strerror(su_errno())));
+    return ELI_SYSTEM;
+  }
+
+#if defined(__APPLE_CC__)
+  {
+    su_sockaddr_t *sa;
+    socklen_t salen = sizeof(*sa);
+    int scope = 0, gni_flags = 0;
+
+    li = calloc(1, sizeof(su_localinfo_t));
+    sa = calloc(1, sizeof(su_sockaddr_t));
+
+    error = getsockname(s, (struct sockaddr *) sa, &salen);
+    if (error < 0 && errno == SOCKET_ERROR) {
+      SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
+		  su_strerror(su_errno())));
+    }
+
+    error = bind(s, (struct sockaddr *) sa, salen);
+
+    if (error < 0) {
+      SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
+		  su_strerror(su_errno())));
+      goto err;
+    }
+
+    su_close(s);
+
+    scope = li_scope4(sa->su_sin.sin_addr.s_addr);
+
+    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+      gni_flags = NI_NUMERICHOST;
+    
+    if (su_xtra) {
+      /* Map IPv4 address to IPv6 address */
+      memset(sa, 0, sizeof(*sa));
+      sa->su_family = AF_INET6;
+      ((int32_t*)&sa->su_sin6.sin6_addr)[3] = sa->su_sin.sin_addr.s_addr;
+      ((int32_t*)&sa->su_sin6.sin6_addr)[2] = htonl(0xffff);
+    }
+
+    li->li_family = sa->su_family;
+    li->li_scope = scope;
+    li->li_index = 0;
+    li->li_addrlen = su_sockaddr_size(sa);
+    li->li_addr = sa;
+
+    if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
+      goto err;
+
+    if (canonname) {
+      if (strchr(canonname, ':') ||
+	  strspn(canonname, "0123456789.") == strlen(canonname))
+	    li->li_flags |= LI_NUMERIC;
+    }
+    else
+      li->li_flags = 0;
+
+    li->li_canonname = canonname;
+
+    canonname = NULL;
+
+    *rresult = li;
+    return 0;
+  }
+#endif
+
+
+# if HAVE_IFNUM
+  /* Get the list of known IP address from the kernel */
+  if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) {
+    /* can't get number of interfaces -- fall back */
+    SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n", 
+		su_strerror(su_errno())));
+    error = ELI_SYSTEM;
+    goto err;
+  }
+
+  SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n", 
+	      numifs));
+
+  if (numifs < 0)
+# endif
+    /* Default to 64 interfaces. Enough? */
+    numifs = 64;
+
+  if (numifs == 0)
+    return 0;
+
+  /*
+   * Allocate memory for SIOCGIFCONF ioctl buffer. This memory block is also
+   * used as li_first, first localinfo struct that is returned, so it can be
+   * freed by freelocalinfo() without any complications.
+   */
+  ifc.ifc_len = numifs * sizeof (struct ifreq);
+  buffer = malloc(sizeof(su_localinfo_t) + ifc.ifc_len + su_xtra);
+  if (!buffer) {
+    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
+    error = ELI_MEMORY;
+    goto err;
+  }
+
+  li_first = (su_localinfo_t *)buffer;
+  memset(li_first, 0, sizeof(su_localinfo_t) + su_xtra);
+  ifc.ifc_buf = buffer + sizeof(su_localinfo_t) + su_xtra;
+  if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+    SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n", 
+		su_strerror(su_errno())));
+    error = ELI_SYSTEM;
+    goto err;
+  }
+
+  buffer = ifc.ifc_buf + ifc.ifc_len;
+
+  for (ifr = ifc.ifc_req;
+       (void *)ifr < (void *)buffer;
+       ifr = ifr_next) {
+    struct ifreq ifreq[1];
+    int scope, if_index, flags = 0, gni_flags = 0;
+    char *if_name;
+    su_sockaddr_t su2[1];
+
+#if SA_LEN
+    if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
+      ifr_next = (struct ifreq *)
+	(ifr->ifr_addr.sa_len + (char *)(&ifr->ifr_addr));
+    else
+#else
+      ifr_next = ifr + 1;
+#endif
+
+    if_name = ifr->ifr_name;
+
+#if defined(SIOCGIFINDEX)
+    ifreq[0] = *ifr;
+    if (ioctl(s, SIOCGIFINDEX, ifreq) < 0) {
+      SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n", 
+		  su_strerror(su_errno())));
+      error = ELI_SYSTEM;
+      goto err;
+    }
+#if HAVE_IFR_INDEX
+    if_index = ifreq->ifr_index;
+#elif HAVE_IFR_IFINDEX
+    if_index = ifreq->ifr_ifindex;
+#else
+#error Unknown index field in struct ifreq
+#endif
+
+#else
+#warning su_localinfo() cannot map interface name to number
+    if_index = 0;
+#endif
+
+    SU_DEBUG_9(("su_localinfo: if %s with index %d\n", if_name, if_index));
+
+#if defined(SIOCGIFFLAGS)
+    ifreq[0] = *ifr;
+    if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) {
+      SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n", 
+		  su_strerror(su_errno())));
+      error = ELI_SYSTEM;
+      goto err;
+    }
+    /* Do not include interfaces that are down unless explicitly asked */
+    if ((ifreq->ifr_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0) {
+      SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n", 
+		  if_name, if_index));
+      continue;
+    }
+#else
+#error su_localinfo() cannot determine interface status
+#endif
+
+#if 0
+    *ifreq = *ifr;
+    ifreq->ifr_addr.sa_family = AF_INET;
+    if (ioctl(s, SIOCGIFADDR, ifreq) < 0) {
+      SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n", 
+		  su_strerror(su_errno())));
+      error = ELI_SYSTEM;
+      goto err;
+    }
+    ifr->ifr_addr = ifreq->ifr_addr;
+#endif
+
+    su = (su_sockaddr_t *)&ifr->ifr_addr;
+
+    if (SU_HAS_INADDR_ANY(su))
+      continue;
+
+    scope = li_scope4(su->su_sin.sin_addr.s_addr);
+
+    if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+	(hints->li_ifname && strcmp(hints->li_ifname, if_name) != 0) ||
+	(hints->li_index && hints->li_index != if_index))
+      continue;
+
+#if SU_HAVE_IN6
+    if (su_xtra) {
+      /* Map IPv4 address to IPv6 address */
+      memset(su2, 0, sizeof(*su2));
+      su2->su_family = AF_INET6;
+      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+      su = su2;
+    }
+#endif
+
+    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+      gni_flags = NI_NUMERICHOST;
+
+    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+      goto err;
+    else if (error > 0)
+      continue;
+    
+    if (canonname)
+      if (strchr(canonname, ':') ||
+	  strspn(canonname, "0123456789.") == strlen(canonname))
+	flags |= LI_NUMERIC;
+
+    if (li_first)
+      li = li_first;      /* Use li_first with all ifr structs to be freed */
+    else if (!(li = calloc(1, (sizeof *li) + su_xtra))) {
+      error = ELI_MEMORY;
+      goto err;
+    }
+    if (!tbf) tbf = li;
+    *lli = li; lli = &li->li_next;
+
+    if (su_xtra)
+      su = (su_sockaddr_t *)memcpy(li + 1, su, su_xtra);
+
+    li->li_flags = flags;
+    li->li_family = su->su_family;
+    li->li_scope = scope;
+    li->li_index = if_index;
+    li->li_addrlen = su_sockaddr_size(su);
+    li->li_addr = su;
+    li->li_canonname = canonname;
+    if (hints->li_flags & LI_IFNAME)
+      li->li_ifname = if_name;
+
+    canonname = NULL;
+    li_first = NULL;
+  }
+
+  if (canonname) free(canonname);
+  if (li_first) free(li_first);
+  su_close(s);
+
+  if (tbf) *rresult = tbf;
+  return 0;
+
+err:
+  if (canonname) free(canonname);
+  if (li_first) free(li_first);
+  su_freelocalinfo(tbf);
+  su_close(s);
+
+  return error;
+}
+#else
+static
+int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+  /* Kikka #3: resolve hostname */
+  char hostname[SU_MAXHOST] = "";
+  char *name, *ifname;
+  struct hostent *h;
+  int i, flags, error, gni_flags = 0;
+  su_localinfo_t *tbf = NULL;
+  su_localinfo_t *li = NULL, **lli = &tbf;
+  su_sockaddr_t *su;
+#if SU_HAVE_IN6
+  socklen_t su_sockaddr_size = 
+    (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : sizeof(struct sockaddr_in);
+  flags = hints->li_flags & (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+#else
+  socklen_t su_sockaddr_size = sizeof(struct sockaddr_in);
+  flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+#endif
+
+  error = ELI_NOERROR;
+
+  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+    if (hints->li_canonname)
+      name = hints->li_canonname;
+    else if (gethostname(name = hostname, sizeof(hostname)) != 0)
+      return ELI_SYSTEM;
+  
+    h = gethostbyname(name);
+
+    if (name)
+      if (strchr(name, ':') ||
+	  strspn(name, "0123456789.") == strlen(name))
+	flags |= LI_NUMERIC;
+
+    for (i = 0; h && h->h_addr_list[i]; i++) {
+      if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+	error = ELI_MEMORY;
+	goto err;
+      }
+      li->li_flags = flags;
+
+      li->li_scope = li_scope4(*(uint32_t *)h->h_addr_list[i]);
+      if (li->li_scope == LI_SCOPE_HOST)
+	li->li_index = 1, ifname = "lo";
+      else
+	li->li_index = 2, ifname = "eth";
+
+      li->li_addrlen = su_sockaddr_size;
+      li->li_addr = su = (su_sockaddr_t *)(li + 1);
+      su->su_family = li->li_family = 
+	li->li_flags & LI_V4MAPPED ? AF_INET6 : AF_INET;
+
+#if SU_HAVE_IN6
+      if (li->li_flags & LI_V4MAPPED) {
+	((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
+	memcpy(&((int32_t*)&su->su_sin6.sin6_addr)[3],
+	       h->h_addr_list[i], h->h_length);
+      }
+      else 
+#endif
+	memcpy(&su->su_sin.sin_addr.s_addr, h->h_addr_list[i], h->h_length);
+      if (li->li_flags & LI_IFNAME) 
+	li->li_ifname = ifname;
+      if (li->li_scope == LI_SCOPE_HOST || li->li_scope == LI_SCOPE_LINK)
+	gni_flags = NI_NUMERICHOST;
+      if ((error = li_name(hints, gni_flags, su, &li->li_canonname)) < 0)
+	goto err;
+      else if (error > 0) {
+	free(li); li = NULL; continue;
+      } else
+	error = ELI_NOADDRESS;
+      *lli = li; lli = &li->li_next; li = NULL;
+    }
+  }
+
+  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_HOST)) {
+    if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+      error = ELI_MEMORY;
+      goto err;
+    }
+    li->li_flags = hints->li_flags & 
+      (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+    li->li_scope = LI_SCOPE_HOST, li->li_index = 1;
+    if (li->li_flags & LI_IFNAME)
+      li->li_ifname = "lo";
+    li->li_addrlen = su_sockaddr_size;
+    li->li_addr = su = (su_sockaddr_t *)(li + 1);
+#if SU_HAVE_IN6
+    if (li->li_flags & LI_V4MAPPED) {
+      su->su_family = li->li_family = AF_INET6;
+      ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
+      ((int32_t*)&su->su_sin6.sin6_addr)[3] = htonl(0x7f000001);
+    }
+    else 
+#endif
+      su->su_family = li->li_family = AF_INET,
+      su->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+
+    if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0) {
+      goto err;
+    } else if (error > 0) {
+      free(li); li = NULL; 
+    } else {
+      *lli = li; lli = &li->li_next; li = NULL;
+    }
+  }
+
+  *rresult = tbf;
+
+  return 0;
+
+err:
+  if (li) su_freelocalinfo(li);
+  su_freelocalinfo(tbf);
+
+  return error;
+}
+
+#endif
+
+#if USE_LOCALINFO0 || !SU_HAVE_IN6
+
+#elif HAVE_PROC_NET_IF_INET6 
+/** Build a list of local IPv6 addresses and append it to *return_result. */
+static
+int localinfo6(su_localinfo_t const *hints, su_localinfo_t **return_result)
+{
+  su_localinfo_t *li = NULL;
+  su_sockaddr_t su[1] = {{ 0 }}, *addr;
+  int error = ELI_NOADDRESS;
+  char *canonname = NULL;
+  char line[80];
+  FILE *f;
+
+  if ((f = fopen("/proc/net/if_inet6", "r"))) {
+    for (;error;) {
+      struct in6_addr in6;
+      unsigned if_index, prefix_len, scope, flags;
+      int addrlen, if_namelen;
+      char ifname[16];
+
+      if (!fgets(line, sizeof(line), f)) {
+	if (feof(f))
+	  error = ELI_NOERROR;
+	break;
+      }
+
+      if (sscanf(line, "%08x%08x%08x%08x %2x %2x %2x %02x %016s\n",
+		 &in6.s6_addr32[0],
+		 &in6.s6_addr32[1],
+		 &in6.s6_addr32[2],
+		 &in6.s6_addr32[3], 
+		 &if_index, &prefix_len, &scope, &flags, ifname) != 9)
+	break;
+
+      flags = 0;
+
+      /* Fix global scope (it is 0) */
+      if (!scope) scope = LI_SCOPE_GLOBAL;
+
+      in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
+      in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
+      in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
+      in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
+
+      if (IN6_IS_ADDR_V4MAPPED(&in6) || IN6_IS_ADDR_V4COMPAT(&in6)) {
+	uint32_t ip4 = *(uint32_t *)(in6.s6_addr + 12);
+	scope = li_scope4(ip4);
+      }
+
+      if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+	  (hints->li_index && hints->li_index != if_index) ||
+	  (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0))
+	continue;
+      
+      su->su_family = AF_INET6;
+      su->su_sin6.sin6_addr = in6; 
+      
+      addrlen = su_sockaddr_size(su);
+
+      if ((error = li_name(hints, 0, su, &canonname)) < 0)
+	break;
+      else if (error > 0)
+	continue;
+      else
+	error = ELI_NOADDRESS;
+
+      if (canonname && 
+	  (strchr(canonname, ':') ||
+	   strspn(canonname, "0123456789.") == strlen(canonname)))
+	flags |= LI_NUMERIC;
+
+      if (hints->li_flags & LI_IFNAME)
+	if_namelen = strlen(ifname) + 1;
+      else
+	if_namelen = 0;
+
+      if ((li = calloc(1, sizeof *li + addrlen + if_namelen)) == NULL) {
+	error = ELI_MEMORY;
+	break;
+      }
+      addr = (su_sockaddr_t*)memcpy((li + 1), su, addrlen);
+      *return_result = li; return_result = &li->li_next;
+
+      li->li_flags = flags;
+      li->li_family = AF_INET6;
+      li->li_scope = scope;
+      li->li_index = if_index;
+      li->li_addr = addr;
+      li->li_addrlen = addrlen;
+      li->li_canonname = canonname;
+      if (if_namelen)
+	li->li_ifname = memcpy(addrlen + (char *)addr, ifname, if_namelen);
+      
+      canonname = NULL;
+    }
+
+    fclose(f);
+  }
+
+  if (canonname) 
+    free(canonname);
+
+  return error;
+}
+#else
+/* Use HOSTADDR6 */
+static
+int localinfo6(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+  char *addr, *ifname;
+  int flags, error;
+  su_localinfo_t *li = NULL;
+  su_sockaddr_t *su;
+  int const su_sockaddr_size = sizeof(*su);
+  
+  error = ELI_NOADDRESS;
+
+#if defined(__APPLE_CC__)
+  {
+    su_sockaddr_t *sa;
+    int salen = sizeof(*sa);
+    int s;
+
+    if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+      if ((addr = getenv("HOSTADDR6"))) {
+
+	li = calloc(1, sizeof(su_localinfo_t));
+	sa = calloc(1, sizeof(su_sockaddr_t));
+
+	sa->su_family = AF_INET6;
+	if (inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0)
+	  goto err;
+	
+	s = su_socket(AF_INET6, SOCK_DGRAM, 0);
+	if (s == -1) {
+	  SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n", 
+		      su_strerror(su_errno())));
+	  return ELI_SYSTEM;
+	}
+	
+	error = getsockname(s, (struct sockaddr *) sa, &salen);
+	if (error < 0 && errno == SOCKET_ERROR) {
+	  SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
+		      su_strerror(su_errno())));
+	}
+	
+	error = bind(s, (struct sockaddr *) sa, salen);
+	
+	if (error < 0) {
+	  SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
+		      su_strerror(su_errno())));
+	  goto err;
+	}
+	
+	su_close(s);
+	
+	li->li_family = sa->su_family;
+	li->li_scope = LI_SCOPE_GLOBAL;
+	li->li_index = 0;
+	li->li_addrlen = su_sockaddr_size(sa);
+	li->li_addr = sa;
+	
+	if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0)
+	  goto err;
+	
+	li->li_flags = NI_NUMERICHOST;
+      }
+    }
+
+    *rresult = li;
+    return 0;
+  }
+#endif
+
+
+  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+    if ((addr = getenv("HOSTADDR6"))) {
+      flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+
+      if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+	error = ELI_MEMORY;
+	goto err;
+      }
+      li->li_flags = flags;
+      li->li_scope = LI_SCOPE_GLOBAL, li->li_index = 2, ifname = "eth";
+      li->li_addrlen = sizeof(*su);
+      li->li_addr = su = (su_sockaddr_t *)(li + 1);
+      su->su_family = li->li_family = AF_INET6;
+      if (inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
+	goto err;
+      if (li->li_flags & LI_IFNAME) 
+	li->li_ifname = ifname;
+      if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0)
+	goto err;
+      else if (error > 0) {
+	free(li); li = NULL; 
+      }
+    }
+  }
+
+  *rresult = li;
+
+  return 0;
+
+err:
+  if (li) su_freelocalinfo(li);
+  return error;
+}
+#endif
+
+
+#if HAVE_GETIFADDRS
+
+#include <ifaddrs.h>
+
+static
+int bsd_localinfo(su_localinfo_t const hints[1], 
+		  su_localinfo_t **return_result)
+{
+  struct ifaddrs *ifa, *results;
+  int error = 0;
+  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+  char *canonname = NULL;
+
+  if (getifaddrs(&results) < 0) {
+    if (errno == ENOMEM)
+      return ELI_MEMORY;
+    else
+      return ELI_SYSTEM;
+  }
+
+  for (ifa = results; ifa; ifa = ifa->ifa_next) {
+    su_localinfo_t *li;
+    su_sockaddr_t *su, su2[1];
+    socklen_t sulen;
+    int scope, flags = 0, gni_flags = 0, if_index = 0;
+    char const *ifname = 0;
+    size_t ifnamelen = 0;
+
+    /* no ip address from if that is down */
+    if ((ifa->ifa_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0)
+      continue;
+
+    su = (su_sockaddr_t *)ifa->ifa_addr;
+
+    if (!su)
+      continue;
+
+    if (su->su_family == AF_INET) {
+      sulen = sizeof(su->su_sin);
+      scope = li_scope4(su->su_sin.sin_addr.s_addr);
+      if (v4_mapped)
+	sulen = sizeof(su->su_sin6);
+    }
+    else if (su->su_family == AF_INET6) {
+      if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
+	continue;
+      sulen = sizeof(su->su_sin6);
+      scope = li_scope6(&su->su_sin6.sin6_addr);
+    }
+    else 
+      continue;
+
+    if (hints->li_flags & LI_IFNAME) {
+      ifname = ifa->ifa_name;
+      if (ifname)
+	ifnamelen = strlen(ifname) + 1;
+    }
+
+    if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+	(hints->li_family && hints->li_family != su->su_family) ||
+	(hints->li_ifname && (!ifname || strcmp(hints->li_ifname, ifname))) ||
+	(hints->li_index && hints->li_index != if_index))
+      continue;
+    
+    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+      gni_flags = NI_NUMERICHOST;
+
+    if (v4_mapped && su->su_family == AF_INET) {
+      /* Map IPv4 address to IPv6 address */
+      memset(su2, 0, sizeof(*su2));
+      su2->su_family = AF_INET6;
+      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+      su = su2;
+    }
+
+    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+      break;
+
+    if (error > 0) {
+      error = 0;
+      continue;
+    }
+    
+    if (canonname)
+      if (strchr(canonname, ':') ||
+	  canonname[strspn(canonname, "0123456789.")] == '\0')
+	flags |= LI_NUMERIC;
+
+    if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
+      SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+      error = ELI_MEMORY;
+      break;
+    } 
+    *return_result = li, return_result = &li->li_next;
+
+    li->li_flags = flags;
+    li->li_family = su->su_family;
+    li->li_scope = scope;
+    li->li_index = if_index;
+    li->li_addrlen = sulen;
+    li->li_addr = memcpy(li + 1, su, sulen);
+    li->li_canonname = canonname;
+    if (ifnamelen) {
+      li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
+    }
+
+    canonname = NULL;
+  }
+
+  if (canonname)
+    free(canonname);
+
+  freeifaddrs(results);
+
+  return error;
+}
+
+#elif USE_LOCALINFO0 && HAVE_IPHLPAPI_H && SU_HAVE_IN6
+
+static 
+char const *ws2ifname(DWORD iftype)
+{
+  switch (iftype) {
+  case IF_TYPE_ETHERNET_CSMACD:         return "eth";
+  case IF_TYPE_IEEE80212:               return "eth";
+  case IF_TYPE_FASTETHER:               return "eth";
+  case IF_TYPE_GIGABITETHERNET:         return "eth";
+  case IF_TYPE_ISO88025_TOKENRING:      return "token";
+  case IF_TYPE_FDDI:                    return "fddi";
+  case IF_TYPE_PPP:                     return "ppp";
+  case IF_TYPE_SOFTWARE_LOOPBACK:       return "lo";
+  case IF_TYPE_SLIP:                    return "sl";
+  case IF_TYPE_FRAMERELAY:              return "fr";
+  case IF_TYPE_ATM:                     return "atm";
+  case IF_TYPE_HIPPI:                   return "hippi";
+  case IF_TYPE_ISDN:                    return "isdn";
+  case IF_TYPE_IEEE80211:               return "wlan";
+  case IF_TYPE_ADSL:                    return "adsl";
+  case IF_TYPE_RADSL:                   return "radsl";
+  case IF_TYPE_SDSL:                    return "sdsl";
+  case IF_TYPE_VDSL:                    return "vdsl";
+  case IF_TYPE_TUNNEL:                  return "tunnel";
+  case IF_TYPE_IEEE1394:                return "fw";
+  case IF_TYPE_OTHER:
+  default:                              return "other";
+  }
+}
+
+static
+int win_localinfo(su_localinfo_t const hints[1], su_localinfo_t **rresult)
+{
+  /* This is Windows XP code, for both IPv6 and IPv4. */
+  size_t iaa_size = 2048;
+  IP_ADAPTER_ADDRESSES *iaa0, *iaa;
+  int error, loopback_seen = 0;
+  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+  char *canonname = NULL;
+  su_localinfo_t *li, **next;
+  int flags = GAA_FLAG_SKIP_MULTICAST;
+  *rresult = NULL; next = rresult;
+
+  iaa0 = malloc(iaa_size);
+  if (!iaa0) {
+    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
+    error = ELI_MEMORY;
+    goto err;
+  }
+  error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
+  if (error == ERROR_BUFFER_OVERFLOW) {
+    if ((iaa0 = realloc(iaa0, iaa_size)))
+      error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
+  }
+  if (error) {
+    SU_DEBUG_1(("su_localinfo: GetAdaptersAddresses failed: %d\n", error));
+    error = ELI_SYSTEM;
+    goto err;
+  }
+  
+  for (iaa = iaa0; iaa; iaa = iaa->Next) {
+    IP_ADAPTER_UNICAST_ADDRESS *ua;
+    IP_ADAPTER_UNICAST_ADDRESS lua[1];
+    int if_index = iaa->IfIndex;
+    int ifnamelen = 0;
+    char ifname[16];
+
+    for (ua = iaa->FirstUnicastAddress; ;ua = ua->Next) {
+      su_sockaddr_t *su;
+      socklen_t sulen;
+      su_sockaddr_t su2[1];
+      int scope, flags = 0, gni_flags = 0;
+
+      if (ua == NULL) {
+	/* There is no loopback interface in windows */
+	if (!loopback_seen && iaa->Next == NULL) {
+	  struct sockaddr_in loopback_sin = { AF_INET, 0, {{ 127, 0, 0, 1 }}};
+
+	  lua->Address.lpSockaddr = (struct sockaddr *)&loopback_sin;
+	  lua->Address.iSockaddrLength = sizeof(loopback_sin);
+	  lua->Next = NULL;
+
+	  iaa->IfType = IF_TYPE_SOFTWARE_LOOPBACK;
+	  if_index = 1;
+
+	  ua = lua;
+	}
+	else
+	  break;
+      }
+
+      su = (su_sockaddr_t *)ua->Address.lpSockaddr;
+      sulen = ua->Address.iSockaddrLength;
+
+      if (su->su_family == AF_INET) {
+	scope = li_scope4(su->su_sin.sin_addr.s_addr);
+	if (v4_mapped)
+	  sulen = sizeof(su->su_sin6);
+	if (scope == LI_SCOPE_HOST)
+	  loopback_seen = 1;
+      }
+      else if (su->su_family == AF_INET6) {
+	if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
+	  continue;
+	scope = li_scope6(&su->su_sin6.sin6_addr);
+      }
+      else 
+	continue;
+
+      if (hints->li_flags & LI_IFNAME) {
+	snprintf(ifname, sizeof(ifname), "%s%u", 
+		 ws2ifname(iaa->IfType), if_index);
+	ifnamelen = strlen(ifname) + 1;
+      }
+
+      if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+	  (hints->li_family && hints->li_family != su->su_family) ||
+	  /* (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0) || */
+	  (hints->li_index && hints->li_index != if_index))
+	continue;
+    
+      if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+	gni_flags = NI_NUMERICHOST;
+
+      if (v4_mapped && su->su_family == AF_INET) {
+	/* Map IPv4 address to IPv6 address */
+	memset(su2, 0, sizeof(*su2));
+	su2->su_family = AF_INET6;
+	((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+	((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+	su = su2;
+      }
+
+      if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+	goto err;
+      else if (error > 0)
+	continue;
+    
+      if (canonname)
+	if (strchr(canonname, ':') ||
+	    strspn(canonname, "0123456789.") == strlen(canonname))
+	  flags |= LI_NUMERIC;
+
+      if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
+	SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+	error = ELI_MEMORY; goto err;
+      } 
+      *next = li, next = &li->li_next;
+
+      li->li_flags = flags;
+      li->li_family = su->su_family;
+      li->li_scope = scope;
+      li->li_index = if_index;
+      li->li_addrlen = sulen;
+      li->li_addr = memcpy(li + 1, su, sulen);
+      li->li_canonname = canonname;
+      if (ifnamelen) {
+	li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
+	/* WideCharToMultiByte(CP_ACP, 0,
+			    ifname, -1, (char *)(li + 1) + sulen, ifnamelen,
+			    NULL, NULL); */
+      }
+
+      canonname = NULL;
+    }
+  }
+
+  if (iaa0) free(iaa0);
+  return 0;
+
+err:
+  if (iaa0) free(iaa0);
+  if (canonname) free(canonname);
+  su_freelocalinfo(*rresult), *rresult = NULL;
+  return error;
+}
+
+#elif HAVE_SIO_ADDRESS_LIST_QUERY
+static
+int localinfo0(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+  /* This is Windows IPv4 code */
+  short family = AF_INET;
+  su_socket_t s;
+  union {
+    SOCKET_ADDRESS_LIST sal[1];
+#if HAVE_INTERFACE_INFO_EX
+    INTERFACE_INFO_EX   ii[1];    
+#else
+    INTERFACE_INFO      ii[1];
+#endif
+    char buffer[2048];
+  } b = {{ 1 }};
+  DWORD salen = sizeof(b);
+  int i, error = -1;
+#if SU_HAVE_IN6
+  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+#endif
+  su_localinfo_t *li, *head = NULL, **next = &head;
+  char *canonname = NULL, *if_name = NULL;
+
+  *rresult = NULL;
+
+  s = su_socket(family, SOCK_DGRAM, 0);
+  if (s == INVALID_SOCKET) {
+    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "su_socket",
+		            su_strerror(su_errno())));
+    return -1;
+  }
+
+  /* get the list of known IP address (NT5 and up) */
+  if (WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0,
+               &b, sizeof(b), &salen, NULL, NULL) == SOCKET_ERROR) {
+    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "SIO_ADDRESS_LIST_QUERY",
+		su_strerror(su_errno())));
+    error = -1; goto err;
+  }
+  if (b.sal->iAddressCount < 1) {
+    SU_DEBUG_1(("su_getlocalinfo: no local addresses\n"));
+    error = -1; goto err;
+  }
+  
+  for (i = 0; i < b.sal->iAddressCount; i++) {
+    su_sockaddr_t *su = (su_sockaddr_t *)b.sal->Address[i].lpSockaddr;
+#if SU_HAVE_IN6
+    socklen_t sulen = v4_mapped ? sizeof(*su) : b.sal->Address[i].iSockaddrLength;
+    su_sockaddr_t su2[1];
+#else
+    socklen_t sulen = b.sal->Address[i].iSockaddrLength;
+#endif
+    int scope, flags = 0, gni_flags = 0;
+
+    scope = li_scope4(su->su_sin.sin_addr.s_addr);
+
+    if (hints->li_scope && (hints->li_scope & scope) == 0)
+      continue;
+    
+    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+      gni_flags = NI_NUMERICHOST;
+
+    if (!(li = calloc(1, sizeof(*li) + sulen))) {
+      SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+      error = -1; goto err;
+    }
+    *next = li, next = &li->li_next;
+
+#if SU_HAVE_IN6
+    if (v4_mapped) {
+      /* Map IPv4 address to IPv6 address */
+      memset(su2, 0, sizeof(*su2));
+      su2->su_family = AF_INET6;
+      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+      su = su2;
+    }
+#endif
+
+    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+      goto err;
+    else if (error > 0)
+      continue;
+    
+    if (canonname)
+      if (strchr(canonname, ':') ||
+	  strspn(canonname, "0123456789.") == strlen(canonname))
+	flags |= LI_NUMERIC;
+   
+    li->li_flags = flags;
+    li->li_family = su->su_family;
+    li->li_scope = scope;
+    li->li_index = i;
+    li->li_addrlen = su_sockaddr_size(su);
+    li->li_addr = su;
+    li->li_canonname = canonname, canonname = NULL;
+    if (hints->li_flags & LI_IFNAME)
+      li->li_ifname = if_name;
+    li->li_addr = (su_sockaddr_t *)(li + 1); 
+    li->li_addrlen = sulen;
+    memcpy(li->li_addr, su, sulen);
+  }
+
+  *rresult = head;
+  su_close(s);
+
+  return 0;
+
+err:
+  if (canonname) free(canonname);
+  su_freelocalinfo(head);
+  su_close(s);
+
+  return error;
+}
+#endif
+
+static 
+int li_name(su_localinfo_t const *hints, 
+	    int gni_flags,
+	    su_sockaddr_t const *su, 
+	    char **ccanonname)
+{
+  char name[SU_MAXHOST];
+  int error;
+  int flags = hints->li_flags;
+
+  *ccanonname = NULL;
+
+  if ((flags & LI_CANONNAME) || hints->li_canonname) {
+    if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
+      gni_flags |= NI_NAMEREQD;      
+    if (flags & LI_NUMERIC)
+      gni_flags |= NI_NUMERICHOST;
+
+    error = su_getnameinfo(su, su_sockaddr_size(su), 
+			   name, sizeof(name), NULL, 0,
+			   gni_flags);
+    if (error) {
+      if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
+	return 1;
+      SU_DEBUG_7(("li_name: getnameinfo() failed\n"));
+      if (!inet_ntop(su->su_family, SU_ADDR(su), name, sizeof name))
+	return ELI_RESOLVER;
+    }
+
+    if (hints->li_canonname && strcasecmp(name, hints->li_canonname))
+      return 1;
+
+    if (!(flags & LI_CANONNAME))
+      return 0;
+
+    if (!(*ccanonname = strdup(name)))
+      return ELI_MEMORY;
+  }
+  return 0;
+}
+
+static
+void li_sort(su_localinfo_t *i, su_localinfo_t **rresult)
+{
+  su_localinfo_t *li, **lli;
+
+#define LI_MAPPED(li) \
+  ((li)->li_family == AF_INET6 &&					\
+   (IN6_IS_ADDR_V4MAPPED(&(li)->li_addr->su_sin6.sin6_addr) ||		\
+    IN6_IS_ADDR_V4COMPAT(&(li)->li_addr->su_sin6.sin6_addr)))
+
+  /* Sort addresses according to scope (and mappedness) */
+  for (li = i; li; li = i) {
+    i = li->li_next;
+    for (lli = rresult; *lli; lli = &(*lli)->li_next) {
+      if ((*lli)->li_scope < li->li_scope)
+	break;
+#if SU_HAVE_IN6
+      if (LI_MAPPED(*lli) > LI_MAPPED(li))
+	break;
+#endif
+    }
+    li->li_next = *lli;
+    *lli = li;
+  }
+}
+
+/**Get local IP address.
+ *
+ * @deprecated
+ * Use su_getlocalinfo() instead.
+ */
+int su_getlocalip(su_sockaddr_t *sa)
+{
+  su_localinfo_t *li = NULL, hints[1] = {{ 0 }};
+
+  hints->li_family = sa->su_sa.sa_family ? sa->su_sa.sa_family : AF_INET;
+
+  if (su_getlocalinfo(hints, &li) == 0) {
+    memcpy(sa, li->li_addr, li->li_addrlen);
+    su_freelocalinfo(li);
+    return 0;
+  }
+  else 
+    return -1;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_log.c
+ *
+ * Implementation of generic logging interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri Feb 23 17:30:13 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_errno.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#define SU_LOG_IS_INIT(log) pthread_mutex_trylock((log)->log_init)
+#define SU_LOG_DO_INIT(log)
+#define SU_LOG_LOCK(log)    pthread_mutex_lock((log)->log_lock)
+#define SU_LOG_UNLOCK(log)  pthread_mutex_unlock((log)->log_lock)
+#else
+#define SU_LOG_IS_INIT(log) ((log)->log_init)
+#define SU_LOG_DO_INIT(log) ((log)->log_init = 1)
+#define SU_LOG_LOCK(log) 
+#define SU_LOG_UNLOCK(log)
+#endif
+
+/**@defgroup su_log Logging Interface
+ *
+ * Generic logging interface.
+ *
+ * The @b su_log submodule contains a generic logging interface. The
+ * interface provides means for redirecting the log and filtering log
+ * messages based on message priority.
+ *
+ * @sa @ref debug_logs, <sofia-sip/su_log.h>, 
+ * su_llog(), su_vllog(), #su_log_t, #SU_LOG,
+ * SU_DEBUG_0(), SU_DEBUG_1(), SU_DEBUG_2(), SU_DEBUG_3(), SU_DEBUG_5(), 
+ * SU_DEBUG_7(), SU_DEBUG_9()
+ */
+
+/** Log message of socket error @errcode at level 0. */
+void su_perror2(const char *s, int errcode)
+{
+  su_log("%s: %s\n", s, su_strerror(errcode));
+}
+
+/** Log socket error message at level 0. */
+void su_perror(const char *s)
+{
+  su_perror2(s, su_errno());
+}
+
+/** Log a message to default log. 
+ *
+ * This function is a replacement for printf().
+ *
+ * Messages are always logged to the default log.
+ */
+void su_log(char const *fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  su_vllog(su_log_default, 0, fmt, ap);
+  va_end(ap);
+}
+
+/** Log a message with level. 
+ *
+ * @note This function is used mainly by SU_DEBUG_n() macros.
+ */
+void su_llog(su_log_t *log, unsigned level, char const *fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  su_vllog(log, level, fmt, ap);
+  va_end(ap);
+}
+
+/** Log a message with level (stdarg version). */
+void su_vllog(su_log_t *log, unsigned level, char const *fmt, va_list ap)
+{
+  su_logger_f *logger;
+  void *stream;
+
+  assert(log);
+
+  if (!log->log_init)
+    su_log_init(log);
+
+  if (log->log_init > 1 ? 
+      level > log->log_level :
+      level > su_log_default->log_level)
+    return;
+
+  logger = log->log_logger;
+  stream = log->log_stream;
+
+  if (!logger) {
+    logger = su_log_default->log_logger;
+    stream = su_log_default->log_stream;
+  }
+
+  if (logger)
+    logger(stream, fmt, ap);
+}
+
+static char const not_initialized[1];
+static char const *explicitly_initialized = not_initialized;
+
+/** Initialize a log */
+void su_log_init(su_log_t *log)
+{
+  char *env;
+
+  if (log->log_init)
+    return;
+
+  if (explicitly_initialized == not_initialized)
+    explicitly_initialized = getenv("SHOW_DEBUG_LEVELS");
+
+  if (log != su_log_default && !su_log_default->log_init)
+    su_log_init(su_log_default);
+
+  if (log->log_env && (env = getenv(log->log_env))) {
+    int level = atoi(env);
+    
+    /* Why? */
+    /* if (level == 0) level = 1; */
+    log->log_level = level;
+    log->log_init = 2;
+
+    if (explicitly_initialized) 
+      su_llog(log, 0, "%s: initialized log to level %u (%s=%s)\n", 
+	      log->log_name, log->log_level, log->log_env, env);
+  }
+  else {
+    log->log_level = log->log_default;
+    log->log_init = 1;
+    if (explicitly_initialized) {
+      if (log != su_log_default)
+	su_llog(log, 0, "%s: logging at default level %u\n", 
+		log->log_name, su_log_default->log_level);
+      else
+	su_llog(log, 0, "%s: initialized log to level %u (default)\n", 
+		log->log_name, log->log_level);
+    }
+  }
+}
+
+/**Redirect a log.
+ *
+ * The function su_log_redirect() redirects the su_log() output to
+ * @a logger function. The @a logger function has following prototype:
+ *
+ * @code
+ * void logger(void *logarg, char const *format, va_list ap);
+ * @endcode
+ * 
+ * If @a logger is NULL, the default logger will be used. If @a log is NULL,
+ * the default logger is changed.
+ */
+void su_log_redirect(su_log_t *log, su_logger_f *logger, void *logarg)
+{
+  if (log == NULL)
+    log = su_log_default;
+  /* XXX - locking ? */
+  log->log_logger = logger;
+  log->log_stream = logarg;
+}
+
+/** Set log level.
+ *
+ * The function su_log_set_level() sets the logging level.  The log events
+ * have certain level (0..9); if logging level is lower than the level of
+ * the event, the log message is ignored.
+ * 
+ * If @a log is NULL, the default log level is changed.
+ */
+void su_log_set_level(su_log_t *log, unsigned level)
+{
+  if (log == NULL)
+    log = su_log_default;
+
+  log->log_level = level;
+  log->log_init = 2;
+
+  if (explicitly_initialized == not_initialized)
+    explicitly_initialized = getenv("SHOW_DEBUG_LEVELS");
+
+  if (explicitly_initialized)
+    su_llog(log, 0, "%s: set log to level %u\n", 
+	    log->log_name, log->log_level);
+}
+
+/** Set log level.
+ *
+ * The function su_log_soft_set_level() sets the logging level if it is not
+ * already set, or the environment variable controlling the log level is not
+ * set. 
+ *
+ * The log events have certain level (0..9); if logging level is lower than
+ * the level of the event, the log message is ignored.
+ * 
+ * If @a log is NULL, the default log level is changed.
+ */
+void su_log_soft_set_level(su_log_t *log, unsigned level)
+{
+  if (log == NULL)
+    log = su_log_default;
+  if (log->log_init > 1)
+    return;
+  if (log->log_env && getenv(log->log_env)) {
+    su_log_init(log);
+  } else {
+    log->log_level = level;
+    log->log_init = 2;
+    if (explicitly_initialized)
+      su_llog(log, 0, "%s: soft set log to level %u\n", 
+	      log->log_name, log->log_level);
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,491 @@
+#define compile \
+{ gcc -o su_md5 -O2 -g -Wall -DTEST -I. su_md5.c } ; exit 0
+/* -*- c-style: java -*- */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm. The algorithm is
+ * due to Ron Rivest. This code was initially 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.
+ */
+
+/** @ingroup su_md5
+ * 
+ * @CFILE su_md5.c MD5 Implementation
+ *
+ * To compute the message digest of a chunk of bytes, declare an su_md5_t
+ * context structure, pass it to su_md5_init(), call su_md5_update() as
+ * needed on buffers full of bytes, and then call su_md5_digest(), which
+ * will fill a supplied 16-byte array with the current digest.
+ *
+ * @note
+ * This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+ * not require an integer type which is exactly 32 bits.  This work
+ * draws on the changes for the same purpose by Tatu Ylonen
+ * <ylo at cs.hut.fi> as part of SSH, but since I didn't actually use
+ * that code, there is no copyright issue.  I hereby disclaim
+ * copyright in any changes I have made; this code remains in the
+ * public domain.
+ *
+ * @note Regarding su_* namespace: this avoids potential conflicts
+ * with libraries such as some versions of Kerberos.  No particular
+ * need to worry about whether the system supplies an MD5 library, as
+ * this file is only about 3k of object code. 
+ *
+ */
+
+#include <string.h>	/* for memcpy() and memset() */
+
+#include "sofia-sip/su_md5.h"
+
+static void su_md5_transform(uint32_t buf[4], const unsigned char inraw[64]);
+
+/* Little-endian byte-swapping routines.  Note that these do not depend on
+   the size of datatypes such as cvs_uint32, nor do they require us to
+   detect the endianness of the machine we are running on.  It is possible
+   they should be macros for speed, but I would be surprised if they were a
+   performance bottleneck for MD5. These are inlined by any sane compiler,
+   anyways. */
+
+static uint32_t getu32(const unsigned char *addr)
+{
+  return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+	  | addr[1]) << 8 | addr[0];
+}
+
+static void putu32(uint32_t data, unsigned char *addr)
+{
+  addr[0] = (unsigned char)data;
+  addr[1] = (unsigned char)(data >> 8);
+  addr[2] = (unsigned char)(data >> 16);
+  addr[3] = (unsigned char)(data >> 24);
+}
+
+/** Initialize MD5 context.
+ *
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ * 
+ * @param ctx Pointer to context structure.
+ */
+void
+su_md5_init(su_md5_t *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;
+}
+
+/** Clear MD5 context.
+ *
+ * The function su_md5_deinit() clears MD5 context.
+ * 
+ * @param context  Pointer to MD5 context structure.
+ */
+void su_md5_deinit(su_md5_t *context)
+{
+  memset(context, 0, sizeof *context);
+}
+
+/** Update MD5 context.
+ *
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ *
+ * @param ctx Pointer to context structure
+ * @param b   Pointer to data
+ * @param len Length of @a b as bytes
+ */
+void
+su_md5_update(su_md5_t *ctx,
+	      void const *b,
+	      usize_t len)
+{
+  unsigned char const *buf = (unsigned char const *)b;
+  uint32_t t;
+
+  /* Update bitcount */
+
+  t = ctx->bits[0];
+  if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
+    ctx->bits[1]++;	/* Carry from low to high */
+  ctx->bits[1] += (uint32_t)(len >> 29);
+  
+  t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+  
+  /* Handle any leading odd-sized chunks */
+  
+  if ( t ) {
+    unsigned char *p = ctx->in + t;
+    
+    t = 64 - t;
+
+    if (len < t) {
+      memcpy(p, buf, len);
+      return;
+    }
+
+    memcpy(p, buf, t);
+    su_md5_transform (ctx->buf, ctx->in);
+    buf += t;
+    len -= t;
+  }
+  
+  /* Process data in 64-byte chunks */
+  
+  while (len >= 64) {
+    su_md5_transform(ctx->buf, buf);
+    buf += 64;
+    len -= 64;
+  }
+
+  /* Handle any remaining bytes of data. */
+  memcpy(ctx->in, buf, len);
+}
+
+/** Copy memory, fix case to lower. */
+static 
+void mem_i_cpy(unsigned char *d, unsigned char const *s, size_t len)
+{
+  size_t i;
+
+  for (i = 0; i < len; i++)
+    if (s[i] >= 'A' && s[i] <= 'Z')
+      d[i] = s[i] + ('a' - 'A');
+    else
+      d[i] = s[i];
+}
+
+/**Update MD5 context.
+ *
+ * The function su_md5_iupdate() updates context to reflect the
+ * concatenation of another buffer full of case-independent characters.
+ *
+ * @param ctx Pointer to context structure
+ * @param b   Pointer to data
+ * @param len Length of @a b as bytes
+ */
+void
+su_md5_iupdate(su_md5_t *ctx,
+	       void const *b,
+	       usize_t len)
+{
+  unsigned char const *buf = (unsigned char const *)b;
+  uint32_t t;
+
+  /* Update bitcount */
+
+  t = ctx->bits[0];
+  if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
+    ctx->bits[1]++;	/* Carry from low to high */
+  ctx->bits[1] += (uint32_t)(len >> 29);
+  
+  t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+  
+  /* Handle any leading odd-sized chunks */
+  
+  if ( t ) {
+    unsigned char *p = ctx->in + t;
+    
+    t = sizeof(ctx->in) - t;
+
+    if (len < t) {
+      mem_i_cpy(p, buf, len);
+      return;
+    }
+    mem_i_cpy(p, buf, t);
+    su_md5_transform (ctx->buf, ctx->in);
+    buf += t;
+    len -= t;
+  }
+  
+  /* Process data in 64-byte chunks */
+  while (len >= sizeof(ctx->in)) {
+    mem_i_cpy(ctx->in, buf, sizeof(ctx->in));
+    su_md5_transform(ctx->buf, ctx->in);
+    buf += sizeof(ctx->in);
+    len -= sizeof(ctx->in);
+  }
+
+  /* Handle any remaining bytes of data. */
+  mem_i_cpy(ctx->in, buf, len);
+}
+
+/** Update MD5 context with contents of string.
+ *
+ * The function su_md5_strupdate() updates context to reflect the
+ * concatenation of NUL-terminated string.
+ *
+ * @param ctx Pointer to context structure
+ * @param s   Pointer to string
+ */
+void su_md5_strupdate(su_md5_t *ctx, char const *s)
+{
+  if (s) 
+    su_md5_update(ctx, s, strlen(s));
+}
+
+/** Update MD5 context with contents of string, including final NUL.
+ *
+ * The function su_md5_str0update() updates context to reflect the
+ * concatenation of NUL-terminated string, including the final NUL.
+ *
+ * @param ctx Pointer to context structure
+ * @param s   Pointer to string
+ */
+void su_md5_str0update(su_md5_t *ctx, char const *s)
+{
+  if (!s) 
+    s = "";
+
+  su_md5_update(ctx, s, strlen(s) + 1);
+}
+
+/** Update MD5 context with contents of case-independent string.
+ *
+ * The function su_md5_striupdate() updates context to reflect the
+ * concatenation of NUL-terminated string.
+ *
+ * @param ctx Pointer to context structure
+ * @param s   Pointer to string
+ */
+void su_md5_striupdate(su_md5_t *ctx, char const *s)
+{
+  if (s) 
+    su_md5_iupdate(ctx, s, strlen(s));
+}
+
+/** Update MD5 context with contents of case-independent string, including
+ * final NUL.
+ *
+ * The function su_md5_stri0update() updates context to reflect the
+ * concatenation of NUL-terminated string, including the final NUL.
+ *
+ * @param ctx Pointer to context structure
+ * @param s   Pointer to string
+ */
+void su_md5_stri0update(su_md5_t *ctx, char const *s)
+{
+  if (!s) 
+    s = "";
+
+  su_md5_iupdate(ctx, s, strlen(s) + 1);
+}
+
+
+/** Generate digest.
+ *
+ * Final wrapup. Pad message to 64-byte boundary with the bit pattern 1 0*
+ * (64-bit count of bits processed, MSB-first), then concatenate message
+ * with its length (measured in bits) as 64-byte big-endian integer.
+ *
+ * @param context  Pointer to context structure
+ * @param digest   Digest array to be filled
+ */
+void
+su_md5_digest(su_md5_t const *context, uint8_t digest[16])
+{
+  unsigned count;
+  unsigned char *p;
+
+  su_md5_t ctx[1];
+
+  ctx[0] = context[0];
+  
+  /* 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 needde 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 */
+    memset(p, 0, count);
+    su_md5_transform (ctx->buf, ctx->in);
+    
+    /* Now fill the next block with 56 bytes */
+    memset(ctx->in, 0, 56);
+  } else {
+    /* Pad block to 56 bytes */
+    memset(p, 0, count-8);
+  }
+  
+  /* Append length in bits and transform */
+  putu32(ctx->bits[0], ctx->in + 56);
+  putu32(ctx->bits[1], ctx->in + 60);
+  
+  su_md5_transform(ctx->buf, ctx->in);
+  putu32(ctx->buf[0], digest);
+  putu32(ctx->buf[1], digest + 4);
+  putu32(ctx->buf[2], digest + 8);
+  putu32(ctx->buf[3], digest + 12);
+  memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+void su_md5_hexdigest(su_md5_t const *ctx,
+		      char digest[2 * SU_MD5_DIGEST_SIZE + 1])
+{
+  uint8_t b, bin[SU_MD5_DIGEST_SIZE];
+  short i, j;
+
+  su_md5_digest(ctx, bin);
+
+  for (i = j = 0; i < 16; i++) {
+    b = (bin[i] >> 4) & 15;
+    digest[j++] = b + (b > 9 ? 'a' - 10 : '0');
+    b = bin[i] & 15;
+    digest[j++] = b + (b > 9 ? 'a' - 10 : '0');
+  }
+
+  digest[j] = '\0';
+}
+
+#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 &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/** @internal
+ *
+ * Add 64 bytes of data to hash.
+ *
+ * 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
+su_md5_transform(uint32_t buf[4], const unsigned char inraw[64])
+{
+  register uint32_t a, b, c, d;
+  uint32_t in[16];
+  int i;
+
+  for (i = 0; i < 16; ++i)
+    in[i] = getu32 (inraw + 4 * i);
+
+  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

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_MODULE_DEBUG_H
+/** Defined when <su_module_debug.h> has been included. */
+#define SU_MODULE_DEBUG_H
+
+/**@ingroup su_log
+ * @file su_module_debug.h
+ * @brief Debug log for @b su module
+ *
+ * The su_module_debug.h defines a common debug log #su_log_global for all
+ * functions within @b su module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Wed Jan 29 18:18:49 2003 ppessi
+ * 
+ */
+
+#include <sofia-sip/su_log.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Debugging log for @b su module. */
+SOFIAPUBVAR su_log_t su_log_global[];
+#define SU_LOG (su_log_global)
+#include <sofia-sip/su_debug.h>
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_MODULE_DEBUG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,307 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_os_nw
+ *
+ * @CFILE su_os_nw.c  
+ * Implementation of OS-specific network events interface.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @date Created: Fri Aug 11 07:30:04 2006 mela
+ *
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define SU_MSG_ARG_T    struct su_network_changed_s
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_debug.h"
+#include "sofia-sip/su_os_nw.h"
+#include "sofia-sip/su_debug.h"
+
+/* Works only with pthreads */
+#if SU_HAVE_PTHREADS
+
+#include <pthread.h>
+
+#if defined(__APPLE_CC__)
+#include <AvailabilityMacros.h>
+#include <sys/cdefs.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+#include <SystemConfiguration/SCDynamicStoreKey.h>
+#include <SystemConfiguration/SCSchemaDefinitions.h>
+#endif /* __APPLE_CC__ */
+
+struct su_network_changed_s {
+  su_root_t                  *su_root;
+  su_home_t                  *su_home;
+
+#if defined (__APPLE_CC__)
+  SCDynamicStoreRef           su_storeRef[1];
+  CFRunLoopSourceRef          su_sourceRef[1];
+#endif
+
+  pthread_t                   su_os_thread;
+
+  su_network_changed_f       *su_network_changed_cb;
+  su_network_changed_magic_t *su_network_changed_magic;
+};
+
+#if defined(__APPLE_CC__)
+static void su_nw_changed_msg_recv(su_root_magic_t *rm,
+				   su_msg_r msg,
+				   su_network_changed_t *snc)
+{
+  su_network_changed_magic_t *magic = snc->su_network_changed_magic;
+
+  assert(magic);
+
+  /* SU_DEBUG_5(("su_nw_changed_msg_recv: entering.\n")); */
+
+  snc->su_network_changed_cb(magic, snc->su_root);
+
+  return;
+}
+
+
+void nw_changed_cb(SCDynamicStoreRef store, 
+		   CFArrayRef changedKeys, 
+		   void *info)
+{
+  su_network_changed_t *snc = (su_network_changed_t *) info;
+  su_network_changed_t *snc2;
+  su_msg_r rmsg = SU_MSG_R_INIT;
+
+  SU_DEBUG_7(("nw_changed_cb: entering.\n"));
+
+  if (su_msg_create(rmsg,
+		    su_root_task(snc->su_root),
+		    su_root_task(snc->su_root),
+		    su_nw_changed_msg_recv,
+		    sizeof *snc) == SU_FAILURE) {
+
+    return;
+  }    
+
+  snc2 = su_msg_data(rmsg); assert(snc2);
+  snc2->su_root = snc->su_root;
+  snc2->su_home = snc->su_home;
+  memcpy(snc2->su_storeRef, snc->su_storeRef, sizeof(SCDynamicStoreRef));
+  memcpy(snc2->su_sourceRef, snc->su_sourceRef, sizeof(CFRunLoopSourceRef));
+  snc2->su_os_thread = snc->su_os_thread;
+  snc2->su_network_changed_cb = snc->su_network_changed_cb;
+  snc2->su_network_changed_magic = snc->su_network_changed_magic;
+  
+  if (su_msg_send(rmsg) == SU_FAILURE) {
+    su_msg_destroy(rmsg);
+    return;
+  }
+
+  return;
+}
+
+static OSStatus
+CreateIPAddressListChangeCallbackSCF(SCDynamicStoreCallBack callback,
+				     void *contextPtr,
+				     SCDynamicStoreRef *storeRef,
+				     CFRunLoopSourceRef *sourceRef)
+    // Create a SCF dynamic store reference and a
+    // corresponding CFRunLoop source.  If you add the
+    // run loop source to your run loop then the supplied
+    // callback function will be called when local IP
+    // address list changes.
+{
+    OSStatus                err = 0;
+    SCDynamicStoreContext   context = {0, NULL, NULL, NULL, NULL};
+    SCDynamicStoreRef       ref;
+    CFStringRef             pattern;
+    CFArrayRef              patternList;
+    CFRunLoopSourceRef      rls;
+
+    assert(callback   != NULL);
+    assert( storeRef  != NULL);
+    assert(*storeRef  == NULL);
+    assert( sourceRef != NULL);
+    assert(*sourceRef == NULL);
+
+    ref = NULL;
+    pattern = NULL;
+    patternList = NULL;
+    rls = NULL;
+
+    // Create a connection to the dynamic store, then create
+    // a search pattern that finds all IPv4 entities.
+    // The pattern is "State:/Network/Service/[^/]+/IPv4".
+
+    context.info = contextPtr;
+    ref = SCDynamicStoreCreate( NULL,
+                                CFSTR("AddIPAddressListChangeCallbackSCF"),
+                                callback,
+                                &context);
+    //err = MoreSCError(ref);
+    if (err == noErr) {
+        pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(
+                                NULL,
+                                kSCDynamicStoreDomainState,
+                                kSCCompAnyRegex,
+                                kSCEntNetIPv4);
+        //err = MoreSCError(pattern);
+    }
+
+    // Create a pattern list containing just one pattern,
+    // then tell SCF that we want to watch changes in keys
+    // that match that pattern list, then create our run loop
+    // source.
+
+    if (err == noErr) {
+        patternList = CFArrayCreate(NULL,
+                                    (const void **) &pattern, 1,
+                                    &kCFTypeArrayCallBacks);
+        //err = CFQError(patternList);
+    }
+    if (err == noErr) {
+      //err = MoreSCErrorBoolean(
+                SCDynamicStoreSetNotificationKeys(
+                    ref,
+                    NULL,
+                    patternList);
+		//      );
+    }
+    if (err == noErr) {
+        rls = SCDynamicStoreCreateRunLoopSource(NULL, ref, 0);
+        //err = MoreSCError(rls);
+    }
+
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,
+		       kCFRunLoopDefaultMode);
+
+    // Clean up.
+
+    //CFQRelease(pattern);
+    //CFQRelease(patternList);
+    if (err != noErr) {
+      //CFQRelease(ref);
+        ref = NULL;
+    }
+    *storeRef = ref;
+    *sourceRef = rls;
+
+    assert( (err == noErr) == (*storeRef  != NULL) );
+    assert( (err == noErr) == (*sourceRef != NULL) );
+
+    return err;
+}
+#endif /* __APPLE_CC__ */
+
+
+#if defined(__APPLE_CC__)
+static void *su_start_nw_os_thread(void *ptr)
+{
+  su_network_changed_t *snc = (su_network_changed_t *) ptr;
+
+  assert(snc);
+
+  CreateIPAddressListChangeCallbackSCF(nw_changed_cb,
+				       (void *) snc,
+				       snc->su_storeRef,
+				       snc->su_sourceRef);
+
+  CFRunLoopRun();
+
+  return NULL;
+}
+#endif
+
+/** Register a callback for the network change event.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+su_network_changed_t
+*su_root_add_network_changed(su_home_t *home, su_root_t *root,
+			     su_network_changed_f *network_changed_cb,
+			     su_network_changed_magic_t *magic)
+{
+#if defined (__APPLE_CC__)
+  su_network_changed_t *snc = NULL;
+#endif
+
+  assert(home && root && network_changed_cb && magic);
+
+  /* Not implemented for others than OSX */
+#if !defined (__APPLE_CC__)
+  return NULL;
+#else
+
+  snc = su_zalloc(home, sizeof *snc);
+  
+  if (!snc)
+    return NULL;
+
+  snc->su_home = home;
+  snc->su_root = root;
+  snc->su_network_changed_cb = network_changed_cb;
+  snc->su_network_changed_magic = magic;
+  
+  if ((pthread_create(&(snc->su_os_thread), NULL,
+		      su_start_nw_os_thread,
+		      (void *) snc)) != 0) {
+    return NULL;
+  }
+
+  return snc;
+#endif
+}
+
+/** Remove a callback registered for the network change event.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+int su_root_remove_network_changed(su_network_changed_t *snc)
+{
+  return -1;
+}
+
+#else
+
+su_network_changed_t
+*su_root_add_network_changed(su_home_t *home, su_root_t *root,
+			     su_network_changed_f *network_changed_cb,
+			     su_network_changed_magic_t *magic)
+{
+  return NULL;
+}
+
+int su_root_remove_network_changed(su_network_changed_t *snc)
+{
+  return -1;
+}
+
+#endif /* SU_HAVE_PTHREADS */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1787 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_osx_runloop.c
+ *
+ * OS-Independent Socket Syncronization Interface.
+ *
+ * This looks like nth reincarnation of "reactor".  It implements the
+ * poll/select/WaitForMultipleObjects and message passing functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+/* React to multiple events per one poll() to make sure 
+ * that high-priority events can never completely mask other events.
+ * Enabled by default on all platforms except WIN32 */
+#ifndef WIN32
+#define SU_ENABLE_MULTISHOT_POLL 1
+#else
+#define SU_ENABLE_MULTISHOT_POLL 0
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_osx_runloop.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_debug.h"
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __func__))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __FUNCTION__))
+#else
+#define enter (void)0
+#endif
+
+
+#if SU_HAVE_PTHREADS
+/* Pthread implementation */
+#include <pthread.h>
+#define SU_HAVE_MBOX 1
+#else
+#define SU_HAVE_MBOX 0
+#endif
+
+#if HAVE_SOCKETPAIR
+#define MBOX_SEND  1
+#else
+#define MBOX_SEND  0
+#endif
+
+static su_port_t *su_osx_runloop_create(void) __attribute__((__malloc__));
+
+/* Callback for CFObserver and CFSocket */
+static
+void cf_observer_cb(CFRunLoopObserverRef observer, 
+		    CFRunLoopActivity activity, 
+		    void *info);
+static void su_port_osx_socket_cb(CFSocketRef s, 
+				  CFSocketCallBackType callbackType, 
+				  CFDataRef address, 
+				  const void *data, 
+				  void *info);
+static CFSocketCallBackType map_poll_event_to_cf_event(int events);
+
+static void su_port_osx_lock(su_port_t *self, char const *who);
+static void su_port_osx_unlock(su_port_t *self, char const *who);
+static void su_port_osx_incref(su_port_t *self, char const *who);
+static void su_port_osx_decref(su_port_t *self, int blocking, char const *who);
+
+static int su_port_osx_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_port_osx_register(su_port_t *self,
+			    su_root_t *root, 
+			    su_wait_t *wait, 
+			    su_wakeup_f callback,
+			    su_wakeup_arg_t *arg,
+			    int priority);
+static int su_port_osx_unregister(su_port_t *port,
+			      su_root_t *root, 
+			      su_wait_t *wait,	
+			      su_wakeup_f callback, 
+			      su_wakeup_arg_t *arg);
+
+static int su_port_osx_deregister(su_port_t *self, int i);
+
+static int su_port_osx_unregister_all(su_port_t *self,
+			   su_root_t *root);
+
+static int su_port_osx_getmsgs(su_port_t *self);
+static
+int su_port_osx_eventmask(su_port_t *self, int index, int socket, int events);
+static
+void su_port_osx_run(su_port_t *self);
+static
+void su_port_osx_break(su_port_t *self);
+static
+su_duration_t su_port_osx_step(su_port_t *self, su_duration_t tout);
+
+#if 0
+unsigned su_port_query(su_port_t *, su_wait_t *, unsigned n_waits);
+void su_port_event(su_port_t *, su_wait_t *waitobj);
+#endif
+
+static
+int su_port_osx_own_thread(su_port_t const *port);
+
+static
+int su_port_osx_add_prepoll(su_port_t *port,
+			su_root_t *root, 
+			su_prepoll_f *, 
+			su_prepoll_magic_t *);
+
+static
+int su_port_osx_remove_prepoll(su_port_t *port,
+			   su_root_t *root);
+
+static
+su_timer_t **su_port_osx_timers(su_port_t *port);
+
+static
+int su_port_osx_multishot(su_port_t *port, int multishot);
+
+static
+int su_port_osx_threadsafe(su_port_t *port);
+
+static
+int su_port_osx_yield(su_port_t *port);
+
+su_port_vtable_t const su_port_osx_vtable[1] =
+  {{
+      /* su_vtable_size: */ sizeof su_port_osx_vtable,
+      su_port_osx_lock,
+      su_port_osx_unlock,
+      su_port_osx_incref,
+      su_port_osx_decref,
+      NULL /* su_port_osx_runloop */, /* XXX - was: gsource, */
+      su_port_osx_send,
+      su_port_osx_register,
+      su_port_osx_unregister,
+      su_port_osx_deregister,
+      su_port_osx_unregister_all,
+      su_port_osx_eventmask,
+      su_port_osx_run,
+      su_port_osx_break,
+      su_port_osx_step,
+      su_port_osx_own_thread,
+      su_port_osx_add_prepoll,
+      su_port_osx_remove_prepoll,
+      su_port_osx_timers,
+      su_port_osx_multishot,
+      su_port_osx_threadsafe,
+      su_port_osx_yield
+    }};
+
+static int su_port_osx_wait_events(su_port_t *self, su_duration_t tout);
+
+
+/* *
+ * Port is a per-thread reactor.  
+ *
+ * Multiple root objects executed by single thread share a su_port_t object. 
+ */
+struct su_port_s {
+  su_home_t        sup_home[1];
+
+  su_port_vtable_t const *sup_vtable;
+  
+  unsigned         sup_running;
+  unsigned         sup_source_fired;
+
+
+#if SU_HAVE_PTHREADS
+  pthread_t        sup_tid;
+  pthread_mutex_t  sup_mutex[1];
+#if __CYGWIN__
+  pthread_mutex_t  sup_reflock[1];
+  int              sup_ref;
+#else
+  pthread_rwlock_t sup_ref[1];
+#endif
+#else
+  int              sup_ref;
+#endif
+
+#if SU_HAVE_MBOX
+  su_socket_t      sup_mbox[MBOX_SEND + 1];
+  su_wait_t        sup_mbox_wait;
+#endif
+
+  CFRunLoopRef        sup_main_loop;
+  CFRunLoopSourceRef *sup_sources;
+  CFSocketRef        *sup_sockets;
+  
+  unsigned         sup_multishot; /**< Multishot operation? */
+
+  unsigned         sup_registers; /** Counter incremented by 
+				      su_port_register() or 
+				      su_port_unregister()
+				   */
+  int              sup_n_waits; /**< Active su_wait_t in su_waits */
+  int              sup_size_waits; /**< Size of allocate su_waits */
+
+  int              sup_pri_offset; /**< Offset to prioritized waits */
+
+#define INDEX_MAX (0x7fffffff)
+
+  /** Indices from index returned by su_root_register() to tables below. 
+   *
+   * Free elements are negative. Free elements form a list, value of free
+   * element is (0 - index of next free element).
+   *
+   * First element sup_indices[0] points to first free element. 
+   */
+  int             *sup_indices;
+
+  int             *sup_reverses; /** Reverse index */
+  su_wakeup_f     *sup_wait_cbs; 
+  su_wakeup_arg_t**sup_wait_args; 
+  su_root_t      **sup_wait_roots; 
+
+  su_wait_t       *sup_waits; 
+
+  /* Pre-poll callback */
+  su_prepoll_f    *sup_prepoll; 
+  su_prepoll_magic_t *sup_pp_magic;
+  su_root_t       *sup_pp_root;
+
+  /* Timer list */
+  su_timer_t      *sup_timers;
+
+  /* Message list - this is protected by lock  */
+  su_msg_t        *sup_head;
+  su_msg_t       **sup_tail;
+
+#if 0
+  int              sup_free_index;   /**< Number of first free index */
+  int             *sup_indices; /** Indices to registrations */
+
+  int             *sup_reverses; /** Reverse index */
+  su_wakeup_f     *sup_wait_cbs; 
+  su_wakeup_arg_t**sup_wait_args; 
+  su_root_t      **sup_wait_roots; 
+
+  su_wait_t       *sup_waits; 
+
+  /* Pre-poll callback */
+  su_prepoll_f    *sup_prepoll; 
+  su_prepoll_magic_t *sup_pp_magic;
+  su_root_t       *sup_pp_root;
+
+  /* Timer list */
+  su_timer_t      *sup_timers;
+
+  /* Message list - this is protected by lock  */
+  su_msg_t        *sup_head;
+  su_msg_t       **sup_tail;
+#endif
+};
+
+
+/* Struct for CFSocket callbacks; contains current CFSource index */
+typedef struct {
+  su_port_t *o_port;
+  int        o_current;
+  int        o_count;
+} osx_magic_t;
+
+
+#if SU_HAVE_PTHREADS
+#define SU_PORT_OSX_OWN_THREAD(p)   (pthread_equal((p)->sup_tid, pthread_self()))
+
+#if __CYGWIN__
+
+/* Debugging versions */
+#define SU_PORT_OSX_INITREF(p)      (pthread_mutex_init((p)->sup_reflock, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_OSX_INCREF(p, f)    (pthread_mutex_lock(p->sup_reflock), p->sup_ref++, pthread_mutex_unlock(p->sup_reflock), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_OSX_DECREF(p, f)    do {					\
+    pthread_mutex_lock(p->sup_reflock);	p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+    if ((p->sup_ref) == 0) {			\
+      printf("decref(%p) to 0 by %s\n", (p), f); su_port_osx_destroy(p); }	\
+    else { printf("decref(%p) to %u by %s\n", (p), p->sup_ref, f); }  } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f)    do { printf("zapref(%p) by %s\n", (p), f), \
+    pthread_mutex_lock(p->sup_reflock);	p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+  if ((p->sup_ref) != 0) { \
+    assert(!"SU_PORT_OSX_ZAPREF"); } \
+  su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p) \
+   (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_OSX_LOCK(p, f)    \
+   (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_OSX_UNLOCK(p, f)  \
+  (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#elif 1
+#define SU_PORT_OSX_INITREF(p)      (pthread_rwlock_init(p->sup_ref, NULL))
+#define SU_PORT_OSX_INCREF(p, f)    (pthread_rwlock_rdlock(p->sup_ref))
+#define SU_PORT_OSX_DECREF(p, f)    do { pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) == 0) su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f)    do { pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+    assert(!"SU_PORT_OSX_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+  su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p)     (pthread_mutex_init((p)->sup_mutex, NULL))
+#define SU_PORT_OSX_LOCK(p, f)      (pthread_mutex_lock((p)->sup_mutex))
+#define SU_PORT_OSX_UNLOCK(p, f)    (pthread_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_PORT_OSX_INITREF(p)      (pthread_rwlock_init((p)->sup_ref, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_OSX_INCREF(p, f)    (pthread_rwlock_rdlock(p->sup_ref), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_OSX_DECREF(p, f)    do {					\
+    pthread_rwlock_unlock(p->sup_ref);					\
+    if (pthread_rwlock_trywrlock(p->sup_ref) == 0) {			\
+      printf("decref(%p) to 0 by %s\n", (p), f); su_port_osx_destroy(p); }	\
+    else { printf("decref(%p) by %s\n", (p), f); }  } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f)    do { printf("zapref(%p) by %s\n", (p), f), \
+  pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+    assert(!"SU_PORT_OSX_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+  su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p) \
+   (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_OSX_LOCK(p, f)    \
+   (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_OSX_UNLOCK(p, f)  \
+  (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#endif
+
+#else /* !SU_HAVE_PTHREADS */
+
+#define SU_PORT_OSX_OWN_THREAD(p)  1
+#define SU_PORT_OSX_INITLOCK(p)    (void)(p)
+#define SU_PORT_OSX_LOCK(p, f)      (void)(p)
+#define SU_PORT_OSX_UNLOCK(p, f)    (void)(p)
+#define SU_PORT_OSX_ZAPREF(p, f)    ((p)->sup_ref--)
+
+#define SU_PORT_OSX_INITREF(p)      ((p)->sup_ref = 1)
+#define SU_PORT_OSX_INCREF(p, f)    ((p)->sup_ref++)
+#define SU_PORT_OSX_DECREF(p, f) \
+do { if (--((p)->sup_ref) == 0) su_port_osx_destroy(p); } while (0);
+
+#endif
+
+#if SU_HAVE_MBOX
+static int su_port_osx_wakeup(su_root_magic_t *magic, 
+			  su_wait_t *w,
+			  su_wakeup_arg_t *arg);
+#endif
+
+static void su_port_osx_destroy(su_port_t *self);
+
+/** Create a reactor object.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic     pointer to user data
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ *
+ * @NEW_1_12_4.
+ */
+su_root_t *su_root_osx_runloop_create(su_root_magic_t *magic)
+{
+  return su_root_create_with_port(magic, su_osx_runloop_create());
+}
+
+
+void osx_enabler_cb(CFSocketRef s, 
+		    CFSocketCallBackType type, 
+		    CFDataRef address, 
+		    const void *data, 
+		    void *info)
+{
+  CFRunLoopRef  rl;
+  osx_magic_t  *magic = (osx_magic_t *) info;
+  su_port_t    *self = magic->o_port;
+  su_duration_t tout = 0;
+  su_time_t     now = su_now();
+  
+  rl = CFRunLoopGetCurrent();
+
+  if (self->sup_running) {
+    
+    if (self->sup_prepoll)
+      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+    
+    if (self->sup_head)
+      su_port_osx_getmsgs(self);
+    
+    if (self->sup_timers)
+      su_timer_expire(&self->sup_timers, &tout, now);
+  }
+  
+  CFRunLoopWakeUp(rl);
+  
+}
+
+
+/**@internal
+ *
+ * Allocates and initializes a message port. It creates a mailbox used to.
+ * wake up the tasks waiting on the port if needed.  Currently, the
+ * mailbox is simply an UDP socket connected to itself.
+ *
+ * @return
+ *   If successful a pointer to the new message port is returned, otherwise
+ *   NULL is returned.  
+ */
+su_port_t *su_osx_runloop_create(void)
+{
+  su_port_t *self;
+
+  SU_DEBUG_9(("su_osx_runloop_create() called\n"));
+
+  self = su_home_clone(NULL, sizeof(*self));
+
+  if (self) {
+#if SU_HAVE_MBOX
+    int af;
+    su_socket_t mb = INVALID_SOCKET;
+    char const *why;
+#endif
+    CFRunLoopObserverRef cf_observer; 
+    osx_magic_t *osx_magic = NULL;
+    CFRunLoopObserverContext cf_observer_cntx[1] = {{0, NULL, NULL,
+						     NULL, NULL}};
+
+    self->sup_vtable = su_port_osx_vtable;
+    
+    SU_PORT_OSX_INITREF(self);
+    SU_PORT_OSX_INITLOCK(self);
+    self->sup_tail = &self->sup_head;
+
+    self->sup_multishot = 0; /* XXX (SU_ENABLE_MULTISHOT_POLL) != 0; */
+
+#if SU_HAVE_PTHREADS
+    self->sup_tid = pthread_self();
+#endif
+  
+#if SU_HAVE_MBOX
+#if HAVE_SOCKETPAIR
+#if defined(AF_LOCAL)
+    af = AF_LOCAL;
+#else
+    af = AF_UNIX;
+#endif
+    if (socketpair(af, SOCK_STREAM, 0, self->sup_mbox) == -1) {
+      why = "su_port_osx_init: socketpair"; goto error;
+    }
+
+    mb = self->sup_mbox[0];
+    su_setblocking(self->sup_mbox[0], 0);
+    su_setblocking(self->sup_mbox[1], 0);
+#else
+    {
+      struct sockaddr_in sin = { sizeof(struct sockaddr_in), 0 };
+      socklen_t sinsize = sizeof sin;
+      struct sockaddr *sa = (struct sockaddr *)&sin;
+
+      af = PF_INET;
+
+      self->sup_mbox[0] = mb = su_socket(af, SOCK_DGRAM, IPPROTO_UDP);
+      if (mb == INVALID_SOCKET) {
+	why = "su_port_osx_init: socket"; goto error;
+      }
+  
+      sin.sin_family = AF_INET;
+      sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.1 */
+      
+      /* Get a port for us */
+      if (bind(mb, sa, sizeof sin) == -1) {
+	why = "su_port_osx_init: bind"; goto error;
+      }
+
+      if (getsockname(mb, sa, &sinsize) == -1) {
+	why = "su_port_osx_init: getsockname"; goto error;
+      }
+    
+      if (connect(mb, sa, sinsize) == -1) {
+	why = "su_port_osx_init: connect"; goto error;
+      }
+    }
+#endif    
+
+    if (su_wait_create(&self->sup_mbox_wait, mb, SU_WAIT_IN) == -1) {
+      why = "su_port_osx_init: su_wait_create"; goto error;
+    }
+
+    if (su_port_osx_register(self, NULL, &self->sup_mbox_wait,
+			     su_port_osx_wakeup, 
+			     (su_wakeup_arg_t *)self->sup_mbox, 0)
+	== -1) {
+      why = "su_port_osx_create: su_port_osx_register"; goto error;
+    }
+
+    osx_magic = calloc(1, sizeof(*osx_magic));
+    osx_magic->o_port = self;
+    cf_observer_cntx->info = osx_magic;
+    
+    cf_observer =
+      CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting | kCFRunLoopBeforeWaiting,
+			      TRUE, 0, cf_observer_cb, cf_observer_cntx);
+    
+    CFRunLoopAddObserver(CFRunLoopGetCurrent(),
+			 cf_observer,
+			 kCFRunLoopDefaultMode);
+    
+    SU_DEBUG_9(("su_port_osx_create() returns %p\n", self));
+    
+    return self;
+    
+  error:
+    su_perror(why);
+    su_port_osx_destroy(self), self = NULL;
+#endif
+  }
+  
+  SU_DEBUG_9(("su_port_osx_create() returns %p\n", self));
+  
+  return self;
+}
+
+
+static
+void cf_observer_cb(CFRunLoopObserverRef observer, 
+		    CFRunLoopActivity activity, 
+		    void *info)
+{
+  CFRunLoopRef  rl;
+  osx_magic_t  *magic = (osx_magic_t *) info;
+  su_port_t    *self = magic->o_port;
+  su_duration_t tout = 0;
+  su_time_t     now = su_now();
+
+  rl = CFRunLoopGetCurrent();
+
+  if (self->sup_running) {
+
+    if (self->sup_prepoll)
+      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+    
+    if (self->sup_head)
+      su_port_osx_getmsgs(self);
+    
+    if (self->sup_timers)
+      su_timer_expire(&self->sup_timers, &tout, now);
+  } else
+    SU_DEBUG_9(("cf_observer_cb(): PORT IS NOT RUNNING!\n"));
+
+  CFRunLoopWakeUp(rl);
+  
+  return;
+}
+
+/** @internal Destroy a port. */
+void su_port_osx_destroy(su_port_t *self)
+{
+  assert(self);
+
+  SU_DEBUG_9(("su_port_osx_destroy() called\n"));
+
+#if SU_HAVE_MBOX
+  if (self->sup_mbox[0] != INVALID_SOCKET) {
+    su_port_osx_unregister(self, NULL, &self->sup_mbox_wait, NULL, 
+		       (su_wakeup_arg_t *)self->sup_mbox);
+    su_wait_destroy(&self->sup_mbox_wait);
+    su_close(self->sup_mbox[0]); self->sup_mbox[0] = INVALID_SOCKET;
+#if HAVE_SOCKETPAIR
+    su_close(self->sup_mbox[1]); self->sup_mbox[1] = INVALID_SOCKET;
+#endif
+    SU_DEBUG_9(("su_port_osx_destroy() close mailbox\n"));
+  }
+#endif
+  if (self->sup_sources) 
+    free(self->sup_sources), self->sup_sources = NULL;
+  if (self->sup_sockets) 
+    free(self->sup_sockets), self->sup_sockets = NULL;
+  if (self->sup_waits) 
+    free(self->sup_waits), self->sup_waits = NULL;
+  if (self->sup_wait_cbs)
+    free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+  if (self->sup_wait_args)
+    free(self->sup_wait_args), self->sup_wait_args = NULL;
+  if (self->sup_wait_roots)
+    free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+  if (self->sup_reverses)
+    free(self->sup_reverses), self->sup_reverses = NULL;
+  if (self->sup_indices)
+    free(self->sup_indices), self->sup_indices = NULL;
+
+  SU_DEBUG_9(("su_port_osx_destroy() freed registrations\n"));
+
+  su_home_zap(self->sup_home);
+
+  SU_DEBUG_9(("su_port_osx_destroy() returns\n"));
+
+}
+
+static void su_port_osx_lock(su_port_t *self, char const *who)
+{
+  SU_PORT_OSX_LOCK(self, who);
+}
+
+static void su_port_osx_unlock(su_port_t *self, char const *who)
+{
+  SU_PORT_OSX_UNLOCK(self, who);
+}
+
+static void su_port_osx_incref(su_port_t *self, char const *who)
+{
+  SU_PORT_OSX_INCREF(self, who);
+}
+
+static void su_port_osx_decref(su_port_t *self, int blocking, char const *who)
+{
+  if (blocking)
+    SU_PORT_OSX_ZAPREF(self, who);
+  else
+    SU_PORT_OSX_DECREF(self, who);
+}
+
+static
+CFSocketCallBackType map_poll_event_to_cf_event(int events)
+{
+  CFSocketCallBackType type = 0;
+
+  if (events & SU_WAIT_IN)
+    type |= kCFSocketReadCallBack;
+  
+  if (events & SU_WAIT_OUT)
+    type |= kCFSocketWriteCallBack;
+  
+#if 0
+  if (events & SU_WAIT_CONNECT)
+    type |= kCFSocketConnectCallBack;
+  
+  if (events & SU_WAIT_ACCEPT)
+    type |= kCFSocketAcceptCallBack;
+#endif
+
+  return type;
+}
+
+
+static
+int map_cf_event_to_poll_event(CFSocketCallBackType type)
+{
+  int event = 0;
+
+  if (type & kCFSocketReadCallBack)
+    event |= SU_WAIT_IN;
+  
+  if (type & kCFSocketWriteCallBack)
+    event |= SU_WAIT_OUT;
+  
+  if (type & kCFSocketConnectCallBack)
+    event |= SU_WAIT_CONNECT;
+  
+  if (type & kCFSocketAcceptCallBack)
+    event |= SU_WAIT_ACCEPT;
+
+  return event;
+}
+
+
+static
+void su_port_osx_socket_cb(CFSocketRef s, 
+			   CFSocketCallBackType type, 
+			   CFDataRef address, 
+			   const void *data, 
+			   void *info)
+{
+  osx_magic_t       *magic = (osx_magic_t *) info;
+  su_port_t         *self = magic->o_port;
+  int                curr = magic->o_current;
+  su_duration_t tout = 0;
+  
+#if SU_HAVE_POLL
+  {
+    su_root_t *root;
+    su_wait_t *waits = self->sup_waits;
+    int n = self->sup_indices[curr];
+    
+    assert(self->sup_reverses[n] == curr);
+    
+    SU_DEBUG_9(("socket_cb(%p): count %u index %d\n", self->sup_sources[n], magic->o_count, curr));
+    
+    waits[n].revents = map_poll_event_to_cf_event(type);
+
+    root = self->sup_wait_roots[n];
+    self->sup_wait_cbs[n](root ? su_root_magic(root) : NULL, 
+			  &waits[n], 
+			  self->sup_wait_args[n]);
+    
+    if (self->sup_running) {
+      su_port_osx_getmsgs(self);
+      
+      if (self->sup_timers)
+	su_timer_expire(&self->sup_timers, &tout, su_now());
+
+      if (self->sup_head)
+	tout = 0;
+
+      /* CFRunLoopWakeUp(CFRunLoopGetCurrent()); */
+    }
+    
+    /* Tell to run loop an su socket fired */
+    self->sup_source_fired = 1;
+  }
+#endif
+  
+}
+
+#if SU_HAVE_MBOX
+/** @internal Message box wakeup function. */
+static int su_port_osx_wakeup(su_root_magic_t *magic, /* NULL */
+			      su_wait_t *w,
+			      su_wakeup_arg_t *arg)
+{
+  char buf[32];
+  su_socket_t s = *(su_socket_t *)arg;
+  su_wait_events(w, s);
+  recv(s, buf, sizeof(buf), 0);
+
+  /* CFRunLoopWakeUp(CFRunLoopGetCurrent()); */
+
+  return 0;
+}
+#endif
+
+/** @internal Send a message to the port. */
+int su_port_osx_send(su_port_t *self, su_msg_r rmsg)
+{
+  CFRunLoopRef rl;
+
+  if (self) {
+    int wakeup;
+
+    SU_PORT_OSX_LOCK(self, "su_port_osx_send");
+    
+    wakeup = self->sup_head == NULL;
+
+    *self->sup_tail = rmsg[0]; rmsg[0] = NULL;
+    self->sup_tail = &(*self->sup_tail)->sum_next;
+
+#if SU_HAVE_MBOX
+    /* if (!pthread_equal(pthread_self(), self->sup_tid)) */
+    if (wakeup)
+    {
+      assert(self->sup_mbox[MBOX_SEND] != INVALID_SOCKET);
+
+      if (send(self->sup_mbox[MBOX_SEND], "X", 1, 0) == -1) {
+#if HAVE_SOCKETPAIR
+	if (su_errno() != EWOULDBLOCK)
+#endif
+	  su_perror("su_msg_send: send()");
+      }
+    }
+#endif
+
+    SU_PORT_OSX_UNLOCK(self, "su_port_osx_send");
+
+    rl = CFRunLoopGetCurrent();
+    CFRunLoopWakeUp(rl);
+
+    return 0;
+  }
+  else {
+    su_msg_destroy(rmsg);
+    return -1;
+  }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval Number of messages sent
+ */
+int su_port_osx_getmsgs(su_port_t *self)
+{
+  int n = 0;
+
+  if (self->sup_head) {
+    su_msg_f f;
+    su_msg_t *msg, *queue;
+
+    SU_PORT_OSX_LOCK(self, "su_port_getmsgs");
+
+    queue = self->sup_head;
+    self->sup_tail = &self->sup_head;
+    self->sup_head = NULL;
+
+    SU_PORT_OSX_UNLOCK(self, "su_port_osx_getmsgs");
+
+    for (msg = queue; msg; msg = queue) {
+      queue = msg->sum_next;
+      msg->sum_next = NULL;
+
+      f = msg->sum_func;
+      if (f) 
+	f(SU_ROOT_MAGIC(msg->sum_to->sut_root), &msg, msg->sum_data);
+      su_msg_delivery_report(&msg);
+      n++;
+    }
+
+    /* Check for wait events that may have been generated by messages */
+    su_port_osx_wait_events(self, 0);
+  }
+
+  return n;
+}
+
+static int o_count;
+
+/** @internal
+ *
+ *  Register a @c su_wait_t object. The wait object, a callback function and
+ *  a argument pointer is stored in the port object.  The callback function
+ *  will be called when the wait object is signaled.
+ *
+ *  Please note if identical wait objects are inserted, only first one is
+ *  ever signalled.
+ * 
+ * @param self	     pointer to port
+ * @param root	     pointer to root object
+ * @param waits	     pointer to wait object
+ * @param callback   callback function pointer
+ * @param arg	     argument given to callback function when it is invoked
+ * @param priority   relative priority of the wait object 
+ *              (0 is normal, 1 important, 2 realtime)
+ * 
+ * @return
+ *   The function @su_port_osx_register returns nonzero index of the wait object, 
+ *   or -1 upon an error.  */
+int su_port_osx_register(su_port_t *self,
+			 su_root_t *root, 
+			 su_wait_t *wait, 
+			 su_wakeup_f callback,
+			 su_wakeup_arg_t *arg,
+			 int priority)
+{
+  int i, j, n;
+  CFRunLoopRef rl;
+  CFRunLoopSourceRef *sources, source;
+  CFSocketRef cf_socket, *sockets;
+  int events = 0;
+  osx_magic_t *osx_magic = NULL;
+  CFSocketContext cf_socket_cntx[1] = {{0, NULL, NULL, NULL, NULL}};
+  CFOptionFlags flags = 0;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  n = self->sup_n_waits;
+
+  if (n >= SU_WAIT_MAX)
+    return su_seterrno(ENOMEM);
+
+  if (n >= self->sup_size_waits) {
+    /* Reallocate size arrays */
+    int size;
+    int *indices;
+    int *reverses;
+    su_wait_t *waits;
+    su_wakeup_f *wait_cbs;
+    su_wakeup_arg_t **wait_args;
+    su_root_t **wait_tasks;
+
+    if (self->sup_size_waits == 0)
+      size = su_root_size_hint;
+    else 
+      size = 2 * self->sup_size_waits;
+
+    if (size < SU_WAIT_MIN)
+      size = SU_WAIT_MIN;
+
+    /* Too large */
+    if (-3 - size > 0)
+      return (errno = ENOMEM), -1;
+
+    indices = realloc(self->sup_indices, (size + 1) * sizeof(*indices));
+    if (indices) {
+      self->sup_indices = indices;
+
+      for (i = self->sup_size_waits; i <= size; i++)
+	indices[i] = -1 - i;
+    }
+
+    reverses = realloc(self->sup_reverses, size * sizeof(*waits));
+    if (reverses) {
+      for (i = self->sup_size_waits; i < size; i++)
+	reverses[i] = -1;
+      self->sup_reverses = reverses;
+    }
+      
+    sources = realloc(self->sup_sources, size * sizeof(*sources));
+    if (sources)
+      self->sup_sources = sources;
+
+    sockets = realloc(self->sup_sockets, size * sizeof(*sockets));
+    if (sockets)
+      self->sup_sockets = sockets;
+
+    waits = realloc(self->sup_waits, size * sizeof(*waits));
+    if (waits)
+      self->sup_waits = waits;
+
+    wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+    if (wait_cbs)
+      self->sup_wait_cbs = wait_cbs;
+
+    wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+    if (wait_args)
+      self->sup_wait_args = wait_args;
+
+    /* Add sup_wait_roots array, if needed */
+    wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+    if (wait_tasks) 
+      self->sup_wait_roots = wait_tasks;
+
+    if (!(indices && 
+	  reverses && sources && sockets && waits && wait_cbs && wait_args && wait_tasks)) {
+      return -1;
+    }
+
+    self->sup_size_waits = size;
+  }
+
+  i = -self->sup_indices[0]; assert(i <= self->sup_size_waits);
+
+  if (priority > 0) {
+    /* Insert */
+    for (n = self->sup_n_waits; n > 0; n--) {
+      j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1);
+      self->sup_indices[j] = n;
+      self->sup_reverses[n] = self->sup_reverses[n-1];
+      self->sup_sources[n] = self->sup_sources[n-1];
+      self->sup_sockets[n] = self->sup_sockets[n-1];
+      self->sup_waits[n] = self->sup_waits[n-1];
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+      self->sup_wait_args[n] = self->sup_wait_args[n-1];
+      self->sup_wait_roots[n] = self->sup_wait_roots[n-1];	
+    }
+
+    self->sup_pri_offset++;
+  }
+  else {
+    /* Append - no need to move anything */
+    n = self->sup_n_waits;
+  }
+
+  self->sup_n_waits++;
+
+  self->sup_indices[0] = self->sup_indices[i];  /* Free index */
+  self->sup_indices[i] = n;
+
+  self->sup_reverses[n] = i;
+  self->sup_waits[n] = *wait;
+  self->sup_wait_cbs[n] = callback;
+  self->sup_wait_args[n] = arg;
+  self->sup_wait_roots[n] = root;
+
+  self->sup_registers++;
+
+  /* XXX -- mela: leak, leak -- free() somewheeeere */
+  osx_magic = calloc(1, sizeof(*osx_magic));
+  osx_magic->o_port = self;
+  osx_magic->o_current = i;
+  osx_magic->o_count = ++o_count;
+  cf_socket_cntx->info = osx_magic;
+
+  events = map_poll_event_to_cf_event(wait->events);
+
+  cf_socket = CFSocketCreateWithNative(NULL,
+				       (CFSocketNativeHandle) su_wait_socket(wait),
+				       events, su_port_osx_socket_cb, cf_socket_cntx);
+
+  flags = CFSocketGetSocketFlags(cf_socket);
+  flags &= ~kCFSocketCloseOnInvalidate;
+
+  CFSocketSetSocketFlags(cf_socket, flags);
+
+  CFRetain(cf_socket);
+  source = CFSocketCreateRunLoopSource(NULL, cf_socket, 0);
+
+  SU_DEBUG_9(("source(%p): count %u index %d\n", source, o_count, i));
+
+  rl = CFRunLoopGetCurrent();
+
+  CFRunLoopAddSource(rl, source, kCFRunLoopDefaultMode);
+
+  CFRetain(source);
+  self->sup_sources[n] = source;
+  self->sup_sockets[n] = cf_socket;
+
+  CFRunLoopWakeUp(rl);
+
+  /* Just like epoll, we return -1 or positive integer */
+
+  return i;
+}
+
+/** Deregister a su_wait_t object. */
+static
+int su_port_osx_deregister0(su_port_t *self, int i)
+{
+  CFRunLoopRef rl;
+  int n, N, *indices, *reverses;
+
+  indices = self->sup_indices;
+  reverses = self->sup_reverses;
+
+  n = indices[i]; assert(n >= 0); assert(i == reverses[n]);
+
+  N = --self->sup_n_waits;
+  
+  rl = CFRunLoopGetCurrent();
+  CFSocketInvalidate(self->sup_sockets[n]);
+  CFRelease(self->sup_sockets[n]);
+  CFRunLoopRemoveSource(rl, self->sup_sources[n], kCFRunLoopDefaultMode);
+  CFRelease(self->sup_sources[n]);
+
+  CFRunLoopWakeUp(rl);
+
+  if (n < self->sup_pri_offset) {
+    int j = --self->sup_pri_offset;
+    if (n != j) {
+      assert(reverses[j] > 0);
+      assert(indices[reverses[j]] == j);
+      indices[reverses[j]] = n;
+      reverses[n] = reverses[j];
+
+      self->sup_sources[n] = self->sup_sources[j];
+      self->sup_sockets[n] = self->sup_sockets[j];
+      self->sup_waits[n] = self->sup_waits[j];
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[j];
+      self->sup_wait_args[n] = self->sup_wait_args[j];
+      self->sup_wait_roots[n] = self->sup_wait_roots[j];
+      n = j;
+    }
+  }
+
+  if (n < N) {
+    assert(reverses[N] > 0);
+    assert(indices[reverses[N]] == N);
+
+    indices[reverses[N]] = n;
+    reverses[n] = reverses[N];
+
+    self->sup_sources[n] = self->sup_sources[N];
+    self->sup_sockets[n] = self->sup_sockets[N];
+    self->sup_waits[n] = self->sup_waits[N];
+    self->sup_wait_cbs[n] = self->sup_wait_cbs[N];
+    self->sup_wait_args[n] = self->sup_wait_args[N];
+    self->sup_wait_roots[n] = self->sup_wait_roots[N];
+    n = N;
+  }
+
+
+  reverses[n] = -1;
+  memset(&self->sup_waits[n], 0, sizeof self->sup_waits[n]);
+  self->sup_sources[n] = NULL;
+  self->sup_sockets[n] = NULL;
+  self->sup_wait_cbs[n] = NULL;
+  self->sup_wait_args[n] = NULL;
+  self->sup_wait_roots[n] = NULL;
+  
+  indices[i] = indices[0];
+  indices[0] = -i;
+
+  self->sup_registers++;
+
+  return i;
+}
+
+
+/** Unregister a su_wait_t object.
+ *  
+ *  The function su_port_osx_unregister() unregisters a su_wait_t object. The
+ *  wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param root     - pointer to root object
+ * @param wait     - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg      - argument given to callback function when it is invoked 
+ *                   (may be NULL)
+ * 
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_port_osx_unregister(su_port_t *self,
+		       su_root_t *root, 
+		       su_wait_t *wait,	
+		       su_wakeup_f callback, /* XXX - ignored */
+		       su_wakeup_arg_t *arg)
+{
+  int n, N;
+
+  assert(self);
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  N = self->sup_n_waits;
+
+  for (n = 0; n < N; n++) {
+    if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) == 0) {
+      return su_port_osx_deregister0(self, self->sup_reverses[n]);
+    }
+  }
+
+  su_seterrno(ENOENT);
+
+  return -1;
+}
+
+/** Deregister a su_wait_t object.
+ *  
+ *  The function su_port_osx_deregister() deregisters a su_wait_t registrattion. 
+ *  The wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param i        - registration index
+ * 
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_port_osx_deregister(su_port_t *self, int i)
+{
+  su_wait_t wait[1] = { SU_WAIT_INIT };
+  int retval;
+
+  assert(self);
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  if (i <= 0 || i > self->sup_size_waits)
+    return su_seterrno(EBADF);
+
+  if (self->sup_indices[i] < 0)
+    return su_seterrno(EBADF);
+    
+  retval = su_port_osx_deregister0(self, i);
+
+  su_wait_destroy(wait);
+
+  return retval;
+}
+
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_port_osx_unregister_all() unregisters all su_wait_t objects
+ * and destroys all queued timers associated with given root object.
+ * 
+ * @param  self     - pointer to port object
+ * @param  root     - pointer to root object
+ * 
+ * @return Number of wait objects removed.
+ */
+int su_port_osx_unregister_all(su_port_t *self, 
+			   su_root_t *root)
+{
+  int i, j, index, N;
+  int                *indices, *reverses;
+  su_wait_t          *waits;
+  su_wakeup_f        *wait_cbs;
+  su_wakeup_arg_t   **wait_args;
+  su_root_t         **wait_roots;
+  CFRunLoopRef        rl;
+  CFRunLoopSourceRef *sources;
+  CFSocketRef        *sockets;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  N          = self->sup_n_waits;
+  indices    = self->sup_indices;
+  reverses   = self->sup_reverses;
+  sources    = self->sup_sources; 
+  sockets    = self->sup_sockets; 
+  waits      = self->sup_waits; 
+  wait_cbs   = self->sup_wait_cbs; 
+  wait_args  = self->sup_wait_args;
+  wait_roots = self->sup_wait_roots; 
+  
+  rl = CFRunLoopGetCurrent();
+
+  for (i = j = 0; i < N; i++) {
+    index = reverses[i]; assert(index > 0 && indices[index] == i);
+
+    if (wait_roots[i] == root) {
+      if (i < self->sup_pri_offset)
+	self->sup_pri_offset--;
+
+      indices[index] = indices[0];
+      indices[0] = -index;
+      continue;
+    }
+
+    if (i != j) {
+      indices[index] = j;
+
+      CFSocketInvalidate(self->sup_sockets[j]);
+      CFRelease(self->sup_sockets[j]);
+      CFRunLoopRemoveSource(rl, sources[j], kCFRunLoopDefaultMode);
+      CFRelease(sources[j]);
+
+      reverses[j]   = reverses[i];
+      sources[j]    = sources[i];
+      sockets[j]    = sockets[i];
+      waits[j]      = waits[i];
+      wait_cbs[j]   = wait_cbs[i];
+      wait_args[j]  = wait_args[i];
+      wait_roots[j] = wait_roots[i];
+    }
+    
+    j++;
+  }
+
+  /* Prepare for removing CFSources */
+  for (i = j; i < N; i++) {
+    reverses[i] = -1;
+
+    CFSocketInvalidate(self->sup_sockets[i]);
+    CFRelease(self->sup_sockets[i]);
+    CFRunLoopRemoveSource(rl, sources[i], kCFRunLoopDefaultMode);
+    CFRunLoopSourceInvalidate(sources[i]);
+
+    sources[i] = NULL;
+    sockets[i] = NULL;
+    wait_cbs[i] = NULL;
+    wait_args[i] = NULL;
+    wait_roots[i] = NULL;
+  }
+  memset(&waits[j], 0, (char *)&waits[N] - (char *)&waits[j]);
+
+  /* Tell run loop things have changed */
+  CFRunLoopWakeUp(rl);
+
+  self->sup_n_waits = j;
+  self->sup_registers++;
+
+  return N - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_port_osx_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port   pointer to port object
+ * @param index  registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_port_osx_eventmask(su_port_t *self, int index, int socket, int events)
+{
+  int n, ret;
+
+  assert(self);
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  if (index <= 0 || index > self->sup_size_waits)
+    return su_seterrno(EBADF);
+  n = self->sup_indices[index];
+  if (n < 0)
+    return su_seterrno(EBADF);
+
+  ret = su_wait_mask(&self->sup_waits[n], socket, events);
+
+  CFSocketSetSocketFlags(self->sup_sockets[n],
+			 map_poll_event_to_cf_event(events));
+  
+  return ret;
+}
+
+/** @internal
+ *
+ *  Copies the su_wait_t objects from the port. The number of wait objects
+ *  can be found out by calling su_port_osx_query() with @a n_waits as zero.
+ * 
+ * @note This function is called only by friends.
+ *
+ * @param self     - pointer to port object
+ * @param waits    - pointer to array to which wait objects are copied
+ * @param n_waits  - number of wait objects fitting in array waits
+ *
+ * @return Number of wait objects, or 0 upon an error.
+ */
+unsigned su_port_osx_query(su_port_t *self, su_wait_t *waits, unsigned n_waits)
+{
+  unsigned n;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  n = self->sup_n_waits;
+
+  if (n_waits != 0) {
+    if (waits && n_waits >= n)
+      memcpy(waits, self->sup_waits, n * sizeof(*waits));
+    else
+      n = 0;
+  }
+
+  return n;
+}
+
+/** @internal Enable multishot mode.
+ *
+ * The function su_port_osx_multishot() enables, disables or queries the
+ * multishot mode for the port. The multishot mode determines how the events
+ * are scheduled by port. If multishot mode is enabled, port serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self      pointer to port object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ * 
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_port_osx_multishot(su_port_t *self, int multishot)
+{
+  if (multishot < 0)
+    return self->sup_multishot;
+  else if (multishot == 0 || multishot == 1)
+    return self->sup_multishot = multishot;
+  else 
+    return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_port_osx_threadsafe(su_port_t *port)
+{
+  return su_home_threadsafe(port->sup_home);
+}
+
+/** Prepare root to be run on OSX Run Loop.
+ *
+ * Sets #su_root_t object to be callable by the application's run loop. This
+ * function is to be used instead of su_root_run() for OSX applications
+ * using Core Foundation's Run Loop.
+ *
+ * The function su_root_osx_prepare_run() returns immmediately.
+ * 
+ * @param root     pointer to root object
+ * 
+ * @NEW_1_12_4.
+ */
+void su_root_osx_prepare_run(su_root_t *root)
+{
+  su_port_t *self = root->sur_task->sut_port;
+  CFRunLoopRef rl;
+  su_duration_t tout = 0;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  enter;
+
+  self->sup_running = 1;
+  rl = CFRunLoopGetCurrent();
+
+  if (self->sup_prepoll)
+    self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+  if (self->sup_head)
+    su_port_osx_getmsgs(self);
+  
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, su_now());
+
+  if (!self->sup_running)
+    return;
+
+  CFRetain(rl);
+  self->sup_main_loop = rl;
+
+  return;
+}
+
+/** @internal Main loop.
+ * 
+ * The function @c su_port_osx_run() waits for wait objects and the timers
+ * associated with the port object.  When any wait object is signaled or
+ * timer is expired, it invokes the callbacks, and returns waiting.
+ * 
+ * The function @c su_port_osx_run() runs until @c su_port_osx_break() is called
+ * from a callback.
+ * 
+ * @param self     pointer to port object
+ * 
+ */
+void su_port_osx_run(su_port_t *self)
+{
+  CFRunLoopRef rl;
+  su_duration_t tout = 0;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  enter;
+
+  self->sup_running = 1;
+  rl = CFRunLoopGetCurrent();
+
+  if (self->sup_prepoll)
+    self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+  if (self->sup_head)
+    su_port_osx_getmsgs(self);
+  
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, su_now());
+
+  if (!self->sup_running)
+    return;
+
+  CFRetain(rl);
+  self->sup_main_loop = rl;
+
+  /* if there are messages do a quick wait */
+  if (self->sup_head)
+    tout = 0;
+
+  CFRunLoopRun();
+
+  self->sup_main_loop = NULL;
+
+}
+
+#if tuning
+/* This version can help tuning... */
+void su_port_osx_run_tune(su_port_t *self)
+{
+  int i;
+  int timers = 0, messages = 0, events = 0;
+  su_duration_t tout = 0, tout0;
+  su_time_t started = su_now(), woken = started, bedtime = woken;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  for (self->sup_running = 1; self->sup_running;) {
+    tout0 = tout, tout = 2000;
+
+    timers = 0, messages = 0;
+
+    if (self->sup_prepoll)
+      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+    if (self->sup_head)
+      messages = su_port_osx_getmsgs(self);
+
+    if (self->sup_timers)
+      timers = su_timer_expire(&self->sup_timers, &tout, su_now());
+
+    if (!self->sup_running)
+      break;
+
+    if (self->sup_head)      /* if there are messages do a quick wait */
+      tout = 0;
+
+    bedtime = su_now();
+
+    events = su_port_osx_wait_events(self, tout);
+
+    woken = su_now();
+
+    if (messages || timers || events)
+      SU_DEBUG_1(("su_port_osx_run(%p): %.6f: %u messages %u timers %u "
+		  "events slept %.6f/%.3f\n",
+		  self, su_time_diff(woken, started), messages, timers, events,
+		  su_time_diff(woken, bedtime), tout0 * 1e-3));
+
+    if (!self->sup_running)
+      break;
+  }
+}
+#endif
+
+/** @internal
+ * The function @c su_port_osx_break() is used to terminate execution of @c
+ * su_port_osx_run(). It can be called from a callback function.
+ * 
+ * @param self     pointer to port
+ * 
+ */
+void su_port_osx_break(su_port_t *self)
+{
+  if (self->sup_main_loop)
+    CFRunLoopStop(self->sup_main_loop);
+
+  self->sup_running = 0; 
+}
+
+/** @internal
+ * The function @c su_port_osx_wait_events() is used to poll() for wait objects
+ *
+ * @param self     pointer to port
+ * @param tout     timeout in milliseconds
+ *
+ * @return number of events handled
+ */
+static
+int su_port_osx_wait_events(su_port_t *self, su_duration_t tout)
+{
+  int i, events = 0;
+  su_wait_t *waits = self->sup_waits;
+  unsigned n = self->sup_n_waits;
+#if HAVE_POLL
+  unsigned version = self->sup_registers;
+#endif
+  su_root_t *root;
+
+  i = su_wait(waits, n, tout);
+
+  if (i >= 0 && (unsigned)i < n) {
+#if HAVE_POLL			
+    /* poll() can return events for multiple wait objects */
+    if (self->sup_multishot) {
+      for (; i < n; i++) {
+        if (waits[i].revents) {
+          root = self->sup_wait_roots[i];
+          self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+                                &waits[i],
+                                self->sup_wait_args[i]);
+          events++;
+          /* Callback function used su_register()/su_deregister() */
+          if (version != self->sup_registers)
+            break;
+        }
+      }
+    }
+#else /* !HAVE_POLL */
+    if (0) {
+    }
+#endif
+    else {
+      root = self->sup_wait_roots[i];
+      self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+                            &self->sup_waits[i],
+                            self->sup_wait_args[i]);
+      events++;
+    }
+  }
+
+  return events;
+}
+
+/** @internal 
+ * Used to check wait events in callbacks that take lots of time
+ *
+ * This function does a timeout 0 poll() and runs wait objects.
+ *
+ * @param port     pointer to port
+ *
+ * @return number of events handled
+ */
+static
+int su_port_osx_yield(su_port_t *port)
+{
+  return su_port_osx_wait_events(port, 0);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with 
+ * the root object.  When any wait object is signaled or timer is
+ * expired, it invokes the callbacks. 
+ * 
+ *   This function returns when a callback has been invoked or @c tout
+ *   milliseconds is elapsed. 
+ *
+ * @param self     pointer to port
+ * @param tout     timeout in milliseconds
+ * 
+ * @return
+ *   Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ *   there are no active timers.
+ */
+su_duration_t su_port_osx_step(su_port_t *self, su_duration_t tout)
+{
+  CFRunLoopRef rl;
+  su_time_t now = su_now();
+  CFAbsoluteTime start;
+  int ret, timeout = tout > INT32_MAX ? INT32_MAX : tout;
+
+  assert(SU_PORT_OSX_OWN_THREAD(self));
+
+  rl = CFRunLoopGetCurrent();
+
+  if (!rl)
+    return -1;
+
+  CFRunLoopWakeUp(rl);
+
+  if (tout < timeout)
+    timeout = tout;
+
+  if (self->sup_prepoll)
+    self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+  if (self->sup_head)
+    su_port_osx_getmsgs(self);
+
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, now);
+
+  /* if there are messages do a quick wait */
+  if (self->sup_head)
+    tout = 0;
+
+  start = CFAbsoluteTimeGetCurrent();
+  for (;;) {
+    /* Run loop with only one pass, indicate if a source was processed */
+    ret = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+			     0,
+			     TRUE);
+
+    /* Ok, one of our sources was fired */
+    if (self->sup_source_fired == 1) {
+      self->sup_source_fired = 0;
+      break;
+    }
+
+    /* Check how long to run this loop */
+    if (CFAbsoluteTimeGetCurrent() >= start + timeout / 1000)
+      break;
+  }
+  
+  if (self->sup_head)
+    su_port_osx_getmsgs(self);
+
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, su_now());
+
+  if (self->sup_head)
+    tout = 0;
+
+  return tout;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_port_osx_own_thread(su_port_t const *self)
+{
+  return self == NULL || SU_PORT_OSX_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ *  Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f    pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_port_osx_dump(su_port_t const *self, FILE *f)
+{
+  int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+  if (f == NULL)
+    f = stdout;
+
+  fprintf(f, "su_port_osx_t at %p:\n", self);
+  fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+#if SU_HAVE_PTHREADS
+  fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+#endif
+#if SU_HAVE_MBOX
+  fprintf(f, "\tport mbox %d (%s%s%s)\n", self->sup_mbox[0],
+	  IS_WAIT_IN(&self->sup_mbox_wait),
+	  IS_WAIT_OUT(&self->sup_mbox_wait),
+	  IS_WAIT_ACCEPT(&self->sup_mbox_wait));
+#endif
+  fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+  for (i = 0; i < self->sup_n_waits; i++) {
+    
+  }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_port_osx_add_prepoll(su_port_t *port,
+			su_root_t *root, 
+			su_prepoll_f *callback, 
+			su_prepoll_magic_t *magic)
+{
+  if (port->sup_prepoll)
+    return -1;
+
+  port->sup_prepoll = callback;
+  port->sup_pp_magic = magic;
+  port->sup_pp_root = root;
+
+  return 0;
+}
+
+int su_port_osx_remove_prepoll(su_port_t *port,
+			   su_root_t *root)
+{
+  if (port->sup_pp_root != root)
+    return -1;
+
+  port->sup_prepoll = NULL;
+  port->sup_pp_magic = NULL;
+  port->sup_pp_root = NULL;
+
+  return 0;
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_port_osx_timers(su_port_t *self)
+{
+  return &self->sup_timers;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE su_perf.c
+ *
+ * Performance test for su message passing
+ *
+ * @internal
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+struct perf;
+#define SU_ROOT_MAGIC_T struct perf
+#define SU_MSG_ARG_T    struct message
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+
+struct perf {
+  enum { PINGER = 1, PONGER = 2 } const sort;
+  char const *const name;
+  unsigned          running : 1;
+  unsigned          target;
+  unsigned          n;
+  su_root_t        *root;
+  struct sockaddr_in sin;
+};
+
+struct message {
+  su_time_t started;
+};
+
+void
+do_exit(struct perf *x, su_msg_r msg, struct message *m)
+{
+  su_root_break(su_task_root(su_msg_to(msg)));
+}
+
+int
+do_init(su_root_t *root, struct perf *p)
+{
+  p->root = root;
+  return 0;
+}
+
+void
+do_print(struct perf *p, su_msg_r msg, struct message *m)
+{
+  su_time_t now = su_now();
+  double dur = su_time_diff(now, m->started);
+  
+  printf("su_perf: %g message exchanges per second"
+	 " (%d message exchanges in %g seconds)\n",
+	 (double)p->n / dur, p->n, dur);
+  su_msg_create(msg, su_root_parent(p->root), su_root_task(p->root),
+		do_exit, sizeof(*m));
+  *su_msg_data(msg) = *m;
+  su_msg_send(msg);
+}
+
+void
+do_ping(struct perf *p, su_msg_r msg, struct message *m)
+{
+  if (p->sort == PINGER) {
+    p->n++;
+
+    if (p->n % 100 == 0) {
+      if (su_duration(su_now(), m->started) > p->target) {
+	do_print(p, msg, m);
+	return;
+      }
+    }
+  }
+
+  su_msg_reply(msg, msg, do_ping, sizeof(*m));
+  *su_msg_data(msg) = *m;
+  su_msg_send(msg);
+}
+
+void
+do_destroy(su_root_t *t, struct perf *p)
+{
+  p->running = 0;
+}
+
+void usage(char *name)
+{
+  fprintf(stderr, "usage: %s [-1] [n]\n", name);
+  exit(2);
+}
+
+/*
+ * Measure how many message passes can be done in a second.
+ *
+ * Create a ponger and pinger, responding to incoming message do_ping
+ *
+ * After "target" rounds, print out elapsed time and number of messages 
+ * passed.
+ *
+ */
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+  su_msg_r start_msg = SU_MSG_R_INIT;
+
+  struct perf 
+    pinger = { PINGER, "ping", 1, 0 }, 
+    ponger = { PONGER, "pong", 1, 0x7fffffff};
+
+  int have_threads = 1;
+  char *argv0 = argv[0];
+  char *argv1 = argv[1];
+
+  if (argv1 && strcmp(argv1, "-1") == 0)
+    have_threads = 0, argv1 = argv[2];
+
+  if (!argv1)
+    argv1 = "10000";
+
+  if (strlen(argv1) != strspn(argv1, "0123456789"))
+    usage(argv0);
+
+  pinger.target = strtoul(argv1, NULL, 0);
+
+  su_init(); atexit(su_deinit);
+
+  root = su_root_create(NULL);
+  
+  su_root_threading(root, have_threads);
+
+  if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1);
+  if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1); 
+
+  if (su_msg_create(start_msg, su_clone_task(pong), su_clone_task(ping), 
+		    do_ping, sizeof(struct message)) == 0) {
+    su_msg_data(start_msg)->started = su_now();
+    su_msg_send(start_msg);
+
+    su_root_run(root);
+  }
+
+#if 0
+  su_clone_wait(root, ping);
+  su_clone_wait(root, pong);
+
+  while (pinger.running || ponger.running)
+    su_root_step(root, 100L);
+#endif
+
+  su_root_destroy(root);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1480 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_port.c
+ *
+ * OS-Independent Socket Syncronization Interface.
+ *
+ * This looks like nth reincarnation of "reactor".  It implements the
+ * poll/select/WaitForMultipleObjects and message passing functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+/* React to multiple events per one poll() to make sure 
+ * that high-priority events can never completely mask other events.
+ * Enabled by default on all platforms except WIN32 */
+#ifndef WIN32
+#define SU_ENABLE_MULTISHOT_POLL 1
+#else
+#define SU_ENABLE_MULTISHOT_POLL 0
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+#if SU_HAVE_PTHREADS
+/* Pthread implementation */
+#include <pthread.h>
+#define SU_HAVE_MBOX 1
+#else
+#define SU_HAVE_MBOX 0
+#endif
+
+#if HAVE_SOCKETPAIR
+#define MBOX_SEND  1
+#else
+#define MBOX_SEND  0
+#endif
+
+#if HAVE_EPOLL
+#include <sys/epoll.h>
+
+#define POLL2EPOLL_NEEDED \
+  (POLLIN != EPOLLIN || POLLOUT != EPOLLOUT || POLLPRI != EPOLLPRI || \
+   POLLERR != EPOLLERR || POLLHUP != EPOLLHUP)
+ 
+#define POLL2EPOLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))
+#define EPOLL2POLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))
+
+#endif
+
+static void su_port_lock(su_port_t *self, char const *who);
+static void su_port_unlock(su_port_t *self, char const *who);
+static void su_port_incref(su_port_t *self, char const *who);
+static void su_port_decref(su_port_t *self, int blocking, char const *who);
+
+static struct _GSource *su_port_gsource(su_port_t *port);
+
+static int su_port_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_port_register(su_port_t *self,
+			    su_root_t *root, 
+			    su_wait_t *wait, 
+			    su_wakeup_f callback,
+			    su_wakeup_arg_t *arg,
+			    int priority);
+static int su_port_unregister(su_port_t *port,
+			      su_root_t *root, 
+			      su_wait_t *wait,	
+			      su_wakeup_f callback, 
+			      su_wakeup_arg_t *arg);
+
+static int su_port_deregister(su_port_t *self, int i);
+
+static int su_port_unregister_all(su_port_t *self,
+			   su_root_t *root);
+static
+int su_port_eventmask(su_port_t *self, int index, int socket, int events);
+static
+void su_port_run(su_port_t *self);
+static
+void su_port_break(su_port_t *self);
+static
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout);
+
+static
+int su_port_own_thread(su_port_t const *port);
+
+static
+int su_port_add_prepoll(su_port_t *port,
+			su_root_t *root, 
+			su_prepoll_f *, 
+			su_prepoll_magic_t *);
+
+static
+int su_port_remove_prepoll(su_port_t *port,
+			   su_root_t *root);
+
+static
+su_timer_t **su_port_timers(su_port_t *port);
+
+static
+int su_port_multishot(su_port_t *port, int multishot);
+
+static
+int su_port_threadsafe(su_port_t *port);
+
+static
+int su_port_yield(su_port_t *port);
+
+su_port_vtable_t const su_port_vtable[1] =
+  {{
+      /* su_vtable_size: */ sizeof su_port_vtable,
+      su_port_lock,
+      su_port_unlock,
+      su_port_incref,
+      su_port_decref,
+      su_port_gsource,
+      su_port_send,
+      su_port_register,
+      su_port_unregister,
+      su_port_deregister,
+      su_port_unregister_all,
+      su_port_eventmask,
+      su_port_run,
+      su_port_break,
+      su_port_step,
+      su_port_own_thread,
+      su_port_add_prepoll,
+      su_port_remove_prepoll,
+      su_port_timers,
+      su_port_multishot,
+      su_port_threadsafe,
+      su_port_yield
+    }};
+
+static int su_port_wait_events(su_port_t *self, su_duration_t tout);
+
+
+/** 
+ * Port is a per-thread reactor.  
+ *
+ * Multiple root objects executed by single thread share a su_port_t object. 
+ */
+struct su_port_s {
+  su_home_t        sup_home[1];
+
+  su_port_vtable_t const *sup_vtable;
+  
+  unsigned         sup_running;
+
+#if SU_HAVE_PTHREADS
+  pthread_t        sup_tid;
+  pthread_mutex_t  sup_mutex[1];
+#if __CYGWIN__
+  pthread_mutex_t  sup_reflock[1];
+  int              sup_ref;
+#else
+  pthread_rwlock_t sup_ref[1];
+#endif
+#else
+  int              sup_ref;
+#endif
+
+#if SU_HAVE_MBOX
+  su_socket_t      sup_mbox[MBOX_SEND + 1];
+  su_wait_t        sup_mbox_wait;
+#endif
+
+#if HAVE_EPOLL
+  /** epoll() fd */
+  int              sup_epoll;
+#endif
+
+  unsigned         sup_multishot; /**< Multishot operation? */
+
+  unsigned         sup_registers; /** Counter incremented by 
+				      su_port_register() or 
+				      su_port_unregister()
+				   */
+  int              sup_n_waits; /**< Active su_wait_t in su_waits */
+  int              sup_size_waits; /**< Size of allocate su_waits */
+
+  int              sup_pri_offset; /**< Offset to prioritized waits */
+
+#if !SU_HAVE_WINSOCK
+#define INDEX_MAX (0x7fffffff)
+#else 
+  /* We use WSAWaitForMultipleEvents() */
+#define INDEX_MAX (64)
+#endif
+
+  /** Indices from index returned by su_root_register() to tables below. 
+   *
+   * Free elements are negative. Free elements form a list, value of free
+   * element is (0 - index of next free element).
+   *
+   * First element sup_indices[0] points to first free element. 
+   */
+  int             *sup_indices;
+
+  int             *sup_reverses; /** Reverse index */
+  su_wakeup_f     *sup_wait_cbs; 
+  su_wakeup_arg_t**sup_wait_args; 
+  su_root_t      **sup_wait_roots; 
+
+  su_wait_t       *sup_waits; 
+
+  /* Pre-poll callback */
+  su_prepoll_f    *sup_prepoll; 
+  su_prepoll_magic_t *sup_pp_magic;
+  su_root_t       *sup_pp_root;
+
+  /* Timer list */
+  su_timer_t      *sup_timers;
+
+  /* Message list - this is protected by lock  */
+  su_msg_t        *sup_head;
+  su_msg_t       **sup_tail;
+};
+
+#if SU_HAVE_PTHREADS
+#define SU_PORT_OWN_THREAD(p)   (pthread_equal((p)->sup_tid, pthread_self()))
+
+#if __CYGWIN__
+
+/* Debugging versions */
+#define SU_PORT_INITREF(p)      (pthread_mutex_init((p)->sup_reflock, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_INCREF(p, f)    (pthread_mutex_lock(p->sup_reflock), p->sup_ref++, pthread_mutex_unlock(p->sup_reflock), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_DECREF(p, f)    do {					\
+    pthread_mutex_lock(p->sup_reflock);	p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+    if ((p->sup_ref) == 0) {			\
+      printf("decref(%p) to 0 by %s\n", (p), f); su_port_destroy(p); }	\
+    else { printf("decref(%p) to %u by %s\n", (p), p->sup_ref, f); }  } while(0)
+
+#define SU_PORT_ZAPREF(p, f)    do { printf("zapref(%p) by %s\n", (p), f), \
+    pthread_mutex_lock(p->sup_reflock);	p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+  if ((p->sup_ref) != 0) { \
+    assert(!"SU_PORT_ZAPREF"); } \
+  su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p) \
+   (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_LOCK(p, f)    \
+   (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_UNLOCK(p, f)  \
+  (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#elif 1
+#define SU_PORT_INITREF(p)      (pthread_rwlock_init(p->sup_ref, NULL))
+#define SU_PORT_INCREF(p, f)    (pthread_rwlock_rdlock(p->sup_ref))
+#define SU_PORT_DECREF(p, f)    do { pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) == 0) su_port_destroy(p); } while(0)
+
+#define SU_PORT_ZAPREF(p, f)    do { pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+    assert(!"SU_PORT_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+  su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p)     (pthread_mutex_init((p)->sup_mutex, NULL))
+#define SU_PORT_LOCK(p, f)      (pthread_mutex_lock((p)->sup_mutex))
+#define SU_PORT_UNLOCK(p, f)    (pthread_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_PORT_INITREF(p)      (pthread_rwlock_init((p)->sup_ref, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_INCREF(p, f)    (pthread_rwlock_rdlock(p->sup_ref), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_DECREF(p, f)    do {					\
+    pthread_rwlock_unlock(p->sup_ref);					\
+    if (pthread_rwlock_trywrlock(p->sup_ref) == 0) {			\
+      printf("decref(%p) to 0 by %s\n", (p), f); su_port_destroy(p); }	\
+    else { printf("decref(%p) by %s\n", (p), f); }  } while(0)
+
+#define SU_PORT_ZAPREF(p, f)    do { printf("zapref(%p) by %s\n", (p), f), \
+  pthread_rwlock_unlock(p->sup_ref); \
+  if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+    assert(!"SU_PORT_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+  su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p) \
+   (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_LOCK(p, f)    \
+   (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_UNLOCK(p, f)  \
+  (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#endif
+
+#else /* !SU_HAVE_PTHREADS */
+
+#define SU_PORT_OWN_THREAD(p)  1
+#define SU_PORT_INITLOCK(p)    (void)(p)
+#define SU_PORT_LOCK(p, f)      (void)(p)
+#define SU_PORT_UNLOCK(p, f)    (void)(p)
+#define SU_PORT_ZAPREF(p, f)    ((p)->sup_ref--)
+
+#define SU_PORT_INITREF(p)      ((p)->sup_ref = 1)
+#define SU_PORT_INCREF(p, f)    ((p)->sup_ref++)
+#define SU_PORT_DECREF(p, f) \
+do { if (--((p)->sup_ref) == 0) su_port_destroy(p); } while (0);
+
+#endif
+
+#if SU_HAVE_MBOX
+static int su_port_wakeup(su_root_magic_t *magic, 
+			  su_wait_t *w,
+			  su_wakeup_arg_t *arg);
+#endif
+
+static void su_port_destroy(su_port_t *self);
+
+/**@internal
+ *
+ * Allocates and initializes a message port. It creates a mailbox used to.
+ * wake up the tasks waiting on the port if needed.  Currently, the
+ * mailbox is simply an UDP socket connected to itself.
+ *
+ * @return
+ *   If successful a pointer to the new message port is returned, otherwise
+ *   NULL is returned.  
+ */
+su_port_t *su_port_create(void)
+{
+  su_port_t *self;
+
+  SU_DEBUG_9(("su_port_create() called\n"));
+
+  self = su_home_clone(NULL, sizeof(*self));
+
+  if (self) {
+#if SU_HAVE_MBOX
+    int af;
+    su_socket_t mb = INVALID_SOCKET;
+    char const *why;
+#endif
+
+    self->sup_vtable = su_port_vtable;
+    
+    SU_PORT_INITREF(self);
+    SU_PORT_INITLOCK(self);
+    self->sup_tail = &self->sup_head;
+
+    self->sup_multishot = (SU_ENABLE_MULTISHOT_POLL) != 0;
+
+#if SU_HAVE_PTHREADS
+    self->sup_tid = pthread_self();
+#endif
+
+#if HAVE_EPOLL
+    self->sup_epoll = epoll_create(su_root_size_hint);
+    if (self->sup_epoll == -1)
+      SU_DEBUG_3(("su_port(%p): epoll_create(): %s\n", self, strerror(errno)));
+    else
+      SU_DEBUG_9(("su_port(%p): epoll_create() => %u: OK\n",
+		  self, self->sup_epoll));
+#endif
+  
+#if SU_HAVE_MBOX
+#if HAVE_SOCKETPAIR
+#if defined(AF_LOCAL)
+    af = AF_LOCAL;
+#else
+    af = AF_UNIX;
+#endif
+    if (socketpair(af, SOCK_STREAM, 0, self->sup_mbox) == -1) {
+      why = "su_port_init: socketpair"; goto error;
+    }
+
+    mb = self->sup_mbox[0];
+    su_setblocking(self->sup_mbox[0], 0);
+    su_setblocking(self->sup_mbox[1], 0);
+#else
+    {
+      struct sockaddr_in sin = { sizeof(struct sockaddr_in), 0 };
+      socklen_t sinsize = sizeof sin;
+      struct sockaddr *sa = (struct sockaddr *)&sin;
+
+      af = PF_INET;
+
+      self->sup_mbox[0] = mb = su_socket(af, SOCK_DGRAM, IPPROTO_UDP);
+      if (mb == INVALID_SOCKET) {
+	why = "su_port_init: socket"; goto error;
+      }
+  
+      sin.sin_family = AF_INET;
+      sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.1 */
+      
+      /* Get a port for us */
+      if (bind(mb, sa, sizeof sin) == -1) {
+	why = "su_port_init: bind"; goto error;
+      }
+
+      if (getsockname(mb, sa, &sinsize) == -1) {
+	why = "su_port_init: getsockname"; goto error;
+      }
+    
+      if (connect(mb, sa, sinsize) == -1) {
+	why = "su_port_init: connect"; goto error;
+      }
+    }
+#endif    
+
+    if (su_wait_create(&self->sup_mbox_wait, mb, SU_WAIT_IN) == -1) {
+      why = "su_port_init: su_wait_create"; goto error;
+    }
+
+    if (su_port_register(self, NULL, &self->sup_mbox_wait, su_port_wakeup, 
+			 (su_wakeup_arg_t *)self->sup_mbox, 0)
+	== -1) {
+      why = "su_port_create: su_port_register"; goto error;
+    }
+
+    SU_DEBUG_9(("su_port_create() returns %p\n", self));
+
+    return self;
+
+  error:
+    su_perror(why);
+    su_port_destroy(self), self = NULL;
+#endif
+  }
+
+  SU_DEBUG_9(("su_port_create() returns %p\n", self));
+
+  return self;
+}
+
+/** @internal Destroy a port. */
+void su_port_destroy(su_port_t *self)
+{
+  assert(self);
+
+  SU_DEBUG_9(("su_port_destroy() called\n"));
+
+#if SU_HAVE_MBOX
+  if (self->sup_mbox[0] != INVALID_SOCKET) {
+    su_port_unregister(self, NULL, &self->sup_mbox_wait, NULL, 
+		       (su_wakeup_arg_t *)self->sup_mbox);
+    su_wait_destroy(&self->sup_mbox_wait);
+    su_close(self->sup_mbox[0]); self->sup_mbox[0] = INVALID_SOCKET;
+#if HAVE_SOCKETPAIR
+    su_close(self->sup_mbox[1]); self->sup_mbox[1] = INVALID_SOCKET;
+#endif
+    SU_DEBUG_9(("su_port_destroy() close mailbox\n"));
+  }
+#endif
+  if (self->sup_waits) 
+    free(self->sup_waits), self->sup_waits = NULL;
+  if (self->sup_wait_cbs)
+    free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+  if (self->sup_wait_args)
+    free(self->sup_wait_args), self->sup_wait_args = NULL;
+  if (self->sup_wait_roots)
+    free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+  if (self->sup_reverses)
+    free(self->sup_reverses), self->sup_reverses = NULL;
+  if (self->sup_indices)
+    free(self->sup_indices), self->sup_indices = NULL;
+
+  SU_DEBUG_9(("su_port_destroy() freed registrations\n"));
+
+  su_home_zap(self->sup_home);
+
+  SU_DEBUG_9(("su_port_destroy() returns\n"));
+
+}
+
+static void su_port_lock(su_port_t *self, char const *who)
+{
+  SU_PORT_LOCK(self, who);
+}
+
+static void su_port_unlock(su_port_t *self, char const *who)
+{
+  SU_PORT_UNLOCK(self, who);
+}
+
+static void su_port_incref(su_port_t *self, char const *who)
+{
+  SU_PORT_INCREF(self, who);
+}
+
+static void su_port_decref(su_port_t *self, int blocking, char const *who)
+{
+  if (blocking)
+    SU_PORT_ZAPREF(self, who);
+  else
+    SU_PORT_DECREF(self, who);
+}
+
+static struct _GSource *su_port_gsource(su_port_t *self)
+{
+  return NULL;
+}
+
+#if SU_HAVE_MBOX
+/** @internal Message box wakeup function. */
+static int su_port_wakeup(su_root_magic_t *magic, /* NULL */
+			  su_wait_t *w,
+			  su_wakeup_arg_t *arg)
+{
+  char buf[32];
+  su_socket_t s = *(su_socket_t *)arg;
+  su_wait_events(w, s);
+  recv(s, buf, sizeof(buf), 0);
+  return 0;
+}
+#endif
+
+/** @internal Send a message to the port. */
+int su_port_send(su_port_t *self, su_msg_r rmsg)
+{
+  if (self) {
+    int wakeup;
+
+    SU_PORT_LOCK(self, "su_port_send");
+    
+    wakeup = self->sup_head == NULL;
+
+    *self->sup_tail = rmsg[0]; rmsg[0] = NULL;
+    self->sup_tail = &(*self->sup_tail)->sum_next;
+
+#if SU_HAVE_MBOX
+    /* if (!pthread_equal(pthread_self(), self->sup_tid)) */
+    if (wakeup)
+    {
+      assert(self->sup_mbox[MBOX_SEND] != INVALID_SOCKET);
+
+      if (send(self->sup_mbox[MBOX_SEND], "X", 1, 0) == -1) {
+#if HAVE_SOCKETPAIR
+	if (su_errno() != EWOULDBLOCK)
+#endif
+	  su_perror("su_msg_send: send()");
+      }
+    }
+#endif
+
+    SU_PORT_UNLOCK(self, "su_port_send");
+
+    return 0;
+  }
+  else {
+    su_msg_destroy(rmsg);
+    return -1;
+  }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval Number of messages sent
+ */
+int su_port_getmsgs(su_port_t *self)
+{
+  int n = 0;
+
+  if (self->sup_head) {
+    su_msg_f f;
+    su_msg_t *msg, *queue;
+
+    SU_PORT_LOCK(self, "su_port_getmsgs");
+
+    queue = self->sup_head;
+    self->sup_tail = &self->sup_head;
+    self->sup_head = NULL;
+
+    SU_PORT_UNLOCK(self, "su_port_getmsgs");
+
+    for (msg = queue; msg; msg = queue) {
+      queue = msg->sum_next;
+      msg->sum_next = NULL;
+
+      f = msg->sum_func;
+      if (f) 
+	f(SU_ROOT_MAGIC(msg->sum_to->sut_root), &msg, msg->sum_data);
+      su_msg_delivery_report(&msg);
+      n++;
+    }
+
+    /* Check for wait events that may have been generated by messages */
+    su_port_wait_events(self, 0);
+  }
+
+  return n;
+}
+
+/** @internal
+ *
+ *  Register a @c su_wait_t object. The wait object, a callback function and
+ *  a argument pointer is stored in the port object.  The callback function
+ *  will be called when the wait object is signaled.
+ *
+ *  Please note if identical wait objects are inserted, only first one is
+ *  ever signalled.
+ * 
+ * @param self	     pointer to port
+ * @param root	     pointer to root object
+ * @param waits	     pointer to wait object
+ * @param callback   callback function pointer
+ * @param arg	     argument given to callback function when it is invoked
+ * @param priority   relative priority of the wait object 
+ *              (0 is normal, 1 important, 2 realtime)
+ * 
+ * @return
+ *   Positive index of the wait object, 
+ *   or -1 upon an error.
+ */
+int su_port_register(su_port_t *self,
+		     su_root_t *root, 
+		     su_wait_t *wait, 
+		     su_wakeup_f callback,
+		     su_wakeup_arg_t *arg,
+		     int priority)
+{
+  int i, j, n;
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  n = self->sup_n_waits;
+
+  if (n >= SU_WAIT_MAX)
+    return su_seterrno(ENOMEM);
+
+  if (n >= self->sup_size_waits) {
+    /* Reallocate size arrays */
+    int size;
+    int *indices;
+    int *reverses;
+    su_wait_t *waits;
+    su_wakeup_f *wait_cbs;
+    su_wakeup_arg_t **wait_args;
+    su_root_t **wait_tasks;
+
+    if (self->sup_size_waits == 0)
+      size = su_root_size_hint;
+    else 
+      size = 2 * self->sup_size_waits;
+
+    if (size < SU_WAIT_MIN)
+      size = SU_WAIT_MIN;
+
+    /* Too large */
+    if (-3 - size > 0)
+      return (errno = ENOMEM), -1;
+
+    indices = realloc(self->sup_indices, (size + 1) * sizeof(*indices));
+    if (indices) {
+      self->sup_indices = indices;
+
+      if (self->sup_size_waits == 0)
+	indices[0] = -1;
+
+      for (i = self->sup_size_waits + 1; i <= size; i++)
+	indices[i] = -1 - i;
+    }
+
+    reverses = realloc(self->sup_reverses, size * sizeof(*waits));
+    if (reverses) {
+      for (i = self->sup_size_waits; i < size; i++)
+	reverses[i] = -1;
+      self->sup_reverses = reverses;
+    }
+      
+    waits = realloc(self->sup_waits, size * sizeof(*waits));
+    if (waits)
+      self->sup_waits = waits;
+
+    wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+    if (wait_cbs)
+      self->sup_wait_cbs = wait_cbs;
+
+    wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+    if (wait_args)
+      self->sup_wait_args = wait_args;
+
+    /* Add sup_wait_roots array, if needed */
+    wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+    if (wait_tasks) 
+      self->sup_wait_roots = wait_tasks;
+
+    if (!(indices && 
+	  reverses && waits && wait_cbs && wait_args && wait_tasks)) {
+      return -1;
+    }
+
+    self->sup_size_waits = size;
+  }
+
+  i = -self->sup_indices[0]; assert(i <= self->sup_size_waits);
+
+#if HAVE_EPOLL
+  if (self->sup_epoll != -1) {
+    struct epoll_event ev;
+
+    ev.events = POLL2EPOLL(wait->events);
+    ev.data.u64 = 0;
+    ev.data.u32 = (uint32_t)i;
+
+    if (epoll_ctl(self->sup_epoll, EPOLL_CTL_ADD, wait->fd, &ev) == -1) {
+      SU_DEBUG_0(("EPOLL_CTL_ADD(%u, %u) failed: %s\n",
+		  wait->fd, ev.events, strerror(errno)));
+      return -1;
+    }
+  }
+  else
+#endif  
+  if (priority > 0) {
+    /* Insert */
+    for (n = self->sup_n_waits; n > 0; n--) {
+      j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1);
+      self->sup_indices[j] = n;
+      self->sup_reverses[n] = j;
+      self->sup_waits[n] = self->sup_waits[n-1];
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+      self->sup_wait_args[n] = self->sup_wait_args[n-1];
+      self->sup_wait_roots[n] = self->sup_wait_roots[n-1];	
+    }
+
+    self->sup_pri_offset++;
+  }
+  else {
+    /* Append - no need to move anything */
+    n = self->sup_n_waits;
+  }
+
+  self->sup_n_waits++;
+
+  self->sup_indices[0] = self->sup_indices[i];  /* Free index */
+  self->sup_indices[i] = n;
+
+  self->sup_reverses[n] = i;
+  self->sup_waits[n] = *wait;
+  self->sup_wait_cbs[n] = callback;
+  self->sup_wait_args[n] = arg;
+  self->sup_wait_roots[n] = root;
+
+  self->sup_registers++;
+
+  /* Just like epoll, we return -1 or positive integer */
+
+  return i;
+}
+
+/** Deregister a su_wait_t object. */
+static
+int su_port_deregister0(su_port_t *self, int i)
+{
+  int n, N, *indices, *reverses;
+
+  indices = self->sup_indices;
+  reverses = self->sup_reverses;
+
+  n = indices[i]; assert(n >= 0);
+
+#if HAVE_EPOLL
+  if (self->sup_epoll != -1) {
+    su_wait_t *wait = &self->sup_waits[n];
+    struct epoll_event ev;
+
+    ev.events = POLL2EPOLL(wait->events);
+    ev.data.u64 = (uint64_t)0;
+    ev.data.u32 = (uint32_t)i;
+
+    if (epoll_ctl(self->sup_epoll, EPOLL_CTL_DEL, wait->fd, &ev) == -1) {
+      SU_DEBUG_1(("su_port(%p): EPOLL_CTL_DEL(%u): %s\n", self, 
+		  wait->fd, su_strerror(su_errno())));
+    }
+  }
+#endif
+
+  N = --self->sup_n_waits;
+  
+  if (n < self->sup_pri_offset) {
+    int j = --self->sup_pri_offset;
+    if (n != j) {
+      assert(reverses[j] > 0);
+      assert(indices[reverses[j]] == j);
+      indices[reverses[j]] = n;
+      reverses[n] = reverses[j];
+
+      self->sup_waits[n] = self->sup_waits[j];
+      self->sup_wait_cbs[n] = self->sup_wait_cbs[j];
+      self->sup_wait_args[n] = self->sup_wait_args[j];
+      self->sup_wait_roots[n] = self->sup_wait_roots[j];
+      n = j;
+    }
+  }
+
+  if (n < N) {
+    assert(reverses[N] > 0);
+    assert(indices[reverses[N]] == N);
+
+    indices[reverses[N]] = n;
+    reverses[n] = reverses[N];
+
+    self->sup_waits[n] = self->sup_waits[N];
+    self->sup_wait_cbs[n] = self->sup_wait_cbs[N];
+    self->sup_wait_args[n] = self->sup_wait_args[N];
+    self->sup_wait_roots[n] = self->sup_wait_roots[N];
+    n = N;
+  }
+
+  reverses[n] = -1;
+  memset(&self->sup_waits[n], 0, sizeof self->sup_waits[n]);
+  self->sup_wait_cbs[n] = NULL;
+  self->sup_wait_args[n] = NULL;
+  self->sup_wait_roots[n] = NULL;
+  
+  indices[i] = indices[0];
+  indices[0] = -i;
+
+  self->sup_registers++;
+
+  return i;
+}
+
+
+/** Unregister a su_wait_t object.
+ *  
+ *  The function su_port_unregister() unregisters a su_wait_t object. The
+ *  wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param root     - pointer to root object
+ * @param wait     - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg      - argument given to callback function when it is invoked 
+ *                   (may be NULL)
+ *
+ * @deprecated Use su_port_deregister() instead. 
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_port_unregister(su_port_t *self,
+		       su_root_t *root, 
+		       su_wait_t *wait,	
+		       su_wakeup_f callback, /* XXX - ignored */
+		       su_wakeup_arg_t *arg)
+{
+  int n, N;
+
+  assert(self);
+  assert(SU_PORT_OWN_THREAD(self));
+
+  N = self->sup_n_waits;
+
+  for (n = 0; n < N; n++) {
+    if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) == 0) {
+      return su_port_deregister0(self, self->sup_reverses[n]);
+    }
+  }
+
+  su_seterrno(ENOENT);
+
+  return -1;
+}
+
+/** Deregister a su_wait_t object.
+ *  
+ *  The function su_port_deregister() deregisters a su_wait_t registrattion. 
+ *  The wait object, a callback function and a argument are removed from the
+ *  port object.
+ * 
+ * @param self     - pointer to port object
+ * @param i        - registration index
+ * 
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_port_deregister(su_port_t *self, int i)
+{
+  su_wait_t wait[1] = { SU_WAIT_INIT };
+  int retval;
+
+  assert(self);
+  assert(SU_PORT_OWN_THREAD(self));
+
+  if (i <= 0 || i > self->sup_size_waits)
+    return su_seterrno(EBADF);
+
+  if (self->sup_indices[i] < 0)
+    return su_seterrno(EBADF);
+    
+  retval = su_port_deregister0(self, i);
+
+  su_wait_destroy(wait);
+
+  return retval;
+}
+
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_port_unregister_all() unregisters all su_wait_t objects
+ * and destroys all queued timers associated with given root object.
+ * 
+ * @param  self     - pointer to port object
+ * @param  root     - pointer to root object
+ * 
+ * @return Number of wait objects removed.
+ */
+int su_port_unregister_all(su_port_t *self, 
+			   su_root_t *root)
+{
+  int i, j, index, N;
+  int             *indices, *reverses;
+  su_wait_t       *waits;
+  su_wakeup_f     *wait_cbs;
+  su_wakeup_arg_t**wait_args;
+  su_root_t      **wait_roots;
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  N          = self->sup_n_waits;
+  indices    = self->sup_indices;
+  reverses   = self->sup_reverses;
+  waits      = self->sup_waits; 
+  wait_cbs   = self->sup_wait_cbs; 
+  wait_args  = self->sup_wait_args;
+  wait_roots = self->sup_wait_roots; 
+  
+  for (i = j = 0; i < N; i++) {
+    index = reverses[i]; assert(index > 0 && indices[index] == i);
+
+    if (wait_roots[i] == root) {
+      /* XXX - we should free all resources associated with this, too */
+#if HAVE_EPOLL
+      if (self->sup_epoll != -1) {
+	int fd = waits[i].fd;
+	struct epoll_event ev;
+
+	ev.events = POLL2EPOLL(waits[i].events);
+	ev.data.u64 = (uint64_t)0;
+	ev.data.u32 = (uint32_t)index;
+
+	if (epoll_ctl(self->sup_epoll, EPOLL_CTL_DEL, fd, &ev) == -1) {
+	  SU_DEBUG_1(("EPOLL_CTL_DEL(%u): %s\n", 
+		      waits[i].fd, su_strerror(su_errno())));
+	}
+      }
+#endif
+      if (i < self->sup_pri_offset)
+	self->sup_pri_offset--;
+
+      indices[index] = indices[0];
+      indices[0] = -index;
+      continue;
+    }
+
+    if (i != j) {
+      indices[index] = j;
+      reverses[j]   = reverses[i];
+      waits[j]      = waits[i];
+      wait_cbs[j]   = wait_cbs[i];
+      wait_args[j]  = wait_args[i];
+      wait_roots[j] = wait_roots[i];
+    }
+    
+    j++;
+  }
+  
+  for (i = j; i < N; i++) {
+    reverses[i] = -1;
+    wait_cbs[i] = NULL;
+    wait_args[i] = NULL;
+    wait_roots[i] = NULL;
+  }
+  memset(&waits[j], 0, (char *)&waits[N] - (char *)&waits[j]);
+
+  self->sup_n_waits = j;
+  self->sup_registers++;
+
+  return N - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_port_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port   pointer to port object
+ * @param index  registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_port_eventmask(su_port_t *self, int index, int socket, int events)
+{
+  int n;
+  assert(self);
+  assert(SU_PORT_OWN_THREAD(self));
+
+  if (index <= 0 || index > self->sup_size_waits)
+    return su_seterrno(EBADF);
+  n = self->sup_indices[index];
+  if (n < 0)
+    return su_seterrno(EBADF);
+
+#if HAVE_EPOLL
+  if (self->sup_epoll != -1) {
+    su_wait_t *wait = &self->sup_waits[n];
+    struct epoll_event ev;
+
+    wait->events = events;
+
+    ev.events = POLL2EPOLL(events);
+    ev.data.u64 = (uint64_t)0;
+    ev.data.u32 = (uint32_t)index;
+
+    if (epoll_ctl(self->sup_epoll, EPOLL_CTL_MOD, wait->fd, &ev) == -1) {
+      SU_DEBUG_1(("su_port(%p): EPOLL_CTL_MOD(%u): %s\n", self, 
+		  wait->fd, su_strerror(su_errno())));
+      return -1;
+    }
+  }
+#endif
+
+  return su_wait_mask(&self->sup_waits[n], socket, events);
+}
+
+#if 0
+/** @internal
+ *
+ * Copies the su_wait_t objects from the port. The number of wait objects
+ * can be found out by calling su_port_query() with @a n_waits as zero.
+ * 
+ * @note This function is called only by friends.
+ *
+ * @param self     - pointer to port object
+ * @param waits    - pointer to array to which wait objects are copied
+ * @param n_waits  - number of wait objects fitting in array waits
+ *
+ * @return Number of wait objects, or 0 upon an error.
+ */
+unsigned su_port_query(su_port_t *self, su_wait_t *waits, unsigned n_waits)
+{
+  unsigned n;
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  n = self->sup_n_waits;
+
+  if (n_waits != 0) {
+    if (waits && n_waits >= n)
+      memcpy(waits, self->sup_waits, n * sizeof(*waits));
+    else
+      n = 0;
+  }
+
+  return n;
+}
+#endif
+
+/** @internal Enable multishot mode.
+ *
+ * The function su_port_multishot() enables, disables or queries the
+ * multishot mode for the port. The multishot mode determines how the events
+ * are scheduled by port. If multishot mode is enabled, port serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self      pointer to port object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ * 
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_port_multishot(su_port_t *self, int multishot)
+{
+  if (multishot < 0)
+    return self->sup_multishot;
+  else if (multishot == 0 || multishot == 1)
+    return self->sup_multishot = multishot;
+  else 
+    return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_port_threadsafe(su_port_t *port)
+{
+  return su_home_threadsafe(port->sup_home);
+}
+
+/** @internal Main loop.
+ * 
+ * The function @c su_port_run() waits for wait objects and the timers
+ * associated with the port object.  When any wait object is signaled or
+ * timer is expired, it invokes the callbacks, and returns waiting.
+ * 
+ * The function @c su_port_run() runs until @c su_port_break() is called
+ * from a callback.
+ * 
+ * @param self     pointer to port object
+ * 
+ */
+void su_port_run(su_port_t *self)
+{
+  su_duration_t tout = 0;
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  for (self->sup_running = 1; self->sup_running;) {
+    tout = 2000;
+
+    if (self->sup_prepoll)
+      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+    if (self->sup_head)
+      su_port_getmsgs(self);
+
+    if (self->sup_timers)
+      su_timer_expire(&self->sup_timers, &tout, su_now());
+
+    if (!self->sup_running)
+      break;
+
+    if (self->sup_head)      /* if there are messages do a quick wait */
+      tout = 0;
+
+    su_port_wait_events(self, tout);
+  }
+}
+
+#if tuning
+/* This version can help tuning... */
+void su_port_run_tune(su_port_t *self)
+{
+  int i;
+  int timers = 0, messages = 0, events = 0;
+  su_duration_t tout = 0, tout0;
+  su_time_t started = su_now(), woken = started, bedtime = woken;
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  for (self->sup_running = 1; self->sup_running;) {
+    tout0 = tout, tout = 2000;
+
+    timers = 0, messages = 0;
+
+    if (self->sup_prepoll)
+      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+    if (self->sup_head)
+      messages = su_port_getmsgs(self);
+
+    if (self->sup_timers)
+      timers = su_timer_expire(&self->sup_timers, &tout, su_now());
+
+    if (!self->sup_running)
+      break;
+
+    if (self->sup_head)      /* if there are messages do a quick wait */
+      tout = 0;
+
+    bedtime = su_now();
+
+    events = su_port_wait_events(self, tout);
+
+    woken = su_now();
+
+    if (messages || timers || events)
+      SU_DEBUG_1(("su_port_run(%p): %.6f: %u messages %u timers %u "
+		  "events slept %.6f/%.3f\n",
+		  self, su_time_diff(woken, started), messages, timers, events,
+		  su_time_diff(woken, bedtime), tout0 * 1e-3));
+
+    if (!self->sup_running)
+      break;
+  }
+}
+#endif
+
+/** @internal
+ * The function @c su_port_break() is used to terminate execution of @c
+ * su_port_run(). It can be called from a callback function.
+ * 
+ * @param self     pointer to port
+ * 
+ */
+void su_port_break(su_port_t *self)
+{
+  self->sup_running = 0; 
+}
+
+/** @internal
+ * The function @c su_port_wait_events() is used to poll() for wait objects
+ *
+ * @param self     pointer to port
+ * @param tout     timeout in milliseconds
+ *
+ * @return number of events handled
+ */
+static
+int su_port_wait_events(su_port_t *self, su_duration_t tout)
+{
+  int i, events = 0;
+  su_wait_t *waits = self->sup_waits;
+  int n = self->sup_n_waits;
+  su_root_t *root;
+#if HAVE_POLL
+  unsigned version = self->sup_registers;
+#endif
+#if HAVE_EPOLL
+  
+  if (self->sup_epoll != -1) {
+    int const M = 4;
+    struct epoll_event ev[M];
+    int j, index;
+    int *indices = self->sup_indices;
+    
+    n = epoll_wait(self->sup_epoll, ev, self->sup_multishot ? M : 1, tout);
+
+    assert(n <= M);
+
+    for (j = 0; j < n; j++) {
+      su_root_t *root;
+      su_root_magic_t *magic;
+
+      if (!ev[j].events || ev[j].data.u32 > INDEX_MAX)
+	continue;
+      index = (int)ev[j].data.u32;
+      assert(index > 0 && index <= self->sup_size_waits);
+      i = indices[index]; assert(i >= 0 && i <= self->sup_n_waits);
+      root = self->sup_wait_roots[i];
+      magic = root ? su_root_magic(root) : NULL;
+      waits[i].revents = ev[j].events;
+      self->sup_wait_cbs[i](magic, &waits[i], self->sup_wait_args[i]);
+      events++;
+      /* Callback function used su_register()/su_deregister() */
+      if (version != self->sup_registers)
+	break;
+    }
+    
+    return n < 0 ? n : events;
+  }
+#endif
+
+  i = su_wait(waits, (unsigned)n, tout);
+
+  if (i >= 0 && i < n) {
+#if HAVE_POLL			
+    /* poll() can return events for multiple wait objects */
+    if (self->sup_multishot) {
+      for (; i < n; i++) {
+        if (waits[i].revents) {
+          root = self->sup_wait_roots[i];
+          self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+                                &waits[i],
+                                self->sup_wait_args[i]);
+          events++;
+          /* Callback function used su_register()/su_deregister() */
+          if (version != self->sup_registers)
+            break;
+        }
+      }
+    }
+#else /* !HAVE_POLL */
+    if (0) {
+    }
+#endif
+    else {
+      root = self->sup_wait_roots[i];
+      self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+                            &self->sup_waits[i],
+                            self->sup_wait_args[i]);
+      events++;
+    }
+  }
+
+  return events;
+}
+
+/** @internal 
+ * Used to check wait events in callbacks that take lots of time
+ *
+ * This function does a timeout 0 poll() and runs wait objects.
+ *
+ * @param port     pointer to port
+ *
+ * @return number of events handled
+ */
+static
+int su_port_yield(su_port_t *port)
+{
+  return su_port_wait_events(port, 0);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with 
+ * the root object.  When any wait object is signaled or timer is
+ * expired, it invokes the callbacks. 
+ * 
+ *   This function returns when a callback has been invoked or @c tout
+ *   milliseconds is elapsed. 
+ *
+ * @param self     pointer to port
+ * @param tout     timeout in milliseconds
+ * 
+ * @return
+ *   Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ *   there are no active timers.
+ */
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
+{
+  su_time_t now = su_now();
+
+  assert(SU_PORT_OWN_THREAD(self));
+
+  if (self->sup_prepoll)
+    self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+  if (self->sup_head)
+    su_port_getmsgs(self);
+
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, now);
+
+  /* if there are messages do a quick wait */
+  if (self->sup_head)
+    tout = 0;
+
+  if (su_port_wait_events(self, tout))
+    tout = 0;
+  else
+    tout = SU_WAIT_FOREVER;
+
+  if (self->sup_head)
+    su_port_getmsgs(self);
+
+  if (self->sup_timers)
+    su_timer_expire(&self->sup_timers, &tout, su_now());
+
+  if (self->sup_head)
+    tout = 0;
+
+  return tout;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_port_own_thread(su_port_t const *self)
+{
+  return self == NULL || SU_PORT_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ *  Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f    pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_port_dump(su_port_t const *self, FILE *f)
+{
+  int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+  if (f == NULL)
+    f = stdout;
+
+  fprintf(f, "su_port_t at %p:\n", self);
+  fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+#if SU_HAVE_PTHREADS
+  fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+#endif
+#if SU_HAVE_MBOX
+  fprintf(f, "\tport mbox %d (%s%s%s)\n", self->sup_mbox[0],
+	  IS_WAIT_IN(&self->sup_mbox_wait),
+	  IS_WAIT_OUT(&self->sup_mbox_wait),
+	  IS_WAIT_ACCEPT(&self->sup_mbox_wait));
+#endif
+  fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+  for (i = 0; i < self->sup_n_waits; i++) {
+    
+  }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_port_add_prepoll(su_port_t *port,
+			su_root_t *root, 
+			su_prepoll_f *callback, 
+			su_prepoll_magic_t *magic)
+{
+  if (port->sup_prepoll)
+    return -1;
+
+  port->sup_prepoll = callback;
+  port->sup_pp_magic = magic;
+  port->sup_pp_root = root;
+
+  return 0;
+}
+
+int su_port_remove_prepoll(su_port_t *port,
+			   su_root_t *root)
+{
+  if (port->sup_pp_root != root)
+    return -1;
+
+  port->sup_prepoll = NULL;
+  port->sup_pp_magic = NULL;
+  port->sup_pp_root = NULL;
+
+  return 0;
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_port_timers(su_port_t *self)
+{
+  return &self->sup_timers;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,360 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_PORT_H
+/** Defined when <su_port.h> has been included. */
+#define SU_PORT_H
+
+/**@IFILE su_port.h 
+ *
+ * @brief Internal OS-independent syncronization interface.
+ *
+ * This looks like the "reactor" pattern.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri May 12 14:13:34 2000 ppessi
+ */
+
+#ifndef SU_MSG_ARG_T
+#define SU_MSG_ARG_T union { char anoymous[4]; }
+#endif
+
+#ifndef SU_WAIT_H
+#include "sofia-sip/su_wait.h"
+#endif
+
+#ifndef SU_MODULE_DEBUG_H
+#include "su_module_debug.h"
+#endif
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <assert.h>
+
+#define SU_WAIT_MIN    (16)
+
+SOFIA_BEGIN_DECLS
+
+/** Message */
+struct su_msg_s {
+  isize_t        sum_size;
+  su_msg_t      *sum_next;
+  su_task_r      sum_to;
+  su_task_r      sum_from;
+  su_msg_f       sum_func;
+  su_msg_f       sum_report;
+  su_msg_arg_t   sum_data[1];		/* minimum size, may be extended */
+};
+
+struct _GSource;
+
+/** Root structure */
+struct su_root_s {
+  int              sur_size;
+  su_root_magic_t *sur_magic;
+  su_root_deinit_f sur_deinit;
+  su_task_r        sur_task;
+  su_task_r        sur_parent;
+  unsigned         sur_threading : 1;
+  unsigned         sur_deiniting : 1;
+};
+
+#define SU_ROOT_MAGIC(r) ((r) ? (r)->sur_magic : NULL)
+
+/** Virtual function table for port */
+typedef struct {
+  unsigned su_vtable_size;
+  void (*su_port_lock)(su_port_t *port, char const *who);
+  void (*su_port_unlock)(su_port_t *port, char const *who);
+  void (*su_port_incref)(su_port_t *port, char const *who);
+  void (*su_port_decref)(su_port_t *port, int block, char const *who);
+  struct _GSource *(*su_port_gsource)(su_port_t *port);
+  int (*su_port_send)(su_port_t *self, su_msg_r rmsg);
+  int (*su_port_register)(su_port_t *self,
+		       su_root_t *root, 
+		       su_wait_t *wait, 
+		       su_wakeup_f callback,
+		       su_wakeup_arg_t *arg,
+		       int priority);
+  int (*su_port_unregister)(su_port_t *port,
+			    su_root_t *root, 
+			    su_wait_t *wait,	
+			    su_wakeup_f callback, 
+			    su_wakeup_arg_t *arg);
+  int (*su_port_deregister)(su_port_t *self, int i);
+  int (*su_port_unregister_all)(su_port_t *self,
+			     su_root_t *root);
+  int (*su_port_eventmask)(su_port_t *self, int index, int socket, int events);
+  void (*su_port_run)(su_port_t *self);
+  void (*su_port_break)(su_port_t *self);
+  su_duration_t (*su_port_step)(su_port_t *self, su_duration_t tout);
+  
+  int (*su_port_own_thread)(su_port_t const *port);
+  
+  int (*su_port_add_prepoll)(su_port_t *port,
+			     su_root_t *root, 
+			     su_prepoll_f *, 
+			     su_prepoll_magic_t *);
+  
+  int (*su_port_remove_prepoll)(su_port_t *port,
+				su_root_t *root);
+
+  su_timer_t **(*su_port_timers)(su_port_t *port);
+
+  int (*su_port_multishot)(su_port_t *port, int multishot);
+
+  int (*su_port_threadsafe)(su_port_t *port);
+  
+  /* Extension from > 1.12.0 */
+  int (*su_port_yield)(su_port_t *port);
+} su_port_vtable_t;
+
+SOFIAPUBFUN su_port_t *su_port_create(void)
+     __attribute__((__malloc__));
+
+SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg);
+SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_t const * t,
+						su_time_t now);
+SOFIAPUBFUN su_root_t *su_root_create_with_port(su_root_magic_t *magic,
+						su_port_t *port);
+
+#if SU_PORT_IMPLEMENTATION
+
+#else
+struct su_port_s {
+  su_home_t               sup_home[1];
+  su_port_vtable_t const *sup_vtable;
+};
+
+static inline
+void su_port_lock(su_port_t *self, char const *who)
+{
+  if (self) self->sup_vtable->su_port_lock(self, who);
+}
+
+#define SU_PORT_LOCK(p, f)      (su_port_lock(p, #f))
+ 
+static inline
+void su_port_unlock(su_port_t *self, char const *who)
+{
+  if (self) self->sup_vtable->su_port_unlock(self, who);
+}
+
+#define SU_PORT_UNLOCK(p, f)    (su_port_unlock(p, #f))
+
+static inline
+void su_port_incref(su_port_t *self, char const *who)
+{
+  if (self) self->sup_vtable->su_port_incref(self, who);
+}
+
+#define SU_PORT_INCREF(p, f)    (su_port_incref(p, #f))
+ 
+static inline
+void su_port_decref(su_port_t *self, char const *who)
+{
+  if (self) self->sup_vtable->su_port_decref(self, 0, who);
+}
+
+#define SU_PORT_DECREF(p, f)    (su_port_decref(p, #f))
+
+static inline
+void su_port_zapref(su_port_t *self, char const *who)
+{
+  if (self) self->sup_vtable->su_port_decref(self, 1, who);
+}
+
+#define SU_PORT_ZAPREF(p, f)    (su_port_zapref(p, #f))
+
+static inline
+struct _GSource *su_port_gsource(su_port_t *self)
+{
+  return self ? self->sup_vtable->su_port_gsource(self) : NULL;
+}
+
+
+static inline
+int su_port_send(su_port_t *self, su_msg_r rmsg)
+{
+  if (self) 
+    return self->sup_vtable->su_port_send(self, rmsg);
+  errno = EINVAL;
+  return -1;
+}
+
+
+static inline
+int su_port_register(su_port_t *self,
+		     su_root_t *root, 
+		     su_wait_t *wait, 
+		     su_wakeup_f callback,
+		     su_wakeup_arg_t *arg,
+		     int priority)
+{
+  if (self)
+    return self->sup_vtable->su_port_register(self, root, wait,
+					      callback, arg, priority);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_unregister(su_port_t *self,
+		       su_root_t *root, 
+		       su_wait_t *wait,	
+		       su_wakeup_f callback, 
+		       su_wakeup_arg_t *arg)
+{
+  if (self)
+    return self->sup_vtable->
+      su_port_unregister(self, root, wait, callback, arg);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_deregister(su_port_t *self, int i)
+{
+  if (self)
+    return self->sup_vtable->
+      su_port_deregister(self, i);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_unregister_all(su_port_t *self,
+			   su_root_t *root)
+{
+  if (self)
+    return self->sup_vtable->
+      su_port_unregister_all(self, root);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_eventmask(su_port_t *self, int index, int socket, int events)
+{
+  if (self)
+    return self->sup_vtable->
+      su_port_eventmask(self, index, socket, events);
+  assert(self);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+void su_port_run(su_port_t *self)
+{
+  if (self)
+    self->sup_vtable->su_port_run(self);
+}
+
+static inline
+void su_port_break(su_port_t *self)
+{
+  if (self)
+    self->sup_vtable->su_port_break(self);
+}
+
+static inline
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
+{
+  if (self)
+    return self->sup_vtable->su_port_step(self, tout);
+  errno = EINVAL;
+  return (su_duration_t)-1;
+}
+
+
+static inline
+int su_port_own_thread(su_port_t const *self)
+{
+  return self == NULL || self->sup_vtable->su_port_own_thread(self);
+}
+
+static inline
+int su_port_add_prepoll(su_port_t *self,
+			su_root_t *root, 
+			su_prepoll_f *prepoll, 
+			su_prepoll_magic_t *magic)
+{
+  if (self)
+    return self->sup_vtable->
+      su_port_add_prepoll(self, root, prepoll, magic);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_remove_prepoll(su_port_t *self,
+			   su_root_t *root)
+{
+  if (self)
+    return self->sup_vtable->su_port_remove_prepoll(self, root);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+su_timer_t **su_port_timers(su_port_t *self)
+{
+  if (self)
+    return self->sup_vtable->su_port_timers(self);
+  errno = EINVAL;
+  return NULL;
+}
+
+static inline
+int su_port_multishot(su_port_t *self, int multishot)
+{
+  if (self)
+    return self->sup_vtable->su_port_multishot(self, multishot);
+
+  assert(self);
+  errno = EINVAL;
+  return -1;
+}
+
+static inline
+int su_port_threadsafe(su_port_t *self)
+{
+  if (self)
+    return self->sup_vtable->su_port_threadsafe(self);
+
+  assert(self);
+  errno = EINVAL;
+  return -1;
+}
+
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_PORT_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,672 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ *
+ * @file su_proxy.c 
+ *
+ * @brief Transport level proxy demonstrating various @b su features.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed May 23 17:42:40 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include <assert.h>
+
+typedef struct proxy_s proxy_t;
+typedef struct forwarder_s forwarder_t;
+typedef struct buffer_s buffer_t;
+
+#define SU_ROOT_MAGIC_T proxy_t
+#define SU_MSG_ARG_T    su_socket_t
+#define SU_WAKEUP_ARG_T forwarder_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+#include "su_module_debug.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "su_proxy"
+#endif
+
+struct proxy_s 
+{
+  su_home_t      pr_home[1];
+  su_root_t     *pr_root;
+  su_addrinfo_t *pr_addrinfo;
+  forwarder_t   *pr_forwarders;
+};
+
+struct forwarder_s 
+{
+  forwarder_t  *f_next;
+  forwarder_t **f_prev;
+  proxy_t      *f_pr;
+  su_socket_t   f_socket;
+  su_wait_t     f_wait[2];
+  forwarder_t  *f_peer;
+  su_sockaddr_t f_dest[1];
+  buffer_t     *f_buf;
+  unsigned long f_sent;		/* bytes sent */
+  unsigned      f_shutdown : 1;
+  unsigned      f_upstream : 1;
+};
+
+struct buffer_s
+{
+  buffer_t  *b_next;
+  buffer_t **b_prev;
+  int        b_sent;
+  int        b_used;
+  char       b_data[8192];
+};
+
+char const help[] =
+"usage: su_proxy [-ntu] remotehost remoteport [localport]\n";
+
+void usage(void)
+{
+  fputs(help, stderr);
+}
+
+static int pr_init(proxy_t *pr);
+static int pr_config(proxy_t *pr, int argc, char *argv[]);
+static int pr_run(proxy_t *pr);
+static void pr_deinit(proxy_t *pr);
+
+static forwarder_t *forwarder_create(proxy_t *pr);
+static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai);
+static void forwarder_deinit(forwarder_t *f);
+static int forwarder_init_stream(forwarder_t *f);
+static int forwarder_init_dgram(forwarder_t *f);
+static int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_stream_peer(proxy_t *pr, forwarder_t *f);
+static int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b);
+static int forwarder_append(forwarder_t *f, buffer_t *b0);
+static int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_shutdown(forwarder_t *f);
+static void forwarder_close(forwarder_t *f1);
+
+int main(int argc, char *argv[])
+{
+  proxy_t pr[1] = {{{ SU_HOME_INIT(pr) }}};
+  int error;
+
+  error = pr_init(pr);
+  if (error == 0) {
+    if ((error = pr_config(pr, argc, argv)) > 1)
+      usage();
+  }
+
+  if (error == 0)
+    error = pr_run(pr);
+
+  pr_deinit(pr);
+   
+  su_deinit();
+
+  exit(error);
+}
+
+int pr_init(proxy_t *pr)
+{
+  su_init();
+  su_home_init(pr->pr_home);
+  pr->pr_root = su_root_create(pr);
+  return pr->pr_root ? 0 : 1;
+}
+
+int pr_config(proxy_t *pr, int argc, char *argv[])
+{
+  su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};
+  char *service;
+  int error;
+  char const *option;
+
+  /* char const *argv0 = argv[0]; */
+
+  while (argv[1][0] == '-') {
+    option = argv[1];
+    argv++, argc--;
+    if (strcmp(option, "--") == 0)
+      break;
+    else if (strcmp(option, "-n") == 0) {
+      hints->ai_flags |= AI_NUMERICHOST;
+    }
+    else if (strcmp(option, "-d") == 0) {
+      hints->ai_socktype = SOCK_DGRAM;
+    }
+    else if (strcmp(option, "-s") == 0) {
+      hints->ai_socktype = SOCK_STREAM;
+    }
+    else if (strcmp(option, "-4") == 0) {
+      hints->ai_family = AF_INET;
+    }
+#if SU_HAVE_IN6
+    else if (strcmp(option, "-6") == 0) {
+      hints->ai_family = AF_INET6;
+    }
+#endif
+  }
+
+  if (argc < 3)
+    return 2;
+
+  if ((error = su_getaddrinfo(argv[1], argv[2], hints, &res))) {
+    fprintf(stderr, "getaddrinfo: %s:%s: %s\n", 
+	    argv[1], argv[2], su_gai_strerror(error));
+    return 1;
+  }
+
+    pr->pr_addrinfo = res;
+
+  if (argv[3]) 
+    service = argv[3];
+  else
+    service = argv[2];
+
+  hints->ai_flags |= AI_PASSIVE;
+
+  if ((error = su_getaddrinfo(NULL, service, hints, &res))) {
+    fprintf(stderr, "getaddrinfo: %s: %s\n", service, su_gai_strerror(error));
+    return 1;
+  }
+
+  for (ai = res; 
+       ai;
+       ai = ai->ai_next) {
+    forwarder_create_listener(pr, ai);
+  }
+
+  su_freeaddrinfo(res);
+  
+  if (!pr->pr_forwarders) {
+    fprintf(stderr, "%s:%s: %s\n", argv[1], argv[2], "unable to forward");
+    return 1;
+  }
+
+  return 0;
+}
+
+void pr_deinit(proxy_t *pr)
+{
+  if (pr->pr_addrinfo)
+    su_freeaddrinfo(pr->pr_addrinfo), pr->pr_addrinfo = NULL;
+
+  if (pr->pr_root)
+    su_root_destroy(pr->pr_root), pr->pr_root = NULL;
+
+  su_home_deinit(pr->pr_home);
+  
+  su_deinit();
+}
+
+static int pr_run(proxy_t *pr)
+{
+  su_root_run(pr->pr_root);
+
+  return 0;
+}
+
+forwarder_t *forwarder_create(proxy_t *pr)
+{
+  forwarder_t *f;
+
+  assert(pr);
+
+  f = su_zalloc(pr->pr_home, sizeof (*f));
+
+  if (f) {
+    f->f_socket = INVALID_SOCKET;
+    su_wait_init(f->f_wait);
+    su_wait_init(f->f_wait + 1);
+    f->f_pr = pr;
+    if ((f->f_next = pr->pr_forwarders))
+      f->f_next->f_prev = &f->f_next;
+    f->f_prev = &pr->pr_forwarders;
+    pr->pr_forwarders = f;
+  }
+
+  return f;
+}
+
+void forwarder_destroy(forwarder_t *f)
+{
+  if (f) {
+    forwarder_deinit(f);
+
+    if (f->f_peer) {
+      f->f_peer->f_peer = NULL;
+      forwarder_destroy(f->f_peer);
+      f->f_peer = NULL;
+    }
+    assert(f->f_prev);
+
+    if ((*f->f_prev = f->f_next))
+      f->f_next->f_prev = f->f_prev;
+
+    su_free(f->f_pr->pr_home, f);
+  }
+}
+
+void forwarder_deinit(forwarder_t *f)
+{
+  su_root_unregister(f->f_pr->pr_root, f->f_wait, NULL, f);
+  su_wait_destroy(f->f_wait);
+  su_root_unregister(f->f_pr->pr_root, f->f_wait + 1, NULL, f);
+  su_wait_destroy(f->f_wait + 1);
+  if (f->f_socket != INVALID_SOCKET)
+    su_close(f->f_socket), f->f_socket = INVALID_SOCKET;
+  if (f->f_buf)
+    su_free(f->f_pr->pr_home, f->f_buf), f->f_buf = NULL;
+}
+
+static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai)
+{
+  forwarder_t *f;
+  su_socket_t s;
+
+  if (ai->ai_socktype != SOCK_STREAM &&
+      ai->ai_socktype != SOCK_DGRAM)
+    return NULL;
+
+  f = forwarder_create(pr);
+
+  if (f) {
+    s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if (s != INVALID_SOCKET) {
+      f->f_socket = s;
+      su_setblocking(s, 0);
+      su_setreuseaddr(s, 1);
+      if (bind(s, ai->ai_addr, ai->ai_addrlen) >= 0) {
+	if (ai->ai_socktype == SOCK_STREAM ? 
+	    forwarder_init_stream(f) >= 0 : 
+	    forwarder_init_dgram(f) >= 0)
+	  return f;
+      }
+      else {
+	SU_DEBUG_1(("%s: bind: %s\n", __func__, su_strerror(su_errno())));
+      }
+    }
+  }
+
+  forwarder_destroy(f);
+  
+  return NULL;
+}
+
+int forwarder_init_stream(forwarder_t *f)
+{
+  if (listen(f->f_socket, SOMAXCONN) < 0)
+    return SOCKET_ERROR;
+  
+  if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_ACCEPT) < 0)
+    return SOCKET_ERROR;
+
+  if (su_root_register(f->f_pr->pr_root, f->f_wait, 
+		       forwarder_accept, f, 0) < 0)
+    return SOCKET_ERROR;
+
+  return 0;
+}
+
+int forwarder_init_dgram(forwarder_t *f)
+{
+  /* Unimplemented */
+  return SOCKET_ERROR;
+}
+
+/** Accept a connection. */
+int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0)
+{
+  forwarder_t *f;
+  su_sockaddr_t *su;
+  socklen_t  sulen;
+  int events;
+  
+  events = su_wait_events(w, f0->f_socket);
+
+  f = forwarder_create(pr);
+
+  if (f) {
+    su = f->f_dest;
+    sulen = sizeof(f->f_dest);
+    f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen);
+    f->f_upstream = 1;
+    if (f->f_socket != INVALID_SOCKET) {
+      char buf[SU_ADDRSIZE];
+      
+      SU_DEBUG_3(("accept: connection from %s:%u\n",
+		  inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
+		  ntohs(su->su_port)));
+
+      if (!su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) &&
+	  !su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
+	if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) {
+	  /* success */
+	  return 0;
+	}
+      }
+      else {
+	SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
+      }
+    }
+  }
+
+  forwarder_destroy(f);
+
+  return 0;
+}
+
+int forwarder_stream_peer(proxy_t *pr, forwarder_t *f_peer)
+{
+  forwarder_t *f;
+  su_addrinfo_t *ai;
+
+  assert(f_peer);
+  
+  f = forwarder_create(pr);
+  if (!f) {
+    SU_DEBUG_1(("%s: cannot allocate peer\n", __func__));
+    goto error;
+  }
+
+  for (ai = pr->pr_addrinfo; ai; ai = ai->ai_next) {
+    if (ai->ai_socktype == SOCK_STREAM)
+      break;
+  }
+
+  if (!ai) {
+    SU_DEBUG_1(("%s: no matching destination\n", __func__));
+    goto error;
+  }
+
+  f->f_socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+  if (f->f_socket == INVALID_SOCKET) {
+    SU_DEBUG_1(("%s: socket: %s\n", __func__, su_strerror(su_errno())));
+    goto error;
+  }
+
+  if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) ||
+      su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
+    SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
+    goto error;
+  }
+
+  /* Asynchronous connect */
+  su_setblocking(f->f_socket, 0);
+  su_seterrno(0);
+  connect(f->f_socket, ai->ai_addr, ai->ai_addrlen);
+  memcpy(f->f_dest, ai->ai_addr, ai->ai_addrlen);
+
+  if (su_errno() != EINPROGRESS) {
+    SU_DEBUG_1(("%s: connect: %s\n", __func__, su_strerror(su_errno())));
+    goto error;
+  }
+
+  if (su_root_register(pr->pr_root, f->f_wait + 1, 
+		       forwarder_connected, f, 0) == -1) {
+    SU_DEBUG_1(("%s: cannot register\n", __func__));
+    goto error;
+  }
+
+  f->f_peer = f_peer;
+  f_peer->f_peer = f;
+  return 0;
+
+ error:
+  forwarder_destroy(f);
+  return SOCKET_ERROR;
+}
+
+/** Connection is complete. */
+int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+  int events, error;
+  forwarder_t *f_peer;
+
+  events = su_wait_events(w, f->f_socket);
+
+  error = su_soerror(f->f_socket);
+
+  if (error) {
+    SU_DEBUG_1(("connect: %s\n", su_strerror(error)));
+    forwarder_destroy(f);
+    return 0;
+  }
+
+  su_root_unregister(pr->pr_root, f->f_wait + 1, forwarder_connected, f);
+
+  /* Wait for data, forward it to peer */
+  assert(f->f_peer);
+  f_peer = f->f_peer;
+  su_root_register(pr->pr_root, f->f_wait, forwarder_recv, f, 0);
+  su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
+
+  return 0;
+}
+
+/** Receive data, forward it to peer */
+int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+  buffer_t b[1];
+  int n, events;
+
+  events = su_wait_events(w, f->f_socket);
+
+  n = recv(f->f_socket, b->b_data, sizeof(b->b_data), 0);
+
+  if (n > 0) {
+    b->b_sent = 0; b->b_used = n;
+    if (f->f_peer->f_buf) {
+      forwarder_append(f, b); 
+      return 0;
+    }
+    if (forwarder_send(pr, f->f_peer, b) >= 0) {
+      if (b->b_sent < b->b_used) {
+	su_root_unregister(pr->pr_root, w, forwarder_recv, f);
+	su_root_register(pr->pr_root, f->f_peer->f_wait + 1, 
+			 forwarder_empty, f->f_peer, 0);
+	forwarder_append(f, b);
+      }
+      return 0;
+    }
+    else {
+      /* Error when sending */
+    }
+  }
+  if (n < 0) {
+    int error = su_errno();
+    SU_DEBUG_1(("recv: %s\n", su_strerror(error)));
+  
+    if (error == EINTR || error == EAGAIN || error == EWOULDBLOCK) {
+      return 0;
+    }
+    /* XXX */
+    forwarder_destroy(f);
+  }
+
+  /* shutdown */
+  forwarder_shutdown(f);	
+
+  return 0;
+}
+
+int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b)
+{
+  int n, error;
+  
+  do {
+    n = send(f->f_socket, b->b_data + b->b_sent, b->b_used - b->b_sent, 0);
+
+    if (n < 0) {
+      error = su_errno();
+      if (error == EINTR)
+	continue;
+      SU_DEBUG_1(("send: %s\n", su_strerror(error)));
+      if (error != EAGAIN && error != EWOULDBLOCK)
+	return -error;
+    }
+    else {
+      f->f_sent += n;
+    }
+  }
+  while (n > 0 && (b->b_sent += n) < b->b_used);
+
+  return b->b_used - b->b_sent;
+}
+
+int forwarder_append(forwarder_t *f, buffer_t *b0)
+{
+  buffer_t *b, **bb;
+  int unsent;
+
+  /* Find last buffer */
+  for (bb = &f->f_buf; *bb; bb = &(*bb)->b_next)
+    ;
+
+  unsent = b0->b_used - b0->b_sent;
+  assert(unsent > 0);
+
+  b = su_alloc(f->f_pr->pr_home, offsetof(buffer_t, b_data[unsent]));
+  if (b) {
+    *bb = b;
+    b->b_next = NULL;
+    b->b_prev = bb;
+    b->b_used = unsent;
+    b->b_sent = 0;
+    memcpy(b->b_data, b0->b_data + b->b_sent, unsent);
+  }
+
+  return b ? 0 : -1;
+}
+
+/** Empty forwarder buffers */
+int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+  buffer_t *b;
+  int n, events;
+
+  events = su_wait_events(w, f->f_socket);
+
+  while ((b = f->f_buf)) {
+    n = forwarder_send(f->f_pr, f, b);
+    if (n == 0) {
+      if ((f->f_buf = b->b_next))
+	b->b_next->b_prev = &f->f_buf;
+      su_free(f->f_pr->pr_home, b);
+      continue;
+    }
+    else if (n < 0) {
+      /* XXX */
+    }
+    break;
+  }
+
+  if (!f->f_buf) {
+    forwarder_t *f_peer = f->f_peer;
+
+    su_root_unregister(pr->pr_root, w, forwarder_empty, f);
+
+    if (!f->f_shutdown) {
+      /* Buffer is empty - start receiving */
+      su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
+    }
+    else {
+      if (shutdown(f->f_socket, 1) < 0) {
+	SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
+      }
+      if (f_peer->f_shutdown) {
+	forwarder_close(f);
+      }
+    }
+  }
+
+  return 0;
+}
+
+int forwarder_shutdown(forwarder_t *f)
+{
+  forwarder_t *f_peer = f->f_peer;
+  su_sockaddr_t *su = f->f_dest;
+  char buf[SU_ADDRSIZE];
+  
+  SU_DEBUG_3(("forwarder_shutdown: shutdown from %s:%u\n",
+	      inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
+	      ntohs(su->su_port)));
+  
+  if (su_root_unregister(f->f_pr->pr_root, f->f_wait, forwarder_recv, f) < 0) {
+    SU_DEBUG_1(("%s: su_root_unregister failed\n", __func__));
+  }
+
+  if (shutdown(f->f_socket, 0) < 0) {
+    SU_DEBUG_1(("shutdown(0): %s\n", su_strerror(su_errno())));
+  }
+  f_peer->f_shutdown = 1;
+  if (!f_peer->f_buf) {
+    if (shutdown(f_peer->f_socket, 1) < 0) {
+      SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
+    }
+    if (f->f_shutdown) {
+      forwarder_close(f);
+    }
+  }
+  return 0;
+}
+
+/** Close a peer pair */
+void forwarder_close(forwarder_t *f)
+{
+  su_sockaddr_t *su1, *su2;
+  char const *d1, *d2;
+  char buf1[SU_ADDRSIZE], buf2[SU_ADDRSIZE];
+
+  if (f->f_upstream)
+    su1 = f->f_dest, su2 = f->f_peer->f_dest, d1 = "up", d2 = "down";
+  else
+    su2 = f->f_dest, su1 = f->f_peer->f_dest, d2 = "up", d1 = "down";
+
+  SU_DEBUG_3(("forwarder_close: connection from %s:%u to %s:%d\n",
+	      inet_ntop(su1->su_family, SU_ADDR(su1), buf1, sizeof(buf1)),
+	      ntohs(su1->su_port),
+	      inet_ntop(su2->su_family, SU_ADDR(su2), buf2, sizeof(buf2)),
+	      ntohs(su2->su_port)));
+
+  forwarder_destroy(f);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1630 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_root.c 
+ * OS-independent synchronization interface. 
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sofia-sip/su.h"
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+struct su_root_s;
+
+typedef struct su_cloned_s {
+  struct su_root_s *sc_root;
+  int *sc_wait;
+#if SU_HAVE_PTHREADS
+  pthread_t  sc_tid;
+  pthread_mutex_t sc_pause[1];
+  pthread_cond_t sc_resume[1];
+  int sc_paused;
+#endif  
+} su_cloned_t;
+
+#define SU_ROOT_MAGIC_T struct su_root_magic_s
+#define SU_WAKEUP_ARG_T struct su_wakeup_arg_s
+#define SU_TIMER_ARG_T  struct su_timer_arg_s
+#define SU_CLONE_T      su_msg_t
+#define SU_MSG_ARG_T    struct su_cloned_s
+
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+/**@ingroup su_wait
+ * 
+ * @page su_root_t Tasks and root objects
+ *
+ * A task is the basic execution unit for the Sofia event-driven programming
+ * model. According to the model, the program can ask that the event loop
+ * invokes a callback function when a certain event occurs. Such events
+ * include @ref su_root_register "I/O activity", @ref su_timer_t "timers" or
+ * a @ref su_msg_t "message" from other task. The event loop is run with
+ * function su_root_run() or su_root_step().
+ *
+ * Root object gives access to the task control. The root object represents
+ * the task to the code running within task. Through the root, the task code
+ * can access its context object (magic) and thread-synchronization features
+ * like wait objects, timers, and messages.
+ *
+ * When a message is sent between tasks, a task reference #su_task_r is used
+ * to reprent the task address. Reference counting is used to make sure that
+ * the task references stay valid.
+ *
+ * The public API contains following functions:
+ *    - su_root_create() [Do not call from cloned task]
+ *    - su_root_destroy() [Do not call from cloned task]
+ *    - su_root_magic()
+ *    - su_root_register()
+ *    - su_root_deregister()
+ *    - su_root_unregister()
+ *    - su_root_threading()
+ *    - su_root_run() [Do not call from cloned task]
+ *    - su_root_break() [Do not call from cloned task]
+ *    - su_root_step() [Do not call from cloned task]
+ *    - su_root_task()
+ *
+ * New tasks can be created via su_clone_start() function.
+ */
+
+/**@ingroup su_wait 
+ * 
+ * @page su_root_register Registering Wait Objects
+ *
+ * When application expects I/O events, it can create a wait object and
+ * register it, a callback function and a context pointer to the #su_root_t
+ * object using the su_root_register() function. Whenever the wait object
+ * receives an event, the registered @link ::su_wakeup_f callback function
+ * @endlink is invoked.
+ *
+ * When successful, the su_root_register() returns an small non-negative
+ * integer representing the registration. The registration can be
+ * manipulated with su_root_eventmask() function, for instance, when sending
+ * through a socket block, the application can add SU_WAIT_OUT event to the
+ * mask.
+ *
+ * The registration can be removed using su_root_deregister() function.
+ */
+
+/**@ingroup su_wait
+ * 
+ * Contains hint of number of sockets supported by su_root_t */ 
+int su_root_size_hint = 64;
+
+/* =========================================================================
+ * Tasks
+ */
+
+su_task_r const su_task_null = SU_TASK_R_INIT;
+
+#define SU_TASK_ZAP(t, f) \
+  while (t->sut_port) { \
+   SU_PORT_DECREF(t->sut_port, f); t->sut_port = NULL; break; }
+
+#define SU_TASK_ZAPP(t, f) \
+  do { if (t->sut_port) { \
+   SU_PORT_DECREF(t->sut_port, f); t->sut_port = NULL; } \
+   t->sut_root = NULL; } while(0)
+
+/**
+ * Initialize a task handle with su_task_null.
+ *
+ * @param task task handle
+ *
+ * @return A reference to the initialized task handle.
+ */
+_su_task_r su_task_init(su_task_r task)
+{
+  assert(task);
+
+  memset(task, 0, sizeof(task));
+  return task;
+}
+
+/**
+ * Destroy a task handle
+ *
+ * @param task task handle
+ */
+void su_task_deinit(su_task_r task)
+{
+  assert(task);
+
+  SU_TASK_ZAP(task, su_task_deinit);
+  task->sut_root = NULL;
+}
+
+/**
+ * Create a new task handle.
+ *
+ * @param task task reference
+ * @param root pointer to root object
+ * @param port pointer to port object
+ *
+ * @return New task handle.
+ */
+_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port)
+{
+  assert(task);
+
+  task->sut_root = root;
+  if ((task->sut_port = port)) {
+    SU_PORT_INCREF(port, su_task_new);
+  }
+  return task;
+}
+
+/**
+ * Duplicates a task handle.
+ *
+ * @param  dst      destination task reference
+ * @param  src      source task reference
+ */
+void su_task_copy(su_task_r dst, su_task_r const src)
+{
+  su_port_t *port;
+  
+  assert(src); assert(dst);
+
+  SU_TASK_ZAP(dst, su_task_copy);
+
+  port = src->sut_port;
+  if (port) {
+    SU_PORT_INCREF(port, su_task_copy);
+  }
+
+  dst[0] = src[0];
+}
+
+#define SU_TASK_COPY(d, s, by) (void)((d)[0]=(s)[0], \
+  (s)->sut_port?(void)SU_PORT_INCREF(s->sut_port, by):(void)0)
+
+/**
+ * Moves a task handle.
+ *
+ * @param  dst      destination task reference
+ * @param  src      source task reference
+ */
+void su_task_move(su_task_r dst, su_task_r src)
+{
+  SU_TASK_ZAP(dst, su_task_move);
+  dst[0] = src[0];
+  src->sut_port = 0;
+  src->sut_root = 0;
+}
+
+/**
+ * Compare two tasks with each other.
+ * 
+ * @param a  First task
+ * @param b  Second task
+ * 
+ * @retval negative number, if a < b
+ * @retval positive number, if a > b
+ * @retval 0, if a == b.
+ */
+int su_task_cmp(su_task_r const a, su_task_r const b)
+{
+  intptr_t retval = a->sut_port - b->sut_port;
+  retval = retval ? retval : (char *)a->sut_root - (char *)b->sut_root;
+
+  if (sizeof(retval) != sizeof(int)) {
+    if (retval < 0)
+      retval = -1;
+    else if (retval > 0)
+      retval = 1;
+  }
+
+  return (int)retval;
+}
+
+/**
+ * Tests if a task is running.
+ *
+ * @param task  task handle
+ *
+ * @retval true (nonzero) if task is not stopped, 
+ * @retval zero if it is null or stopped.
+ */
+int su_task_is_running(su_task_r const task)
+{
+  return 
+    task && 
+    task->sut_port && 
+    task->sut_root;
+}
+
+/** @internal
+ * Attach a root object to the task handle.
+ *
+ * @param self task handle
+ * @param root pointer to the root object
+ * 
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+int su_task_attach(su_task_r self, su_root_t *root)
+{
+  if (self->sut_port) {
+    self->sut_root = root;
+    return 0;
+  }
+  else 
+    return -1;
+}
+
+/** 
+ * Get root pointer attached to a task handle.
+ *
+ * @param self task handle
+ *
+ * @return 
+ * A pointer to root object attached to the task handle, or NULL if no root
+ * object has been attached.
+ */
+su_root_t *su_task_root(su_task_r const self)
+{
+  if (self->sut_port) return self->sut_root; else return NULL;
+}
+
+#if 0
+/** @internal
+ * Detach a root pointer from task handle.
+ * @bug Not used anymore.
+ */
+int su_task_detach(su_task_r self)
+{
+  self->sut_root = NULL;
+  return 0;
+}
+#endif
+
+/**
+ * Return the timer list associated with given task.
+ * 
+ * @param task task handle
+ *
+ * @return A timer list of the task. If there are no timers, it returns
+ * NULL.
+ */
+su_timer_t **su_task_timers(su_task_r const task)
+{
+  return task ? su_port_timers(task->sut_port) : NULL;
+}
+
+#if SU_HAVE_PTHREADS
+
+struct su_task_execute
+{
+  pthread_mutex_t mutex[1];
+  pthread_cond_t cond[1];
+  int (*function)(void *);
+  void *arg;
+  int value;
+};
+
+static void _su_task_execute(su_root_magic_t *m,
+			     su_msg_r msg,
+			     su_msg_arg_t *a)
+{
+  struct su_task_execute *frame = *(struct su_task_execute **)a;
+  pthread_mutex_lock(frame->mutex);
+  frame->value = frame->function(frame->arg);
+  frame->function = NULL;	/* Mark as completed */
+  pthread_cond_signal(frame->cond);
+  pthread_mutex_unlock(frame->mutex);
+}
+
+#endif
+
+/** Execute by task thread
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_task_execute(su_task_r const task,
+		    int (*function)(void *), void *arg,
+		    int *return_value)
+{
+  if (function == NULL)
+    return (errno = EFAULT), -1;
+
+  if (!su_port_own_thread(task->sut_port)) {
+#if SU_HAVE_PTHREADS
+    int success;
+    su_msg_r m = SU_MSG_R_INIT;
+    struct su_task_execute frame = {
+      { PTHREAD_MUTEX_INITIALIZER },
+      { PTHREAD_COND_INITIALIZER },
+      function, arg, 0
+    };
+
+    if (su_msg_create(m, task, su_task_null,
+		      _su_task_execute, (sizeof &frame)) < 0)
+      return -1;
+
+    *(struct su_task_execute **)su_msg_data(m) = &frame;
+
+    pthread_mutex_lock(frame.mutex);
+
+    success = su_msg_send(m);
+
+    if (success == 0)
+      while (frame.function)
+	pthread_cond_wait(frame.cond, frame.mutex);
+    else
+      su_msg_destroy(m);
+
+    pthread_mutex_unlock(frame.mutex);
+    pthread_mutex_destroy(frame.mutex);
+    pthread_cond_destroy(frame.cond);
+
+    if (return_value)
+      *return_value = frame.value;
+
+    return success;
+#else
+    return (errno = ENOSYS), -1;
+#endif
+  }
+  else {
+    int value = function(arg);
+
+    if (return_value)
+      *return_value = value;
+
+    return 0;
+  }
+}
+
+_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port);
+int su_task_attach(su_task_r self, su_root_t *root);
+int su_task_detach(su_task_r self);
+
+int su_timer_reset_all(su_timer_t **t0, su_task_r);
+
+/**@ingroup su_wait
+ * 
+ * @page su_clone_t Clone Objects
+ *
+ * The process may be divided into many tasks via cloning. Several tasks may
+ * run in context of one thread, or each task may be run by its own thread. 
+ * However, only a single thread can execute code within a task. There can
+ * be a 1-to-N mapping from thread to tasks. Thus, software using tasks can
+ * be executed by multiple threads in a multithreaded environment and by a
+ * single thread in a singlethreaded environment.
+ * 
+ * The clones are useful for handling tasks that can be executed by a
+ * separate threads, but which do not block excessively. When threads are
+ * not available or they are not needed, clones can also be run in a
+ * single-threaded mode. Running in single-threaded mode is especially
+ * useful while debugging.
+ * 
+ * A clone task is created with function su_clone_start(). Each clone has
+ * its own root object (su_root_t), which holds a context pointer
+ * (su_root_magic_t *). The context object can be different from that of 
+ * parent task.
+ *
+ * When a clone is started, the clone initialization function is called. The
+ * initialization function should do whatever initialization there is to be
+ * performed, register I/O events and timers, and then return. If the
+ * initialization is successful, the clone task reverts to run the event
+ * loop and invoking the event callbacks until its parent stops it by
+ * calling su_clone_wait() which invokes the deinit function. The clone task
+ * is destroyed when the deinit function returns. 
+ *
+ * The public API consists of following functions:
+ *    - su_clone_start()
+ *    - su_clone_task()
+ *    - su_clone_wait()
+ *    - su_clone_forget()
+ *
+ * @note 
+ * There is only one event loop for each thread which can be shared by
+ * multiple clone tasks. Therefore, the clone tasks can not explicitly run
+ * or step the event loop, but they are limited to event callbacks. A clone
+ * task may not call su_root_break(), su_root_run() or su_root_step().
+ */
+
+static void su_root_deinit(su_root_t *self);
+
+/* Note that is *not* necessary same as su_root_t,
+ * as su_root_t can be extended */
+
+#define sur_port sur_task->sut_port
+#define sur_root sur_task->sut_root
+
+#define SU_ROOT_OWN_THREAD(r) (su_port_own_thread(r->sur_port))
+
+/** Create a reactor object.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic     pointer to user data
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ */
+su_root_t *su_root_create(su_root_magic_t *magic)
+{
+  return su_root_create_with_port(magic, su_port_create());
+}
+
+/** Create a reactor object using given message port.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic     pointer to user data
+ * @param port      pointer to a message port
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ */
+su_root_t *su_root_create_with_port(su_root_magic_t *magic,
+				    su_port_t *port)
+{
+  su_root_t *self;
+
+  if (!port)
+    return NULL;
+
+  self = su_salloc(NULL, sizeof(struct su_root_s));
+
+  if (self) {
+    self->sur_magic = magic;
+#if SU_HAVE_PTHREADS
+    self->sur_threading = SU_HAVE_PTHREADS;
+#else
+    self->sur_threading = 0;
+#endif
+    su_task_new(self->sur_task, self, port);
+  } else {
+    su_port_decref(port, "su_root_create");
+  }
+
+  return self;
+}
+
+/** Destroy a synchronization object.
+ * 
+ *  Stop and free an instance of su_root_t
+ *
+ * @param self     pointer to a root object.
+ */
+void su_root_destroy(su_root_t *self)
+{
+  if (self) {
+    assert(SU_ROOT_OWN_THREAD(self));
+    su_root_deinit(self);
+    su_free(NULL, self);
+  }
+}
+
+/** @internal Deinitialize a synchronization object.
+ *
+ *  Deinitialize an instance of su_root_t
+ *
+ * @param self     pointer to a root object.
+ */
+static void su_root_deinit(su_root_t *self)
+{
+  self->sur_deiniting = 1;
+
+  if (self->sur_deinit) {
+    su_root_deinit_f deinit = self->sur_deinit;
+    su_root_magic_t *magic = self->sur_magic;
+    self->sur_deinit = NULL;
+    deinit(self, magic);
+  }
+
+  if (self->sur_port) {
+    int n_w = su_port_unregister_all(self->sur_port, self);
+    int n_t = su_timer_reset_all(su_task_timers(self->sur_task), self->sur_task);
+
+    if (n_w || n_t)
+      SU_DEBUG_1(("su_root_deinit: "
+		  "%u registered waits, %u timers\n", n_w, n_t));
+  }
+
+  SU_TASK_ZAP(self->sur_parent, su_root_deinit);
+  SU_TASK_ZAP(self->sur_task, su_root_deinit);
+}
+
+/** Set the context pointer.
+ *
+ *  Set the context pointer (magic) of a root object.
+ *
+ * @param self      pointer to a root object
+ * @param magic     pointer to user data
+ *
+ * @retval 0  when successful,
+ * @retval -1 upon error.
+ */
+int su_root_set_magic(su_root_t *self, su_root_magic_t *magic)
+{
+  assert(SU_ROOT_OWN_THREAD(self));
+
+  if (self) {
+    self->sur_magic = magic;
+  }
+
+  return 0;
+}
+
+/** Set threading option.
+ *
+ *   Controls whether su_clone_start() creates a new thread.
+ *
+ * @param self      pointer to a root object
+ * @param enable    if true, enable threading, if false, disable threading
+ *
+ * @return True if threading is enabled.
+ */
+int su_root_threading(su_root_t *self, int enable)
+{
+  if (self) {
+    assert(SU_ROOT_OWN_THREAD(self));
+
+#if SU_HAVE_PTHREADS
+    self->sur_threading = enable = enable != 0;
+    return enable;
+#endif
+  }
+
+  return 0;
+}
+
+/** Get context pointer.
+ *
+ *  The function su_root_magic() returns the user context pointer that was
+ *  given input to su_root_create() or su_root_set_magic().
+ *
+ * @param self      pointer to a root object
+ *
+ * @return A pointer to user data
+ */
+su_root_magic_t *su_root_magic(su_root_t *self)
+{
+  return self ? self->sur_magic : NULL;
+}
+
+/** Get a GSource */
+struct _GSource *su_root_gsource(su_root_t *self)
+{
+  return self ? su_port_gsource(self->sur_port) : NULL;
+}
+
+/** Register a su_wait_t object. 
+ *
+ *  The function su_root_register() registers a su_wait_t object. The wait
+ *  object, a callback function and a argument are stored to the root
+ *  object. The callback function is called, when the wait object is
+ *  signaled.
+ *
+ *  Please note if identical wait objects are inserted, only first one is
+ *  ever signalled.
+ *
+ * @param self      pointer to root object
+ * @param wait      pointer to wait object
+ * @param callback  callback function pointer
+ * @param arg       argument given to callback function when it is invoked
+ * @param priority  relative priority of the wait object
+ *                  (0 is normal, 1 important, 2 realtime)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_root_register(su_root_t *self,
+		     su_wait_t *wait,
+		     su_wakeup_f callback,
+		     su_wakeup_arg_t *arg,
+		     int priority)
+{
+  assert(self && self->sur_port);
+
+  if (!self || !self->sur_port)
+    return -1;
+
+  return su_port_register(self->sur_port, self, wait, callback, arg, priority);
+}
+
+/** Unregister a su_wait_t object.
+ *
+ *  The function su_root_unregister() unregisters a su_wait_t object. The
+ *  wait object, a callback function and a argument are removed from the
+ *  root object.
+ *
+ * @param self      pointer to root object
+ * @param wait      pointer to wait object
+ * @param callback  callback function pointer (may be NULL)
+ * @param arg       argument given to callback function when it is invoked
+ *                  (may be NULL)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_root_unregister(su_root_t *self,
+		       su_wait_t *wait,
+		       su_wakeup_f callback, /* XXX - ignored */
+		       su_wakeup_arg_t *arg)
+{
+  assert(self && self->sur_port);
+
+  if (!self || !self->sur_port)
+    return -1;
+
+  return su_port_unregister(self->sur_port, self, wait, callback, arg);
+}
+
+/** Remove a su_wait_t registration.
+ *
+ *  The function su_root_deregister() deregisters a su_wait_t object. The
+ *  wait object, a callback function and a argument are removed from the
+ *  root object. The wait object is destroyed.
+ *
+ * @param self      pointer to root object
+ * @param i         registration index
+ *
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_root_deregister(su_root_t *self, int i)
+{
+  if (i == 0 || i == -1)
+    return -1;
+
+  assert(self && self->sur_port);
+
+  if (!self || !self->sur_port)
+    return -1;
+
+  return su_port_deregister(self->sur_port, i);
+}
+
+/** Set mask for a registered event.
+ *
+ * The function su_root_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param self   pointer to root object
+ * @param index  registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_root_eventmask(su_root_t *self, int index, int socket, int events)
+{
+  assert(self && self->sur_port);
+
+  if (!self || !self->sur_port)
+    return -1;
+
+  return su_port_eventmask(self->sur_port, index, socket, events);
+}
+
+/** Set multishot mode.
+ *
+ * The function su_root_multishot() enables, disables or queries the
+ * multishot mode for the root. The multishot mode determines how the events
+ * are scheduled by root. If multishot mode is enabled, root serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self      pointer to root object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ * 
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_root_multishot(su_root_t *self, int multishot)
+{
+  if (self && self->sur_port) {
+    return su_port_multishot(self->sur_port, multishot);
+  } else {
+    return (errno = EINVAL), -1;
+  }
+}
+
+
+/** Run event and message loop.
+ *
+ * The function su_root_run() runs the root main loop. The root loop waits
+ * for wait objects and the timers associated with the root object. When any
+ * wait object is signaled or timer is expired, it invokes the callbacks,
+ * and returns waiting.
+ *
+ * This function returns when su_root_break() is called from a callback.
+ *
+ * @param self      pointer to root object
+ *
+ */
+void su_root_run(su_root_t *self)
+{
+  assert(self && self->sur_port);
+
+  if (self && self->sur_port)
+    su_port_run(self->sur_port);
+}
+
+/** Terminate event loop.
+ *
+ *   The function su_root_break() is used to terminate execution of
+ *   su_root_run(). It can be called from a callback function.
+ *
+ * @param self      pointer to root object
+ */
+void su_root_break(su_root_t *self)
+{
+  assert(self && self->sur_port);
+
+  if (self && self->sur_port)
+    su_port_break(self->sur_port);
+}
+
+/** Process events, timers and messages.
+ *
+ *   The function su_root_step() waits for wait objects and the timers
+ *   associated with the root object.  When any wait object is signaled or
+ *   timer is expired, it invokes the callbacks.
+ *
+ *   This function returns when a callback has been invoked or tout
+ *   milliseconds is elapsed.
+ *
+ * @param self      pointer to root object
+ * @param tout      timeout in milliseconds
+ *
+ * @return Milliseconds to the next invocation of timer, or SU_WAIT_FOREVER
+ *         if there are no active timers.
+ */
+su_duration_t su_root_step(su_root_t *self, su_duration_t tout)
+{
+  assert(self && self->sur_port);
+
+  return su_port_step(self->sur_port, tout);
+}
+
+/**Run event and message loop for given duration.
+ *
+ * The function su_root_sleep() runs event loop for @a duration milliseconds.
+ * The event loop waits for wait objects and the timers associated with the
+ * @a root object.  When any wait object is signaled, timer is expired, or
+ * message is received, it invokes the callbacks and returns waiting.
+ *
+ * @param self      pointer to root object
+ * @param duration  milliseconds to run event loop
+ */
+su_duration_t su_root_sleep(su_root_t *self, su_duration_t duration)
+{
+  su_duration_t retval, accrued = 0;
+  su_time_t started = su_now();
+
+  assert(self && self->sur_port);
+
+  do {
+    retval = su_port_step(self->sur_port, duration - accrued);
+    accrued = su_duration(su_now(), started);
+  } while (accrued < duration);
+
+  return retval;
+}
+
+/** Check wait events in callbacks that take lots of time
+ *
+ * This function does a 0 timeout poll() and runs wait objects
+ *
+ * @param self pointer to root object
+ */
+int su_root_yield(su_root_t *self)
+{
+  if (self && self->sur_task[0].sut_port) {
+    su_port_t *port = self->sur_task[0].sut_port;
+    /* Make sure we have su_port_yield extension */
+    if (port->sup_vtable->su_vtable_size >= 
+	offsetof(su_port_vtable_t, su_port_yield) 
+	&& port->sup_vtable->su_port_yield)
+      return port->sup_vtable->su_port_yield(port);
+  }
+  errno = EINVAL;
+  return -1;
+}
+
+/** Get task reference.
+ *
+ *   The function su_root_task() is used to retrieve the task reference
+ *   (PId) related with the root object.
+ *
+ * @param self      a pointer to a root object
+ *
+ * @return The function su_root_task() returns a reference to the task
+ *         object.
+ */
+_su_task_r su_root_task(su_root_t const *self)
+{
+  if (self)
+    return self->sur_task;
+  else
+    return su_task_null;
+}
+
+/** Get parent task reference.
+ *
+ *   The function su_root_parent() is used to retrieve the task reference
+ *   (PId) of the parent task.
+ *
+ * @param self      a pointer to a root object
+ *
+ * @return The function su_root_parent() returns a reference to the parent
+ *         task object.
+ */
+_su_task_r su_root_parent(su_root_t const *self)
+{
+  if (self)
+    return self->sur_parent;
+  else
+    return su_task_null;
+}
+
+/** Add a pre-poll callback. */
+int su_root_add_prepoll(su_root_t *root, 
+			su_prepoll_f *callback, 
+			su_prepoll_magic_t *magic)
+{
+  if (root == NULL || root->sur_port == NULL)
+    return -1;
+
+  return su_port_add_prepoll(root->sur_port, root, callback, magic);
+}
+
+/** Remove a pre-poll callback */
+int su_root_remove_prepoll(su_root_t *root)
+{
+  if (root == NULL || root->sur_port == NULL)
+    return -1;
+
+  return su_port_remove_prepoll(root->sur_port, root);
+}
+
+/* ========================================================================
+ * su_clone_t
+ */
+
+/* - su_clone_forget() */
+
+#if SU_HAVE_PTHREADS
+struct clone_args
+{
+  su_root_t      * self;
+  su_root_init_f   init;
+  su_root_deinit_f deinit;
+  pthread_mutex_t  mutex;
+  pthread_cond_t   cv;
+  int              retval;
+  su_msg_r         clone;
+  su_root_t const *parent;
+};
+
+static void su_clone_report2(su_root_magic_t *m,
+			     su_msg_r msg,
+			     su_cloned_t *sc);
+
+static void su_clone_signal_parent(void *varg)
+{
+  struct clone_args *arg = (struct clone_args *)varg;
+
+  pthread_mutex_lock(&arg->mutex);
+  pthread_cond_signal(&arg->cv);
+  pthread_mutex_unlock(&arg->mutex);
+}
+
+/** Message function for clone message.
+ *
+ * This calls the clone task deinitialization function, which should make
+ * sure that no more messages are sent by clone task.
+ *
+ * @sa su_clone_wait()
+ */
+static void su_clone_break(su_root_magic_t *m,
+			   su_msg_r msg,
+			   su_cloned_t *sc)
+{
+  su_root_t *root = sc->sc_root;
+
+  root->sur_deiniting = 1;
+
+  if (root->sur_deinit) {
+    su_root_deinit_f deinit = root->sur_deinit;
+    su_root_magic_t *magic = root->sur_magic;
+    root->sur_deinit = NULL;
+    deinit(root, magic);
+  }
+}
+
+/** Delivery report function for clone message.
+ *
+ * This is executed by parent task. This is the last message sent by clone task.
+ */
+static void su_clone_report(su_root_magic_t *m,
+			    su_msg_r msg,
+			    su_cloned_t *sc)
+{
+  su_msg_report(msg, su_clone_report2);
+}
+
+/** Back delivery report function for clone message.
+ *
+ * This is executed by clone task. It completes the three way handshake and
+ * it is used to signal clone that it can destroy its port.
+ */
+static void su_clone_report2(su_root_magic_t *m,
+			    su_msg_r msg,
+			    su_cloned_t *sc)
+{
+  su_root_break(sc->sc_root);
+  if (sc->sc_wait)
+    *sc->sc_wait = 0;
+}
+
+static void *su_clone_main(void *varg)
+{
+  struct clone_args *arg = (struct clone_args *)varg;
+  su_root_t *self = arg->self;
+  su_port_t *port;
+  su_cloned_t *sc;
+
+  pthread_cleanup_push(su_clone_signal_parent, varg);
+
+#if SU_HAVE_WINSOCK
+  su_init();
+#endif
+
+  port = su_port_create();
+  if (!port)
+    pthread_exit(NULL);
+  su_port_threadsafe(port);
+  SU_PORT_INCREF(port, su_clone_main);
+
+  /* Change task ownership */
+  SU_PORT_INCREF(self->sur_task->sut_port = port, su_clone_main);
+  self->sur_task->sut_root = self;
+
+  if (su_msg_create(arg->clone,
+		    self->sur_task, su_root_task(arg->parent),
+		    su_clone_break, sizeof(self)) != 0) {
+    su_port_decref(self->sur_port, "su_clone_main");
+    self->sur_port = NULL;
+    pthread_exit(NULL);
+  }
+
+  su_msg_report(arg->clone, su_clone_report);
+
+  sc = su_msg_data(arg->clone);
+  sc->sc_root = self;
+  sc->sc_tid = pthread_self();
+
+  pthread_mutex_init(sc->sc_pause, NULL);
+  pthread_cond_init(sc->sc_resume, NULL);
+  pthread_mutex_lock(sc->sc_pause);
+
+  if (arg->init && arg->init(self, self->sur_magic) != 0) {
+    if (arg->deinit)
+      arg->deinit(self, self->sur_magic);
+    su_msg_destroy(arg->clone);
+    su_port_decref(self->sur_port, "su_clone_main");
+    self->sur_port = NULL;
+    pthread_exit(NULL);
+  }
+
+  arg->retval = 0;
+
+  pthread_cleanup_pop(1);  /* signal change of ownership */
+
+  su_root_run(self);   /* Do the work */
+
+  su_root_destroy(self);   /* Cleanup root */   
+
+  SU_PORT_ZAPREF(port, su_clone_main);
+
+#if SU_HAVE_WINSOCK
+  su_deinit();
+#endif
+
+  return NULL;
+}
+#endif
+
+static void su_clone_xyzzy(su_root_magic_t *m,
+			   su_msg_r msg,
+			   su_cloned_t *sc)
+{
+  su_root_destroy(sc->sc_root);
+  if (sc->sc_wait)
+    *sc->sc_wait = 0;
+}
+
+/** Start a clone task.
+ *
+ * The function su_clone_start() allocates and initializes a sub-task. 
+ * Depending on the settings, a separate thread may be created to execute
+ * the sub-task. The sub-task is represented by clone handle to the rest of
+ * the application. The function su_clone_start() returns the clone handle
+ * in @a return_clone. The clone handle is used to communicate with the
+ * newly created clone task using messages.
+ *
+ * A new #su_root_t object is created for the sub-task with the @a magic as
+ * the root context pointer. Because the sub-task may or may not have its
+ * own thread, all its activity must be scheduled via this root object. In
+ * other words, the sub-task can be schedule
+ * -# I/O events with su_root_register()
+ * -# timers with su_timer_set(), su_timer_set_at() or su_timer_run()
+ * -# messages with su_msg_send().
+ *
+ * Messages can also be used to pass information between tasks or threads.
+ *
+ * In multi-threaded implementation, su_clone_start() launches a new thread,
+ * and the initialization routine is executed by this newly created thread. 
+ * The calling thread blocks until the initialization routine completes. If
+ * the initialization routine returns #su_success (0), the sub-task is
+ * considered to be created successfully. After the successful
+ * initialization, the sub-task continues to execeute the function
+ * su_root_run().
+ *
+ * In single-threaded implementations, just a new root object is created. 
+ * The initialization routine is called directly from su_clone_start().
+ *
+ * If the initalization function @a init fails, the sub-task (either the
+ * newly created thread or the current thread executing the su_clone_start()
+ * function) calls the deinitialization function, and su_clone_start()
+ * returns NULL.
+ *
+ * @param parent   root to be cloned (may be NULL if multi-threaded)
+ * @param return_clone reference to a clone [OUT]
+ * @param magic    pointer to user data
+ * @param init     initialization function
+ * @param deinit   deinitialization function
+ *
+ * @return 0 if successfull, -1 upon an error.
+ *
+ * @sa su_root_threading(), su_clone_task(), su_clone_stop(), su_clone_wait(),
+ * su_clone_forget().
+ */
+int su_clone_start(su_root_t *parent,
+		   su_clone_r return_clone,
+		   su_root_magic_t *magic,
+		   su_root_init_f init,
+		   su_root_deinit_f deinit)
+{
+  su_root_t *child;
+  int retval = -1;
+
+  if (parent) {
+    assert(SU_ROOT_OWN_THREAD(parent));
+    assert(parent->sur_port);
+  }
+#if !SU_HAVE_PTHREADS
+  else {
+    /* if we don't have threads, we *must* have parent root */
+    return -1;
+  }
+#endif
+
+  child = su_salloc(NULL, sizeof(struct su_root_s));
+
+#if SU_HAVE_PTHREADS
+  if (child && (parent == NULL || parent->sur_threading)) {
+    struct clone_args arg = {
+      NULL, NULL, NULL,
+      PTHREAD_MUTEX_INITIALIZER,
+      PTHREAD_COND_INITIALIZER,
+      -1,
+      SU_MSG_R_INIT,
+      NULL
+    };
+
+    int thread_created = 0;
+    pthread_t tid;
+
+    su_port_threadsafe(parent->sur_port);
+
+    arg.self = child;
+    arg.init = init;
+    arg.deinit = deinit;
+    arg.parent = parent;
+
+    child->sur_magic = magic;
+    child->sur_deinit = deinit;
+    child->sur_threading = parent->sur_threading;
+
+    SU_TASK_COPY(child->sur_parent, su_root_task(parent), su_clone_start);
+
+    pthread_mutex_lock(&arg.mutex);
+    if (pthread_create(&tid, NULL, su_clone_main, &arg) == 0) {
+      pthread_cond_wait(&arg.cv, &arg.mutex);
+      thread_created = 1;
+    }
+    pthread_mutex_unlock(&arg.mutex);
+
+    if (arg.retval != 0) {
+      if (thread_created)
+	pthread_join(tid, NULL);
+      su_root_destroy(child), child = NULL;
+    }
+    else {
+      retval = 0;
+      *return_clone = *arg.clone;
+    }
+  } else
+#endif
+  if (child) {
+    assert(parent);
+
+    child->sur_magic = magic;
+    child->sur_deinit = deinit;
+    child->sur_threading = parent->sur_threading;
+
+    SU_TASK_COPY(child->sur_parent, su_root_task(parent), su_clone_start);
+    SU_TASK_COPY(child->sur_task, child->sur_parent, su_clone_start);
+    su_task_attach(child->sur_task, child);
+
+    if (su_msg_create(return_clone,
+		      child->sur_task, su_root_task(parent),
+		      su_clone_xyzzy, sizeof(child)) == 0) {
+      if (init == NULL || init(child, magic) == 0) {
+	su_cloned_t *sc = su_msg_data(return_clone);
+	sc->sc_root = child;
+#if SU_HAVE_PTHREADS
+	sc->sc_tid = pthread_self();
+	pthread_mutex_init(sc->sc_pause, NULL);
+	pthread_cond_init(sc->sc_resume, NULL);
+	pthread_mutex_lock(sc->sc_pause);
+#endif
+	retval = 0;
+      } else {
+	if (deinit)
+	  deinit(child, magic);
+	su_msg_destroy(return_clone);
+	su_root_destroy(child), child = NULL;
+      }
+    }
+    else {
+      su_root_destroy(child), child = NULL;
+    }
+  }
+
+  return retval;
+}
+
+/** Get reference to clone task.
+ * 
+ * @param clone Clone pointer
+ *
+ * @return A reference to the task structure of the clone.
+ */
+_su_task_r su_clone_task(su_clone_r clone)
+{
+  return su_msg_to(clone);
+}
+
+/**Forget the clone.
+ * 
+ * Normally, the clone task executes until it is stopped.  If the parent
+ * task does not need to stop the task, it can "forget" the clone.  The
+ * clone exits independently of the parent task.
+ *
+ * @param rclone Reference to the clone.
+ */
+void su_clone_forget(su_clone_r rclone)
+{
+  su_msg_destroy(rclone);
+}
+
+/** Stop the clone.
+ *
+ * @deprecated. Use su_clone_wait().
+ */
+void su_clone_stop(su_clone_r rclone)
+{
+  su_msg_send(rclone);
+}
+
+/** Stop a clone and wait until it is has completed.
+ *
+ * The function su_clone_wait() is used to stop the clone task and wait
+ * until it has cleaned up. The clone task is destroyed asynchronously. The
+ * parent sends a message to clone, clone deinitializes itself and then
+ * replies. After the reply message is received by the parent, it will send
+ * a third message back to clone.
+ *
+ * The parent destroy all messages to or from clone task before calling
+ * su_clone_wait(). The parent task may not send any messages to the clone
+ * after calling su_clone_wait(). The su_clone_wait() function blocks until
+ * the cloned task is destroyed. During that time, the parent task must be
+ * prepared to process all the messages sent by clone task. This includes
+ * all the messages sent by clone before destroy message reached the clone.
+ */
+void su_clone_wait(su_root_t *root, su_clone_r rclone)
+{
+  su_cloned_t *sc = su_msg_data(rclone);
+
+  if (sc) {
+#if SU_HAVE_PTHREADS
+    pthread_t clone_tid = sc->sc_tid;
+#endif
+    int one = 1;
+    /* This does 3-way handshake. 
+     * First, su_clone_break() is executed by clone. 
+     * The message is returned to parent (this task), 
+     * which executes su_clone_report().
+     * Then the message is again returned to clone, 
+     * which executes su_clone_report2() and exits.
+     */
+    sc->sc_wait = &one;
+    su_msg_send(rclone);
+
+    su_root_step(root, 0);
+    su_root_step(root, 0);
+
+    while (one)
+      su_root_step(root, 10);
+
+#if SU_HAVE_PTHREADS
+    if (!pthread_equal(clone_tid, pthread_self()))
+      pthread_join(clone_tid, NULL);
+#endif
+  }
+}
+
+#if SU_HAVE_PTHREADS		/* No-op without threads */
+static
+void su_clone_paused(su_root_magic_t *magic, su_msg_r msg, su_msg_arg_t *arg)
+{
+  su_cloned_t *cloned = *(su_cloned_t **)arg;
+  assert(cloned);
+  pthread_cond_wait(cloned->sc_resume, cloned->sc_pause);
+}
+#endif
+
+/** Pause a clone.
+ *
+ * Obtain a exclusive lock on clone's private data.
+ *
+ * @retval 0 if successful (and clone is paused)
+ * @retval -1 upon an error
+ */
+int su_clone_pause(su_clone_r rclone)
+{
+#if SU_HAVE_PTHREADS		/* No-op without threads */
+  su_cloned_t *cloned = su_msg_data(rclone);
+  su_msg_r m = SU_MSG_R_INIT;
+
+  if (!cloned)
+    return (errno = EFAULT), -1;
+
+  if (pthread_equal(pthread_self(), cloned->sc_tid))
+    return 0;
+
+  if (su_msg_create(m, su_clone_task(rclone), su_task_null,
+		    su_clone_paused, sizeof cloned) < 0)
+    return -1;
+
+  *(su_cloned_t **)su_msg_data(m) = cloned;
+
+  if (su_msg_send(m) < 0)
+    return -1;
+
+  if (pthread_mutex_lock(cloned->sc_pause) < 0)
+    return -1;
+  pthread_cond_signal(cloned->sc_resume);
+#endif
+
+  return 0;
+}
+
+/** Resume a clone.
+ *
+ * Give up a exclusive lock on clone's private data.
+ *
+ * @retval 0 if successful (and clone is resumed)
+ * @retval -1 upon an error
+ */
+int su_clone_resume(su_clone_r rclone)
+{
+#if SU_HAVE_PTHREADS		/* No-op without threads */
+  su_cloned_t *cloned = su_msg_data(rclone);
+
+  if (!cloned)
+    return (errno = EFAULT), -1;
+
+  if (pthread_equal(pthread_self(), cloned->sc_tid))
+    return 0;
+
+  if (pthread_mutex_unlock(cloned->sc_pause) < 0)
+    return -1;
+#endif
+
+  return 0;
+}
+
+
+/* =========================================================================
+ * Messages
+ */
+
+/**
+ * Allocates a message of given size.
+ *
+ * The function @c su_msg_create() allocates a message with given data size.
+ * If successful, it moves the new message handle to the @c rmsg.
+ *
+ * @param  rmsg   handle to the new message (may be uninitialized prior calling)
+ * @param  to     the recipient task
+ * @param  from   the sender task
+ * @param  wakeup function that is called when message is delivered
+ * @param  size   size of the message data
+ *
+ * @retval  0 if successful,
+ * @retval -1 if message allocation fails.  
+ */
+int su_msg_create(su_msg_r        rmsg,
+		  su_task_r const to,
+		  su_task_r const from,
+		  su_msg_f        wakeup,
+		  isize_t         size)
+{
+  su_port_t *port = to->sut_port;
+  su_msg_t *msg;
+
+  SU_PORT_LOCK(port, su_msg_create);
+  msg = su_zalloc(NULL /*port->sup_home*/, sizeof(*msg) + size);
+  SU_PORT_UNLOCK(port, su_msg_create);
+
+  if (msg) {
+    msg->sum_size = sizeof(*msg) + size;
+    SU_TASK_COPY(msg->sum_to, to, su_msg_create);
+    SU_TASK_COPY(msg->sum_from, from, su_msg_create);
+    msg->sum_func = wakeup;
+    *rmsg = msg;
+    return 0;
+  } 
+
+  *rmsg = NULL;
+  return -1;
+}
+
+/** Add a delivery report function to a message.
+ * 
+ * The delivery report funcgtion gets called by the sending task after the
+ * message was delivered and the message function was executed. (The
+ * su_root_t message delivery loop calls su_msg_delivery_report() 
+ * 
+ */
+int su_msg_report(su_msg_r msg,
+		  su_msg_f report)
+{
+  if (msg && msg[0] && msg[0]->sum_report == NULL) {
+    msg[0]->sum_report = report;
+    return 0;
+  }
+
+  return -1;
+}
+
+/**
+ * Allocates a reply message of given size.
+ *
+ * @param reply     handle to the new message (may be uninitialized prior calling)
+ * @param msg       the incoming message
+ * @param wakeup    function that is called when message is delivered
+ * @param size      size of the message data
+ *
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+
+int su_msg_reply(su_msg_r reply, su_msg_r const msg,
+		 su_msg_f wakeup, isize_t size)
+{
+  su_msg_r msg0;
+
+  assert(msg != reply);
+
+  *msg0 = *msg;
+  *reply = NULL;
+
+  return su_msg_create(reply, su_msg_from(msg0), su_msg_to(msg0), wakeup, size);
+}
+
+
+/** Send a delivery report.
+ *
+ * If the sender has attached a delivery report function to message with
+ * su_msg_report(), the message is returned to the message queue of the
+ * sending task. The sending task calls the delivery report function when it
+ * has received the message.
+ */
+void su_msg_delivery_report(su_msg_r msg)
+{
+  su_task_r swap;
+
+  if (!msg || !msg[0])
+    return;
+
+  if (!msg[0]->sum_report) {
+    su_msg_destroy(msg);
+    return;
+  }
+
+  *swap = *msg[0]->sum_from;
+  *msg[0]->sum_from = *msg[0]->sum_to;
+  *msg[0]->sum_to = *swap;
+
+  msg[0]->sum_func = msg[0]->sum_report;
+  msg[0]->sum_report = NULL;
+  su_msg_send(msg);
+}
+
+/** Save a message. */
+void su_msg_save(su_msg_r save, su_msg_r msg)
+{
+  if (save) {
+    if (msg)
+      save[0] = msg[0];
+    else
+      save[0] = NULL;
+  }
+  if (msg)
+    msg[0] = NULL;
+}
+
+/**
+ * Destroys an unsent message.
+ *
+ * @param rmsg       message handle.
+ */
+void su_msg_destroy(su_msg_r rmsg)
+{
+  assert(rmsg);
+
+  if (rmsg[0]) {
+    /* su_port_t *port = rmsg[0]->sum_to->sut_port; */
+
+    /* SU_PORT_INCREF(port, su_msg_destroy); */
+    SU_TASK_ZAP(rmsg[0]->sum_to, su_msg_destroy);
+    SU_TASK_ZAP(rmsg[0]->sum_from, su_msg_destroy);
+
+    su_free(NULL /* port->sup_home */, rmsg[0]);
+    /* SU_PORT_UNLOCK(port, su_msg_destroy); */
+
+    /* SU_PORT_DECREF(port, su_msg_destroy); */
+  }
+
+  rmsg[0] = NULL;
+}
+
+/** Gets a pointer to the message data area. 
+ *
+ * The function @c su_msg_data() returns a pointer to the message data
+ * area. If @c rmsg contains a @c NULL handle, or message size is 0, @c NULL
+ * pointer is returned.
+ *
+ * @param rmsg       message handle
+ *
+ * @return A pointer to the message data area is returned.  
+ */
+su_msg_arg_t *su_msg_data(su_msg_cr rmsg)
+{
+  if (rmsg[0] && rmsg[0]->sum_size > sizeof(su_msg_t))
+    return rmsg[0]->sum_data;
+  else
+    return NULL;
+}
+
+/** Get size of message data area. */
+isize_t su_msg_size(su_msg_cr rmsg)
+{
+  return rmsg[0] ? rmsg[0]->sum_size - sizeof(su_msg_t) : 0;
+}
+
+/** Get sending task.
+ *
+ * Returns the task handle belonging to the sender of the message.
+ *
+ * If the message handle contains NULL the function @c su_msg_from
+ * returns NULL.
+ *
+ * @param msg       message handle
+ *
+ * @return The task handle of the sender is returned.  
+ */
+_su_task_r su_msg_from(su_msg_r const msg)
+{
+  return msg[0] ? msg[0]->sum_from : NULL;
+}
+
+/** Get destination task.
+ *
+ * The function @c su_msg_from returns the task handle belonging to the
+ * recipient of the message.
+ *
+ * If the message handle contains NULL the function @c su_msg_to
+ * returns NULL.
+ *
+ * @param msg       message handle
+ *
+ * @return The task handle of the recipient is returned.  
+ */
+_su_task_r su_msg_to(su_msg_r const msg)
+{
+  return msg[0] ? msg[0]->sum_to : NULL;
+}
+
+/** Remove references to 'from' and 'to' tasks from a message. 
+ *
+ * @param msg       message handle
+ */
+void su_msg_remove_refs(su_msg_r const msg)
+{
+  if (msg[0]) {
+    su_task_deinit(msg[0]->sum_to);
+    su_task_deinit(msg[0]->sum_from);
+  }
+}
+
+/**Send a message. 
+ *
+ * The function @c su_msg_send() sends the message. The message is added to
+ * the recipients message queue, and recipient is waken up. The caller may
+ * not alter the message or the data associated with it after the message
+ * has been sent.
+ *
+ * @param rmsg message handle
+ *
+ * @retval 0 if signal was sent successfully or handle was @c NULL,
+ * @retval -1 otherwise.
+ */
+int su_msg_send(su_msg_r rmsg)
+{
+  assert(rmsg);
+
+  if (rmsg[0]) {
+    su_msg_t *msg = rmsg[0];
+    assert(msg->sum_to->sut_port);
+    return su_port_send(msg->sum_to->sut_port, rmsg);
+  }
+
+  return 0;		
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @CFILE su_sprintf.c  su_*sprintf() functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Apr 17 20:05:21 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#if defined(va_copy)
+/* Xyzzy */
+#elif defined(__va_copy)
+#define va_copy(dst, src) __va_copy((dst), (src))
+#else
+#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
+#endif
+
+#include "sofia-sip/su_alloc.h"
+
+/**Copy a formatted string. 
+ *
+ * The function su_vsprintf() print a string according to a @a fmt like
+ * vprintf() or vsnprintf(). The resulting string is copied to a memory area
+ * fresly allocated from a memory @a home. The returned string is reclaimed
+ * when @a home is destroyed. It can explicitly be freed with su_free() or
+ * free() if @a home is NULL.
+ *
+ * @param home pointer to memory home (may be NULL)
+ * @param fmt format string
+ * @param ap @e stdarg argument list (must match with the @a fmt format string)
+ * 
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char *su_vsprintf(su_home_t *home, char const *fmt, va_list ap)
+{
+  int n;
+  size_t len;
+  char *rv, s[128];
+  va_list aq;
+
+  va_copy(aq, ap);
+  n = vsnprintf(s, sizeof(s), fmt, aq);
+  va_end(aq);
+
+  if (n >= 0 && (size_t)n + 1 < sizeof(s)) 
+    return su_strdup(home, s);
+  
+  len = n > 0 ? (size_t)n + 1 : 2 * sizeof(s);
+
+  for (rv = su_alloc(home, len);
+       rv;
+       rv = su_realloc(home, rv, len)) {
+    va_copy(aq, ap);
+    n = vsnprintf(rv, len, fmt, aq);
+    va_end(aq);
+    if (n > -1 && (size_t)n < len)
+      break;
+    if (n > -1)			/* glibc >2.1 */
+      len = (size_t)n + 1;		
+    else			/* glibc 2.0 */
+      len *= 2;
+
+    if (len > INT_MAX)
+      return (void)su_free(home, rv), NULL;
+  }
+
+  return rv;
+}
+
+/**Copy a formatted string. 
+ *
+ * The function su_sprintf() print a string according to a @a fmt like
+ * printf() or snprintf(). The resulting string is copied to a memory area
+ * freshly allocated from a memory @a home. The returned string is reclaimed
+ * when @a home is destroyed. It can explicitly be freed with su_free() or
+ * free() if @a home is NULL.
+ *
+ * @param home pointer to memory home (may be NULL)
+ * @param fmt format string
+ * @param ... argument list (must match with the @a fmt format string)
+ * 
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char *su_sprintf(su_home_t *home, char const *fmt, ...)
+{
+  va_list ap;
+  char *rv;
+
+  va_start(ap, fmt);
+  rv = su_vsprintf(home, fmt, ap);
+  va_end(ap);
+
+  return rv;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @CFILE su_strdup.c  Home-based string duplication functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Jul 19 10:06:14 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "sofia-sip/su_alloc.h"
+
+/** Duplicate a string, allocate memory from @a home.
+ *
+ * The function su_strdup() duplicates the string @a s.  It allocates @c
+ * strlen(s)+1 bytes from @a home, copies the contents of @a s to the newly
+ * allocated memory, and returns pointer to the duplicated string.
+ *
+ * @param home  pointer to memory home
+ * @param s     string to be duplicated
+ * 
+ * @return The function su_strdup() returns pointer to the newly created
+ *         string, or @c NULL upon an error.
+ */
+char *su_strdup(su_home_t *home, char const *s)
+{
+  if (s) {
+    size_t n = strlen(s);
+    char *retval = su_alloc(home, n + 1);
+    if (retval)
+      strncpy(retval, s, n)[n] = 0;
+    return retval;
+  }
+  return NULL;
+}
+
+/**Concate two strings, allocate memory for result from @a home.
+ *
+ * Concatenate the strings @a s1 and @a s2. The @c strlen(s1)+strlen(s2)+1
+ * bytes is allocated from @a home, the contents of @a s1 and @a s2 is
+ * copied to the newly allocated memory area, and pointer to the
+ * concatenated string is returned.
+ *
+ * @param home  pointer to memory home
+ * @param s1    string to be first string
+ * @param s2    string to be first string
+ * 
+ * @return Pointer to the newly created string is returned, or @c NULL upon
+ * an error.
+ */
+char *su_strcat(su_home_t *home, char const *s1, char const *s2)
+{
+  size_t n1, n2;
+  char *retval;
+
+  if (s1 == NULL)
+    return su_strdup(home, s2);
+  else if (s2 == NULL)
+    return su_strdup(home, s1);
+
+  n1 = strlen(s1); n2 = strlen(s2);
+  retval = su_alloc(home, n1 + n2 + 1);
+  if (retval) {
+    memcpy(retval, s1, n1);
+    memcpy(retval + n1, s2, n2);
+    retval[n1 + n2] = '\0';
+  }
+
+  return retval;
+}
+
+/**Concate multiple strings, allocate memory for result from @a home.
+ *
+ * Concatenate the strings in list. The lenght of result is calculate,
+ * result is allocated from @a home, the contents of strings is copied to
+ * the newly allocated memory arex, and pointer to the concatenated string is
+ * returned.
+ *
+ * @param home  pointer to memory home
+ * @param ...  NULL-terminated list of strings to be concatenated
+ * 
+ * @return Pointer to the newly created string is returned, or @c NULL upon
+ * an error.
+ */
+char *su_strcat_all(su_home_t *home, ...)
+{
+  int i, n;
+  size_t size = 0;
+  va_list va;
+  char *s, *retval, *end;
+
+  /* Count number arguments and their size */
+  va_start(va, home);
+  s = va_arg(va, char *);
+  for (n = 0; s; s = va_arg(va, char *), n++)
+    size += strlen(s);
+  va_end(va);
+
+  retval = su_alloc(home, size + 1);
+  if (retval) {
+    s = retval;
+    end = s + size + 1;
+
+    va_start(va, home);
+
+    for (i = 0; i < n; i++)
+      s = (char *)memccpy(s, va_arg(va, char const *), '\0', end - s) - 1;
+
+    va_end(va);
+
+    retval[size] = '\0';
+  }
+
+  return retval;
+}
+
+
+
+/** Duplicate a string with given size, allocate memory from @a home.
+ *
+ * The function su_strndup() duplicates the string @a s.  It allocates @c n+1
+ * bytes from @a home, copies the contents of @a s to the newly allocated
+ * memory, and returns pointer to the duplicated string.  The duplicated
+ * string is always NUL-terminated.
+ *
+ * @param home  pointer to memory home
+ * @param s     string to be duplicated
+ * @param n     size of the resulting string
+ * 
+ * @return The function su_strndup() returns pointer to the newly created
+ *         string, or @c NULL upon an error.
+ */
+char *su_strndup(su_home_t *home, char const *s, isize_t n)
+{
+  if (s) {
+    char *retval = su_alloc(home, n + 1);
+    if (retval)
+      strncpy(retval, s, n)[n] = 0;
+    return retval;
+  }
+  return NULL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,712 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_strlst String Lists
+ *
+ * Lists of strings.
+ *
+ * String lists using #su_home_t.
+ *
+ */
+
+/**@ingroup su_strlst
+ * @CFILE su_strlst.c
+ * @brief String lists.
+ *
+ * The string lists can be used to concatenate a large number of strings, or
+ * split a string to smaller pieces (e.g., lines).
+ *
+ * Example of concatenating a number of strings to @a s:
+ * @code
+ * su_strlst_t *l = su_strlist_create(home);
+ * su_strlst_append(l, "=============");
+ * su_slprintf(l, "a is: %d", a)
+ * su_slprintf(l, "b is: %d", b)
+ * su_slprintf(l, "c is: %d", c)
+ * su_strlst_append(l, "------------");
+ * su_slprintf(l, "total: %d", a + b + c));
+ * su_strlst_append(l, "=============");
+ * s = su_strlst_join(l, "\n");
+ * @endcode
+ *
+ * Another example, splitting a string into lines and counting the number of
+ * non-empty ones:
+ * @code
+ * usize_t i, n;
+ * su_strlst_t *l;
+ * 
+ * l = su_strlst_split(NULL, buf, "\n");
+ * 
+ * nonempty = 0;
+ * 
+ * for (i = 0; i < su_strlst_len(l); i++) {
+ *   n = strcspn(su_strlst_item(l, i), " \t");
+ *   if (su_strlst_item(l, i)[n])
+ *     nonempty++;
+ * }
+ * 
+ * su_strlst_destroy(l);
+ * @endcode
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Fri May  3 09:22:59 2002 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su_config.h"
+#include "sofia-sip/su_strlst.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+#include <string.h>
+
+#include <assert.h>
+
+#if defined(va_copy)
+/* Xyzzy */
+#elif defined(__va_copy)
+#define va_copy(dst, src) __va_copy((dst), (src))
+#else
+#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
+#endif
+
+enum { N = 8 };
+
+struct su_strlst_s
+{
+  su_home_t    sl_home[1];
+  size_t       sl_size;
+  size_t       sl_len;
+  size_t       sl_total;
+  char const **sl_list;
+};
+
+/** Create a list with initial values */
+static
+su_strlst_t *su_strlst_vcreate_with_by(su_home_t *home,
+				       char const *value,
+				       va_list va,
+				       int deeply)
+{
+  su_strlst_t *self;
+  size_t i, n, m;
+  size_t total, size;
+
+  m = 0, total = 0;
+
+  /* Count arguments and their length */
+  if (value) {
+    char const *s;
+    va_list va0;
+
+    va_copy(va0, va);
+    for (s = value; s; m++, s = va_arg(va0, char *))
+      total += strlen(s);
+    va_end(va0);
+  }
+
+  for (n = N; m > n; n *= 2)
+    ;
+
+  size = sizeof(*self) + n * sizeof(*self->sl_list);
+  if (deeply)
+    size += total + m;
+
+  self = su_home_clone(home, size);
+  if (self) {
+    self->sl_size = n;
+    self->sl_list = (char const **)(self + 1);
+    self->sl_len = m;
+    self->sl_total = total;
+
+    if (deeply) {
+      char *s = (char *)(self->sl_list + self->sl_size);
+      char *end = s + total + m;
+
+      for (i = 0; i < m; i++) {
+	assert(s);
+	self->sl_list[i] = s;
+	s = memccpy(s, value, '\0', end - s);
+	value = va_arg(va, char const *);
+      }
+    }
+    else {
+      for (i = 0; i < m; i++) {
+	self->sl_list[i] = value;
+	value = va_arg(va, char const *);
+      }
+    }
+  }
+
+  return self;
+}
+
+/** Create an empty string list.
+ *
+ * The list is initially empty. The memory home for the list is cloned from
+ * @a home.
+ *
+ */
+su_strlst_t *su_strlst_create(su_home_t *home)
+{
+  su_strlst_t *self;
+
+  self = su_home_clone(home, sizeof(*self) + N * sizeof(*self->sl_list));
+  if (self) {
+    self->sl_size = N;
+    self->sl_list = (char const **)(self + 1);
+  }
+  return self;
+}
+
+/** Create a string list with initial values.
+ *
+ * The list is initialized with strings in argument. The argument list is
+ * terminated with NULL. The memory home for the list is cloned from @a
+ * home.
+ */
+su_strlst_t *su_strlst_create_with(su_home_t *home, char const *value, ...)
+{
+  va_list va;
+  su_strlst_t *l;
+
+  va_start(va, value);
+  l = su_strlst_vcreate_with_by(home, value, va, 0);
+  va_end(va);
+
+  return l;
+}
+
+/** Create a string list with initial values.
+ *
+ * The string list is initialized with strings from @a va_list @a va. The
+ * argument list is terminated with NULL. The memory home for the list is
+ * cloned from @a home.
+ */
+su_strlst_t *su_strlst_vcreate_with(su_home_t *home,
+				    char const *value,
+				    va_list va)
+{
+  return su_strlst_vcreate_with_by(home, value, va, 0);
+}
+
+/** Create a string list with duplicatedd initial values.
+ *
+ * The list is initialized with copies of strings in argument list. The
+ * argument list is terminated with NULL. The memory home for the list is
+ * cloned from @a home.
+ */
+su_strlst_t *su_strlst_create_with_dup(su_home_t *home, char const *value, ...)
+{
+  va_list va;
+  su_strlst_t *l;
+
+  va_start(va, value);
+  l = su_strlst_vcreate_with_by(home, value, va, 1);
+  va_end(va);
+
+  return l;
+}
+
+/** Create a string list with duplicates of initial values.
+ *
+ * The string list is initialized with copies of strings from @a va_list @a
+ * va. The argument list is terminated with NULL. The memory home for the
+ * list is cloned from @a home.
+ */
+su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *home,
+					char const *value,
+					va_list va)
+{
+  return su_strlst_vcreate_with_by(home, value, va, 1);
+}
+
+
+/** Copy a string list */
+static
+su_strlst_t *su_strlst_copy_by(su_home_t *home, 
+			       su_strlst_t const *orig, 
+			       int deeply)
+{
+  su_strlst_t *self;
+  size_t N, i, size, deepsize = 0;
+
+  if (orig == NULL)
+    return NULL;
+
+  N = orig->sl_size;
+
+  if (deeply)
+    deepsize = orig->sl_len + orig->sl_total;
+
+  size = sizeof(*self) + N * sizeof(self->sl_list[0]) + deepsize;
+
+  self = su_home_clone(home, size);
+  if (self) {
+    self->sl_size = N;
+    self->sl_list = (char const **)(self + 1);
+
+    self->sl_len = N = orig->sl_len;
+    self->sl_total = orig->sl_total;
+
+    if (deeply) {
+      char *s = (char *)(self->sl_list + self->sl_size);
+      char *end = s + deepsize;
+      for (i = 0; i < N; i++) {
+	self->sl_list[i] = s;
+	s = memccpy(s, orig->sl_list[i], '\0', end - s);
+	assert(s);
+      }
+    }
+    else {
+      for (i = 0; i < N; i++) {
+	self->sl_list[i] = orig->sl_list[i];
+      }
+    }
+  }
+
+  return self;
+}
+
+/** Shallow copy a string list. */
+su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig)
+{
+  return su_strlst_copy_by(home, orig, 0);
+}
+
+/** Deep copy a string list. */
+su_strlst_t *su_strlst_dup(su_home_t *home, su_strlst_t const *orig)
+{
+  return su_strlst_copy_by(home, orig, 1);
+}
+
+/** Destroy a string list.
+ *
+ * The function su_strlst_destroy() destroys a list of strings and frees all
+ * duplicated strings belonging to it.
+ */
+void su_strlst_destroy(su_strlst_t *self)
+{
+  su_home_zap(self->sl_home);
+}
+
+/** Increase the list size for next item, if necessary. */
+static int su_strlst_increase(su_strlst_t *self)
+{
+  if (self->sl_size <= self->sl_len + 1) {
+    size_t size = 2 * self->sl_size * sizeof(self->sl_list[0]);
+    char const **list;
+
+    if (self->sl_list != (char const **)(self + 1)) {
+      list = su_realloc(self->sl_home, (void *)self->sl_list, size);
+    } else {
+      list = su_alloc(self->sl_home, size);
+      if (list)
+	memcpy(list, self->sl_list, self->sl_len * sizeof(*self->sl_list));
+    }
+    
+    if (!list)
+      return 0;
+
+    self->sl_list = list;
+    self->sl_size = 2 * self->sl_size;
+  }
+
+  return 1;
+}
+
+/**Duplicate and append a string to list. 
+ *
+ * @param self  pointer to a string list object
+ * @param str   string to be duplicated and appended
+ *
+ * @return
+ * Pointer to duplicated string, if successful, or NULL upon an error.
+ */
+char *su_strlst_dup_append(su_strlst_t *self, char const *str)
+{
+  size_t len;
+
+  if (str == NULL)
+    str = "";
+
+  len = strlen(str);
+
+  if (self && su_strlst_increase(self)) {
+    char *retval = su_alloc(self->sl_home, len + 1);
+    if (retval) {
+      memcpy(retval, str, len);
+      retval[len] = 0;
+      self->sl_list[self->sl_len++] = retval;
+      self->sl_total += len;
+    }
+    return retval;
+  }
+  return NULL;
+}
+
+/**Append a string to list.
+ *
+ * The string is not copied, and it @b must not be modified while string
+ * list exists.
+ *
+ * @param self  pointer to a string list object
+ * @param str   string to be appended
+ *
+ * @return
+ * Pointer to string, if successful, or NULL upon an error.
+ */
+char const *su_strlst_append(su_strlst_t *self, char const *str)
+{
+  if (str == NULL)
+    str = "";
+
+  if (self && su_strlst_increase(self)) {
+    self->sl_list[self->sl_len++] = str;
+    self->sl_total += strlen(str);
+    return str;
+  }
+  return NULL;
+}
+
+/**Append a formatted string to the list.
+ *
+ * Format a string according to a @a fmt like printf(). The resulting string
+ * is copied to a memory area freshly allocated from a the memory home of
+ * the list and appended to the string list.
+ *
+ * @param self  pointer to a string list object
+ * @param fmt format string
+ * @param ... argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char const *su_slprintf(su_strlst_t *self, char const *fmt, ...)
+{
+  char const *str;
+  va_list ap;
+  va_start(ap, fmt);
+  str = su_slvprintf(self, fmt, ap);
+  va_end(ap);
+
+  return str;
+}
+
+/**Append a formatted string to the list.
+ *
+ * Format a string according to a @a fmt like vprintf(). The resulting
+ * string is copied to a memory area freshly allocated from a the memory
+ * home of the list and appended to the string list.
+ *
+ * @param self  pointer to a string list object
+ * @param fmt  format string
+ * @param ap   stdarg argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap)
+{
+  char *str = NULL;
+
+  if (self && su_strlst_increase(self)) {
+    str = su_vsprintf(self->sl_home, fmt, ap);
+    if (str) {
+      self->sl_list[self->sl_len++] = str;
+      self->sl_total += strlen(str);
+    }
+  }
+  return str;
+}
+
+/**Returns a numbered item from the list of strings. The numbering starts from
+ * 0.
+ * 
+ * @param self  pointer to a string list object
+ * @param i     string index
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+char const *su_strlst_item(su_strlst_t const *self, usize_t i)
+{
+  if (self && i < self->sl_len)
+    return self->sl_list[i];
+  else
+    return NULL;
+}
+
+/**Sets a item to the list of strings. 
+ *
+ * Note that the item numbering starts from 0.
+ * 
+ * @param self  pointer to a string list object
+ * @param i     string index
+ * @param s     string to be set as item @a i
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+char const *su_strlst_set_item(su_strlst_t *self, usize_t i, char const *s)
+{
+  char const *old = NULL;
+
+  if (self == NULL)
+    return NULL;
+  else if (i == self->sl_len)
+    return (void)su_strlst_append(self, s), NULL;
+  else if (i > self->sl_len)
+    return NULL;
+
+  if (s == NULL)
+    s = "";
+
+  old = self->sl_list[i];
+
+  self->sl_list[i] = s;
+
+  return old;
+}
+
+/**Removes a numbered item from the list of strings. The numbering starts from
+ * 0. The caller is responsible of reclaiming memory used by the removed string.
+ * 
+ * @param self  pointer to a string list object
+ * @param i     string index
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+SU_DLL char const *su_strlst_remove(su_strlst_t *self, usize_t i)
+{
+  if (self && i < self->sl_len) {
+    char const *s = self->sl_list[i];
+
+    memmove(&self->sl_list[i], &self->sl_list[i + 1], 
+	    &self->sl_list[self->sl_len] - &self->sl_list[i]);
+
+    self->sl_len--;
+
+    return s;
+  }
+  else
+    return NULL;
+}
+
+
+
+/** Concatenate list of strings to one string.
+ *
+ * The function su_strlst_join() concatenates the list of strings. Between
+ * each string in list it uses @a sep. The separator is not inserted after
+ * the last string in list, but one can always append an empty string to the
+ * list.
+ *
+ * The string is allocated from the memory @a home. If @a home is NULL, the
+ * string is allocated using malloc().
+ *
+ * @param self  pointer to a string list object
+ * @param home  home pointer
+ * @param sep   separator (may be NULL)
+ *
+ * @return 
+ *
+ * The function su_strlst_join() returns a concatenation of the strings in
+ * list, or NULL upon an error.
+ */
+char *su_strlst_join(su_strlst_t *self, su_home_t *home, char const *sep)
+{
+  if (!sep)
+    sep = "";
+
+  if (self && self->sl_len > 0) {
+    size_t seplen = strlen(sep);
+    size_t total = self->sl_total + seplen * (self->sl_len - 1);
+    char *retval;
+
+    retval = su_alloc(home, total + 1);
+
+    if (retval) {
+      char *s = retval;
+      size_t i = 0, len;
+
+      for (;;) {
+	len = strlen(self->sl_list[i]);
+	memcpy(s, self->sl_list[i], len), s += len;
+	if (++i >= self->sl_len)
+	  break;
+	memcpy(s, sep, seplen),	s += seplen;
+      }
+      *s = '\0';
+      assert(s == retval + total);
+    }
+
+    return retval;
+  }
+
+  return su_strdup(home, "");
+}
+
+static inline
+su_strlst_t *
+su_strlst_split0(su_strlst_t *l, char *str, char const *sep)
+{
+  size_t n = sep ? strlen(sep) : 0;
+  char *s;
+
+  if (n > 0) {
+    while ((s = strstr(str, sep))) {
+      *s = '\0';
+      if (!su_strlst_append(l, str))
+	return NULL;
+      str = s + n;
+    }
+  }
+
+  if (!su_strlst_append(l, str))
+    return NULL;
+
+  return l;
+}
+
+/**Split a string. 
+ *
+ * Splits a string to substrings. It returns a string list object. The
+ * string to be split is not copied but instead modified in place. Use
+ * su_strlst_dup_split() if you do not want to modify @a str.
+ *
+ * @param home  home pointer
+ * @param str     string to be split
+ * @param sep   separator between substrings
+ *
+ * @return
+ * Pointer to list of strings, if successful, or NULL upon an error.
+ */
+su_strlst_t *
+su_strlst_split(su_home_t *home, char *str, char const *sep)
+{
+  if (str) {
+    su_strlst_t *l = su_strlst_create(home);
+
+    if (!su_strlst_split0(l, str, sep))
+      su_strlst_destroy(l), l = NULL;
+
+    return l;
+  }
+  return NULL;
+}
+
+/**Duplicate and split a string. 
+ *
+ * Duplicates a string and splits the result to substrings. It returns a
+ * string list object. The string to be splitted is not modified.
+ *
+ * @param home  home pointer
+ * @param cstr  string to be split
+ * @param sep   separator between substrings
+ *
+ * @return
+ * Pointer to list of strings, if successful, or NULL upon an error.
+ */
+su_strlst_t *su_strlst_dup_split(su_home_t *home, 
+				 char const *cstr, 
+				 char const *sep)
+{
+  if (cstr) {
+    su_strlst_t *l = su_strlst_create(home);
+
+    if (l) {
+      char *s = su_strdup(su_strlst_home(l), cstr);
+
+      if (s && !su_strlst_split0(l, s, sep))
+	su_strlst_destroy(l), l = NULL;
+    }
+
+    return l;
+  }
+  return NULL;
+}
+
+/** Get number of items in list. 
+ *
+ * The function su_strlst_len() returns the number of items in the 
+ * string list.
+ * 
+ */
+usize_t su_strlst_len(su_strlst_t const *l)
+{
+  return l ? l->sl_len : 0;
+}
+
+/**Get a string array from list. 
+ *
+ * The function su_strlst_get_array() returns an array of strings. The
+ * length of the array is always one longer than the length of the string
+ * list, and the last string in the returned array is always NULL.
+ * 
+ * @param self pointer to a string list object
+ *
+ * @return
+ * Pointer to array of strings, or NULL if error occurred.
+ */
+char const **su_strlst_get_array(su_strlst_t *self)
+{
+  if (self) {
+    char const **retval;
+    size_t size = sizeof(retval[0]) * (self->sl_len + 1);
+
+    retval = su_alloc(self->sl_home, size);
+    
+    if (retval) {
+      memcpy(retval, self->sl_list, sizeof(retval[0]) * self->sl_len);
+      retval[self->sl_len] = NULL;
+      return retval;
+    }
+  }
+
+  return NULL;
+}
+
+/**Free a string array. 
+ *
+ * The function su_strlst_free_array() discards a string array allocated
+ * with su_strlst_get_array().
+ * 
+ * @param self  pointer to a string list object
+ * @param array  string array to be freed
+ *
+ */
+void su_strlst_free_array(su_strlst_t *self, char const **array)
+{
+  if (array)
+    su_free(self->sl_home, (void *)array);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ * 
+ * @CFILE su_tag.c  
+ *
+ * Special tags.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 20:03:38 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+
+#include <sofia-sip/su_config.h>
+#include <sofia-sip/su_tag_class.h>
+
+extern tag_class_t null_tag_class[1];
+extern tag_class_t skip_tag_class[1];
+extern tag_class_t next_tag_class[1];
+extern tag_class_t any_tag_class[1];
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ * 
+ * @CFILE su_tag_io.c
+ * @brief Printing tag lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Wed Feb 21 12:12:27 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/su_tag_inline.h>
+
+/** Print tags */
+void tl_print(FILE *f, char const *title, tagi_t const lst[])
+{
+  fputs(title, f);
+
+  for (; lst; lst = t_next(lst)) {
+    char buffer[4096];
+    char const *fmt = "   %s\n";
+    int n;
+
+    buffer[0] = '\0';
+
+    n = t_snprintf(lst, buffer, sizeof(buffer));
+
+    if (n + 1 < (int)sizeof(buffer)) {
+      if (n > 0 && buffer[n - 1] == '\n')
+	fmt = "   %s";
+    }
+    else 
+      buffer[sizeof(buffer) - 1] = '\0';
+    fprintf(f, fmt, buffer);
+  }
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1606 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ * 
+ * @CFILE su_taglist.c  
+ *
+ * Implementation of tag items and lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 20:03:38 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(va_copy)
+/* Xyzzy */
+#elif defined(__va_copy)
+#define va_copy(dst, src) __va_copy((dst), (src))
+#else
+#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
+#endif
+
+#include <assert.h>
+
+#include <sofia-sip/su_config.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/su_tagarg.h>
+
+/**@defgroup su_tag Tag Item Lists
+ *
+ * Object-oriented tag routines for Sofia utility library.
+ *
+ * The <su_tag.h> defines a interface to object-oriented tag list routines. 
+ * A tag list is a linear list (array) of tag items, tagi_t structures,
+ * terminated by a TAG_END() item. Each tag item has a label, tag, (@c
+ * t_tag) and a value (@c t_value). The tag is a pointer (tag_type_t) to a
+ * structure defining how the value should be interpreted, in other words,
+ * the name and the type of the value. The value or pointer to the actual
+ * value is stored as opaque data (tag_value_t). The tag item structure is
+ * defined as follows:
+ *
+ * @code
+ * typedef struct {
+ *   tag_type_t   t_tag;
+ *   tag_value_t  t_value;
+ * } tagi_t;
+ * @endcode
+ *
+ * The tag lists are central concept in the Sofia APIs. The tags lists can
+ * be used to a list of named arguments to a @ref tagarg "@em tagarg"
+ * function, to store variable amount of data in a memory area, and pass
+ * data between processes and threads.
+ * 
+ * The tagged argument lists can be used like named arguments in
+ * higher-level languages. The argument list consists of tag-value pairs;
+ * tags specify the name and type of the value. All the tag items are not
+ * necessarily interpreted by the called function, but it can pass the list
+ * to other functions. This feature is used also by the Sofia APIs, the
+ * lower-layer settings and options are frequently passed through the
+ * upper-layer API in the tag lists.
+ * 
+ * The tagged argument lists are constructed using special macros that
+ * expand to two function arguments, tag and value. Each tag item macro
+ * checks its arguments type so the tagged argument lists are typesafe if
+ * the list is correctly constructed.
+ * 
+ * Each function documents the tags it accepts and also the tags it may pass
+ * to the lower layers (at least in theory).
+ * 
+ * @par Special Tags
+ *
+ * There are a new special tags that are used to control and modify the tag
+ * list processing itself. These special tags are as follows:
+ * - TAG_NULL() or TAG_END() - indicates the end of tag list
+ * - TAG_SKIP() - indicates an empty (overwritten) tag item 
+ * - TAG_NEXT() - contains a pointer to the next tag list.
+ *
+ * The tag type structures are declared as tag_typedef_t. They can be
+ * defined by the macros found in <su_tag_class.h>. See nta_tag.c or
+ * su_tag_test.c for an example.
+ *
+ */
+
+/**@class tag_class_s sofia-sip/su_tag_class.h <sofia-sip/su_tag_class.h>
+ *
+ * @brief Virtual function table for @ref su_tag "tags".
+ *
+ * The struct tag_class_s contains virtual function table for tags,
+ * specifying non-default behaviour of different tags. It provides functions
+ * for copying, matching, printing and converting the tagged values.
+ */
+
+#ifdef longlong
+typedef longlong unsigned llu;
+#else
+typedef long unsigned llu;
+#endif
+
+/** Print a tag. */
+int t_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  tag_type_t tt = TAG_TYPE_OF(t);
+  int n, m;
+  
+  n = snprintf(b, size, "%s::%s: ", 
+               tt->tt_ns ? tt->tt_ns : "",
+	       tt->tt_name ? tt->tt_name : "null");
+  if (n < 0)
+    return n;
+
+  if ((size_t)n > size)
+    size = n;
+
+  if (tt->tt_snprintf)
+    m = tt->tt_snprintf(t, b + n, size - n);
+  else
+    m = snprintf(b + n, size - n, "%llx", (llu)t->t_value);
+
+  if (m < 0)
+    return m;
+
+  if (m == 0 && (size_t)n < size)
+    b[--n] = '\0';
+
+  return n + m;
+}
+
+/** Get next tag item from list.
+ */
+tagi_t *tl_next(tagi_t const *t)
+{
+  tag_type_t tt;
+
+  t = t_next(t);
+
+  for (tt = TAG_TYPE_OF(t); t && tt->tt_next; tt = TAG_TYPE_OF(t)) {
+    t = tt->tt_next(t);
+  }
+
+  return (tagi_t *)t;
+}
+
+/**Move a tag list.
+ * 
+ * The function tl_tmove() moves the tag list arguments to @a dst.  The @a
+ * dst must have big enough for all arguments.
+ * 
+ * @param dst   pointer to the destination buffer
+ * @param size  sizeof @a dst
+ * @param t_tag,t_value,... tag list
+ *
+ * @return
+ * The function tl_tmove() returns number of tag list items initialized.
+ */
+size_t tl_tmove(tagi_t *dst, size_t size, 
+		tag_type_t t_tag, tag_value_t t_value, ...)
+{
+  size_t n = 0, N = size / sizeof(tagi_t);
+  tagi_t tagi[1];
+  va_list ap;
+  
+  va_start(ap, t_value); 
+
+  tagi->t_tag = t_tag, tagi->t_value = t_value;
+
+  for (;;) {
+    assert((size_t)((char *)&dst[n] - (char *)dst) < size);
+    if (n < N)
+      dst[n] = *tagi;
+    n++;
+    if (t_end(tagi)) 
+      break;
+
+    tagi->t_tag = va_arg(ap, tag_type_t);
+    tagi->t_value = va_arg(ap, tag_value_t);
+  }
+
+  va_end(ap);
+
+  return n;
+}
+
+/**Move a tag list.
+ * 
+ * The function tl_move() copies the tag list @a src to the buffer @a
+ * dst. The size of the @a dst list must be at least @c tl_len(src) bytes.
+ * 
+ * @param dst pointer to the destination buffer
+ * @param src tag list to be moved
+ *
+ * @return
+ * The function tl_move() returns a pointer to the @a dst list after last
+ * moved element.  
+ */
+tagi_t *tl_move(tagi_t *dst, tagi_t const src[])
+{
+  do {
+    dst = t_move(dst, src);
+  }
+  while ((src = t_next(src)));
+
+  return dst;
+}
+
+/** Calculate effective length of a tag list as bytes. */
+size_t tl_len(tagi_t const lst[])
+{
+  size_t len = 0;
+  
+  do {
+    len += t_len(lst);
+  } 
+  while ((lst = t_next(lst)));
+
+  return len;
+}
+
+/** Calculate the size of extra memory areas associated with tag list. */
+size_t tl_xtra(tagi_t const lst[], size_t offset)
+{
+  size_t xtra = offset;
+
+  for (; lst; lst = t_next(lst))
+    xtra += t_xtra(lst, xtra);
+
+  return xtra - offset;
+}
+
+/** Duplicate a tag list.
+ *
+ * Deep copy the tag list @a src to the buffer @a dst. Memory areas
+ * associated with @a src are copied to buffer at @a **bb.
+ *
+ * This is a rather low-level function. See tl_adup() for a more convenient
+ * functionality.
+ *
+ * The size of the @a dst buffer must be at least @c tl_len(src) bytes.  The
+ * size of buffer @a **bb must be at least @c tl_dup_xtra(src) bytes. 
+ * 
+ * @param[out] dst pointer to the destination buffer
+ * @param[in] src tag list to be duplicated
+ * @param[in,out] bb  pointer to pointer to buffer
+ *
+ * @return
+ * A pointer to the @a dst list after last
+ * duplicated taglist element.  
+ *
+ * The pointer at @a *bb is updated to the byte after last duplicated memory
+ * area.
+ */
+tagi_t *tl_dup(tagi_t dst[], tagi_t const src[], void **bb)
+{
+  do {
+    dst = t_dup(dst, src, bb);
+  } while ((src = t_next(src)));
+
+  return dst;
+}
+	       
+
+/** Free a tag list.
+ *
+ * The function tl_free() frees resources associated with a tag list.
+ * In other words, it calls t_free on each tag item on the list. 
+ *
+ */
+void tl_free(tagi_t list[])
+{
+  while (list)
+    list = t_free(list);
+}
+
+/** Allocate and duplicate a tag list using memory home. */
+tagi_t *tl_adup(su_home_t *home, tagi_t const lst[])
+{
+  size_t len = tl_len(lst);
+  size_t xtra = tl_xtra(lst, 0);
+  void *b = su_alloc(home, len + xtra);
+  tagi_t *d, *newlst = b;
+
+  void *end = (char *)b + len + xtra;
+  tagi_t *tend = (tagi_t*)((char *)b + len);
+
+  b = (char *)b + len;
+
+  d = tl_dup(newlst, lst, &b);
+
+  assert(b == end); assert(tend == d); (void)end; (void)tend;
+
+  return newlst;
+}
+
+/** Allocate and duplicate tagged arguments as a tag list using memory home. */
+tagi_t *tl_tlist(su_home_t *home, tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t *tl;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+  tl = tl_adup(home, ta_args(ta));
+  ta_end(ta);
+
+  return tl;
+}
+
+/** Find first tag item with type @a tt from list. */
+tagi_t *tl_find(tagi_t const lst[], tag_type_t tt)
+{
+  return (tagi_t *)t_find(tt, lst);
+}
+
+/** Find last tag item with type @a tt from list. */
+tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt)
+{
+  tagi_t const *last, *next;
+  
+  for (next = last = t_find(tt, lst); next; next = t_find(tt, t_next(last)))
+    last = next;
+
+  return (tagi_t *)last;
+}
+
+static inline
+int t_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  if (value == NULL)
+    return 0;
+
+  if (tt->tt_class->tc_ref_set)
+    return tt->tt_class->tc_ref_set(tt, ref, value);
+
+  *(tag_value_t *)ref = value->t_value;
+
+  return 1;
+}
+
+static int tl_get(tag_type_t tt, void *p, tagi_t const lst[])
+{
+  tagi_t const *t, *latest = NULL;
+  
+  assert(tt);
+  
+  if (tt == NULL || p == NULL)
+    return 0;
+
+  if (tt->tt_class == ref_tag_class)
+    tt = (tag_type_t)tt->tt_magic;
+
+  for (t = t_find(tt, lst); t; t = t_find(tt, t_next(t)))
+    latest = t;
+
+  return t_ref_set(tt, p, latest);
+}
+
+/** Find tags from given list. */
+int tl_gets(tagi_t const lst[], tag_type_t tag, tag_value_t value, ...)
+{
+  int n = 0;
+  tagi_t *t;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  for (t = ta_args(ta); t; t = (tagi_t *)t_next(t)) {
+    tag_type_t tt = t->t_tag;
+
+    if (!tt)
+      continue;
+
+    if (tt->tt_class == ref_tag_class) {
+      assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);
+      n += tl_get(tt, (void *)t->t_value, lst);
+    }
+#if !defined(NDEBUG)
+    else if (tt->tt_class && tt->tt_class->tc_ref_set) {
+      fprintf(stderr, "WARNING: tag %s::%s directly used by tl_gets()\n",
+	      tt->tt_ns, tt->tt_name);
+      assert(tt->tt_class == ref_tag_class);
+    }
+#endif
+  } 
+
+  ta_end(ta);
+
+  return n;
+}
+
+/** Find tags from given list. 
+ *
+ * Copies values of argument tag list into the reference tags in the tag
+ * list @a lst.
+ *
+ * @sa tl_gets()
+ */
+int tl_tgets(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
+{
+  int n = 0;
+  tagi_t *t;
+
+  ta_list ta;
+  ta_start(ta, tag, value);
+
+  for (t = lst; t; t = (tagi_t *)t_next(t)) {
+    tag_type_t tt = t->t_tag;
+
+    if (!tt)
+      continue;
+
+    if (tt->tt_class == ref_tag_class) {
+      assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);
+      n += tl_get(tt, (void *)t->t_value, ta_args(ta));
+    }
+#if !defined(NDEBUG)
+    else if (tt->tt_class->tc_ref_set) {
+      fprintf(stderr, "WARNING: tag %s::%s used in tl_tgets(lst)\n",
+	      tt->tt_ns, tt->tt_name);
+      assert(tt->tt_class == ref_tag_class);
+    }
+#endif
+  } 
+
+  ta_end(ta);
+
+  return n;
+}
+
+
+/** Filter an element in tag list */
+tagi_t *t_filter(tagi_t *dst, 
+		 tagi_t const filter[], 
+		 tagi_t const *src, 
+		 void **bb)
+{
+  tag_type_t tt = TAG_TYPE_OF(src);
+  tagi_t const *f;
+
+  if (dst) {
+    for (f = filter; f; f = t_next(f)) {
+      if (TAG_TYPE_OF(f)->tt_filter)
+	dst = TAG_TYPE_OF(f)->tt_filter(dst, f, src, bb);
+      else if (f->t_tag == tt)
+	dst = t_dup(dst, src, bb); 
+    }
+  }
+  else {
+    size_t d = 0;
+
+    for (f = filter; f; f = t_next(f)) {
+      if (TAG_TYPE_OF(f)->tt_filter)
+	d += (size_t)TAG_TYPE_OF(f)->tt_filter(NULL, f, src, bb);
+      else if (tt == f->t_tag) {
+	d += t_len(src);
+	*bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+      }
+    }
+
+    dst = (tagi_t *)d;
+  }
+
+  return dst;
+}
+
+/** Make filtered copy of a tag list @a src with @a filter to @a dst.
+ *
+ * Each tag in @a src is checked against tags in list @a filter. If the tag
+ * is in the @a filter list, or there is a special filter tag in the list
+ * which matches with the tag in @a src, the tag is duplicated to @a dst using 
+ * memory buffer in @a b.
+ *
+ * When @a dst is NULL, this function calculates the size of the filtered list.
+ *
+ * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
+ * TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_filter(tagi_t dst[], 
+		  tagi_t const filter[], 
+		  tagi_t const src[], 
+		  void **b)
+{
+  tagi_t const *s;
+  tagi_t *d;
+
+  if (dst) {
+    for (s = src, d = dst; s; s = t_next(s))
+      d = t_filter(d, filter, s, b);
+  }
+  else {
+    size_t rv = 0;
+
+    for (s = src, d = dst; s; s = t_next(s)) {
+      d = t_filter(NULL, filter, s, b);
+      rv += (char *)d - (char *)NULL;
+    }
+
+    d = (tagi_t *)rv;
+  }
+
+  return d;
+}
+
+
+
+/**Filter a tag list. 
+ * 
+ * The function tl_afilter() will build a tag list containing tags specified
+ * in @a filter and extracted from @a src.  It will allocate the memory used by
+ * tag list via the specified memory @a home, which may be also @c NULL.
+ *
+ * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(), 
+ * TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[])
+{
+  tagi_t *dst, *d, *t_end = NULL;
+  void *b, *end = NULL;
+  size_t len;
+
+  /* Calculate length of the result */
+  t_end = tl_filter(NULL, filter, src, &end);
+  len = ((char *)t_end - (char *)NULL) + ((char *)end - (char*)NULL);
+
+  if (len == 0)
+    return NULL;
+
+  /* Allocate the result */
+  if (!(dst = su_alloc(home, len)))
+    return NULL;
+
+  /* Build the result */
+  b = (dst + (t_end - (tagi_t *)NULL));
+  d = tl_filter(dst, filter, src, (void **)&b);
+
+  /* Ensure that everything is consistent */
+  assert(d == dst + (t_end - (tagi_t *)NULL));
+  assert(b == (char *)dst + len);
+
+  return dst;
+}
+
+/** Filter tag list @a src with given tags.
+ * 
+ * @sa tl_afilter(), tl_filtered_tlist(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[], 
+		   tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t *tl;
+  ta_list ta;
+  ta_start(ta, tag, value);
+  tl = tl_afilter(home, ta_args(ta), src);
+  ta_end(ta);
+  return tl;
+}
+
+/** Create a filtered tag list.
+ *
+ * @sa tl_afilter(), tl_tfilter(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[], 
+			  tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t *tl;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+  tl = tl_afilter(home, filter, ta_args(ta));
+  ta_end(ta);
+
+  return tl;
+}
+
+
+/** Remove listed tags from the list @a lst. */
+int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
+{
+  tagi_t *l, *l_next;
+  int retval = 0;
+  ta_list ta;
+
+  ta_start(ta, tag, value);
+
+  for (l = lst; l; l = l_next) {
+    if ((l_next = (tagi_t *)t_next(l))) {
+      if (tl_find(ta_args(ta), l->t_tag))
+	l->t_tag = tag_skip;
+      else
+	retval++;
+    }
+  }
+
+  ta_end(ta);
+
+  return retval;
+}
+
+/** Calculate length of a tag list with a @c va_list. */
+size_t tl_vlen(va_list ap)
+{
+  size_t len = 0;
+  tagi_t tagi[2] = {{ NULL }};
+
+  do {
+    tagi->t_tag = va_arg(ap, tag_type_t );
+    tagi->t_value = va_arg(ap, tag_value_t);
+    len += sizeof(tagi_t);
+  } while (!t_end(tagi));
+
+  return len;
+}
+
+/** Convert va_list to tag list */
+tagi_t *tl_vlist(va_list ap)
+{
+  tagi_t *t, *rv;
+  va_list aq;
+
+  va_copy(aq, ap);
+  rv = malloc(tl_vlen(aq));
+  va_end(aq);
+
+  for (t = rv; t; t++) {
+    t->t_tag = va_arg(ap, tag_type_t);
+    t->t_value = va_arg(ap, tag_value_t);
+
+    if (t_end(t))
+      break;
+  }
+
+  return rv;
+}
+
+tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap)
+{
+  tagi_t *t, *rv;
+  tagi_t tagi[1];
+  size_t size;
+
+  tagi->t_tag = tag, tagi->t_value = value;
+
+  if (!t_end(tagi)) {
+    va_list aq;
+    va_copy(aq, ap);
+    size = sizeof(tagi) + tl_vlen(aq);
+    va_end(aq);
+  }
+  else
+    size = sizeof(tagi);
+
+  t = rv = malloc(size);
+
+  for (;t;) {
+    *t++ = *tagi;
+
+    if (t_end(tagi)) 
+      break;
+
+    tagi->t_tag = va_arg(ap, tag_type_t);
+    tagi->t_value = va_arg(ap, tag_value_t);
+  }
+  
+  assert((char *)rv + size == (char *)t);
+
+  return rv;
+}
+
+/** Make a tag list until TAG_NEXT() or TAG_END() */
+tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...)
+{
+  va_list ap;  
+  tagi_t *t;
+
+  va_start(ap, value);
+  t = tl_vlist2(tag, value, ap);
+  va_end(ap);
+
+  return t;
+}
+
+/** Calculate length of a linear tag list. */
+size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap)
+{
+  size_t len = sizeof(tagi_t);
+  tagi_t const *next;
+  tagi_t tagi[3];
+
+  tagi[0].t_tag = tag;
+  tagi[0].t_value = value;
+  tagi[1].t_tag = tag_any;
+  tagi[1].t_value = 0;
+
+  for (;;) {
+    next = tl_next(tagi);
+    if (next != tagi + 1)
+      break;
+    
+    if (tagi->t_tag != tag_skip)
+      len += sizeof(tagi_t);
+    tagi->t_tag = va_arg(ap, tag_type_t);
+    tagi->t_value = va_arg(ap, tag_value_t);
+  }
+
+  for (; next; next = tl_next(next))
+    len += sizeof(tagi_t);
+
+  return len;
+}
+
+/** Make a linear tag list. */
+tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap)
+{
+  va_list aq;
+  tagi_t *t, *rv;
+  tagi_t const *next;
+  tagi_t tagi[2];
+
+  size_t size;
+
+  va_copy(aq, ap);
+  size = tl_vllen(tag, value, aq);
+  va_end(aq);
+
+  t = rv = malloc(size);
+
+  tagi[0].t_tag = tag;
+  tagi[0].t_value = value;
+  tagi[1].t_tag = tag_any;
+  tagi[1].t_value = 0;
+
+  for (;;) {
+    next = tl_next(tagi);
+    if (next != tagi + 1)
+      break;
+
+    if (tagi->t_tag != tag_skip)
+      *t++ = *tagi;
+
+    tagi->t_tag = va_arg(ap, tag_type_t);
+    tagi->t_value = va_arg(ap, tag_value_t);
+  }
+
+  for (; next; next = tl_next(next))
+    *t++ = *next;
+
+  t->t_tag = NULL; t->t_value = 0; t++;
+
+  assert((char *)rv + size == (char *)t);
+
+  return rv;
+}
+
+/** Make a linear tag list until TAG_END().
+ *
+ */
+tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...)
+{
+  va_list ap;  
+  tagi_t *t;
+
+  va_start(ap, value);
+  t = tl_vllist(tag, value, ap);
+  va_end(ap);
+
+  return t;
+}
+
+/** Free a tag list allocated by tl_list(), tl_llist() or tl_vlist(). */
+void tl_vfree(tagi_t *t)
+{
+  if (t)
+    free(t);
+}
+
+/** Convert a string to the a value of a tag. */
+int t_scan(tag_type_t tt, su_home_t *home, char const *s, 
+	   tag_value_t *return_value)
+{
+  if (tt == NULL || s == NULL || return_value == NULL)
+    return -1;
+
+  if (tt->tt_class->tc_scan) {
+    return tt->tt_class->tc_scan(tt, home, s, return_value);
+  }
+  else {			/* Not implemented */
+    *return_value = (tag_value_t)0;
+    return -2;
+  }
+}
+
+
+/* ====================================================================== */
+/* null tag */
+
+tagi_t const *t_null_next(tagi_t const *t)
+{
+  return NULL;
+}
+
+tagi_t *t_null_move(tagi_t *dst, tagi_t const *src)
+{
+  memset(dst, 0, sizeof(*dst));
+  return dst + 1;
+}
+
+tagi_t *t_null_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  memset(dst, 0, sizeof(*dst));
+  return dst + 1;
+}
+
+tagi_t *t_null_copy(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  memset(dst, 0, sizeof(*dst));
+  return dst + 1;
+}
+
+tagi_t const * t_null_find(tag_type_t tt, tagi_t const lst[])
+{
+  return NULL;
+}
+
+tagi_t *t_null_filter(tagi_t *dst, 
+		      tagi_t const filter[], 
+		      tagi_t const *src, 
+		      void **bb)
+{
+  if (TAG_TYPE_OF(src) == tag_null) {
+    if (dst) {
+      dst->t_tag = NULL;
+      dst->t_value = 0;
+    }
+    return dst + 1;
+  }
+  return dst;
+}
+
+tag_class_t null_tag_class[1] = 
+  {{ 
+    sizeof(null_tag_class), 
+    /* tc_next */     t_null_next,
+    /* tc_len */      NULL,
+    /* tc_move */     t_null_move,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      t_null_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     t_null_find,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_null_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+tag_typedef_t tag_null = TAG_TYPEDEF(tag_null, null);
+
+/* ====================================================================== */
+/* end tag */
+
+tagi_t *t_end_filter(tagi_t *dst,
+		     tagi_t const filter[],
+		     tagi_t const *src,
+		     void **bb)
+{
+  return dst;
+}
+
+tag_class_t end_tag_class[1] =
+  {{
+    sizeof(end_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_end_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+/* ====================================================================== */
+/* skip tag - placeholder in tag list */
+
+tagi_t const *t_skip_next(tagi_t const *t)
+{
+  return t + 1;
+}
+
+tagi_t *t_skip_move(tagi_t *dst, tagi_t const *src)
+{
+  return dst;
+}
+
+size_t t_skip_len(tagi_t const *t)
+{
+  return 0;
+}
+
+tagi_t *t_skip_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  return dst;
+}
+
+tagi_t *t_skip_filter(tagi_t *dst, 
+		    tagi_t const filter[], 
+		    tagi_t const *src, 
+		    void **bb)
+{
+  return dst;
+}
+
+tag_class_t skip_tag_class[1] = 
+  {{
+    sizeof(skip_tag_class),
+    /* tc_next */     t_skip_next,
+    /* tc_len */      t_skip_len,
+    /* tc_move */     t_skip_move,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      t_skip_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     t_null_find,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_skip_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+tag_typedef_t tag_skip = TAG_TYPEDEF(tag_skip, skip);
+
+/* ====================================================================== */
+/* next tag - jump to next tag list */
+
+tagi_t const *t_next_next(tagi_t const *t)
+{
+  return (tagi_t *)(t->t_value);
+}
+
+tagi_t *t_next_move(tagi_t *dst, tagi_t const *src)
+{
+  if (!src->t_value)
+    return t_null_move(dst, src);
+  return dst;
+}
+
+size_t t_next_len(tagi_t const *t)
+{
+  if (!t->t_value)
+    return sizeof(*t);
+  return 0;
+}
+
+tagi_t *t_next_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  if (!src->t_value)
+    return t_null_dup(dst, src, bb);
+  return dst;
+}
+
+tagi_t *t_next_filter(tagi_t *dst, 
+		    tagi_t const filter[], 
+		    tagi_t const *src, 
+		    void **bb)
+{
+  return dst;
+}
+
+tag_class_t next_tag_class[1] = 
+  {{
+    sizeof(next_tag_class),
+    /* tc_next */     t_next_next,
+    /* tc_len */      t_next_len,
+    /* tc_move */     t_next_move,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      t_next_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     t_null_find,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_next_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+tag_typedef_t tag_next = TAG_TYPEDEF(tag_next, next);
+
+/* ====================================================================== */
+/* filter tag  - use function to filter tag */
+
+tagi_t *t_filter_with(tagi_t *dst,
+		      tagi_t const *t, 
+		      tagi_t const *src, 
+		      void **bb)
+{
+  tag_filter_f *function;
+
+  if (!src || !t)
+    return dst;
+
+  function = (tag_filter_f *)t->t_value;
+
+  if (!function || !function(t, src))
+    return dst;
+
+  if (dst) {
+    return t_dup(dst, src, bb); 
+  }
+  else {
+    dst = (tagi_t *)((char *)dst + t_len(src));
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst;
+  }
+}
+		   
+tag_class_t filter_tag_class[1] = 
+  {{
+    sizeof(filter_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_filter_with,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+/** Filter tag - apply function in order to filter tag. */
+tag_typedef_t tag_filter = TAG_TYPEDEF(tag_filter, filter);
+
+/* ====================================================================== */
+/* any tag - match to any tag when filtering */
+
+tagi_t *t_any_filter(tagi_t *dst,
+		     tagi_t const filter[], 
+		     tagi_t const *src, 
+		     void **bb)
+{
+  if (!src)
+    return dst;
+  else if (dst) {
+    return t_dup(dst, src, bb); 
+  }
+  else {
+    dst = (tagi_t *)((char *)dst + t_len(src));
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst;
+  }
+}
+		   
+tag_class_t any_tag_class[1] = 
+  {{
+    sizeof(any_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_any_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+/** Any tag - match any tag when filtering. */
+tag_typedef_t tag_any = TAG_TYPEDEF(tag_any, any);
+
+/* ====================================================================== */
+/* ns tag - match to any tag with same namespace when filtering */
+
+static
+tagi_t *t_ns_filter(tagi_t *dst,
+		    tagi_t const filter[], 
+		    tagi_t const *src, 
+		    void **bb)
+{
+  char const *match, *ns;
+
+  if (!src)
+    return dst;
+
+  assert(filter);
+
+  match = TAG_TYPE_OF(filter)->tt_ns;
+  ns = TAG_TYPE_OF(src)->tt_ns;
+
+  if (match == NULL)
+    /* everything matches with this */;
+  else if (match == ns)
+    /* namespaces matche */;
+  else if (ns == NULL)
+    /* no match */
+    return dst;
+  else if (strcmp(match, ns))
+    /* no match */
+    return dst;
+
+  if (dst) {
+    return t_dup(dst, src, bb); 
+  }
+  else {
+    dst = (tagi_t *)((char *)dst + t_len(src));
+    *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+    return dst;
+  }
+}
+
+/** Namespace filtering class */		   
+tag_class_t ns_tag_class[1] = 
+  {{
+    sizeof(ns_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ NULL,
+    /* tc_filter */   t_ns_filter,
+    /* tc_ref_set */  NULL,
+    /* tc_scan */     NULL,
+  }};
+
+/* ====================================================================== */
+/* int tag - pass integer value */
+
+int t_int_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  return snprintf(b, size, "%i", (int)t->t_value);
+}
+
+int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(int *)ref = (int)value->t_value;
+
+  return 1;
+}
+
+int t_int_scan(tag_type_t tt, su_home_t *home, 
+	       char const *s, 
+	       tag_value_t *return_value)
+{
+  int value;
+  char *rest;
+
+  value = strtol(s, &rest, 0);
+  
+  if (s != rest) {
+    *return_value = (tag_value_t)value;
+    return 1;
+  }
+  else {
+    *return_value = (tag_value_t)0;
+    return -1;
+  }
+}
+
+tag_class_t int_tag_class[1] = 
+  {{
+    sizeof(int_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_int_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_int_ref_set,
+    /* tc_scan */     t_int_scan,
+  }};
+
+/* ====================================================================== */
+/* uint tag - pass unsigned integer value */
+
+int t_uint_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  return snprintf(b, size, "%u", (unsigned)t->t_value);
+}
+
+int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(unsigned *)ref = (unsigned)value->t_value;
+
+  return 1;
+}
+
+int t_uint_scan(tag_type_t tt, su_home_t *home, 
+	       char const *s, 
+	       tag_value_t *return_value)
+{
+  unsigned value;
+  char *rest;
+
+  value = strtoul(s, &rest, 0);
+  
+  if (s != rest) {
+    *return_value = (tag_value_t)value;
+    return 1;
+  }
+  else {
+    *return_value = (tag_value_t)0;
+    return -1;
+  }
+}
+
+tag_class_t uint_tag_class[1] = 
+  {{
+    sizeof(int_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_uint_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_uint_ref_set,
+    /* tc_scan */     t_uint_scan,
+  }};
+
+
+/* ====================================================================== */
+/* size tag - pass size_t value @NEW_1_12_5 */
+
+static
+int t_size_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  return snprintf(b, size, MOD_ZU, (size_t)t->t_value);
+}
+
+static
+int t_size_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(size_t *)ref = (size_t)value->t_value;
+
+  return 1;
+}
+
+static
+int t_size_scan(tag_type_t tt, su_home_t *home, 
+		 char const *s, 
+		 tag_value_t *return_value)
+{
+  unsigned longlong value;
+  char *rest;
+
+  value = strtoull(s, &rest, 0);
+  
+  if (s != rest && value <= SIZE_MAX) {
+    *return_value = (tag_value_t)value;
+    return 1;
+  }
+  else {
+    *return_value = (tag_value_t)0;
+    return -1;
+  }
+}
+
+/** Tag class for tags with size_t value. @NEW_1_12_5 */
+tag_class_t size_tag_class[1] = 
+  {{
+    sizeof(int_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_size_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_size_ref_set,
+    /* tc_scan */     t_size_scan,
+  }};
+
+/* ====================================================================== */
+/* usize tag - pass usize_t value */
+
+static
+int t_usize_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(usize_t *)ref = (usize_t)value->t_value;
+
+  return 1;
+}
+
+static
+int t_usize_scan(tag_type_t tt, su_home_t *home, 
+		 char const *s, 
+		 tag_value_t *return_value)
+{
+  unsigned longlong value;
+  char *rest;
+
+  value = strtoull(s, &rest, 0);
+  
+  if (s != rest && value <= USIZE_MAX) {
+    *return_value = (tag_value_t)value;
+    return 1;
+  }
+  else {
+    *return_value = (tag_value_t)0;
+    return -1;
+  }
+}
+
+/** Tag class for tags with usize_t value. @NEW_1_12_5 */
+tag_class_t usize_tag_class[1] = 
+  {{
+    sizeof(int_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_size_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_usize_ref_set,
+    /* tc_scan */     t_usize_scan,
+  }};
+
+
+/* ====================================================================== */
+/* bool tag - pass boolean value */
+
+int t_bool_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  return snprintf(b, size, "%s", t->t_value ? "true" : "false");
+}
+
+int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(int *)ref = (value->t_value != 0);
+
+  return 1;
+}
+
+int t_bool_scan(tag_type_t tt, su_home_t *home, 
+	       char const *s, 
+	       tag_value_t *return_value)
+{
+  int retval;
+  int value = 0;
+
+  if (strncasecmp(s, "true", 4) == 0 
+      && strlen(s + 4) == strspn(s + 4, " \t\r\n")) {
+    value = 1, retval = 1;
+  } else if (strncasecmp(s, "false", 5) == 0 
+	     && strlen(s + 5) == strspn(s + 5, " \t\r\n")) {
+    value = 0, retval = 1;
+  } else {
+    retval = t_int_scan(tt, home, s, return_value);
+    value = *return_value != 0;
+  }
+
+  if (retval == 1)
+    *return_value = (tag_value_t)value;
+  else
+    *return_value = (tag_value_t)0;
+  
+  return retval;
+}
+
+tag_class_t bool_tag_class[1] = 
+  {{
+    sizeof(bool_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_bool_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_bool_ref_set,
+    /* tc_scan */     t_bool_scan,
+  }};
+
+/* ====================================================================== */
+/* ptr tag - pass pointer value */
+
+int t_ptr_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  return snprintf(b, size, "%p", (void *)t->t_value);
+}
+
+int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(void **)ref = (void *)value->t_value;
+
+  return 1;
+}
+
+/* This is not usually very safe, so it is not used */
+int t_ptr_scan(tag_type_t tt, su_home_t *home, 
+	       char const *s, 
+	       tag_value_t *return_value)
+{
+  int retval;
+  void *ptr;
+
+  retval = sscanf(s, "%p", &ptr);
+
+  if (retval == 1)
+    *return_value = (tag_value_t)ptr;
+  else
+    *return_value = (tag_value_t)NULL;
+  
+  return retval;
+}
+
+tag_class_t ptr_tag_class[1] = 
+  {{
+    sizeof(ptr_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_ptr_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     NULL,
+  }};
+
+/* ====================================================================== */
+/* socket tag - pass socket */
+
+#include <sofia-sip/su.h>
+
+int t_socket_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  /* socket can be int or DWORD (or QWORD on win64?) */
+  return snprintf(b, size, LLI, (longlong)t->t_value);
+}
+
+int t_socket_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+  *(su_socket_t *)ref = (su_socket_t)value->t_value;
+
+  return 1;
+}
+
+tag_class_t socket_tag_class[1] = 
+  {{
+    sizeof(socket_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_socket_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_socket_ref_set,
+    /* tc_scan */     NULL,
+  }};
+
+/* ====================================================================== */
+/* str tag - pass string value */
+
+int t_str_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  if (t->t_value) 
+    return snprintf(b, size, "\"%s\"", (char const *)t->t_value);
+  else
+    return snprintf(b, size, "<null>");
+}
+
+int t_str_scan(tag_type_t tt, su_home_t *home, 
+	       char const *s, 
+	       tag_value_t *return_value)
+{
+  int retval;
+
+  s = su_strdup(home, s);
+    
+  if (s)
+    *return_value = (tag_value_t)s, retval = 1;
+  else
+    *return_value = (tag_value_t)NULL, retval = -1;
+  
+  return retval;
+}
+
+tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  dst->t_tag = src->t_tag;
+  if (src->t_value) {
+    char const *s = (char const *)src->t_value;
+    size_t len = strlen(s) + 1;
+    dst->t_value = (tag_value_t)strcpy(*bb, s); 
+    *bb = (char *)*bb + len;
+  }
+  else 
+    dst->t_value = (tag_value_t)0;
+
+  return dst + 1;
+}
+
+size_t t_str_xtra(tagi_t const *t, size_t offset)
+{
+  return t->t_value ? strlen((char *)t->t_value) + 1 : 0;
+}
+
+tag_class_t str_tag_class[1] = 
+  {{
+    sizeof(str_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     t_str_xtra,
+    /* tc_dup */      t_str_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_str_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     t_str_scan,
+  }};
+
+/* ====================================================================== */
+/* cstr tag - pass constant string value (no need to dup) */
+
+/** Tag class for constant strings */
+tag_class_t cstr_tag_class[1] = 
+  {{
+    sizeof(cstr_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_str_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     t_str_scan,
+  }};
+
+/* ====================================================================== */
+/* ref tag - pass reference */
+
+tag_class_t ref_tag_class[1] = 
+  {{
+    sizeof(ref_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     NULL,
+    /* tc_dup */      NULL,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ t_ptr_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     NULL,
+  }};
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,465 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ * @CFILE su_time.c
+ *
+ * @brief Implementation of OS-independent time functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_time.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h> /* Get struct timeval */
+#endif
+
+/**@defgroup su_time Time Handling
+ *
+ * OS-independent timing functions and types for the @b su library.
+ *  
+ * The @b su library provides three different time formats with different
+ * ranges and epochs in the file @b su_time.h:
+ *
+ *   - #su_time_t, second and microsecond as 32-bit values since 1900,
+ *   - #su_duration_t, milliseconds between two times, and
+ *   - #su_ntp_t, standard NTP timestamp (seconds since 1900 as 
+ *     a fixed-point 64-bit value with 32 bits representing subsecond 
+ *     value).
+ */
+
+/**
+ * Compare two timestamps.
+ * 
+ * The function su_time_cmp() compares two su_time_t timestamps.
+ * 
+ * @param t1 first NTP timestamp in su_time_t structure
+ * @param t2 second NTP timestamp in su_time_t structure
+ * 
+ * @retval  Negative, if @a t1 is before @a t2,
+ * @retval  Zero, if @a t1 is same as @a t2, or
+ * @retval  Positive, if @a t1 is after @a t2.
+ * 
+ */
+long su_time_cmp(su_time_t const t1, su_time_t const t2)
+{
+  long retval = 0;
+
+  if (t1.tv_sec > t2.tv_sec) 
+    retval = 1;
+  else if (t1.tv_sec < t2.tv_sec) 
+    retval = -1;
+  else {
+    if (t1.tv_usec > t2.tv_usec) 
+      retval = 1;
+    else if (t1.tv_usec < t2.tv_usec) 
+      retval = -1;
+  }
+
+  return retval;
+}
+
+/**@def SU_TIME_CMP(t1, t2) 
+ *
+ * Compare two timestamps.
+ *
+ * The macro SU_TIME_CMP() compares two su_time_t timestamps.
+ *
+ * @param t1   first NTP timestamp in su_time_t structure
+ * @param t2   second NTP timestamp in su_time_t  structure
+ * 
+ * @retval negative, if t1 is before t2,
+ * @retval zero,     if t1 is same as t2, or
+ * @retval positive, if t1 is after t2.
+ *
+ * @hideinitializer
+ */
+
+/** Difference between two timestamps.
+ *
+ * The function returns difference between two timestamps 
+ * in seconds (t1 - t2).
+ *
+ * @param t1   first timeval
+ * @param t2   second timeval
+ * 
+ * @return
+ *    The difference between two timestamps in seconds as a double.
+ */
+double su_time_diff(su_time_t const t1, su_time_t const t2)
+{
+  return
+    ((double)t1.tv_sec - (double)t2.tv_sec) 
+    + (double)((long)t1.tv_usec - (long)t2.tv_usec) / 1000000.0;
+}
+
+/** Get current time.
+ *
+ *   Return the current timestamp in su_time_t structure.
+ *
+ * @return
+ *   The structure containing the current NTP timestamp.
+ */
+su_time_t su_now(void)
+{
+  su_time_t retval;
+  su_time(&retval);
+  return retval;
+}
+
+/** Print su_time_t timestamp.
+ *
+ *   This function prints a su_time_t timestamp as a decimal number to the 
+ *   given buffer.
+ *
+ * @param s    pointer to buffer
+ * @param n    buffer size
+ * @param tv   pointer to the timeval object
+ * 
+ * @return 
+ *   The number of characters printed, excluding the final @c NUL.
+ */
+int su_time_print(char *s, int n, su_time_t const *tv)
+{
+#ifdef _WIN32
+  return _snprintf(s, n, "%lu.%06lu", tv->tv_sec, tv->tv_usec);
+#else
+  return snprintf(s, n, "%lu.%06lu", tv->tv_sec, tv->tv_usec);
+#endif
+}
+
+/** Time difference in milliseconds.
+ *
+ *   Calculates the duration from t2 to t1 in milliseconds.  
+ *
+ * @param t1   after time
+ * @param t2   before time
+ * 
+ * @return
+ *   The duration in milliseconds between the two times.  If the difference
+ *   is bigger than @c SU_DURATION_MAX, the function su_duration() returns
+ *   @c SU_DURATION_MAX instead.  If the difference is smaller than @c
+ *   -SU_DURATION_MAX, the function su_duration() returns @c
+ *   -SU_DURATION_MAX.
+ */
+su_duration_t su_duration(su_time_t const t1, su_time_t const t2)
+{
+  su_duration_t diff, udiff, tdiff;
+
+  diff = t1.tv_sec - t2.tv_sec;
+  udiff = t1.tv_usec - t2.tv_usec;
+
+  tdiff = diff * 1000 + udiff / 1000;
+
+  if (diff > (SU_DURATION_MAX / 1000) || (diff > 0 && diff > tdiff))
+    return SU_DURATION_MAX;
+  if (diff < (-SU_DURATION_MAX / 1000) || (diff < 0 && diff < tdiff))
+    return -SU_DURATION_MAX;
+
+  return tdiff;
+}
+
+typedef uint64_t su_t64_t;	/* time with 64 bits */
+
+const uint32_t su_res32 = 1000000UL;
+const su_t64_t su_res64 = (su_t64_t)1000000UL;
+
+#define SU_TIME_TO_T64(tv) \
+  (su_res64 * (su_t64_t)(tv).tv_sec + (su_t64_t)(tv).tv_usec)
+#define SU_DUR_TO_T64(d) (1000 * (int64_t)(d))
+
+/** Get NTP timestamp.
+ *
+ * The function su_ntp_now() returns the current NTP timestamp.  NTP
+ * timestamp is seconds elapsed since January 1st, 1900.
+ * 
+ * @return
+ * The current time as NTP timestamp is returned.
+ */
+su_ntp_t su_ntp_now(void)
+{
+  su_time_t t;
+  uint32_t sec, usec;
+
+  su_time(&t);
+
+  sec = t.tv_sec;
+  usec = t.tv_usec;
+
+  /*
+   * Multiply usec by 4294.967296 (ie. 2**32 / 1E6)
+   * 
+   * Utilize fact that 4294.967296 == 4295 - 511 / 15625 
+   */
+  usec = 4295 * usec - (511 * usec + 7812) / 15625;
+  
+  return ((su_ntp_t)sec << 32) + (su_ntp_t)usec;
+}
+
+/** Get NTP seconds.
+ *
+ * The function su_ntp_sec() returns the seconds elapsed since January 1st,
+ * 1900.
+ *
+ * @return
+ * The current time as NTP seconds is returned.
+ */
+uint32_t su_ntp_sec(void)
+{
+  su_time_t t;
+  su_time(&t);
+  return t.tv_sec;
+}
+
+/** High 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_hi() returns high 32 bits of NTP timestamp.
+ */
+uint32_t su_ntp_hi(su_ntp_t ntp)
+{
+  return (uint32_t) (ntp >> 32) & 0xffffffffLU;
+}
+
+
+su_ntp_t su_ntp_hilo(uint32_t hi, uint32_t lo)
+{
+  return ((((su_ntp_t)hi) << 32)) | lo;
+}
+
+/** Low 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_hi() returns low 32 bits of NTP timestamp.
+ */
+uint32_t su_ntp_lo(su_ntp_t ntp)
+{
+  return (uint32_t) ntp & 0xffffffffLU;
+}
+
+/** Middle 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_mw() returns bits 48..16 (middle word) of NTP
+ * timestamp.
+ */
+uint32_t su_ntp_mw(su_ntp_t ntp)
+{
+  return (uint32_t) (ntp >> 16) & 0xffffffffLU;
+}
+
+su_time_t su_t64_to_time(su_t64_t const us)
+{
+  su_time_t tv;
+
+  tv.tv_sec = (unsigned long) (us / su_res64);
+  tv.tv_usec = (unsigned long) (us % su_res64);
+
+  return tv;
+}
+
+/** 
+ * Add milliseconds to the time.
+ *
+ * @param t0  time in seconds and microseconds as @c su_time_t
+ * @param dur milliseconds to be added
+ */
+su_time_t su_time_add(su_time_t t0, su_duration_t dur)
+{
+  return su_t64_to_time(SU_TIME_TO_T64(t0) + SU_DUR_TO_T64(dur));
+}
+
+/** 
+ * Add seconds to the time.
+ *
+ * @param t0  time in seconds and microseconds as @c su_time_t
+ * @param sec seconds to be added
+ *
+ * @return
+ * New time as @c su_time_t.
+ */
+su_time_t su_time_dadd(su_time_t t0, double sec)
+{
+  return su_t64_to_time(SU_TIME_TO_T64(t0) + (int64_t)(su_res32 * sec));
+}
+
+#ifdef WIN32
+
+#include <windows.h>
+
+uint64_t su_nanocounter(void)
+{
+  static ULONGLONG counterfreq = 0;  /*performance counter frequency*/
+  LARGE_INTEGER LargeIntCount = { 0, 0 };
+  ULONGLONG count;
+
+  if(!counterfreq) {
+    LARGE_INTEGER Freq = { 0, 0 };
+    if (!QueryPerformanceFrequency(&Freq)) { 
+      SU_DEBUG_1(("su_counter: QueryPerformanceFrequency failed\n"));
+      return 0;
+    }
+    counterfreq = Freq.QuadPart;
+  }
+
+  if (!QueryPerformanceCounter(&LargeIntCount)) {
+     SU_DEBUG_1(("su_counter: QueryPeformanceCounter failed\n"));
+     return 0;
+  }
+  count = (ULONGLONG) LargeIntCount.QuadPart;
+ 
+  /* return value is in ns */
+  return  ((count * 1000 * 1000 * 1000) / counterfreq) ; 
+}
+
+uint64_t su_counter(void)
+{
+  return su_nanocounter() / 1000U;
+}
+
+#elif HAVE_CLOCK_GETTIME
+
+/** Return CPU counter value in nanoseconds.
+ *
+ * The function su_nanocounter() returns a CPU counter value in nanoseconds
+ * for timing purposes.
+ *
+ * Parameters:
+ * 
+ * @return
+ *   The current CPU counter value in nanoseconds
+ */
+uint64_t su_nanocounter(void)
+{
+  struct timespec tp;
+  struct timeval tv;
+  static int init = 0;
+  static clockid_t cpu = CLOCK_REALTIME;
+
+# define CLOCK_GETTIMEOFDAY 0xdedbeefUL
+  
+  if (init == 0) {
+    init = 1;
+
+    if (0)
+      ;
+#if HAVE_CLOCK_GETCPUCLOCKID
+    else if (clock_getcpuclockid(0, &cpu) != -1 &&
+	     clock_gettime(cpu, &tp) != -1)
+      ;
+#endif
+#ifdef _POSIX_CPUTIME
+    else if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) >= 0)
+      cpu = CLOCK_PROCESS_CPUTIME_ID;
+#endif
+    else if (clock_gettime(CLOCK_REALTIME, &tp) >= 0)
+      cpu = CLOCK_REALTIME;
+    else
+      cpu = CLOCK_GETTIMEOFDAY;
+  }
+
+  if (cpu == CLOCK_GETTIMEOFDAY) {
+    gettimeofday(&tv, NULL);
+    tp.tv_sec = tv.tv_sec, tp.tv_nsec = tv.tv_usec * 1000;
+  }
+  else if (clock_gettime(cpu, &tp) < 0)
+    perror("clock_gettime");
+
+  /* return value is in nanoseconds */
+  return 
+    (uint64_t)((unsigned long)tp.tv_nsec) + 
+    (uint64_t)((unsigned long)tp.tv_sec) * 1000000000ULL;
+}
+
+/** Return CPU counter value in microseconds.
+ *
+ * The function su_counter() returns the CPU counter value in microseconds
+ * for timing purposes.
+ *
+ * Parameters:
+ * 
+ * @return
+ *   The current CPU counter value in microseconds.
+ */
+uint64_t su_counter(void)
+{
+  return su_nanocounter() / 1000U;
+}
+
+#elif HAVE_GETTIMEOFDAY
+uint64_t su_counter(void)
+{
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  /* return value is in microseconds */
+  return 
+    (uint64_t)((unsigned long)tv.tv_usec) + 
+    (uint64_t)((unsigned long)tv.tv_sec) * 1000000ULL;
+}
+
+uint64_t su_nanocounter(void)
+{
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  /* return value is in nanoseconds */
+  return 
+    (uint64_t)((unsigned long)tv.tv_usec) * 1000ULL + 
+    (uint64_t)((unsigned long)tv.tv_sec) * 1000000000ULL;
+}
+
+#else
+
+uint64_t su_counter(void)
+{
+  return (uint64_t)clock();
+}
+
+uint64_t su_nanocounter(void)
+{
+  return (uint64_t)clock() * 1000;
+}
+
+#endif /* WIN32 */
+
+
+
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ * @CFILE su_time0.c
+ * @brief su_time() implementation
+ *
+ * The file su_time0.c contains implementation of OS-independent wallclock
+ * time with microsecond resolution.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ * 
+ * @date Created: Fri May 10 18:13:19 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_time.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h> /* Get struct timeval */
+#endif
+
+#if defined(__MINGW32__)
+#define HAVE_FILETIME 1
+#include <windows.h>
+#endif
+
+#if HAVE_FILETIME
+#define HAVE_FILETIME 1
+#include <windows.h>
+#endif
+
+/** Seconds from 1.1.1900 to 1.1.1970 */
+#define NTP_EPOCH 2208988800UL 
+
+/** Get current time.
+ *
+ * The function @c su_time() fills its argument with the current NTP
+ * timestamp expressed as a su_time_t structure.
+ *
+ * @param tv pointer to the timeval object
+ */
+void su_time(su_time_t *tv)
+{
+#if HAVE_GETTIMEOFDAY
+  if (tv) {
+    gettimeofday((struct timeval *)tv, NULL);
+    tv->tv_sec += NTP_EPOCH;
+  }
+#elif HAVE_FILETIME
+  union {
+    FILETIME       ft[1];
+    ULARGE_INTEGER ull[1];
+  } date;
+
+  GetSystemTimeAsFileTime(date.ft);
+
+  tv->tv_usec = (unsigned long) ((date.ull->QuadPart % 10000000U) / 10);
+  tv->tv_sec = (unsigned long) ((date.ull->QuadPart / 10000000U) - 
+    /* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
+    (299 * 365 + 72) * 24 * 60 * (uint64_t)60);
+#else
+#error no su_time() implementation
+#endif
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,634 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE su_timer.c
+ *
+ * Timer interface for su_root.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * Created: Fri Apr 28 15:45:41 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/rbtree.h"
+
+#include "su_module_debug.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+/**@ingroup su_wait
+ *
+ * @page su_timer_t Timer Objects
+ *
+ *  Timers are used to schedule some task to be executed at given time or
+ *  after a default interval. The default interval is specified when the
+ *  timer is created. We call timer activation "setting the timer", and
+ *  deactivation "resetting the timer" (as in SDL). When the given time has
+ *  arrived or the default interval has elapsed, the timer expires and
+ *  it is ready for execution.
+ *
+ *  The functions used to create, destroy, activate, and manage timers are
+ *  as follows:
+ *   - su_timer_create(),
+ *   - su_timer_destroy(),
+ *   - su_timer_set_interval(),
+ *   - su_timer_set_at(),
+ *   - su_timer_set(),
+ *   - su_timer_set_for_ever(), 
+ *   - su_timer_run(),
+ *   - su_timer_reset(), and
+ *   - su_timer_root().
+ *
+ * @note
+ * Timers use poll() to wake up waiting thread. On Linux, the timer
+ * granularity is determined by HZ kernel parameter, which decided when the
+ * kernel was compiled. With kernel 2.4 the default granularity is 10
+ * milliseconds, and minimum duration of a timer is approximately 20
+ * milliseconds. Naturally, using RTC would give better timing results, but
+ * RTC usage above 64 Hz is privileged operation.
+ *
+ * @par
+ * On Windows, the granularity is determined by the real-time clock timer.
+ * By default, it uses the 18.78 Hz granularity.  That timer can be adjusted
+ * up to 1000 Hz using Windows multimedia library.
+ *
+ * @section su_timer_usage Using Timers
+ *
+ * A timer is created by calling su_timer_create():
+ * @code
+ *   timer = su_timer_create(su_root_task(root), 200);
+ * @endcode
+ * The default duration is given in milliseconds.
+ *
+ * Usually, timer wakeup function should be called at regular intervals. In
+ * such case, the timer is activated using function su_timer_set_for_ever(). 
+ * When the timer is activated it is given the wakeup function and pointer to
+ * context data:
+ * @code
+ *   su_timer_set_for_ever(timer, timer_wakeup, args);
+ * @endcode
+ *
+ * When the interval has passed, the root event loop calls the wakeup
+ * function:
+ * @code
+ *   timer_wakeup(root, timer, args);
+ * @endcode
+ *
+ * If the number of calls to callback function is important, use
+ * su_timer_run() instead. The run timer tries to compensate for missed time
+ * and invokes the callback function several times if needed. (Because the
+ * real-time clock can be adjusted or the program suspended, e.g., while
+ * debugged, the callback function can be called thousends of times in a
+ * row.) Note that while the timer tries to compensate for delays occurred
+ * before and during the callback, it cannot be used as an exact source of
+ * timing information.
+ *
+ * Timer ceases running when su_timer_reset() is called.
+ *
+ * Alternatively, the timer can be @b set for one-time event invocation.
+ * When the timer is set, it is given the wakeup function and pointer to
+ * context data. The actual duration can also be specified using
+ * su_timer_set_at(). @code su_timer_set(timer, timer_wakeup, args);
+ * @endcode
+ *
+ * When the timer expires, the root event loop calls the wakeup function:
+ * @code
+ *   timer_wakeup(root, timer, args);
+ * @endcode
+ *
+ * If the timed event is not needed anymore, the timer can be reset:
+ * @code
+ *   su_timer_reset(timer);
+ * @endcode
+ *
+ * If the timer is expected to be called at regular intervals, it is
+ * possible to set ro run continously with su_timer_run().  While such a
+ * continously running timer is active it @b must @b not @b be @b set using
+ * su_timer_set() or su_timer_set_at().
+ *
+ * When the timer is not needed anymore, the timer object itself should be
+ * destroyed:
+ * @code
+ *   su_timer_destroy(timer);
+ * @endcode
+ */
+
+struct su_timer_s {
+  /** Pointers within red-black tree */
+  su_timer_t     *sut_left, *sut_right, *sut_parent;
+  su_task_r       sut_task;	/**< Task reference */
+  su_time_t       sut_when;	/**< When timer should be waken up next time */
+  su_duration_t   sut_duration;	/**< Timer duration */
+  su_timer_f      sut_wakeup;	/**< Function to call when waken up */
+  su_timer_arg_t *sut_arg;	/**< Pointer to argument data */
+  su_time_t       sut_run;	/**< When this timer was last waken up */
+  unsigned        sut_woken;	/**< Timer has waken up this many times */
+  unsigned short  sut_running;	/**< Timer is running */
+
+  unsigned char   sut_black;	/**< Black node */
+  unsigned char   sut_set;	/**< Timer is set (inserted in tree) */
+};
+
+enum sut_running {
+  reset = 0,
+  run_at_intervals = 1, /**< Compensate missed wakeup calls */
+  run_for_ever = 2	/**< Do not compensate  */
+};
+
+#define SU_TIMER_IS_SET(sut) ((sut)->sut_set)
+
+/* Accessor macros for rbtree */
+#define LEFT(sut) ((sut)->sut_left)
+#define RIGHT(sut) ((sut)->sut_right)
+#define PARENT(sut) ((sut)->sut_parent)
+#define SET_RED(sut) ((sut)->sut_black = 0)
+#define SET_BLACK(sut) ((sut)->sut_black = 1)
+#define CMP(a, b) SU_TIME_CMP((a)->sut_when, (b)->sut_when)
+#define IS_RED(sut) ((sut) && (sut)->sut_black == 0)
+#define IS_BLACK(sut) (!(sut) || (sut)->sut_black == 1)
+#define COPY_COLOR(dst, src) ((dst)->sut_black = (src)->sut_black)
+#define INSERT(sut) ((sut)->sut_set = 1)
+#define REMOVE(sut) ((sut)->sut_set = 0,				\
+  (sut)->sut_left = (sut)->sut_right = (sut)->sut_parent = NULL)
+
+RBTREE_PROTOS(static inline, timers, su_timer_t);
+
+static inline int timers_append(su_timer_t **, su_timer_t *);
+static inline void timers_remove(su_timer_t **, su_timer_t *);
+static inline su_timer_t *timers_succ(su_timer_t const *);
+static inline su_timer_t *timers_prec(su_timer_t const *);
+static inline su_timer_t *timers_first(su_timer_t const *);
+static inline su_timer_t *timers_last(su_timer_t const *);
+
+RBTREE_BODIES(static inline, timers, su_timer_t,
+	      LEFT, RIGHT, PARENT,
+	      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+	      CMP, INSERT, REMOVE);
+
+/** Set the timer. */
+static inline int
+su_timer_set0(su_timer_t **timers,
+	      su_timer_t *t,
+	      su_timer_f wakeup,
+	      su_wakeup_arg_t *arg,
+	      su_time_t when,
+	      su_duration_t offset)
+{
+  if (SU_TIMER_IS_SET(t))
+    timers_remove(timers, t);
+
+  t->sut_wakeup = wakeup;
+  t->sut_arg = arg;
+  t->sut_when = su_time_add(when, offset);
+
+  return timers_append(timers, t);
+}
+
+/** Reset the timer. */
+static inline int
+su_timer_reset0(su_timer_t **timers,
+		su_timer_t *t)
+{
+  if (SU_TIMER_IS_SET(t))
+    timers_remove(timers, t);
+
+  t->sut_wakeup = NULL;
+  t->sut_arg = NULL;
+  t->sut_running = reset;
+
+  memset(&t->sut_run, 0, sizeof(t->sut_run));
+
+  return 0;
+}
+
+
+/**Create a timer.
+ *
+ * Allocate and initialize an instance of su_timer_t.
+ *
+ * @param task a task for root object with which the timer will be associated
+ * @param msec the default duration of the timer
+ *
+ * @return A pointer to allocated timer instance, NULL on error.
+ */
+su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec)
+{
+  su_timer_t *retval;
+
+  assert(msec >= 0);
+
+  if (su_task_cmp(task, su_task_null))
+    retval = su_zalloc(NULL, sizeof(*retval));
+  else
+    retval = NULL;
+
+  if (retval) {
+    su_task_copy(retval->sut_task, task);
+    retval->sut_duration = msec;
+  }
+
+  return retval;
+}
+
+/** Destroy a timer.
+ *
+ * Deinitialize and free an instance of su_timer_t.
+ *
+ * @param t pointer to the timer object
+ */
+void su_timer_destroy(su_timer_t *t)
+{
+  if (t) {
+    su_timer_t **timers = su_task_timers(t->sut_task);
+    if (timers)
+      su_timer_reset0(timers, t);
+    su_task_deinit(t->sut_task);
+    su_free(NULL, t);
+  }
+}
+
+/** Set the timer for the given @a interval.
+ *
+ *  Sets (starts) the given timer to expire after the specified duration.
+ *
+ * @param t       pointer to the timer object
+ * @param wakeup  pointer to the wakeup function
+ * @param arg     argument given to the wakeup function
+ * @param interval duration in milliseconds before timer wakeup is called
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_interval(su_timer_t *t,
+			  su_timer_f wakeup,
+			  su_timer_arg_t *arg,
+			  su_duration_t interval)
+{
+  char const *func = "su_timer_set_interval";
+  su_timer_t **timers;
+
+  if (t == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+    return -1;
+  }
+
+  timers = su_task_timers(t->sut_task);
+  if (timers == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+    return -1;
+  }
+
+  su_timer_set0(timers, t, wakeup, arg, su_now(), interval);
+
+  return 0;
+}
+
+/** Set the timer for the default interval.
+ *
+ *  Sets (starts) the given timer to expire after the default duration.
+ *
+ *  The timer must have an default duration.
+ *
+ * @param t       pointer to the timer object
+ * @param wakeup  pointer to the wakeup function
+ * @param arg     argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set(su_timer_t *t,
+		 su_timer_f wakeup,
+		 su_timer_arg_t *arg)
+{
+  char const *func = "su_timer_set";
+
+  if (t == NULL)
+    return -1;
+
+  assert(t->sut_duration > 0);
+  if (t->sut_duration == 0) {
+    SU_DEBUG_0(("%s(%p): %s\n", func, t, "timer without default duration"));
+    return -1;
+  }
+
+  return su_timer_set_interval(t, wakeup, arg, t->sut_duration);
+}
+
+/** Set timer at known time.
+ *
+ *  Sets the timer to expire at given time.
+ *
+ * @param t       pointer to the timer object
+ * @param wakeup  pointer to the wakeup function
+ * @param arg     argument given to the wakeup function
+ * @param when    time structure defining the wakeup time
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_at(su_timer_t *t,
+		    su_timer_f wakeup,
+		    su_wakeup_arg_t *arg,
+		    su_time_t when)
+{
+  char const *func = "su_timer_set_at";
+  su_timer_t **timers;
+
+  if (t == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+    return -1;
+  }
+
+  timers = su_task_timers(t->sut_task);
+  if (timers == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+    return -1;
+  }
+
+  su_timer_set0(timers, t, wakeup, arg, when, 0);
+
+  return 0;
+}
+
+/** Set the timer for regular intervals.
+ *
+ * Run the given timer continuously, call wakeup function repeately in the
+ * default interval. If a wakeup call is missed, try to make it up (in other
+ * words, this kind of timer fails miserably if time is adjusted and it
+ * should really use /proc/uptime instead of gettimeofday()).
+ *
+ * While a continously running timer is active it @b must @b not @b be @b
+ * set using su_timer_set() or su_timer_set_at().
+ *
+ * The timer must have an non-zero default interval.
+ *
+ * @param t       pointer to the timer object
+ * @param wakeup  pointer to the wakeup function
+ * @param arg     argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_run(su_timer_t *t,
+		 su_timer_f wakeup,
+		 su_timer_arg_t *arg)
+{
+  char const *func = "su_timer_run";
+  su_timer_t **timers;
+  su_time_t now = su_now();
+
+  if (t == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+    return -1;
+  }
+
+  assert(t->sut_duration > 0);
+  if (t->sut_duration == 0) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "timer without default duration"));
+    return -1;
+  }
+
+  timers = su_task_timers(t->sut_task);
+  if (timers == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+    return -1;
+  }
+
+  t->sut_running = run_at_intervals;
+  t->sut_run = now;
+  t->sut_woken = 0;
+
+  su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
+
+  return 0;
+}
+
+/**Set the timer for regular intervals.
+ *
+ * Run the given timer continuously, call wakeup function repeately in the
+ * default interval. While a continously running timer is active it @b must
+ * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike
+ * su_timer_run(), set for ever timer does not try to catchup missed
+ * callbacks.
+ *
+ * The timer must have an non-zero default interval.
+ *
+ * @param t       pointer to the timer object
+ * @param wakeup  pointer to the wakeup function
+ * @param arg     argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_for_ever(su_timer_t *t,
+			  su_timer_f wakeup,
+			  su_timer_arg_t *arg)
+{
+  char const *func = "su_timer_run";
+  su_timer_t **timers;
+  su_time_t now = su_now();
+
+  if (t == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+    return -1;
+  }
+
+  assert(t->sut_duration > 0);
+  if (t->sut_duration == 0) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "timer without default duration"));
+    return -1;
+  }
+
+  timers = su_task_timers(t->sut_task);
+  if (timers == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+    return -1;
+  }
+
+  t->sut_running = run_for_ever;
+  t->sut_run = now;
+  t->sut_woken = 0;
+
+  su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
+
+  return 0;
+}
+
+
+/**Reset the timer.
+ *
+ * Resets (stops) the given timer.
+ *
+ * @param t  pointer to the timer object
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_reset(su_timer_t *t)
+{
+  char const *func = "su_timer_reset";
+  su_timer_t **timers;
+
+  if (t == NULL) {
+    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+    return -1;
+  }
+
+  timers = su_task_timers(t->sut_task);
+
+  su_timer_reset0(timers, t);
+
+  return 0;
+}
+
+/** @internal Check for expired timers in queue.
+ *
+ * The function su_timer_expire() checks a timer queue and executes and
+ * removes expired timers from the queue. It also calculates the time when
+ * the next timer expires.
+ *
+ * @param timers   pointer to the timer queue
+ * @param timeout  timeout in milliseconds [IN/OUT]
+ * @param now      current timestamp
+ *
+ * @return
+ * The number of expired timers.
+ */
+int su_timer_expire(su_timer_t ** const timers,
+		    su_duration_t *timeout,
+		    su_time_t now)
+{
+  su_timer_t *t;
+  su_timer_f f;
+  int n = 0;
+
+  if (!*timers)
+    return n;
+
+  for (;;) {
+    t = timers_first(*timers);
+
+    if (t == NULL || SU_TIME_CMP(t->sut_when, now) > 0)
+      break;
+
+    timers_remove(timers, t);
+
+    f = t->sut_wakeup; t->sut_wakeup = NULL;
+    assert(f);
+
+    if (t->sut_running == run_at_intervals) {
+      while (t->sut_running == run_at_intervals &&
+	     t->sut_duration > 0) {
+	if (su_time_diff(t->sut_when, now) > 0) {
+	  su_timer_set0(timers, t, f, t->sut_arg, t->sut_run, 0);
+	  break;
+	}
+	t->sut_when = t->sut_run = su_time_add(t->sut_run, t->sut_duration);
+	t->sut_woken++;
+	f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
+      }
+    }
+    else if (t->sut_running == run_for_ever) {
+      t->sut_woken++;
+      t->sut_when = now;
+      f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
+      if (t->sut_running == run_for_ever)
+	su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration);
+    }
+    else {
+      t->sut_when = now;
+      f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++;
+    }
+  }
+
+  if (t) {
+    su_duration_t at = su_duration(t->sut_when, now);
+
+    if (at < *timeout)
+      *timeout = at;
+  }
+
+  return n;
+}
+
+
+su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
+{
+  su_duration_t tout;
+
+  if (!t)
+    return SU_DURATION_MAX;
+
+  tout = su_duration(t->sut_when, now);
+
+  return tout > 0 ? tout : 0 ;
+}
+
+/**
+ * Resets and frees all timers belonging to a task.
+ *
+ * The function su_timer_destroy_all() resets and frees all timers belonging
+ * to the specified task in the queue.
+ *
+ * @param timers   pointer to the timers
+ * @param task     task owning the timers
+ *
+ * @return Number of timers reset.
+ */
+int su_timer_reset_all(su_timer_t **timers, su_task_r task)
+{
+  su_timer_t *t, *t_next;
+  int n = 0;
+
+  if (!timers || !*timers)
+    return 0;
+
+  for (t = timers_first(*timers); t; t = t_next) {
+    t_next = timers_succ(t);
+
+    if (su_task_cmp(task, t->sut_task))
+      continue;
+
+    n++;
+    timers_remove(timers, t);
+    su_free(NULL, t);
+  }
+
+  return n;
+}
+
+/** Get the root object owning the timer.
+ *
+ *   The function su_timer_root() return pointer to the root object owning the
+ *   timer.
+ *
+ * @param t pointer to the timer
+ *
+ * @return Pointer to the root object owning the timer.
+ */
+su_root_t *su_timer_root(su_timer_t const *t)
+{
+  return su_task_root(t->sut_task);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,341 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_uniqueid GloballyUniqueIDs
+ *
+ * Globally unique IDs and random integers.
+ *
+ * GloballyUniqueID or #su_guid_t is a 128-bit identifier based on current
+ * time and MAC address of the node generating the ID. A new ID is generated
+ * each time su_guid_generate() is called. Please note that such IDs are @b
+ * not unique if multiple processes are run on the same node.
+ *
+ * Use su_guid_sprintf() to convert #su_guid_t to printable format.
+ * 
+ * The random integers can be generated with functions
+ * - su_randint(),
+ * - su_randmem(), or
+ * - su_random().
+ */
+
+/**@ingroup su_uniqueid
+ *
+ * @CFILE su_uniqueid.c Construct a GloballyUniqueID as per H.225.0 v2.
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ * 
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ */
+
+#include "config.h"
+
+#if defined(_WIN32)
+int _getpid(void);
+#define getpid _getpid
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_time.h"
+#include "sofia-sip/su_uniqueid.h"
+
+/* For random number generator */
+static int initialized = 0;
+
+static void init(void);
+static void init_node(void);
+
+/* Constants */
+static const unsigned version = 1;	/* Current version */
+static const unsigned reserved = 128;	/* DCE variant */
+#define granularity (10000000UL)
+static const uint64_t mask60 = SU_U64_C(0xfffFFFFffffFFFF);
+#define MAGIC (16384)
+
+/* 100-nanosecond intervals between 15 October 1582 and 1 January 1900 */
+static const uint64_t ntp_epoch = 
+(uint64_t)(141427) * (24 * 60 * 60L) * granularity;
+
+/* State */
+static uint64_t timestamp0 = 0;
+static unsigned clock_sequence = MAGIC;
+static unsigned char node[6];
+
+FILE *urandom;
+
+/*
+ * Get current timestamp
+ */
+static uint64_t timestamp(void)
+{
+  uint64_t tl = su_ntp_now();
+  uint64_t hi = su_ntp_hi(tl), lo = su_ntp_lo(tl);
+  
+  lo *= granularity;
+  hi *= granularity;
+
+  tl = hi + (lo >> 32) + ntp_epoch;
+
+#ifdef TESTING
+  printf("timestamp %08x-%08x\n", (unsigned)(tl >>32), (unsigned)tl);
+#endif
+
+  tl &= mask60;
+
+  if (tl <= timestamp0)
+    clock_sequence = (clock_sequence + 1) & (MAGIC - 1);
+
+  timestamp0 = tl;
+
+  return tl;
+}
+
+#if !HAVE_RANDOM
+#define random() rand()
+#define srandom(x) srand(x)
+#endif
+
+/*
+ * Initialize clock_sequence and timestamp0
+ */
+static void init(void)
+{
+  int i;
+
+  static uint32_t seed[32] = { 0 };
+  su_time_t now;
+
+  initialized = 1;
+
+  /* Initialize our random number generator */
+#if HAVE_DEV_URANDOM
+  if (!urandom) 
+    urandom = fopen("/dev/urandom", "rb");
+#endif	/* HAVE_DEV_URANDOM */
+
+  if (urandom) {
+    size_t len = fread(seed, sizeof seed, 1, urandom); (void)len;
+  }
+  else {
+    for (i = 0; i < 16; i++) {
+#if HAVE_CLOCK_GETTIME
+      struct timespec ts;
+      (void)clock_gettime(CLOCK_REALTIME, &ts);
+      seed[2*i] ^= ts.tv_sec; seed[2*i+1] ^= ts.tv_nsec;
+#endif
+      su_time(&now);
+      seed[2*i] ^= now.tv_sec; seed[2*i+1] ^= now.tv_sec;
+    }
+
+    seed[30] ^= getuid(); 
+    seed[31] ^= getpid();
+  }
+
+#if HAVE_INITSTATE
+  initstate(seed[0] ^ seed[1], (char *)&seed, sizeof(seed));
+#else
+  srand(seed[0] ^ seed[1]);
+#endif
+
+  clock_sequence = su_randint(0, MAGIC - 1);
+
+  (void)timestamp();
+
+  init_node();
+}
+
+#if HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#if HAVE_NETPACKET_PACKET_H
+#define HAVE_SOCKADDR_LL 1
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#endif
+#endif
+
+static
+void init_node(void)
+{
+  size_t i;
+
+#if HAVE_GETIFADDRS && HAVE_SOCKADDR_LL
+  struct ifaddrs *ifa, *results;
+
+  if (getifaddrs(&results) == 0) {
+    for (ifa = results; ifa; ifa = ifa->ifa_next) {
+#if HAVE_SOCKADDR_LL
+      struct sockaddr_ll const *sll = (void *)ifa->ifa_addr;
+
+      if (sll == NULL || sll->sll_family != AF_PACKET)
+	continue;
+      switch (sll->sll_hatype) {
+      case ARPHRD_ETHER:
+      case ARPHRD_EETHER:
+      case ARPHRD_IEEE802:
+	break;
+      default:
+	continue;
+      }
+
+      memcpy(node, sll->sll_addr, sizeof node);
+
+      break;
+#endif
+    }
+
+    freeifaddrs(results);
+
+    if (ifa)
+      return;			/* Success */
+  }
+#endif
+
+  if (urandom) {
+    size_t len = fread(node, sizeof node, 1, urandom); (void)len;
+  }
+  else for (i = 0; i < sizeof(node); i++) {
+    unsigned r = random();
+    node[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r;
+  }
+
+  node[0] |= 1;			/* "multicast" address */
+}
+
+size_t su_node_identifier(void *address, size_t addrlen)
+{
+  if (addrlen > sizeof node)
+    addrlen = sizeof node;
+
+  if (!initialized) init();
+
+  memcpy(address, node, addrlen);
+
+  return addrlen;
+}
+
+void su_guid_generate(su_guid_t *v)
+{
+  uint64_t time;
+  unsigned clock;
+
+  if (!initialized) init(); 
+
+  time = timestamp();
+  clock = clock_sequence;
+
+  v->s.time_high_and_version = 
+    htons((unsigned short)(((time >> 48) & 0x0fff) | (version << 12)));
+  v->s.time_mid = htons((unsigned short)((time >> 32) & 0xffff));
+  v->s.time_low = htonl((unsigned long)(time & 0xffffffffUL));
+  v->s.clock_seq_low = clock & 0xff;
+  v->s.clock_seq_hi_and_reserved = (clock >> 8) | reserved;
+  memcpy(v->s.node, node, sizeof(v->s.node));
+}
+
+/*
+ * Human-readable form of GloballyUniqueID
+ */
+isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *v)
+{
+  char mybuf[su_guid_strlen + 1];
+  sprintf(mybuf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+	  (unsigned long)ntohl(v->s.time_low),
+	  ntohs(v->s.time_mid),
+	  ntohs(v->s.time_high_and_version),
+	  v->s.clock_seq_low,
+	  v->s.clock_seq_hi_and_reserved,
+	  v->s.node[0], v->s.node[1], v->s.node[2], 
+	  v->s.node[3], v->s.node[4], v->s.node[5]);
+  memcpy(buf, mybuf, len > sizeof(mybuf) ? sizeof(mybuf) : len);
+  return su_guid_strlen;
+}
+
+/* 
+ * Generate random integer in range [lb, ub] (inclusive) 
+ */
+int su_randint(int lb, int ub)
+{
+  unsigned rnd = 0;
+  
+  if (!initialized) init(); 
+
+  if (urandom) {
+    size_t len = fread(&rnd, 1, sizeof rnd, urandom); (void)len;
+  }
+  else
+    rnd = random();
+
+  if (ub - lb + 1 != 0)
+    rnd %= (ub - lb + 1);
+
+  return rnd + lb;
+}
+
+void *su_randmem(void *mem, size_t siz)
+{
+  size_t i;
+
+  if (!initialized) init(); 
+
+  if (urandom) {
+    size_t len = fread(mem, 1, siz, urandom); (void)len;
+  }
+  else for (i = 0; i < siz; i++) {
+    unsigned r = random();
+    ((char *)mem)[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r;
+  }
+
+  return mem;
+}
+
+/** Get random number for RTP timestamps. 
+ *
+ * This function returns a 32-bit random integer. It also initializes the
+ * random number generator, if needed.
+ */
+uint32_t su_random(void)
+{
+  if (!initialized) init(); 
+
+  if (urandom) {
+    uint32_t rnd;
+    size_t len = fread(&rnd, 1, sizeof rnd, urandom); (void)len;
+    return rnd;
+  }
+
+  return (uint32_t)random();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_vector Vectors
+ *
+ * Pointer vectors.
+ *
+ * Unidimensional arrays using #su_home_t.
+ *
+ */
+
+/**@ingroup su_vector
+ * @CFILE su_vector.c
+ * @brief Simple pointer vectors
+ *
+ * The vectors are resizeable unidimensional arrays.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Fri Sep 27 14:43:29 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include "sofia-sip/su_config.h"
+#include "sofia-sip/su_vector.h"
+
+enum { N = 8 };
+
+struct su_vector_s
+{
+  su_home_t         v_home[1];
+  su_home_t        *v_parent;
+  size_t            v_size;
+  size_t            v_len;
+  su_free_func_t    v_free_func;
+  void              **v_list;
+};
+
+/** Create a vector. 
+ *
+ * The function su_vector_create() creates a pointer vector object. The
+ * vector is initially empty. The function clones a memory home for the
+ * vector object from @a home. If a @a free_func is provided then that
+ * will be used to free the individual nodes (NULL if not used).
+ */
+su_vector_t *su_vector_create(su_home_t *home, su_free_func_t free_func)
+{
+  su_vector_t *vector;
+
+  vector = su_home_clone(home, sizeof(*vector) + N * sizeof(*vector->v_list));
+  if (vector) {
+    vector->v_parent = home;
+    vector->v_size = N;
+    vector->v_free_func = free_func;
+    vector->v_list = (void **)(vector + 1);
+  }
+  return vector;
+}
+
+/** Destroy a vector.
+ *
+ * The function su_vector_destroy() destroys a vector and frees all
+ * its nodes if a freeing function is available
+ */
+void su_vector_destroy(su_vector_t *vector)
+{
+  size_t i;
+
+  if (vector) {
+    if (vector->v_free_func != NULL) {
+      for (i = 0; i < vector->v_len; i++) {
+        (vector->v_free_func)(vector->v_list[i]);
+      }
+    }
+
+    su_home_zap(vector->v_home);
+  }
+}
+
+/** Increase the list size for next item, if necessary. */
+static int su_vector_make_place(su_vector_t *vector, usize_t index)
+{
+  if (vector->v_size <= vector->v_len + 1) {
+    size_t newsize = 2 * vector->v_size * sizeof(vector->v_list[0]);
+    void **list;
+
+    if (newsize < vector->v_size * sizeof(vector->v_list[0])) /* overflow */
+      return -1;
+
+    if (vector->v_list != (void **)(vector + 1) && index == vector->v_len) {
+      if (!(list = su_realloc(vector->v_home, vector->v_list, newsize)))
+	return 0;
+    }
+    else {
+      if (!(list = su_alloc(vector->v_home, newsize)))
+	return 0;
+
+      memcpy(list, vector->v_list, index * sizeof(vector->v_list[0]));
+      memcpy(list + index + 1, vector->v_list + index, 
+	     (vector->v_len - index) * sizeof(vector->v_list[0]));
+
+      if (vector->v_list != (void **)(vector + 1)) {
+	su_free(vector->v_home, vector->v_list);
+      }
+    }
+    
+    vector->v_list = list;
+    vector->v_size *= 2;
+  }
+  else {
+    memmove(vector->v_list + index + 1, vector->v_list + index, 
+	    (vector->v_len - index) * sizeof(vector->v_list[0]));
+  }
+
+  vector->v_len++;
+
+  return 1;
+}
+
+/**Insert an item to vector. 
+ *
+ * The function su_vector_insert() inserts an @a item to the @a vector.
+ * The items after the @a index will be moved further within the vector.
+ *
+ * @param vector pointer to a vector object
+ * @param item   item to be appended
+ * @param index  index for the new item
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int su_vector_insert(su_vector_t *vector, usize_t index, void *item)
+{
+  if (vector && 
+      index <= vector->v_len &&
+      su_vector_make_place(vector, index) > 0) {
+    vector->v_list[index] = item;
+    return 0;
+  }
+  return -1;
+}
+
+/**Remove an item from vector. 
+ *
+ * The function su_vector_remove() removes an item from the @a vector.
+ * The items after the @a index will be moved backwards within the vector.
+ *
+ * @param vector pointer to a vector object
+ * @param index  index for the removed item
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int su_vector_remove(su_vector_t *vector, usize_t index)
+{
+  if (vector && index < vector->v_len) {
+    if (vector->v_free_func)
+        (vector->v_free_func)(vector->v_list[index]);
+    
+    memmove(vector->v_list + index, 
+            vector->v_list + index + 1,
+            (vector->v_len - index - 1) * sizeof(vector->v_list[0]));
+    vector->v_len--;
+    return 0;
+  }
+
+  return -1;
+}
+
+/**Remove all items from vector. 
+ *
+ * The function su_vector_empty() removes all items from the @a vector.
+ *
+ * @param vector pointer to a vector object
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_vector_empty(su_vector_t *vector)
+{
+  size_t i;
+
+  if (vector) {
+    if (vector->v_free_func != NULL) {
+      for (i = 0; i < vector->v_len; i++) {
+        (vector->v_free_func)(vector->v_list[i]);
+      }
+    }
+
+    vector->v_len = 0;
+    return 0;
+  }
+
+  return -1;
+}
+
+/**Append an item to vector. 
+ *
+ * The function su_vector_append() appends an @a item to the @a vector.
+ *
+ * @param vector  pointer to a vector object
+ * @param item    item to be appended
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_vector_append(su_vector_t *vector, void *item)
+{
+  size_t index = vector->v_len;
+
+  if (vector && su_vector_make_place(vector, index)) {
+    vector->v_list[index] = item;
+    return 0;
+  }
+  return -1;
+}
+
+/**Get a numbered item from list. 
+ *
+ * The function su_vector_item() returns a numbered item from vector. The
+ * numbering starts from 0.
+ * 
+ * @param vector  pointer to a vector object
+ * @param i     index
+ *
+ * @return
+ * Pointer, if item exists, or NULL upon an error.
+ */
+void *su_vector_item(su_vector_t const *vector, usize_t i)
+{
+  if (vector && i < vector->v_len)
+    return vector->v_list[i];
+  else
+    return NULL;
+}
+
+/** Get number of items in list. 
+ *
+ * The function su_vector_len() returns the number of items in the 
+ * vector.
+ */
+usize_t su_vector_len(su_vector_t const *l)
+{
+  return l ? l->v_len : 0;
+}
+
+int su_vector_is_empty(su_vector_t const *vector)
+{
+  return su_vector_len(vector) == 0;
+}
+
+/**Get a pointer array from list. 
+ *
+ * The function su_vector_get_array() returns an array of pointer. The
+ * length of the array is always one longer than the length of the vector,
+ * and the last item in the returned array is always NULL.
+ * 
+ * @param vector  pointer to a vector object
+ *
+ * @return
+ * Pointer to array, or NULL if error occurred.
+ */
+void **su_vector_get_array(su_vector_t *vector)
+{
+  if (vector) {
+    void **retval;
+    size_t newsize = sizeof(retval[0]) * (vector->v_len + 1);
+
+    retval = su_alloc(vector->v_home, newsize);
+    
+    if (retval) {
+      retval[vector->v_len] = NULL;
+      return memcpy(retval, vector->v_list, sizeof(retval[0]) * vector->v_len);
+    }
+  }
+
+  return NULL;
+}
+
+/**Free a string array. 
+ *
+ * The function su_vector_free_array() discards a string array allocated
+ * with su_vector_get_array().
+ * 
+ * @param vector  pointer to a vector object
+ * @param array  string array to be freed
+ *
+ */
+void su_vector_free_array(su_vector_t *vector, void **array)
+{
+  su_free(vector->v_home, array);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,313 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ *
+ * @CFILE su_wait.c  
+ * Implementation of OS-independent socket synchronization interface.
+ *
+ * This looks like nth reincarnation of "reactor".  It implements the
+ * (poll()/select()/WaitForMultipleObjects()) functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define SU_INTERNAL_P su_root_t *
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+
+/**@defgroup su_wait Syncronization and Threading
+ * @brief Syncronization and threading interface.
+ *
+ * The Sofia utility library provides simple OS-independent synchronization
+ * interface. The synchronization interface contains primitives for managing
+ * events, messages, timers and threads.
+ *
+ */
+
+/**@ingroup su_wait
+ * @defgroup su_root_ex Example and test code for syncronization and threads
+ *
+ * Example programs demonstrate the su syncronization and threading
+ * primitives.
+ */
+
+
+/**@ingroup su_wait
+ *
+ * @page su_wait_t Wait objects
+ *
+ *   Wait objects are used to signal I/O events to the process.
+ *   The events are as follows:
+ *
+ *   - SU_WAIT_IN       - incoming data is available on socket
+ *   - SU_WAIT_OUT      - data can be sent on socket
+ *   - SU_WAIT_ERR      - an error occurred on socket
+ *   - SU_WAIT_HUP      - the socket connection was closed
+ *   - SU_WAIT_ACCEPT   - a listening socket accepted a new connection attempt
+ *
+ *   It is possible to combine several events with |, binary or operator.
+ *
+ *   The wait objects can be managed with functions as follows:
+ *   - su_wait_create()
+ *   - su_wait_destroy()
+ *   - su_wait()
+ *   - su_wait_events()
+ *   - su_wait_mask()
+ *
+ * @note
+ *   In Unix, the wait object is @c struct @c poll. The structure contains a
+ *   file descriptor, a mask describing expected events, and a mask
+ *   containing the occurred events after calling @c su_wait(), ie. poll().
+ *
+ * @note
+ *   In Windows, the wait object is a @c HANDLE (a descriptor of a Windows
+ *   kernel entity).
+ *
+ */
+
+/**Initialize a wait object.
+ *
+ * The function su_wait_init initializes a memory area of a su_wait_t
+ * object.
+ */
+void su_wait_init(su_wait_t dst[1])
+{
+  su_wait_t const src = SU_WAIT_INIT;
+  *dst = src;
+}
+
+/**Create a wait object.
+ *
+ * The function su_wait_create() creates a new su_wait_t object for an @a
+ * socket, with given @a events.  The new wait object is assigned to the @a
+ * newwait parameter.
+ *
+ * There can be only one wait object per socket. (This is a limitation or
+ * feature of WinSock interface; the limitation is not enforced on other
+ * platforms).
+ *
+ * As a side-effect the socket is put into non-blocking mode when wait
+ * object is created.
+ * 
+ * @param newwait  the newly created wait object (output)
+ * @param socket   socket
+ * @param events   mask for events that can signal this wait object
+ * 
+ * @retval 0 if the call was successful,
+ * @retval -1 upon an error.  
+*/
+int su_wait_create(su_wait_t *newwait, su_socket_t socket, int events)
+{
+#if SU_HAVE_WINSOCK
+  HANDLE h = WSACreateEvent();
+
+  if (newwait == NULL || events == 0 || socket == INVALID_SOCKET) {
+    su_seterrno(WSAEINVAL);
+    return -1;
+  }
+
+  *newwait = 0;
+
+  if (WSAEventSelect(socket, h, events) != 0) {
+    int error = su_errno();
+    WSACloseEvent(h);
+    su_seterrno(error);
+    return -1;
+  }
+
+  *newwait = h;
+
+#elif SU_HAVE_POLL
+  int mode;
+
+  if (newwait == NULL || events == 0 || socket == INVALID_SOCKET) {
+    su_seterrno(EINVAL);
+    return -1;
+  }
+
+  mode = fcntl(socket, F_GETFL, 0);
+  if (mode < 0)
+     return -1;
+  mode |= O_NDELAY | O_NONBLOCK;
+  if (fcntl(socket, F_SETFL, mode) < 0)
+    return -1;
+  
+  newwait->fd = socket;
+  newwait->events = events;
+  newwait->revents = 0;
+#endif
+
+  return 0;
+}
+
+/** Destroy a wait object.
+ *
+ * The function su_wait_destroy() destroys a su_wait_t object.
+ *
+ * @param waitobj  pointer to wait object   
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_wait_destroy(su_wait_t *waitobj)
+{
+#if SU_HAVE_WINSOCK
+  su_wait_t w0 = NULL;
+  if (*waitobj)
+    WSACloseEvent(*waitobj);
+#elif SU_HAVE_POLL
+  su_wait_t w0 = { INVALID_SOCKET, 0, 0 };
+#endif
+  assert(waitobj != NULL);
+  *waitobj = w0;
+
+  return waitobj ? 0 : -1;
+}
+
+/**Wait for multiple events.
+ *
+ * The function su_wait() blocks until an event specified by wait objects in
+ * @a wait array.  If @a timeout is not SU_WAIT_FOREVER, a timeout occurs
+ * after @a timeout milliseconds.
+ * 
+ * In Unix, this is @c poll() or @c select().
+ * 
+ * In Windows, this is @c WSAWaitForMultipleEvents().
+ * 
+ * @param waits    array of wait objects
+ * @param n        number of wait objects in array waits
+ * @param timeout  timeout in milliseconds
+ *
+ * @retval Index of the signaled wait object, if any,
+ * @retval SU_WAIT_TIMEOUT if timeout occurred, or
+ * @retval -1 upon an error.
+ */
+int su_wait(su_wait_t waits[], unsigned n, su_duration_t timeout)
+{
+#if SU_HAVE_WINSOCK
+  DWORD i;
+
+  if (n > 0)
+    i = WSAWaitForMultipleEvents(n, waits, FALSE, timeout, FALSE);
+  else
+    return Sleep(timeout), SU_WAIT_TIMEOUT;
+
+  if (i == WSA_WAIT_TIMEOUT)
+    return SU_WAIT_TIMEOUT;
+  else if (i == WSA_WAIT_FAILED)
+    return SOCKET_ERROR;
+  else
+    return i;
+
+#elif SU_HAVE_POLL
+  for (;;) {
+    int i = poll(waits, n, timeout);
+
+    if (i == 0)
+      return SU_WAIT_TIMEOUT;
+
+    if (i > 0) {
+      unsigned j;
+      for (j = 0; j < n; j++) {
+	if (waits[j].revents)
+	  return j;
+      }
+    }
+  
+    if (errno == EINTR)
+      continue;
+
+    return -1;
+  }  
+#endif
+}
+
+/** Get events.
+ * 
+ *   The function su_wait_events() returns an mask describing events occurred.
+ *
+ * @param waitobj  pointer to wait object   
+ * @param s        socket
+ *
+ * @return Binary mask describing the events.
+ */
+int su_wait_events(su_wait_t *waitobj, su_socket_t s)
+{
+#if SU_HAVE_WINSOCK
+  WSANETWORKEVENTS net_events;
+
+  if (WSAEnumNetworkEvents(s, *waitobj, &net_events) != 0)
+    return SOCKET_ERROR;
+
+  return net_events.lNetworkEvents;
+
+#elif SU_HAVE_POLL
+  /* poll(e, 1, 0); */
+  return waitobj->revents;
+#endif
+}
+
+/** Set event mask.
+ * 
+ *   The function su_wait_mask() sets the mask describing events that can
+ *   signal the wait object.
+ *
+ * @param waitobj  pointer to wait object   
+ * @param s        socket
+ * @param events   new event mask
+ *
+ * @retval  0 when successful, 
+ * @retval -1 upon an error.
+ */
+int su_wait_mask(su_wait_t *waitobj, su_socket_t s, int events)
+{
+#if SU_HAVE_WINSOCK
+  HANDLE e = *waitobj;
+
+  if (WSAEventSelect(s, e, events) != 0) {
+    int error = WSAGetLastError();
+    WSACloseEvent(e);
+    WSASetLastError(error);
+    return -1;
+  }
+#elif SU_HAVE_POLL
+  waitobj->fd = s;
+  waitobj->events = events;
+  waitobj->revents = 0;
+#endif
+
+  return 0;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,174 @@
+#! /usr/bin/env awk
+#
+# Create reference tags and WIN32 initialization functions for tags.
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>
+#
+# Created: Tue Feb 26 14:11:25 2002 ppessi
+#
+
+BEGIN {
+  DEFS = 0;
+  HEADER = 1;
+}
+
+HEADER {
+  HEADER = 0;
+
+  if (OUTNAME != "") {
+    fn = OUTNAME;
+  } else {
+    fn = FILENAME;
+  }
+
+  DLL = fn;
+  sub(/[.]c(at)?/, "_dll.c", DLL);
+
+  if (NODLL) DLL = "/dev/null";
+
+  base = fn;
+  sub(/.*\//, "", base);
+
+  printf("#ifdef _WIN32\n"\
+	 "/*\n" \
+	 " * PLEASE NOTE: \n" \
+	 " * \n" \
+	 " * This file is automatically generated by tag_dll.awk.\n"\
+	 " * It contains magic required by Win32 DLLs to initialize\n"\
+	 " * tag_typedef_t variables.\n"\
+	 " * \n"\
+	 " * Do not, repeat, do not edit this file. Edit '%s' instead.\n"\
+	 " * \n"\
+	 " */\n\n"\
+	 "#define EXPORT __declspec(dllexport)\n\n", base) > DLL;
+
+  if (DLLREF) {
+    print \
+      "#include \"config.h\"\n\n" \
+      "#include <sofia-sip/su_tag_class.h>\n\n" > DLL;
+  }
+
+  REF = fn;
+  sub(/[.]c(at)?/, "_ref.c", REF);
+
+  printf("/*\n" \
+	 " * PLEASE NOTE: \n" \
+	 " * \n" \
+	 " * This file is automatically generated by tag_dll.awk.\n"\
+	 " * It contains tag_typedef_t for tag references.\n"\
+	 " * \n"\
+	 " * Do not, repeat, do not edit this file. Edit '%s' instead.\n"\
+	 " * \n"\
+	 " */\n\n"\
+	 "#include \"config.h\"\n\n"\
+	 "#include <sofia-sip/su_tag_class.h>\n"\
+	 "\n"\
+	 "#ifdef _WIN32\n"\
+	 "#define EXPORT __declspec(dllexport)\n"\
+	 "#else\n"\
+	 "#define EXPORT\n"\
+	 "#endif\n\n",
+	 base) > REF;
+
+  if (LIST) {
+    print "#include <stddef.h>" >REF;
+  }
+  print "" > REF;
+}
+
+/^#define TAG_NAMESPACE/ { 
+  print "#undef TAG_NAMESPACE" > REF; 
+  print $0 > REF; 
+  print "" > REF;
+  print "#undef TAG_NAMESPACE" > DLL; 
+  print $0 > DLL; 
+  print "" > DLL;
+}
+
+!DEFS && /^tag_typedef_t/ { DEFS = 1; }
+
+DEFS && /tag_typedef_t/ {
+  tag = $2;
+  typedefs[tag] = $0;
+
+  if ($0 !~ /NSTAG_TYPEDEF/) {
+    print "extern tag_typedef_t "tag";" > REF;
+    print "EXPORT tag_typedef_t "tag"_ref;" > DLL;
+    print "EXPORT tag_typedef_t "tag"_ref = \n  REFTAG_TYPEDEF("tag");" > REF;
+  }
+
+  gsub(/ = .*$/, ";");
+}
+
+!DLLREF { print $0 > DLL; }
+
+END {
+  if (LIST) {
+    print "\nEXPORT tag_type_t " LIST "[] =\n{" > REF;
+    print "\nEXPORT tag_type_t " LIST "[] =\n{" > DLL; 
+    for (tag in typedefs) {
+      if (typedefs[tag] !~ /NSTAG_TYPEDEF/) {
+        print "  " tag "," > REF;
+        print "  " tag "," > DLL;
+      }
+    }
+    print "  NULL\n};" > REF;
+    print "  NULL\n};" > DLL;
+  }
+
+  printf("\n" \
+	 "#include <windows.h>\n"\
+	 "\n"\
+	 "BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fwdReason, LPVOID fImpLoad)\n"\
+	 "{\n") > DLL;
+
+   for (tag in typedefs) {
+     def = typedefs[tag];
+     if (!DLLREF) {
+       sub(/^tag_typedef_t /, "  tag_typedef_t _", def);
+       print def > DLL;
+     }
+     else {
+       print "  extern tag_typedef_t "tag";" > DLL;
+     }
+     print "  tag_typedef_t _"tag"_ref =\n    REFTAG_TYPEDEF("tag");" > DLL;
+   }
+
+   print "" > DLL;
+
+   for (tag in typedefs) {
+     if (!DLLREF) {
+       print "  *(struct tag_type_s *)" tag " = *_" tag ";" > DLL;
+     }
+     print "  *(struct tag_type_s *)" tag "_ref = *_" tag "_ref;" > DLL;
+   }
+
+   print "\n  return TRUE;" > DLL;
+   print "}" > DLL;
+   print "\n#endif" > DLL;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_htable
+ *
+ * @CFILE test_htable.c
+ *
+ * Test functions for the @b su library hash table implementation.
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/htable.h"
+
+#define TSTFLAGS flags
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "htable_test";
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v|--verbatim]\n", name);
+  exit(2);
+}
+
+static int table_test(int flags);
+
+int main(int argc, char *argv[])
+{
+  int flags = 0;
+
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
+      flags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= table_test(flags); fflush(stdout);
+
+  return retval;
+}
+
+typedef struct hentry_s entry_t;
+HTABLE_DECLARE(htable, ht, entry_t);
+HTABLE_PROTOS(htable, ht, entry_t);
+
+struct hentry_s 
+{
+  unsigned long e_value;
+  unsigned long e_n;
+};
+
+#define HENTRY_HASH(e) ((e)->e_value)
+
+HTABLE_BODIES(htable, ht, entry_t, HENTRY_HASH);
+
+typedef struct context_s
+{
+  su_home_t c_home[1];
+  htable_t c_hash[1];
+} context_t;
+
+context_t *context_create(void) 
+{
+  context_t *c = su_home_clone(NULL, sizeof(*c));
+
+  if (c)
+    htable_resize(c->c_home, c->c_hash, 0);
+
+  return c;
+}
+
+static
+entry_t *search(context_t *c, unsigned long value, unsigned long n, int add)
+{
+  htable_t *ht = c->c_hash;
+  entry_t *e, **ee;
+  unsigned long hash = value;
+
+  /* Search for entry in hash table */
+  for (ee = htable_hash(ht, hash);
+       (e = *ee);
+       ee = htable_next(ht, ee)) {
+    if (e->e_value == value &&
+	e->e_n == n)
+      return e;
+  }
+
+  if (add) {
+    /* Resize hash table */
+    if (htable_is_full(ht)) {
+      htable_resize(c->c_home, ht, 0);
+      fprintf(stderr, "htable: resized to %u with %u entries\n", 
+	      ht->ht_size, ht->ht_used);
+    }
+
+    /* Add an entry */
+    e = su_zalloc(c->c_home, sizeof(*e)); assert(e);
+    e->e_value = value, e->e_n = n;
+
+    htable_append(ht, e);
+  }
+
+  return e;
+}
+
+static int add(context_t *c, unsigned long value, unsigned long n)
+{
+  return search(c, value, n, 1) != NULL;
+}
+
+static
+void zap(context_t *c, entry_t *e)
+{
+  htable_remove(c->c_hash, e);
+  su_free(c->c_home, e);
+}
+
+static unsigned long count(context_t *c, hash_value_t h)
+{
+  entry_t *e, **ee;
+  unsigned long n;
+
+  for (ee = htable_hash(c->c_hash, h), n = 0;
+       (e = *ee); 
+       ee = htable_next(c->c_hash, ee)) {
+    if (e->e_value != h)
+      continue;
+    if (e->e_n == n)
+      n++;
+  }
+
+  return n;
+}
+
+int table_test(int flags)
+{
+  context_t *c;
+  entry_t *e;
+
+  BEGIN();
+
+  TEST0(c = context_create());
+  TEST0(add(c, 0, 1)); TEST0(c->c_hash->ht_table[0]);
+  TEST0(add(c, 1, 2)); TEST0(c->c_hash->ht_table[1]);
+  TEST0(add(c, 2, 3)); TEST0(c->c_hash->ht_table[2]);
+  TEST0(add(c, 0, 4)); TEST0(c->c_hash->ht_table[3]);
+  TEST0(add(c, 2, 5)); TEST0(c->c_hash->ht_table[4]);
+
+  TEST0(e = search(c, 1, 2, 0));
+  zap(c, e);
+  TEST0(c->c_hash->ht_table[0]);
+  TEST0(c->c_hash->ht_table[1]);
+  TEST0(c->c_hash->ht_table[2]);
+  TEST0(c->c_hash->ht_table[3]);
+  TEST0(c->c_hash->ht_table[4] == NULL);
+
+  zap(c, c->c_hash->ht_table[0]);
+
+  TEST0(c->c_hash->ht_table[0]);
+  TEST0(c->c_hash->ht_table[1] == NULL);
+  TEST0(c->c_hash->ht_table[2]);
+  TEST0(c->c_hash->ht_table[3]);
+  TEST0(c->c_hash->ht_table[4] == NULL);
+
+  TEST0(add(c, 0, 6)); TEST0(c->c_hash->ht_table[1]);
+  TEST0(add(c, 1, 7)); TEST0(c->c_hash->ht_table[4]);
+
+  /* Test that zapping entry 0 does not move 2 and 3 */
+  zap(c, c->c_hash->ht_table[0]);
+  TEST0(c->c_hash->ht_table[4] == NULL);
+
+  {
+    /* Insert entries at the end of hash, then resize and check
+       for correct ordering */
+    hash_value_t size = c->c_hash->ht_size, h = size - 1;
+
+    TEST0(add(c, h, 0)); TEST0(add(c, h, 1)); TEST0(add(c, h, 2));
+    TEST0(add(c, h, 3)); TEST0(add(c, h, 4)); TEST0(add(c, h, 5));
+    TEST0(add(c, h, 6)); TEST0(add(c, h, 7)); TEST0(add(c, h, 8));
+
+    TEST(count(c, h), 9);
+    
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+    TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+    TEST(count(c, h), 9);
+  }
+
+  TEST_VOID(su_home_unref(c->c_home));
+
+  END();
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_memmem
+ *
+ * @CFILE test_memmem.c
+ *
+ * Torture tests for memmem() and strcasestr().
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+	     const void *needle, size_t needlelen);
+#endif
+#if !HAVE_STRCASESTR
+char *strcasestr(const char *haystack, const char *needle);
+#endif
+
+#include <string.h>
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "test_memmem";
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int test_notfound(void);
+static int test_pattern(void);
+
+char const *null = NULL;
+
+static int test_notfound(void)
+{
+  char const haystack[] = "abcabcabcabc";
+  char const needle[] = "cab";
+  char const *a;
+  BEGIN();
+
+  TEST_P(memmem(haystack, 12, needle, 3), haystack + 2);
+  TEST_P(memmem(needle, 3, haystack, 12), NULL);
+  TEST_P(memmem(haystack, 12, "", 0), haystack);
+  TEST_P(memmem(haystack, 12, null, 0), haystack);
+  TEST_P(memmem(haystack, 0, "", 0), haystack);
+  TEST_P(memmem(haystack, 0, null, 0), haystack);
+
+  TEST_P(memmem(haystack + 2, 3, needle, 3), haystack + 2);
+  TEST_P(memmem(haystack + 2, 2, needle, 3), NULL);
+  TEST_P(memmem(a = "a\0bc", 4, "a\0bc", 4), a);
+
+  END();
+}
+
+static int test_pattern(void)
+{
+  BEGIN();
+  END();
+}
+
+int test_strcasestr(void)
+{
+  BEGIN();
+
+  {
+    char const hs[] =
+      "A case-folding string searching test consisting of a Long String";
+    char const *s;
+
+    s = strcasestr(hs, "sting");
+    TEST_S(s, hs + 42);
+
+    s = strcasestr(hs, "String");
+    TEST_S(s, hs + 15);
+
+    s = strcasestr(hs, "S");
+    TEST_S(s, hs + 4);
+
+    s = strcasestr(hs, "L");
+    TEST_S(s, hs + 9);
+
+    s = strcasestr(hs, "trings");
+    TEST_1(s == NULL);
+
+    s = strcasestr(hs, "String");
+    TEST_S(s, hs + 15);
+
+    s = strcasestr(hs, "StRiNg");
+    TEST_S(s, hs + 15);
+
+    s = strcasestr(hs, "OnG");
+    TEST_S(s, hs + 54);
+
+    /* Special cases */
+    TEST_1(strcasestr(hs, "") == hs);
+    TEST_1(strcasestr("", "ong") == NULL);
+    TEST_1(strcasestr("", "OnG") == NULL);
+    TEST_1(strcasestr("ong", hs) == NULL);
+    TEST_1(strcasestr("OnG", hs) == NULL);
+    TEST_1(strcasestr(hs, "Z") == NULL);
+    TEST_1(strcasestr(hs, "z") == NULL);
+  }
+
+  {
+    char const hs[] = 
+"A case-folding string searching test consisting of a Very Long String\n"
+
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer felis. "
+"Suspendisse potenti. Morbi malesuada erat eget enim. Sed dui lorem, aliquam "
+"eu, lobortis eget, dapibus vitae, velit. Cras non purus. Suspendisse massa. "
+"Curabitur gravida condimentum massa. Donec nunc magna, lacinia non, "
+"pellentesque ac, laoreet vel, eros. Praesent lectus leo, vestibulum eu, "
+"tempus eu, ullamcorper tristique, mi. Duis fringilla ultricies lacus. Ut "
+"non pede. Donec id libero. Cum sociis natoque penatibus et magnis dis "
+"parturient montes, nascetur ridiculus mus. Phasellus bibendum.\n"
+
+"Vestibulum turpis. Nunc euismod. Maecenas venenatis, purus at pharetra "
+"ultrices, orci orci blandit nisl, eget vulputate enim tortor sed nunc. "
+"Proin sit amet elit. Donec ut justo. In quis nisi. Praesent posuere. "
+"Maecenas porta. Curabitur pharetra. Class aptent taciti sociosqu ad litora "
+"torquent per conubia nostra, per inceptos hymenaeos. Donec suscipit ligula. "
+"Quisque facilisis ante eget mi. Nunc ac est.\n"
+
+"Quisque in sapien eget justo aliquam laoreet. Nullam ultricies est id dolor. "
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse ante "
+"velit, eleifend at, ullamcorper ut, rutrum et, ipsum. Mauris luctus, tellus "
+"non elementum convallis, nunc ipsum hendrerit lectus, ut lacinia elit nulla "
+"ac tellus. In sit amet velit. Maecenas non dolor. Sed commodo diam a pede. "
+"Ut non pede. Vestibulum condimentum turpis vel lacus consectetuer dictum. "
+"Nulla ullamcorper mi eu pede. Donec mauris tortor, facilisis vitae, "
+"hendrerit nec, lobortis nec, eros. Nam sit amet mi. Ut pharetra, orci nec "
+"porta convallis, lacus velit blandit sapien, luctus nonummy lacus dolor vel "
+"sapien. Suspendisse placerat. Donec ante turpis, volutpat eu, hendrerit "
+"vel, eleifend ac, arcu. Nulla facilisi. Sed faucibus facilisis lectus. "
+"Aliquam congue justo nec dui.\n"
+
+"Donec dapibus dui sed nisl. Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n"
+
+"Phasellus congue. Morbi lectus arcu, mattis non, pulvinar et, condimentum "
+"non, mi. Suspendisse vestibulum nunc eu neque. Sed rutrum felis aliquam "
+"urna. Ut tincidunt orci vitae ipsum. Nullam eros. Quisque augue. Quisque "
+"lacinia. Nunc ligula diam, nonummy a, porta in, tristique quis, leo. "
+"Phasellus nunc nulla, fringilla vel, lacinia et, suscipit a, turpis. " 
+"Integer a est. Curabitur mauris lacus, vehicula sit amet, sodales vel, "
+"iaculis vitae, massa. Nam diam est, ultrices vitae, varius et, tempor a, "
+"leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, "
+"per inceptos hymenaeos. Fusce felis nibh, ullamcorper non, malesuada eget, "
+      "facilisis vel, purus.\n";
+
+char const needle[] = 
+"Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n";
+
+char const Needle[] = 
+"PROIN CONGUE. CURABITUR PLACERAT DIAM ID EROS. "
+"PELLENTESQUE VITAE NULLA. QUISQUE AT LOREM ET DOLOR AUCTOR CONSEQUAT. SED "
+"SED TELLUS NON NIBH IMPERDIET VENENATIS. INTEGER ULTRICES DAPIBUS NISI. "
+"AENEAN VEHICULA MALESUADA RISUS. FUSCE EGESTAS MALESUADA LEO. IN "
+"ULLAMCORPER PRETIUM LOREM. VESTIBULUM ANTE IPSUM PRIMIS IN FAUCIBUS ORCI "
+"LUCTUS ET ULTRICES POSUERE CUBILIA CURAE;\n";
+
+    char const *s;
+
+    s = strcasestr(hs, needle);
+    TEST_S(s, hs + 1920);
+
+    s = strcasestr(hs, Needle);
+    TEST_S(s, hs + 1920);
+  }
+
+  END();
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      test_flags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_notfound(); fflush(stdout);
+  retval |= test_pattern(); fflush(stdout);
+  retval |= test_strcasestr(); fflush(stdout);
+
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @file test_poll.c
+ * Example code for su_wait.h.
+ *
+ * This file illustrates how the asynchronous connect can be used with @b su.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_log.h"
+
+void usage(char const *name)
+{
+  fprintf(stderr, "usage: %s [host]\n", name);
+  exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+  su_socket_t s;
+  su_sockaddr_t su = { 0 };
+  char *host = argv[1];
+  char *port = host ? argv[2] : NULL;
+  su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }};
+  int error;
+  
+  if (argv[1] && (strcmp(argv[1], "--help") == 0 || 
+		  strcmp(argv[1], "-?") == 0)) 
+    usage(argv[0]);
+
+  if (!port) port = "echo";
+
+  if ((error = su_getaddrinfo(host, port, hints, &ai))) {
+    fprintf(stderr, "poll_test: su_getaddrinfo(): %s\n", 
+	    su_gai_strerror(error));
+    exit(1);
+  }
+
+  memcpy(SU_ADDR(&su), ai->ai_addr, ai->ai_addrlen);
+
+  s = su_socket(ai->ai_family, SOCK_STREAM, 0);
+  if (s == INVALID_SOCKET) {
+    su_perror("socket");
+    exit(1);
+  }
+
+  su_freeaddrinfo(ai);
+
+  su_setblocking(s, 0);		/* Don't block */
+
+  if (connect(s, &su.su_sa, su_sockaddr_size(&su)) == -1) {
+    if (errno != EINPROGRESS) {
+      su_perror("connect");
+      exit(1);
+    }
+  }
+
+  {
+    su_wait_t w;
+    int n, err;
+
+    su_wait_create(&w, s, SU_WAIT_OUT);
+
+    n = su_wait(&w, 1, SU_WAIT_FOREVER);
+    
+    printf("su_wait returned %d\n", n);
+
+    err = su_soerror(s);
+
+    printf("connect: %s\n", su_strerror(err));
+  }
+
+  exit(0);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,578 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE test_su.c
+ *
+ * @brief Test program for su wait objects, root, timers, clones, and messages.
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P   su_root_t *
+#define SU_MSG_ARG_T    su_sockaddr_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_debug.h"
+
+char const name[] = "su_test";
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __func__))
+#define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "su_test"
+#endif
+
+struct pinger {
+  enum { PINGER = 1, PONGER = 2 } const sort;
+  char const *  name;
+  unsigned      running : 1;
+  unsigned      : 0;
+  su_root_t    *root;
+  su_socket_t   s;
+  su_timer_t   *t;
+  int           id;
+  int           rindex;
+  su_time_t     when;
+  su_sockaddr_t addr;
+  double        rtt_total;
+  int           rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+
+static su_socket_t udpsocket(void) 
+{
+  su_socket_t s;
+  su_sockaddr_t su = { 0 };
+  socklen_t sulen = sizeof(su);
+  char nbuf[64];
+
+  su.su_family = opt_family;
+
+  su_getlocalip(&su);
+
+  s = su_socket(su.su_family, SOCK_DGRAM, 0);
+  if (s == INVALID_SOCKET) {
+    su_perror("udpsocket: socket");
+    exit(1);
+  }
+
+  if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+    su_perror("udpsocket: bind");
+    exit(1);
+  }
+
+  if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+    su_perror("udpsocket: getsockname");
+    exit(1); 
+  }
+
+  if (opt_verbatim)
+    printf("udpsocket: using address [%s]:%u\n",
+	   inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port));
+
+  return s;
+}
+
+static char *snow(su_time_t now)
+{
+  static char buf[24];
+
+  su_time_print(buf, sizeof(buf), &now);
+
+  return buf;
+}
+
+void 
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PINGER);
+
+  p->when = su_now();
+
+  snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+  if (su_sendto(p->s, buf, strlen(buf), 0, 
+		&p->addr, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_ping: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  struct sockaddr * const susa = &su.su_sa;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+  double rtt;
+
+  assert(p0 == p);
+  assert(p->sort == PINGER);
+
+  rtt = su_time_diff(now, p->when);
+
+  p->rtt_total += rtt, p->rtt_n++;
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+  if (n < 0) {
+	  su_perror("do_rtt: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+  do_ping(p, p->t, NULL);
+
+  return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PONGER);
+
+  p->id = 0;
+
+  snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+  if (su_sendto(p->s, buf, strlen(buf), 0, 
+		&p->addr, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_pong: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+
+  assert(p0 == p);
+  assert(p->sort == PONGER);
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+  if (n < 0) {
+	  su_perror("do_recv: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, snow(now));
+
+  fflush(stdout);
+
+#if 0
+  if (p->id)
+    puts("do_recv: already a pending reply");
+
+  if (su_timer_set(p->t, do_pong, p) < 0) {
+    fprintf(stderr, "do_recv: su_timer_set() error\n");
+    return 0;
+  }
+
+  p->id = 1;
+#else
+  do_pong(p, p->t, NULL);
+#endif
+
+  return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+  if (opt_verbatim)
+    printf("do_exit at %s\n", snow(su_now()));
+  su_root_break(su_timer_root(t));
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+  su_wait_t w;
+  su_socket_t s;
+  long interval;
+  su_timer_t *t;
+  su_wakeup_f f;
+  int index;
+#if nomore
+  su_wait_t w0;
+  int index0
+#endif
+
+  enter;
+
+  switch (p->sort) {
+  case PINGER: f = do_rtt;  interval = 200; break;
+  case PONGER: f = do_recv; interval = 40;  break;
+  default:
+    return SU_FAILURE;
+  }
+
+  p->t = t = su_timer_create(su_root_task(root), interval);
+  if (t == NULL) {
+    su_perror("su_timer_create");
+    return SU_FAILURE;
+  }
+
+  /* Create a sockets,  */
+  p->s = s = udpsocket();
+
+#if nomore
+  if (su_wait_create(&w0, s, SU_WAIT_IN) == SOCKET_ERROR) {
+    su_perror("su_wait_create");
+    return SU_FAILURE;
+  }
+
+  index0 = su_root_register(root, &w0, f, p, 0);
+  if (index0 == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+#endif
+
+  if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR) {
+    su_perror("su_wait_create");
+    return SU_FAILURE;
+  }
+
+  index = su_root_register(root, &w, f, p, 0);
+  if (index == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+
+#if nomore
+  su_root_deregister(root, index0);
+#endif
+  p->rindex = index;
+
+  return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+  enter;
+
+  if (opt_verbatim)
+    printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+  su_root_deregister(root, p->rindex);
+  su_timer_destroy(p->t), p->t = NULL;
+  p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  enter;
+
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_ping: %s\n", p->name);
+
+  p->addr = *arg;
+  p->id = 1;
+
+  su_timer_set_interval(p->t, do_ping, p, 0);
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  enter;
+
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_pong: %s\n", p->name);
+
+  p->addr = *arg;
+
+  if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_reply failed!\n");
+  }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  enter;
+
+  if (opt_verbatim)
+    printf("init_ping: %s\n", p->name);
+
+  if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_reply failed!\n");
+  }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+  enter;
+
+  exit(1);
+}
+
+void
+time_test(void)
+{
+  su_time_t now = su_now(), then = now;
+  su_duration_t t1, t2;
+  su_duration_t us;
+
+  enter;
+
+  for (us = 0; us < 1000000; us += 300) {
+    then.tv_sec = now.tv_sec;
+    if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+      then.tv_usec -= 1000000, then.tv_sec++;
+    t1 = su_duration(now, then);
+    t2 = su_duration(then, now);
+    assert(t1 == -t2);
+  }
+
+  if (opt_verbatim)
+    printf("time_test: passed\n");
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+  enter;
+
+  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+  exit(1);
+}
+static char const no_alarm[] = " [--no-alarm]";
+#else
+static char const no_alarm[] = "";
+#endif
+
+void
+usage(int exitcode)
+{
+  fprintf(stderr, "usage: %s [-6vs]%s\n", name, no_alarm);
+
+  exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives, 
+ *                  then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ *                  waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+  su_msg_r start_msg = SU_MSG_R_INIT;
+  su_timer_t *t;
+#if HAVE_ALARM
+  int opt_alarm = 1;
+#endif
+
+  struct pinger 
+    pinger = { PINGER, "ping", 1 }, 
+    ponger = { PONGER, "pong", 1 };
+
+  char *argv0 = argv[0];
+
+  enter;
+
+  while (argv[1]) {
+    if (strcmp(argv[1], "-v") == 0) {
+      opt_verbatim = 1;
+      argv++;
+    }
+#if SU_HAVE_IN6
+    else if (strcmp(argv[1], "-6") == 0) {
+      opt_family = AF_INET6;
+      argv++;
+    }
+#endif
+    else if (strcmp(argv[1], "-s") == 0) {
+      opt_singlethread = 1;
+      argv++;
+    }
+#if HAVE_ALARM
+    else if (strcmp(argv[1], "--no-alarm") == 0) {
+      opt_alarm = 0;
+      argv++;
+    }
+#endif
+    else {
+      usage(1);
+    }
+  }
+
+  signal(SIGTERM, term);
+
+  su_init(); atexit(su_deinit);
+
+  time_test();
+
+#if HAVE_ALARM
+  if (opt_alarm) {
+    alarm(60);
+    signal(SIGALRM, sig_alarm);
+  }
+#endif
+
+  root = su_root_create(NULL);
+  if (!root) perror("su_root_create"), exit(1);
+  
+  su_root_threading(root, !opt_singlethread);
+
+  if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1);
+  if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1); 
+
+  /* Test timer, exiting after 200 milliseconds */
+  t = su_timer_create(su_root_task(root), 200L);
+  if (t == NULL)
+    su_perror("su_timer_create"), exit(1);
+  su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+  su_clone_pause(ping);
+  su_clone_pause(pong);
+
+  su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong), 
+		init_ping, 0);
+  su_msg_send(start_msg);
+
+  su_clone_resume(ping);
+  su_clone_resume(pong);
+
+  su_root_run(root);
+
+  su_clone_wait(root, ping);
+  su_clone_wait(root, pong);
+
+  su_timer_destroy(t);
+
+  if (pinger.rtt_n) {
+    printf("%s executed %u pings in %g, mean rtt=%g sec\n", name, 
+	   pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+  }
+  su_root_destroy(root);
+
+  if (opt_verbatim)
+    printf("%s exiting\n", argv0); 
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,581 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE torture_su_root_osx.c
+ *
+ * @brief Test program for OSX Core Foundation Run Loop and su root
+ * event loop integration.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Sep 26 17:16:02 EEST 2006 mela
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P   su_root_t *
+#define SU_MSG_ARG_T    su_sockaddr_t
+
+#define SU_HAVE_OSX_CF_API 1
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_debug.h"
+
+#include "sofia-sip/su_osx_runloop.h"
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("torture_su_root_osx: %s: entering\n", __func__))
+#define nh_enter (void)SU_DEBUG_9(("torture_su_root_osx %s(%p): entering\n", __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("torture_su_root_osx: %s: entering\n", __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("torture_su_root_osx %s(%p): entering\n", __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "torture_su_root_osx"
+#endif
+
+struct pinger {
+  enum { PINGER = 1, PONGER = 2 } const sort;
+  char const *  name;
+  unsigned      running : 1;
+  unsigned      : 0;
+  su_root_t    *root;
+  su_socket_t   s;
+  su_timer_t   *t;
+  int           id;
+  int           rindex;
+  su_time_t     when;
+  su_sockaddr_t addr;
+  double        rtt_total;
+  int           rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+short opt_root_run = 0;
+
+/* For run loop */
+int running = 0;
+
+static su_socket_t udpsocket(void) 
+{
+  su_socket_t s;
+  su_sockaddr_t su = { 0 };
+  socklen_t sulen = sizeof(su);
+  char nbuf[64];
+  
+  enter;
+
+  su.su_family = opt_family;
+
+  su_getlocalip(&su);
+
+  s = su_socket(su.su_family, SOCK_DGRAM, 0);
+  if (s == INVALID_SOCKET) {
+    su_perror("udpsocket: socket");
+    exit(1);
+  }
+
+  if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+    su_perror("udpsocket: bind");
+    exit(1);
+  }
+
+  if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+    su_perror("udpsocket: getsockname");
+    exit(1); 
+  }
+
+  if (opt_verbatim)
+    printf("udpsocket: using address [%s]:%u\n",
+	   inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port));
+
+  return s;
+}
+
+static char *snow(su_time_t now)
+{
+  static char buf[24];
+
+  enter;
+
+  su_time_print(buf, sizeof(buf), &now);
+
+  return buf;
+}
+
+void 
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  enter;
+
+  printf("%s: pinger p == %x\n", __func__, (unsigned int) p);
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PINGER);
+
+  p->when = su_now();
+
+  snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+  if (su_sendto(p->s, buf, strlen(buf), 0, 
+		&p->addr, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_ping: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  struct sockaddr * const susa = &su.su_sa;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+  double rtt;
+
+  enter;
+
+  assert(p0 == p);
+  assert(p->sort == PINGER);
+
+  rtt = su_time_diff(now, p->when);
+
+  p->rtt_total += rtt, p->rtt_n++;
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+  if (n < 0) {
+	  su_perror("do_rtt: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+  do_ping(p, p->t, NULL);
+
+  return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+  char buf[1024];
+
+  enter;
+
+  assert(p == su_root_magic(su_timer_root(t)));
+  assert(p->sort == PONGER);
+
+  p->id = 0;
+
+  snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+  if (su_sendto(p->s, buf, strlen(buf), 0, 
+		&p->addr, su_sockaddr_size(&p->addr)) == -1) {
+    su_perror("do_pong: send");
+  }
+
+  if (opt_verbatim) {
+    puts(buf);
+    fflush(stdout);
+  }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+  su_sockaddr_t su;
+  socklen_t susize[] = { sizeof(su)};
+  char buf[1024];
+  char nbuf[1024];
+  int n;
+  su_time_t now = su_now();
+
+  enter;
+
+  assert(p0 == p);
+  assert(p->sort == PONGER);
+
+  su_wait_events(w, p->s);
+
+  n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+  if (n < 0) {
+	  su_perror("do_recv: recvfrom");
+	  return 0;
+  }
+  buf[n] = 0;
+
+  if (opt_verbatim)
+    printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+	   n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+	   ntohs(su.su_sin.sin_port), buf, snow(now));
+
+  fflush(stdout);
+
+#if 0
+  if (p->id)
+    puts("do_recv: already a pending reply");
+
+  if (su_timer_set(p->t, do_pong, p) < 0) {
+    fprintf(stderr, "do_recv: su_timer_set() error\n");
+    return 0;
+  }
+
+  p->id = 1;
+#else
+  do_pong(p, p->t, NULL);
+#endif
+
+  return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+  enter;
+
+  if (opt_verbatim)
+    printf("do_exit at %s\n", snow(su_now()));
+  su_root_break(su_timer_root(t));
+
+  running = 0;
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+  su_wait_t w;
+  su_socket_t s;
+  long interval;
+  su_timer_t *t;
+  su_wakeup_f f;
+  int index, index0;
+
+  enter;
+
+  switch (p->sort) {
+  case PINGER: f = do_rtt;  interval = 200; break;
+  case PONGER: f = do_recv; interval = 40;  break;
+  default:
+    return SU_FAILURE;
+  }
+
+  /* Create a sockets,  */
+  s = udpsocket();
+  if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR)
+    su_perror("su_wait_create"), exit(1);
+
+  /* CFSocketEnableCallbacks(s, map_poll_revent_to_cf_event(su_wait_events(&w, s))); */
+
+  p->s = s;
+  p->t = t = su_timer_create(su_root_task(root), interval);
+  if (t == NULL) {
+    su_perror("su_timer_create");
+    return SU_FAILURE;
+  }
+
+  index0 = su_root_register(root, &w, f, p, 0);
+  if (index0 == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+
+  index = su_root_register(root, &w, f, p, 0);
+  if (index == SOCKET_ERROR) {
+    su_perror("su_root_register");
+    return SU_FAILURE;
+  }
+
+  su_root_deregister(root, index0);
+
+  p->rindex = index;
+
+  return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+  enter;
+
+  if (opt_verbatim)
+    printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+
+  su_root_deregister(root, p->rindex);
+  su_timer_destroy(p->t), p->t = NULL;
+
+  p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  enter;
+
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_ping: %s\n", p->name);
+
+  p->addr = *arg;
+  p->id = 1;
+  su_timer_set_at(p->t, do_ping, p, su_now());
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  enter;
+
+  if (!p->running)
+    return;
+
+  if (opt_verbatim)
+    printf("start_pong: %s\n", p->name);
+
+  p->addr = *arg;
+
+  if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_create failed!\n");
+  }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+  su_msg_r reply;
+
+  enter;
+
+  if (opt_verbatim)
+    printf("init_ping: %s\n", p->name);
+
+  if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+    socklen_t sinsize[1] = { sizeof(p->addr) };
+    if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+	== SOCKET_ERROR)
+      su_perror("start_pong: getsockname()"), exit(1);
+    su_msg_send(reply);
+  }
+  else {
+    fprintf(stderr, "su_msg_reply failed!\n");
+  }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+  enter;
+
+  exit(1);
+}
+
+void
+time_test(void)
+{
+  su_time_t now = su_now(), then = now;
+  su_duration_t t1, t2;
+  su_duration_t us;
+
+  enter;
+
+  for (us = 0; us < 1000000; us += 300) {
+    then.tv_sec = now.tv_sec;
+    if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+      then.tv_usec -= 1000000, then.tv_sec++;
+    t1 = su_duration(now, then);
+    t2 = su_duration(then, now);
+    assert(t1 == -t2);
+  }
+
+  if (opt_verbatim)
+    printf("time_test: passed\n");
+}
+
+char const name[] = "torture_su_root_osx";
+
+void
+usage(int exitcode)
+{
+  fprintf(stderr, "usage: %s [-6vs] [pid]\n", name);
+  exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives, 
+ *                  then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ *                  waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+  su_msg_r start_msg = SU_MSG_R_INIT;
+  su_timer_t *t;
+  unsigned long sleeppid = 0;
+
+  struct pinger 
+    pinger = { PINGER, "ping", 1 }, 
+    ponger = { PONGER, "pong", 1 };
+
+  char *argv0 = argv[0];
+
+  enter;
+
+  /* Set static run loop variable on */
+  running = 1;
+
+  while (argv[1]) {
+    if (strcmp(argv[1], "-v") == 0) {
+      opt_verbatim = 1;
+      argv++;
+    }
+#if SU_HAVE_IN6
+    else if (strcmp(argv[1], "-6") == 0) {
+      opt_family = AF_INET6;
+      argv++;
+    }
+#endif
+    else if (strcmp(argv[1], "-s") == 0) {
+      opt_singlethread = 1;
+      argv++;
+    }
+    else if (strcmp(argv[1], "-r") == 0) {
+      opt_root_run = 1;
+      argv++;
+    }
+    else if (strlen(argv[1]) == strspn(argv[1], "0123456789")) {
+      sleeppid = strtoul(argv[1], NULL, 10);
+      argv++;
+    }
+    else {
+      usage(1);
+    }
+  }
+
+  signal(SIGTERM, term);
+
+  su_init(); atexit(su_deinit);
+
+  time_test();
+
+  root = su_root_osx_runloop_create(NULL); 
+
+  if (!root) perror("su_root_osx_runloop_create"), exit(1);
+  
+  su_root_threading(root, 0 && !opt_singlethread);
+
+  if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1);
+  if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+    perror("su_clone_start"), exit(1); 
+
+  /* Test timer, exiting after 200 milliseconds */
+  t = su_timer_create(su_root_task(root), 2000L);
+  if (t == NULL)
+    su_perror("su_timer_create"), exit(1);
+  su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+  su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong), 
+		init_ping, 0);
+  su_msg_send(start_msg);
+
+  if (opt_root_run) {
+    su_root_osx_prepare_run(root);
+    CFRunLoopRun();
+  }
+  else
+    while (running == 1) {
+      su_root_step(root, 20);
+    }
+  
+  su_clone_wait(root, ping);
+  su_clone_wait(root, pong);
+
+  su_timer_destroy(t);
+
+  if (pinger.rtt_n) {
+    printf("%s executed %u pings in %g, mean rtt=%g sec\n", name, 
+	   pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+  }
+  su_root_destroy(root);
+
+  if (opt_verbatim)
+    printf("%s exiting\n", argv0); 
+
+#ifndef HAVE_WIN32
+   if (sleeppid)
+     kill(sleeppid, SIGTERM);
+#endif
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,710 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_rbtree.c
+ * @brief Test red-black tree
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "sofia-sip/rbtree.h"
+
+typedef struct node Node;
+
+struct node {
+  Node *left, *right, *parent;
+  int black;
+  int value;
+  int inserted;
+};
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_rbtree";
+
+/* Define accessor macros */
+#define LEFT(node) ((node)->left)
+#define RIGHT(node) ((node)->right)
+#define PARENT(node) ((node)->parent)
+#define SET_RED(node) ((node)->black = 0)
+#define SET_BLACK(node) ((node)->black = 1)
+#define CMP(a, b) ((a)->value - (b)->value)
+#define IS_RED(node) ((node) && (node)->black == 0)
+#define IS_BLACK(node) (!(node) || (node)->black == 1)
+#define COPY_COLOR(dst, src) ((dst)->black = (src)->black)
+#define INSERT(node) ((void)0)
+#define REMOVE(node) ((node)->left = (node)->right = (node)->parent = NULL)
+
+RBTREE_PROTOS(static inline, redblack, Node);
+
+RBTREE_BODIES(static inline, redblack, Node, LEFT, RIGHT, PARENT,
+	      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+	      CMP, INSERT, REMOVE);
+
+#include <sofia-sip/su_alloc.h>
+
+static
+Node *node_new(su_home_t *home, int value)
+{
+  Node *n = su_zalloc(home, sizeof (*n));
+  
+  n->value = value;
+
+  return n;
+}
+
+/** ceil of log2 */
+unsigned log2ceil(unsigned k)
+{
+  unsigned result = 0;
+
+#if 0
+  if (k > (1 << 32))
+    result += 32, k = (k >> 32) + ((k & ((1 << 32) - 1)) != 0);
+#endif
+  if (k > (1 << 16)) 
+    result += 16, k = (k >> 16) + ((k & ((1 << 16) - 1)) != 0);
+  if (k > (1 << 8)) 
+    result += 8, k = (k >> 8) + ((k & ((1 << 8) - 1)) != 0);
+  if (k > (1 << 4))
+    result += 4, k = (k >> 4) + ((k & 15) != 0);
+  if (k > (1 << 2))
+    result += 2, k = (k >> 2) + ((k & 3) != 0);
+  if (k > (1 << 1))
+    result += 1, k = (k >> 1) + (k & 1);
+  if (k > 1)
+    result += 1;
+  
+  return result;
+}
+
+static
+Node *node_find(Node *tree, int value)
+{
+  while (tree) {
+    if (tree->value == value)
+      break;
+    else if (tree->value < value)
+      tree = tree->right;
+    else
+      tree = tree->left;
+  }
+   
+  return tree;
+}
+
+/** Check consistency */
+static
+int redblack_check(Node const *n)
+{
+  Node const *l, *r;
+
+  if (!n)
+    return 1;
+
+  l = n->left, r = n->right;
+
+  if (n->black || ((!l || l->black) && (!r || r->black)))
+    return (!l || redblack_check(l)) && (!r || redblack_check(r));
+  else
+    return 0;
+}
+
+int test_insert(void)
+{
+  su_home_t *home;
+  Node *tree = NULL, *o, *old;
+  Node *one, *three, *five, *six, *seven;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+  one = node_new(home, 1);
+  three = node_new(home, 3);
+  five = node_new(home, 5);
+  six = node_new(home, 6);
+  seven = node_new(home, 7);
+
+  TEST_1(one); 
+  TEST_1(three);
+  TEST_1(five);
+  TEST_1(six);
+  TEST_1(seven);
+
+  /* Check single node */
+  TEST(redblack_insert(&tree, five, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree, five);
+  TEST_P(five->left, NULL); TEST_P(five->right, NULL);
+  TEST_P(five->parent, NULL); TEST(five->black, 1);
+
+  /* Check after another node: 
+   *
+   *         5b
+   *        / 
+   *       3r
+   */
+  TEST(redblack_insert(&tree, three, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->left, three); TEST(tree->black, 1);
+  TEST_P(three->left, NULL); TEST_P(three->right, NULL);
+  TEST_P(three->parent, tree); TEST(three->black, 0); 
+
+  /* Check third node
+   *         5b
+   *        / \
+   *       3r  7r
+   */
+  TEST(redblack_insert(&tree, seven, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->right, seven); TEST(tree->black, 1);
+  TEST_P(seven->left, NULL); TEST_P(seven->right, NULL);
+  TEST_P(seven->parent, tree); TEST(seven->black, 0); 
+
+  /* Check after fourth node:
+   *         5b
+   *        / \
+   *       3b  7b
+   *      /
+   *     1r  
+   */
+  TEST(redblack_insert(&tree, one, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->left->left, one); 
+  TEST(tree->black, 1); 
+  TEST(tree->left->black, 1); TEST(tree->right->black, 1);
+  TEST_P(one->left, NULL); TEST_P(one->right, NULL);
+  TEST_P(one->parent, tree->left); TEST(one->black, 0); 
+
+  /* Checks that we got after fifth node:
+   *         5b
+   *        / \
+   *       3b  7b
+   *      /   /
+   *     1r  6r
+   */
+  TEST(redblack_insert(&tree, six, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree, five); TEST(five->black, 1);
+  TEST_P(tree->left, three); TEST(three->black, 1);
+  TEST_P(tree->left->left, one); TEST(one->black, 0);
+  TEST_P(tree->right, seven); TEST(seven->black, 1);
+  TEST_P(tree->right->left, six); TEST(six->black, 0);
+
+  /* Insert five second time */
+  old = five;
+  five = node_new(home, 5);
+  TEST(redblack_insert(&tree, five, &o), 0); TEST_P(o, old);
+  TEST_P(tree, five); TEST(five->black, 1);
+  TEST_P(tree->left, three); TEST(three->black, 1);
+  TEST_P(three->parent, five);
+  TEST_P(tree->left->left, one); TEST(one->black, 0);
+  TEST_P(tree->right, seven); TEST(seven->black, 1);
+  TEST_P(seven->parent, five);
+  TEST_P(tree->right->left, six); TEST(six->black, 0);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_rotate(void)
+{
+  su_home_t *home;
+  Node *tree = NULL;
+  Node *x, *y, *o;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  x = node_new(home, 1);
+  y = node_new(home, 2);
+
+  TEST_1(x);
+  TEST_1(y); 
+
+  /*
+   *              x                   y               x
+   * Checks that   \  transforms to  /   and back to   \
+   *                y               x                   y
+   */
+  TEST(redblack_insert(&tree, x, &o), 0); TEST_P(o, NULL);
+  TEST(redblack_insert(&tree, y, &o), 0); TEST_P(o, NULL);
+
+  TEST_P(tree, x); TEST_P(x->right, y);
+  redblack_left_rotate(&tree, x);
+  TEST_P(tree, y); TEST_P(y->left, x);
+  redblack_right_rotate(&tree, y);
+  TEST_P(tree, x); TEST_P(x->right, y);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_simple(void)
+{
+  su_home_t *home;
+  Node *tree = NULL, *o;
+  int i;
+  Node *um, *um103, *um497, *um995;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  for (i = 3; i < 1000; i += 3) {
+    um = node_new(home, i); TEST_1(um);
+    o = (void *)-1; TEST(redblack_insert(&tree, um, &o), 0); TEST_P(o, NULL);
+  }
+
+  um103 = node_new(home, 103); TEST_1(um103);
+  um497 = node_new(home, 497); TEST_1(um497);
+  um995 = node_new(home, 995); TEST_1(um995);
+
+  o = (void *)-1; TEST(redblack_insert(&tree, um995, &o), 0); TEST_P(o, NULL); 
+  o = (void *)-1; TEST(redblack_insert(&tree, um497, &o), 0); TEST_P(o, NULL); 
+  o = (void *)-1; TEST(redblack_insert(&tree, um103, &o), 0); TEST_P(o, NULL);
+
+  um = node_find(tree, 103); TEST_P(um, um103);
+  um = node_find(tree, 497); TEST_P(um, um497);
+  um = node_find(tree, 995); TEST_P(um, um995);
+  um = node_find(tree, 994); TEST_P(um, NULL);
+  um = node_find(tree, 1); TEST_P(um, NULL);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_balance(void)
+{
+  su_home_t *home;
+  Node *tree = NULL, *o = NULL;
+  Node *node, **nodes;
+  int i, j;
+  int const N = 1000;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+  nodes = su_zalloc(home, (N + 2) * (sizeof *nodes)); TEST_1(nodes);
+  nodes++;
+
+  for (i = 0; i < N; i++) {
+    nodes[i] = node = node_new(home, i); TEST_1(node);
+    TEST(redblack_insert(&tree, node, &o), 0);
+    TEST_P(o, NULL);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    node = node_find(tree, i);
+    TEST_1(node); 
+    TEST(node->value, i);
+    TEST_P(nodes[i], node); 
+  }
+
+  node = node_find(tree, 0);
+
+  for (i = 0; i < N; i++) {
+    TEST_1(node); TEST(node->value, i);
+    node = redblack_succ(node);
+  }
+  TEST_1(node == NULL);
+
+  for (i = 0; i < N; i++) {
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    node = node_find(tree, i);
+    TEST_1(node); TEST(node->value, i);
+    redblack_remove(&tree, node);
+    TEST_1(node->parent == NULL && 
+	   node->left == NULL && 
+	   node->right == NULL); 
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = N - 1; i >= 0; i--) {
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[i], &o), 0); 
+    TEST_P(o, NULL);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    redblack_remove(&tree, nodes[i]);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 57) % N;
+    o = (void *)-1;
+    TEST(nodes[sn]->inserted, 0);
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    nodes[sn]->inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 23) % N;	/* 23 is relative prime to N */
+    TEST(nodes[sn]->inserted, 1);
+    redblack_remove(&tree, nodes[sn]);
+    nodes[sn]->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 517) % N;	/* relative prime to N */
+    o = (void *)-1;
+    TEST(nodes[sn]->inserted, 0);
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    nodes[sn]->inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 497) % N;	/* relative prime to N */
+    TEST(nodes[sn]->inserted, 1);
+    redblack_remove(&tree, nodes[sn]);
+    nodes[sn]->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 1957) % N;	/* relative prime to N */
+    o = (void *)-1;
+    TEST(nodes[sn]->inserted, 0);
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    nodes[sn]->inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 1519) % N;	/* relative prime to N */
+    TEST(nodes[sn]->inserted, 1);
+    redblack_remove(&tree, nodes[sn]);
+    nodes[sn]->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N - i - 1;
+    TEST(nodes[i]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[i], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->inserted = 1;
+
+    TEST(nodes[sn]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  for (i = 0; i < N; i++) {
+    node = ((i & 1) ? redblack_succ(tree) : redblack_prec(tree));
+    if (node == NULL)
+      node = tree;
+    TEST(node->inserted, 1);
+    redblack_remove(&tree, node);
+    node->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N - i - 1;
+    TEST(nodes[i]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[i], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->inserted = 1;
+
+    TEST(nodes[sn]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  /* Remove last, first, last, first, ... */
+  for (i = 0; i < N; i++) {
+    node = ((i & 1) ? redblack_first(tree) : redblack_last(tree));
+    TEST_1(node);
+    TEST(node->inserted, 1);
+    redblack_remove(&tree, node);
+    node->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N / 2 + i;
+    TEST(nodes[i]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[i], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->inserted = 1;
+
+    TEST(nodes[sn]->inserted, 0);
+    o = (void *)-1;
+    TEST(redblack_insert(&tree, nodes[sn], &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  /* Remove last, first, last, first, ... */
+  for (i = 0; i < N; i++) {
+    node = ((i & 1) ? redblack_first(tree) : redblack_last(tree));
+    TEST_1(node);
+    TEST(node->inserted, 1);
+    redblack_remove(&tree, node);
+    node->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert in perfect order ... */
+  
+  for (j = N / 2; j > 0; j /= 2) {
+    for (i = N - j; i >= 0; i -= j) {
+      if (nodes[i]->inserted)
+	continue;
+      o = (void *)-1;
+      TEST(redblack_insert(&tree, nodes[i], &o), 0); 
+      TEST_P(o, NULL);
+      nodes[i]->inserted = 1;
+    }
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->inserted, 1);
+    TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+    TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+  }
+
+  /* Remove such nodes that inserts red uncles into tree */
+  for (i = 0; i < N; i++) {
+    node = redblack_last(tree);
+    for (o = node; o; o = redblack_prec(o)) {
+      Node *dad, *granddad, *uncle, *to_be_removed;
+      /* We must have a node with black dad, no brother, red granddad and uncle */
+      if (!(dad = o->parent) || !dad->black)
+	continue;
+      if (dad->left && dad->right)
+	continue;
+      if (!(granddad = dad->parent) || granddad->black)
+	continue;
+      if (granddad->left == dad)
+	uncle = granddad->right;
+      else
+	uncle = granddad->left;
+      if (!uncle || uncle->black)
+	continue;
+      to_be_removed = redblack_prec(o->parent);
+      if (to_be_removed == granddad || to_be_removed == uncle)
+	continue;
+      if (!to_be_removed->left || !to_be_removed->right)
+	continue;
+      node = to_be_removed;
+      break;
+    }
+    TEST(node->inserted, 1);
+    redblack_remove(&tree, node);
+    node->inserted = 0;
+    TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_speed(void)
+{
+  su_home_t *home;
+  Node *tree = NULL, *o = NULL;
+  Node *node;
+  unsigned i;
+  unsigned int const N = 1000000U;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  for (i = 0; i < N; i++) {
+    node = node_new(home, i);
+    TEST(redblack_insert(&tree, node, &o), 0);
+    TEST_P(o, NULL);
+  }
+
+  TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1));
+
+  for (i = 0; i < N; i++) {
+    node = node_find(tree, i);
+    TEST_1(node); TEST(node->value, i);
+  }
+
+  node = node_find(tree, 0);
+  for (i = 0; i < N; i++) {
+    TEST_1(node); TEST(node->value, i);
+    node = redblack_succ(node);
+  }
+  TEST_1(node == NULL);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+
+void usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-v]\n",
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_insert(); fflush(stdout);
+  retval |= test_rotate(); fflush(stdout);
+  retval |= test_simple(); fflush(stdout);
+  retval |= test_balance(); fflush(stdout);
+  retval |= test_speed(); fflush(stdout);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su
+ * 
+ * @file torture_su.c
+ *
+ * Testing functions for su socket functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu May  2 18:17:46 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+char const *name = "su_torture";
+
+static int test_sockaddr(void);
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+/**  */
+int test_sockaddr(void)
+{
+  su_localinfo_t hints[1] = {{ LI_CANONNAME }};
+  su_localinfo_t *li, *res = NULL;
+  int s;
+  su_sockaddr_t  su[1], a[1], b[1];
+
+  BEGIN();
+  
+  hints->li_family = AF_INET;
+
+  TEST(su_getlocalinfo(hints, &res), 0);
+
+  for (li = res; li; li = li->li_next) {
+    if (li->li_addrlen != res->li_addrlen ||
+	memcmp(li->li_addr, res->li_addr, li->li_addrlen) != 0)
+      TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) != 0);
+    else 
+      TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) == 0);
+  }
+
+  memset(su, 0, sizeof su);
+  TEST(su_getlocalip(su), 0);
+
+  if (res->li_family == AF_INET)
+    TEST(su_cmp_sockaddr(res->li_addr, su), 0);
+
+  TEST_1(su_gli_strerror(ELI_NOERROR));
+  TEST_1(su_gli_strerror(ELI_NOADDRESS));
+  TEST_1(su_gli_strerror(ELI_FAMILY));
+  TEST_1(su_gli_strerror(ELI_MEMORY));
+  TEST_1(su_gli_strerror(ELI_RESOLVER));
+  TEST_1(su_gli_strerror(ELI_SYSTEM));
+  TEST_1(su_gli_strerror(-100));
+
+  li = su_copylocalinfo(res); TEST_1(li);
+  su_freelocalinfo(li);
+
+  s = su_socket(res->li_family, SOCK_DGRAM, 0); TEST_1(s != -1);
+  TEST(su_setblocking(s, 0), 0);
+  TEST(su_setblocking(s, 1), 0);
+  TEST(su_close(s), 0);
+
+  su_freelocalinfo(res);
+
+#if SU_HAVE_IN6
+  hints->li_family = AF_INET6;
+  hints->li_flags &= ~LI_CANONNAME;
+  hints->li_flags |= LI_V4MAPPED;
+
+  TEST(su_getlocalinfo(hints, &res), 0);
+  for (li = res; li; li = li->li_next)
+    TEST(li->li_family, AF_INET6);
+
+  su_freelocalinfo(res);
+#endif
+
+  hints->li_flags |= LI_NUMERIC;
+  TEST(su_getlocalinfo(hints, &res), 0);
+
+  hints->li_flags |= LI_NAMEREQD;
+  res = NULL;
+  su_getlocalinfo(hints, &res);
+  su_freelocalinfo(res);
+
+  memset(a, 0, sizeof *a); 
+  memset(b, 0, sizeof *b); 
+
+  TEST_1(su_match_sockaddr(a, b));
+  b->su_family = AF_INET;
+  TEST_1(su_match_sockaddr(a, b));
+  a->su_port = htons(12);
+  TEST_1(!su_match_sockaddr(a, b));
+  b->su_port = htons(12);
+  TEST_1(su_match_sockaddr(a, b));
+  a->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+  TEST_1(su_match_sockaddr(a, b));
+  a->su_family = AF_INET;
+  TEST_1(!su_match_sockaddr(a, b));
+  b->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+  TEST_1(su_match_sockaddr(a, b));
+  a->su_sin.sin_addr.s_addr = 0;
+  TEST_1(su_match_sockaddr(a, b));
+#if SU_HAVE_IN6
+  a->su_family = AF_INET6;
+  TEST_1(!su_match_sockaddr(a, b));
+  b->su_family = AF_INET6;
+  TEST_1(su_match_sockaddr(a, b));
+  b->su_sin6.sin6_addr.s6_addr[15] = 1;
+  TEST_1(su_match_sockaddr(a, b));
+  TEST_1(!su_match_sockaddr(b, a));
+  a->su_sin6.sin6_addr.s6_addr[15] = 2;
+  TEST_1(!su_match_sockaddr(a, b));
+  a->su_family = 0;
+  TEST_1(su_match_sockaddr(a, b));
+  TEST_1(!su_match_sockaddr(b, a));
+#endif
+  END();
+}
+
+#include <sofia-sip/su_wait.h>
+
+int test_sendrecv(void)
+{
+  int s, l, a;
+  int n;
+  su_sockaddr_t su, csu;
+  socklen_t sulen = sizeof su.su_sin, csulen = sizeof csu.su_sin;
+  char b1[8], b2[8], b3[8];
+  su_iovec_t sv[3], rv[3];
+
+  sv[0].siv_base = "one!one!", sv[0].siv_len = 8;
+  sv[1].siv_base = "two!two!", sv[1].siv_len = 8;
+  sv[2].siv_base = "third!", sv[2].siv_len = 6;
+
+  rv[0].siv_base = b1, rv[0].siv_len = 8;
+  rv[1].siv_base = b2, rv[1].siv_len = 8;
+  rv[2].siv_base = b3, rv[2].siv_len = 8;
+
+  BEGIN();
+
+  s = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(s != -1);
+
+  memset(&su, 0, sulen);
+  su.su_len = sulen;
+  su.su_family = AF_INET;
+  TEST(inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1);
+
+  TEST(bind(s, &su.su_sa, sulen), 0);
+  TEST(getsockname(s, &su.su_sa, &sulen), 0);
+
+  n = su_vsend(s, sv, 3, 0, &su, sulen); TEST(n, 8 + 8 + 6);
+  n = su_vrecv(s, rv, 3, 0, &su, &sulen); TEST(n, 8 + 8 + 6);
+
+  TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len);
+  TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len);
+  TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len);
+
+  su_close(s);
+
+  l = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(l != -1);
+  s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+
+  memset(&su, 0, sulen);
+  su.su_len = sulen;
+  su.su_family = AF_INET;
+  TEST(inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1);
+
+  TEST(bind(l, &su.su_sa, sulen), 0);
+  TEST(bind(s, &su.su_sa, sulen), 0);
+
+  TEST(getsockname(l, &su.su_sa, &sulen), 0);
+  TEST(listen(l, 5), 0);
+  
+  TEST(connect(s, &su.su_sa, sulen), 0);
+  a = accept(l, &csu.su_sa, &csulen); TEST_1(a != -1);
+
+  n = su_vsend(s, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6);
+  n = su_vrecv(a, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6);
+
+  TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len);
+  TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len);
+  TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len);
+
+  n = send(a, "", 0, 0); TEST(n, 0);
+  n = su_vsend(a, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6);
+
+  {
+    su_wait_t w[1] = { SU_WAIT_INIT };
+
+    TEST(su_wait_create(w, s, SU_WAIT_IN | SU_WAIT_HUP), 0);
+
+    TEST(su_wait(w, 0, 500), SU_WAIT_TIMEOUT);
+
+    TEST(su_wait(w, 1, 500), 0);
+    TEST(su_wait_events(w, s), SU_WAIT_IN);
+
+    TEST_SIZE(su_getmsgsize(s), 8 + 8 + 6);
+    n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6);
+
+    TEST(su_wait(w, 1, 100), SU_WAIT_TIMEOUT);
+
+    shutdown(a, 2);
+
+    TEST(su_wait(w, 1, 100), 0);
+#if SU_HAVE_WINSOCK
+    TEST_1(su_wait_events(w, s) & SU_WAIT_HUP);
+#else
+    TEST_1(su_wait_events(w, s));
+    n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 0);
+#endif
+
+    su_wait_destroy(w);
+  }
+
+  su_close(a);
+
+  su_close(l);
+  su_close(s); 
+
+  END();
+}
+
+#include <sofia-sip/su_md5.h>
+
+int test_md5(void)
+{
+  BEGIN();
+
+  su_md5_t md5[1], md5i[1];
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+  char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+
+  struct { char *input; uint8_t digest[SU_MD5_DIGEST_SIZE]; } suite[] = {
+    { (""), 
+	{ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+	  0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+    { ("a"), { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+	       0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+    { ("abc"), { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+		 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+    { ("message digest"), 
+      { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+	0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+    { ("abcdefghijklmnopqrstuvwxyz"),
+      { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+	0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+      { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+	0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+
+    { "1234567890123456789012345678901234567890"
+      "1234567890123456789012345678901234567890",
+      { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+	0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }};
+
+  su_md5_init(md5);
+  su_md5_update(md5, suite[0].input, 0);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[0].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_strupdate(md5, suite[1].input);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[1].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_iupdate(md5, suite[2].input, 3);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[2].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_striupdate(md5, suite[3].input);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[3].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_iupdate(md5, suite[4].input, 13);
+  su_md5_striupdate(md5, suite[4].input + 13);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[4].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_update(md5, suite[5].input, 13);
+  su_md5_strupdate(md5, suite[5].input + 13);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[5].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_update(md5, suite[6].input, 13);
+  su_md5_strupdate(md5, suite[6].input + 13);
+  su_md5_digest(md5, digest);
+  TEST_M(digest, suite[6].digest, SU_MD5_DIGEST_SIZE);
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);
+  su_md5_str0update(md5, NULL);
+  su_md5_hexdigest(md5, hexdigest);
+  TEST_S(hexdigest, "93b885adfe0da089cdf634904fd59f71");
+  su_md5_deinit(md5);
+
+  su_md5_init(md5);   
+  su_md5_stri0update(md5, NULL);
+  su_md5_stri0update(md5, "ABBADABBADOO");
+  su_md5_hexdigest(md5, hexdigest);
+  TEST_S(hexdigest, "101e6dd7cfabdb5c74f44b4c545c05cc");
+
+  su_md5_init(md5); 
+  su_md5_update(md5, "\0abbadabbadoo\0", 14);
+  su_md5_hexdigest(md5, hexdigest);
+  TEST_S(hexdigest, "101e6dd7cfabdb5c74f44b4c545c05cc");
+  su_md5_deinit(md5);
+
+  /* Calculate md5 sum of 512 MB of zero */
+  if (getenv("EXPENSIVE_CHECKS")) {
+    char zerokilo[1024] = { '\0' };
+    int i;
+
+    su_md5_init(md5);
+    su_md5_iupdate(md5, zerokilo, 19);
+    for (i = 1; i < 512 * 1024; i++)
+      su_md5_update(md5, zerokilo, 1024);
+    *md5i = *md5;
+
+    su_md5_update(md5, zerokilo, 1024 - 19);
+    su_md5_hexdigest(md5, hexdigest);
+    TEST_S(hexdigest, "aa559b4e3523a6c931f08f4df52d58f2");
+    su_md5_deinit(md5);
+
+    su_md5_iupdate(md5i, zerokilo, 1024 - 19);
+    su_md5_hexdigest(md5i, hexdigest);
+    TEST_S(hexdigest, "aa559b4e3523a6c931f08f4df52d58f2");
+  }
+  END();
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  su_init();
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+  
+  retval |= test_sockaddr();
+  retval |= test_sendrecv();
+  retval |= test_md5(); fflush(stdout);
+
+  su_deinit();
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,683 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @file su_alloc_test.c
+ *
+ * Testing functions for su_alloc functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu May  2 18:17:46 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_alloc_stat.h>
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+int tstflags;
+
+char const *name = "su_alloc_test";
+
+/* Type derived from home */
+typedef struct { su_home_t home[1]; int *p; } exhome_t;
+
+void exdestructor(void *arg)
+{
+  exhome_t *ex = arg;
+  (*ex->p)++;
+}
+
+/** Test basic memory home operations  */
+static int test_alloc(void)
+{
+  exhome_t *h0, *h1, *h2, *h3;
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  enum { N = 40 };
+  void *m0[N], *m1[N], *m;
+  char *c, *c0, *p0, *p1;
+  int i;
+  enum { destructed_once = 1 };
+  int d0, d1a, d1, d2, d3;
+
+  BEGIN();
+
+  TEST_1(h0 = su_home_new(sizeof(*h0)));
+  TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+
+  d0 = d1a = d1 = d2 = d3 = 0;
+  h0->p = &d0; h1->p = &d1a;
+  TEST(su_home_desctructor(h0->home, exdestructor), 0);
+  TEST(su_home_desctructor(h1->home, exdestructor), 0);
+
+  TEST_1(h2 = su_home_ref(h0->home));
+  su_home_unref(h0->home);
+  TEST(d0, 0);
+
+  for (i = 0; i < 128; i++)
+    TEST_1(su_alloc(h0->home, 16));
+
+  for (i = 0; i < 128; i++)
+    TEST_1(su_alloc(h1->home, 16));
+
+  su_home_unref(h1->home);
+  TEST(d1a, destructed_once);
+
+  TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+  TEST(su_home_desctructor(h1->home, exdestructor), 0);
+  h1->p = &d1;
+
+  for (i = 0; i < 128; i++)
+    TEST_1(su_alloc(h1->home, 16));
+
+  for (i = 0; i < 128; i++)
+    TEST_1(su_alloc(h2->home, 16));
+
+  su_home_unref(h2->home); /* Should call destructor of cloned home, too */
+
+  TEST(d0, destructed_once);
+  TEST(d1, destructed_once);
+
+  TEST_1(h0 = su_home_new(sizeof(*h0)));
+  TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+  TEST_1(h2 = su_home_clone(h1->home, sizeof(*h2)));
+  TEST_1(h3 = su_home_clone(h2->home, sizeof(*h3)));
+
+  TEST(su_home_threadsafe(h0->home), 0);
+
+  for (i = 0; i < N; i++) {
+    TEST_1(m0[i] = su_zalloc(h3->home, 20));
+    TEST_1(m1[i] = su_zalloc(h2->home, 20));
+  }
+
+  TEST_1(m = su_zalloc(h2->home, 20));
+
+  TEST_1(su_in_home(h2->home, m));
+  TEST_1(!su_in_home(h2->home, (char *)m + 1));
+  TEST_1(!su_in_home(h2->home, su_in_home));
+  TEST_1(!su_in_home(h3->home, m));
+  TEST_1(!su_in_home(NULL, m));
+  TEST_1(!su_in_home(h3->home, NULL));
+
+  TEST(su_home_move(home, NULL), 0);
+  TEST(su_home_move(NULL, home), 0);
+  TEST(su_home_move(home, h3->home), 0);
+  TEST(su_home_move(h2->home, h3->home), 0);
+  TEST(su_home_move(h1->home, h2->home), 0);
+
+  su_home_preload(home, 1, 1024 + 2 * 8);
+
+  TEST_1(c = su_zalloc(home, 64)); p0 = c; p1 = c + 1024;
+  TEST_P(c = su_realloc(home, c0 = c, 127), c0);
+
+  TEST_1(c = c0 = su_zalloc(home, 1024 - 128));
+  TEST_1(p0 <= c); TEST_1(c < p1);
+  TEST_P(c = su_realloc(home, c, 128), c0);
+  TEST_P(c = su_realloc(home, c, 1023 - 128), c0);
+  TEST_P(c = su_realloc(home, c, 1024 - 128), c0);
+  TEST_1(c = su_realloc(home, c, 1024));
+  TEST_1(c = su_realloc(home, c, 2 * 1024));
+
+  TEST_P(c = su_realloc(home, p0, 126), p0);
+  TEST_1(c = su_realloc(home, p0, 1024));
+  TEST_P(c = su_realloc(home, c, 0), NULL);
+
+  su_home_check(home);
+  su_home_deinit(home);
+
+  su_home_check(h2->home);
+  su_home_zap(h2->home);
+  su_home_check(h0->home);
+  su_home_zap(h0->home);
+
+  END();
+}
+
+static int test_strdupcat(void)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  BEGIN();
+
+  TEST_S(su_strdup(home, "foo"), "foo");
+  TEST_S(su_strcat(home, "foo", "bar"), "foobar");
+  TEST_S(su_strndup(home, "foobar", 3), "foo");
+
+  TEST_S(su_strcat_all(home, NULL), "");
+  TEST_S(su_strcat_all(home, "a", "", "b", "", NULL), "ab");
+
+  su_home_deinit(home);
+
+  END();
+}
+
+#include <stdarg.h>
+
+static int test_sprintf(char const *fmt, ...)
+{
+  BEGIN();
+
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  va_list va;
+
+  TEST_S(su_sprintf(home, "foo%s", "bar"), "foobar");
+
+  va_start(va, fmt);
+  TEST_S(su_vsprintf(home, fmt, va), "foo.bar");
+
+  TEST_S(su_sprintf(home, "foo%200s", "bar"),
+	 "foo                                                             "
+	 "                                                                "
+	 "                                                                "
+	 "        bar");
+
+  su_home_deinit(home);
+
+  END();
+}
+
+static int test_strlst(void)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  su_strlst_t *l, *l1, *l2;
+  char *s;
+  char foo[] = "foo";
+  char bar[] = "bar";
+  char baz[] = "baz";
+
+  su_home_stat_t parent[1], kids[2];
+
+  BEGIN();
+
+  parent->hs_size = (sizeof parent);
+  kids[0].hs_size = (sizeof kids[0]);
+  kids[1].hs_size = (sizeof kids[1]);
+
+  su_home_init_stats(home);
+
+  /* Test API for invalid arguments */
+  TEST_1(l = su_strlst_create(NULL));
+  TEST_1(l2 = su_strlst_dup(home, l));
+  TEST_VOID(su_strlst_destroy(l2));
+  TEST_1(!su_strlst_dup(home, NULL));
+  TEST_1(l1 = su_strlst_copy(home, l));
+  TEST_VOID(su_strlst_destroy(l1));
+  TEST_1(!su_strlst_copy(home, NULL));
+
+  TEST_VOID(su_strlst_destroy(NULL));
+  TEST_VOID(su_strlst_destroy(l));
+
+  TEST_1(!su_strlst_dup_append(NULL, "aa"));
+  TEST_1(!su_strlst_append(NULL, "bee"));
+  TEST_1(!su_strlst_item(NULL, 1));
+  TEST_1(!su_strlst_set_item(NULL, 1, "cee"));
+  TEST_1(!su_strlst_remove(NULL, 1));
+  TEST_S(s = su_strlst_join(NULL, home, "a"), "");
+  TEST_VOID(su_free(home, s));
+
+  TEST_1(!su_strlst_split(home, NULL, "."));
+
+  TEST_1(s = su_strdup(home, "aaa"));
+  TEST_1(l = su_strlst_split(home, s, NULL));
+  TEST_S(su_strlst_item(l, 0), "aaa");
+  TEST_VOID(su_strlst_destroy(l));
+
+  TEST_VOID(su_free(home, s));
+
+  TEST_1(!su_strlst_dup_split(home, NULL, "."));
+
+  TEST_1(l1 = su_strlst_dup_split(home, "aaa", ""));
+  TEST_S(su_strlst_item(l1, 0), "aaa");
+  TEST_VOID(su_strlst_destroy(l1));
+
+  TEST_SIZE(su_strlst_len(NULL), 0);
+  TEST_1(!su_strlst_get_array(NULL));
+  TEST_VOID(su_strlst_free_array(NULL, NULL));
+
+  TEST_1(l = su_strlst_create(home));
+  TEST_VOID(su_strlst_free_array(l, NULL));
+  TEST_S(su_strlst_dup_append(l, "oh"), "oh");
+  TEST_VOID(su_strlst_free_array(l, NULL));
+  TEST_VOID(su_strlst_destroy(l));
+
+  /* Test functionality */
+  TEST_1(l = su_strlst_create(home));
+
+  su_home_init_stats(su_strlst_home(l));
+
+  TEST_S(su_strlst_join(l, home, "bar"), "");
+  TEST_S(su_strlst_append(l, foo), "foo");
+  TEST_S(su_strlst_dup_append(l, bar), "bar");
+  TEST_S(su_strlst_append(l, baz), "baz");
+  TEST_S((s = su_strlst_join(l, home, "!")), "foo!bar!baz");
+
+  TEST_S(su_strlst_item(l, 0), foo);
+  TEST_S(su_strlst_item(l, 1), bar);
+  TEST_S(su_strlst_item(l, 2), baz);
+  TEST_P(su_strlst_item(l, 3), NULL);
+  TEST_P(su_strlst_item(l, (unsigned)-1), NULL);
+
+  TEST_1(l1 = su_strlst_copy(su_strlst_home(l), l));
+  TEST_1(l2 = su_strlst_dup(su_strlst_home(l), l));
+
+  strcpy(foo, "hum"); strcpy(bar, "pah"); strcpy(baz, "hah");
+
+  TEST_S(su_strlst_dup_append(l1, "kuik"), "kuik");
+  TEST_S(su_strlst_dup_append(l2, "uik"), "uik");
+
+  TEST_S((s = su_strlst_join(l, home, ".")), "hum.bar.hah");
+  TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah.kuik");
+  TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz.uik");
+
+  su_strlst_destroy(l2);
+
+  su_home_get_stats(su_strlst_home(l), 0, kids, sizeof kids);
+
+  TEST_SIZE(kids->hs_clones, 2);
+  TEST64(kids->hs_allocs.hsa_number, 3);
+  TEST64(kids->hs_frees.hsf_number, 1);
+
+  su_strlst_destroy(l);
+
+  TEST_S(s, "hum.bar.hah");
+
+  TEST_1(l = su_strlst_create(home));
+
+  su_home_init_stats(su_strlst_home(l));
+
+  TEST_S(su_strlst_join(l, home, "bar"), "");
+  TEST_S(su_strlst_append(l, "a"), "a");
+  TEST_S(su_strlst_append(l, "b"), "b");
+  TEST_S(su_strlst_append(l, "c"), "c");
+  TEST_S(su_strlst_append(l, "d"), "d");
+  TEST_S(su_strlst_append(l, "e"), "e");
+  TEST_S(su_strlst_append(l, "f"), "f");
+  TEST_S(su_strlst_append(l, "g"), "g");
+  TEST_S(su_strlst_append(l, "h"), "h");
+  TEST_S(su_strlst_append(l, "i"), "i");
+  TEST_S(su_strlst_append(l, "j"), "j");
+
+  TEST_S((s = su_strlst_join(l, home, "")), "abcdefghij");
+  TEST_S(su_strlst_append(l, "a"), "a");
+  TEST_S(su_strlst_append(l, "b"), "b");
+  TEST_S(su_strlst_append(l, "c"), "c");
+  TEST_S(su_strlst_append(l, "d"), "d");
+  TEST_S(su_strlst_append(l, "e"), "e");
+  TEST_S(su_strlst_append(l, "f"), "f");
+  TEST_S(su_strlst_append(l, "g"), "g");
+  TEST_S(su_strlst_append(l, "h"), "h");
+  TEST_S(su_strlst_append(l, "i"), "i");
+  TEST_S(su_strlst_append(l, "j"), "j");
+
+  TEST_S((s = su_strlst_join(l, home, "")), "abcdefghijabcdefghij");
+
+  su_home_get_stats(su_strlst_home(l), 0, kids + 1, (sizeof kids[1]));
+  su_home_stat_add(kids, kids + 1);
+
+  su_strlst_destroy(l);
+
+  su_home_get_stats(home, 1, parent, (sizeof parent));
+
+  su_home_check(home);
+  su_home_deinit(home);
+
+  su_home_init(home);
+
+  {
+    char s[] = "foo\nfaa\n";
+    TEST_1((l = su_strlst_split(home, s, "\n")));
+    TEST_SIZE(su_strlst_len(l), 3);
+    TEST_1(su_strlst_append(l, "bar"));
+    TEST_S(su_strlst_join(l, home, "\n"), "foo\nfaa\n\nbar");
+  }
+
+  {
+    char s[] = "foo";
+    TEST_1((l = su_strlst_split(home, s, "\n")));
+    TEST_SIZE(su_strlst_len(l), 1);
+  }
+
+  {
+    char s[] = "\n\n";
+    TEST_1((l = su_strlst_split(home, s, "\n")));
+    TEST_SIZE(su_strlst_len(l), 3);
+  }
+
+  {
+    char s[] = "";
+    TEST_1((l = su_strlst_split(home, s, "\n")));
+    TEST_SIZE(su_strlst_len(l), 1);
+  }
+
+  {
+    int i;
+
+#define S \
+      "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\n" \
+      "n\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n" \
+      "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\n" \
+      "N\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n"
+
+    char s[] = S;
+
+    TEST_1((l = su_strlst_split(home, s, "\n")));
+    TEST_SIZE(su_strlst_len(l), 53);
+    TEST_1(su_strlst_append(l, "bar"));
+    TEST_S(su_strlst_join(l, home, "\n"), S "\nbar");
+
+    TEST_1(!su_strlst_remove(l, 54));
+
+    for (i = 0; i < 54; i++) {
+      TEST_1(su_strlst_remove(l, 0));
+      TEST_1(!su_strlst_remove(l, 53 - i));
+      TEST_SIZE(su_strlst_len(l), 53 - i);
+    }
+
+    TEST_1(!su_strlst_remove(l, 0));
+    TEST_SIZE(su_strlst_len(l), 0);
+  }
+
+  {
+    char const *s0;
+
+    TEST_1(l = su_strlst_create_with(NULL, s0 = "a", "b", NULL));
+    TEST_1(su_strlst_item(l, 0) == s0);
+    TEST_S(su_strlst_item(l, 0), "a");
+    TEST_S(su_strlst_item(l, 1), "b");
+    TEST_1(su_strlst_item(l, 2) == NULL);
+
+    TEST_S(su_slprintf(l, "1: %u", 1), "1: 1");
+    TEST_S(su_slprintf(l, "1.0: %g", 1.0), "1.0: 1");
+
+    TEST_1(su_strlst_append(l, ""));
+
+    TEST_S(su_strlst_join(l, home, "\n"), 
+	   "a\n" "b\n" "1: 1\n" "1.0: 1\n");
+
+    TEST_VOID(su_strlst_destroy(l));
+
+    TEST_1(l2 = su_strlst_create_with_dup(NULL,
+					  s0 = "0", "1", "2", "3",
+					  "4", "5", "6", "7",
+					  NULL));
+    TEST_1(su_strlst_item(l2, 0) != s0);
+    TEST_S(su_strlst_item(l2, 0), "0");
+    TEST_S(su_strlst_item(l2, 1), "1");
+    TEST_S(su_strlst_item(l2, 2), "2");
+    TEST_S(su_strlst_item(l2, 3), "3");
+    TEST_S(su_strlst_item(l2, 4), "4");
+    TEST_S(su_strlst_item(l2, 5), "5");
+    TEST_S(su_strlst_item(l2, 6), "6");
+    TEST_S(su_strlst_item(l2, 7), "7");
+    TEST_1(su_strlst_item(l2, 8) == NULL);
+
+    TEST_S(su_strlst_join(l2, home, ""), "01234567");
+
+    TEST_VOID(su_strlst_destroy(l2));
+  }
+  su_home_check(home);
+  su_home_deinit(home);
+
+  END();
+}
+
+#include <sofia-sip/su_vector.h>
+
+typedef struct test_data_s {
+  su_home_t test_home[1];
+  int data;
+} test_data_t;
+
+static void test_vector_free(void *data)
+{
+  su_home_zap((su_home_t *) data);
+}
+
+static int test_vectors(void)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  su_vector_t *v, *w;
+  test_data_t *data1, *data2, *data3, *data4;
+  char foo[] = "foo";
+  char bar[] = "bar";
+  char baz[] = "baz";
+  void **a;
+  int i;
+
+  BEGIN();
+
+  TEST_1(v = su_vector_create(home, NULL));
+  TEST_1(su_vector_is_empty(v));
+  TEST(su_vector_append(v, foo), 0);
+  TEST(su_vector_append(v, bar), 0);
+  TEST(su_vector_insert(v, 0, baz), 0);
+
+  TEST_P(su_vector_item(v, 0), baz);
+  TEST_P(su_vector_item(v, 1), foo);
+  TEST_P(su_vector_item(v, 2), bar);
+  TEST_P(su_vector_item(v, 3), NULL);
+  TEST_P(su_vector_item(v, (unsigned)-1), NULL);
+  TEST_1(!su_vector_is_empty(v));
+
+  su_vector_destroy(v);
+
+  TEST_1(v = su_vector_create(home, NULL));
+  TEST(su_vector_insert(v, 0, "j"), 0);
+  TEST(su_vector_insert(v, 0, "i"), 0);
+  TEST(su_vector_insert(v, 0, "h"), 0);
+  TEST(su_vector_insert(v, 0, "g"), 0);
+  TEST(su_vector_insert(v, 0, "f"), 0);
+  TEST(su_vector_insert(v, 0, "e"), 0);
+  TEST(su_vector_insert(v, 0, "d"), 0);
+  TEST(su_vector_insert(v, 0, "c"), 0);
+  TEST(su_vector_insert(v, 0, "b"), 0);
+  TEST(su_vector_insert(v, 0, "a"), 0);
+
+  TEST_SIZE(su_vector_len(v), 10);
+  TEST_1(a = su_vector_get_array(v));
+
+  for (i = 0; i < 10; i++) {
+    TEST_S(su_vector_item(v, i), a[i]);
+  }
+
+  TEST_P(su_vector_item(v, 10), NULL);
+  TEST_P(a[10], NULL);
+
+  TEST_1(w = su_vector_create(home, NULL));
+  TEST(su_vector_append(w, "a"), 0);
+  TEST(su_vector_append(w, "b"), 0);
+  TEST(su_vector_append(w, "c"), 0);
+  TEST(su_vector_append(w, "d"), 0);
+  TEST(su_vector_append(w, "e"), 0);
+  TEST(su_vector_append(w, "f"), 0);
+  TEST(su_vector_append(w, "g"), 0);
+  TEST(su_vector_append(w, "h"), 0);
+  TEST(su_vector_append(w, "i"), 0);
+  TEST(su_vector_append(w, "j"), 0);
+
+  TEST_SIZE(su_vector_len(w), 10);
+
+  for (i = 0; i < 10; i++) {
+    TEST_S(su_vector_item(v, i), a[i]);
+  }
+
+  su_vector_empty(w);
+  TEST_1(su_vector_is_empty(w));
+
+  su_vector_destroy(v);
+  su_vector_destroy(w);
+
+  TEST_1(v = su_vector_create(home, test_vector_free));
+  data1 = su_home_clone(home, sizeof(test_data_t));
+  data1->data = 1;
+
+  data2 = su_home_clone(home, sizeof(test_data_t));
+  data2->data = 2;
+
+  data3 = su_home_clone(home, sizeof(test_data_t));
+  data3->data = 3;
+
+  data4 = su_home_clone(home, sizeof(test_data_t));
+  data4->data = 4;
+
+  TEST(su_vector_append(v, data1), 0);
+  TEST(su_vector_append(v, data2), 0);
+  TEST(su_vector_append(v, data3), 0);
+  TEST(su_vector_append(v, data4), 0);
+
+  TEST_SIZE(su_vector_len(v), 4);
+
+  TEST_P(su_vector_item(v, 0), data1);
+  TEST_P(su_vector_item(v, 1), data2);
+  TEST_P(su_vector_item(v, 2), data3);
+  TEST_P(su_vector_item(v, 3), data4);
+
+  TEST(data1->data, 1);
+  TEST(data2->data, 2);
+  TEST(data3->data, 3);
+  TEST(data4->data, 4);
+
+  TEST(su_vector_remove(v, 2), 0);
+
+  TEST_SIZE(su_vector_len(v), 3);
+
+  TEST_P(su_vector_item(v, 0), data1);
+  TEST_P(su_vector_item(v, 1), data2);
+  TEST_P(su_vector_item(v, 2), data4);
+
+  TEST(data1->data, 1);
+  TEST(data2->data, 2);
+  TEST(data4->data, 4);
+
+  su_vector_destroy(v);
+
+  su_home_check(home);
+  su_home_deinit(home);
+
+  END();
+}
+
+#define ALIGNMENT (8)
+#define ALIGN(n)  ((size_t)((n) + (ALIGNMENT - 1)) & (size_t)~(ALIGNMENT - 1))
+
+static int test_auto(void)
+{
+  BEGIN();
+
+  int i;
+  su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)];
+  char *b = NULL;
+  su_home_stat_t hs[1];
+
+  TEST_1(!su_home_auto(tmphome, sizeof tmphome[0]));
+  TEST_1(su_home_auto(tmphome, sizeof tmphome));
+
+  for (i = 0; i < 8192; i++)
+    TEST_1(su_alloc(tmphome, 12));
+
+  TEST_VOID(su_home_deinit(tmphome));
+
+  TEST_1(su_home_auto(tmphome, sizeof tmphome));
+
+  su_home_init_stats(tmphome);
+
+  for (i = 1; i < 8192; i++) {
+    TEST_1(b = su_realloc(tmphome, b, i));
+    b[i - 1] = '\125';
+  }
+
+  for (i = 1; i < 8192; i++) {
+    TEST(b[i - 1], '\125');
+  }
+
+  for (i = 1; i < 8192; i++) {
+    TEST_1(b = su_realloc(tmphome, b, i));
+    b[i - 1] = '\125';
+
+    if ((i % 32) == 0)
+      TEST_1(b = su_realloc(tmphome, b, 1));
+  }
+
+  su_home_get_stats(tmphome, 0, hs, sizeof *hs);
+
+  TEST64(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number, 
+	  8191 + 8191 + 8191 / 32);
+  TEST64(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number,
+	 8191 + 8191 + 8191 / 32 - 1);
+  /*
+    This test depends on macro SU_HOME_AUTO_SIZE() calculating
+    offsetof(su_block_t, sub_nodes[7]) correctly with
+
+    ((3 * sizeof (void *) + 4 * sizeof(unsigned) +
+      7 * (sizeof (long) + sizeof(void *)) + 7)
+  */
+  TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload);
+
+  su_free(tmphome, b);
+
+  for (i = 1; i < 8192; i++)
+    TEST_1(b = su_alloc(tmphome, 1));
+
+  TEST_VOID(su_home_deinit(tmphome));
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_alloc();
+  retval |= test_strdupcat();
+  retval |= test_sprintf("%s.%s", "foo", "bar");
+  retval |= test_strlst();
+  retval |= test_vectors();
+  retval |= test_auto();
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_su_bm.c
+ * @brief Test string search with Boyer-Moore algorithm 
+ *  
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Sun Apr 17 21:02:10 2005 ppessi
+ */
+
+#include "config.h"
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_bm";
+int tstflags;
+
+#define TORTURELOG(x)		       \
+  do {				       \
+    if (tstflags & (2 * tst_verbatim)) \
+      printf x;			       \
+  } while(0)
+    
+#include "su_bm.c"
+
+int test_bm(void)
+{
+  BEGIN();
+  
+  {
+    char const hs[] = 
+      "A Boyer-Moore string searching test consisting of a Long String";
+    char const *s;
+
+    s = bm_memmem(hs, strlen(hs), "sting", 5, NULL);
+
+    TEST_S(s, hs + 41);
+
+    s = bm_memmem(hs, strlen(hs), "String", 6, NULL);
+    TEST_S(s, hs + 57);
+
+    s = bm_memmem(hs, strlen(hs), "S", 1, NULL);
+    TEST_S(s, hs + 57);
+
+    s = bm_memmem(hs, strlen(hs), "M", 1, NULL);
+    TEST_S(s, hs + 8);
+
+    s = bm_memcasemem(hs, strlen(hs), "M", 1, NULL);
+    TEST_S(s, hs + 8);
+
+    s = bm_memcasemem(hs, strlen(hs), "trings", 6, NULL);
+    TEST_1(s == NULL);
+
+    s = bm_memcasemem(hs, strlen(hs), "String", 6, NULL);
+    TEST_S(s, hs + 14);
+
+    s = bm_memcasemem(hs, strlen(hs), "StRiNg", 6, NULL);
+    TEST_S(s, hs + 14);
+
+    s = bm_memcasemem(hs, strlen(hs), "OnG", 3, NULL);
+    TEST_S(s, hs + 53);
+
+    /* Special cases */
+    TEST_1(bm_memmem(hs, strlen(hs), "", 0, NULL) == hs);
+    TEST_1(bm_memmem(NULL, strlen(hs), "ong", 3, NULL) == NULL);
+    TEST_1(bm_memmem(hs, strlen(hs), NULL, 1, NULL) == NULL);
+    TEST_1(bm_memmem("ong", 3, hs, strlen(hs), NULL) == NULL);
+    TEST_1(bm_memmem(hs, 0, "ong", 3, NULL) == NULL);
+    TEST_1(bm_memmem(hs, strlen(hs), "Z", 1, NULL) == NULL);
+
+    TEST_1(bm_memcasemem(hs, strlen(hs), "", 0, NULL) == hs);
+    TEST_1(bm_memcasemem(NULL, strlen(hs), "OnG", 3, NULL) == NULL);
+    TEST_1(bm_memcasemem(hs, strlen(hs), NULL, 1, NULL) == NULL);
+    TEST_1(bm_memcasemem("OnG", 3, hs, strlen(hs), NULL) == NULL);
+    TEST_1(bm_memcasemem(hs, 0, "OnG", 3, NULL) == NULL);
+    TEST_1(bm_memcasemem(hs, strlen(hs), "Z", 1, NULL) == NULL);
+  }
+
+  END();
+}
+
+int test_bm_long(void)
+{
+  BEGIN();
+  
+  {
+    char const hs[] = 
+"A Boyer-Moore string searching test consisting of a Very Long String\n"
+
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer felis. "
+"Suspendisse potenti. Morbi malesuada erat eget enim. Sed dui lorem, aliquam "
+"eu, lobortis eget, dapibus vitae, velit. Cras non purus. Suspendisse massa. "
+"Curabitur gravida condimentum massa. Donec nunc magna, lacinia non, "
+"pellentesque ac, laoreet vel, eros. Praesent lectus leo, vestibulum eu, "
+"tempus eu, ullamcorper tristique, mi. Duis fringilla ultricies lacus. Ut "
+"non pede. Donec id libero. Cum sociis natoque penatibus et magnis dis "
+"parturient montes, nascetur ridiculus mus. Phasellus bibendum.\n"
+
+"Vestibulum turpis. Nunc euismod. Maecenas venenatis, purus at pharetra "
+"ultrices, orci orci blandit nisl, eget vulputate enim tortor sed nunc. "
+"Proin sit amet elit. Donec ut justo. In quis nisi. Praesent posuere. "
+"Maecenas porta. Curabitur pharetra. Class aptent taciti sociosqu ad litora "
+"torquent per conubia nostra, per inceptos hymenaeos. Donec suscipit ligula. "
+"Quisque facilisis ante eget mi. Nunc ac est.\n"
+
+"Quisque in sapien eget justo aliquam laoreet. Nullam ultricies est id dolor. "
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse ante "
+"velit, eleifend at, ullamcorper ut, rutrum et, ipsum. Mauris luctus, tellus "
+"non elementum convallis, nunc ipsum hendrerit lectus, ut lacinia elit nulla "
+"ac tellus. In sit amet velit. Maecenas non dolor. Sed commodo diam a pede. "
+"Ut non pede. Vestibulum condimentum turpis vel lacus consectetuer dictum. "
+"Nulla ullamcorper mi eu pede. Donec mauris tortor, facilisis vitae, "
+"hendrerit nec, lobortis nec, eros. Nam sit amet mi. Ut pharetra, orci nec "
+"porta convallis, lacus velit blandit sapien, luctus nonummy lacus dolor vel "
+"sapien. Suspendisse placerat. Donec ante turpis, volutpat eu, hendrerit "
+"vel, eleifend ac, arcu. Nulla facilisi. Sed faucibus facilisis lectus. "
+"Aliquam congue justo nec dui.\n"
+
+"Donec dapibus dui sed nisl. Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n"
+
+"Phasellus congue. Morbi lectus arcu, mattis non, pulvinar et, condimentum "
+"non, mi. Suspendisse vestibulum nunc eu neque. Sed rutrum felis aliquam "
+"urna. Ut tincidunt orci vitae ipsum. Nullam eros. Quisque augue. Quisque "
+"lacinia. Nunc ligula diam, nonummy a, porta in, tristique quis, leo. "
+"Phasellus nunc nulla, fringilla vel, lacinia et, suscipit a, turpis. " 
+"Integer a est. Curabitur mauris lacus, vehicula sit amet, sodales vel, "
+"iaculis vitae, massa. Nam diam est, ultrices vitae, varius et, tempor a, "
+"leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, "
+"per inceptos hymenaeos. Fusce felis nibh, ullamcorper non, malesuada eget, "
+      "facilisis vel, purus.\n";
+
+char const needle[] = 
+"Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n";
+
+char const Needle[] = 
+"PROIN CONGUE. CURABITUR PLACERAT DIAM ID EROS. "
+"PELLENTESQUE VITAE NULLA. QUISQUE AT LOREM ET DOLOR AUCTOR CONSEQUAT. SED "
+"SED TELLUS NON NIBH IMPERDIET VENENATIS. INTEGER ULTRICES DAPIBUS NISI. "
+"AENEAN VEHICULA MALESUADA RISUS. FUSCE EGESTAS MALESUADA LEO. IN "
+"ULLAMCORPER PRETIUM LOREM. VESTIBULUM ANTE IPSUM PRIMIS IN FAUCIBUS ORCI "
+"LUCTUS ET ULTRICES POSUERE CUBILIA CURAE;\n";
+
+    size_t nlen = strlen(needle);
+
+    bm_fwd_table_t *fwd;
+
+    char const *s;
+
+    s = bm_memmem(hs, strlen(hs), needle, nlen, NULL);
+
+    TEST_S(s, hs + 1919);
+
+    fwd = bm_memmem_study(needle, nlen);
+
+    s = bm_memmem(hs, strlen(hs), needle, nlen, fwd);
+
+    TEST_S(s, hs + 1919);
+
+    TEST_1(bm_memmem(hs, strlen(hs), Needle, nlen, NULL) == 0);
+
+    s = bm_memcasemem(hs, strlen(hs), Needle, nlen, NULL);
+
+    fwd = bm_memcasemem_study(Needle, nlen);
+
+    s = bm_memcasemem(hs, strlen(hs), Needle, nlen, fwd);
+
+    TEST_S(s, hs + 1919);
+
+    free(fwd);
+  }
+
+  END();
+}
+
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  /* Set our name */
+  if (strchr(argv[0], '/')) 
+    name = strrchr(argv[0], '/') + 1;
+  else
+    name = argv[0];
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else if (strcmp(argv[i], "-l") == 0)
+      tstflags |= 2 * tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_bm(); fflush(stdout);
+  retval |= test_bm_long(); fflush(stdout);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,333 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_su_port.c
+ * @brief Test su_port interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct su_root_magic_s;
+
+#define SU_ROOT_MAGIC_T struct su_root_magic_s
+
+#include "su_port.c"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "torture_su_port";
+#endif
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_port";
+
+int N0 = SU_HAVE_MBOX, N = 128, I = 128 + 1;
+
+int test_sup_indices(su_port_t const *port)
+{
+  int i, n;
+  int *indices = port->sup_indices;
+  int *reverses = port->sup_reverses;
+  int N = port->sup_size_waits;
+
+  if (indices == NULL)
+    return N == 0 && port->sup_n_waits == 0;
+
+  for (i = 0, n = 0; i < N; i++) {
+    if (reverses[i] > 0) {
+      if (indices[reverses[i]] != i)
+	return 0;
+      n++;
+    }
+  }
+
+  if (n != port->sup_n_waits)
+    return 0;
+  
+  n = 0;
+
+  for (i = 1; i <= N; i++) {
+    if (indices[i] >= 0) {
+      if (reverses[indices[i]] != i)
+	return 0;
+      n++;
+    }
+  }
+
+  if (n != port->sup_n_waits)
+    return 0;
+
+  for (i = indices[0]; -i <= N; i = indices[-i]) {
+    if (i >= 0)
+      return 0;
+    n++;
+  }
+
+  return n == port->sup_size_waits;
+}
+
+struct su_root_magic_s 
+{
+  int error, *sockets, *regs, *wakeups;
+};
+
+static int callback(su_root_magic_t *magic, 
+		    su_wait_t *w,
+		    su_wakeup_arg_t *arg)
+{
+  intptr_t i = (intptr_t)arg;
+
+  assert(magic);
+ 
+  if (i <= 0 || i > I)
+    return ++magic->error;
+
+  su_wait_events(w, magic->sockets[i]);
+
+  magic->wakeups[i]++;
+
+#if HAVE_POLL
+  if (w->fd != magic->sockets[i])
+    return ++magic->error;
+#endif
+
+  return 0;
+}
+
+int test_wakeup(su_port_t *port, su_root_magic_t *magic)
+{
+  int i;
+
+  for (i = N0; i < N; i++) {
+    su_sockaddr_t su[1]; socklen_t sulen = sizeof su;
+    int n, woken = magic->wakeups[i];
+    char buf[1];
+    if (magic->regs[i] == 0)
+      continue;
+
+    if (getsockname(magic->sockets[i], &su->su_sa, &sulen) < 0)
+      su_perror("getsockname"), exit(1);
+    if (su_sendto(magic->sockets[1], "X", 1, 0, su, sulen) < 0)
+      su_perror("su_sendto"), exit(1);
+    n = su_port_wait_events(port, 100);
+    if (n != 1)
+      return 1;
+    if (magic->error)
+      return 2;
+    if (magic->wakeups[i] != woken + 1)
+      return 3;
+    if (recv(magic->sockets[i], buf, 1, 0) != 1)
+      return 4;
+  }
+
+  return 0;
+}
+
+int test_register(void)
+{
+  su_port_t *port;
+  su_sockaddr_t su[1];
+  intptr_t i;
+  int sockets[256] = { 0 };
+  int reg[256] = { 0 };
+  int wakeups[256] = { 0 };
+  int prioritized;
+  su_wait_t wait[256];
+  su_root_magic_t magic[1] = {{ 0 }};
+  su_root_t root[1] = {{ sizeof root }};
+
+  BEGIN();
+
+  root->sur_magic = magic;
+
+  memset(su, 0, sizeof su);
+  su->su_len = sizeof su->su_sin;
+  su->su_family = AF_INET;
+  su->su_sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+
+  memset(wait, 0, sizeof wait);
+
+  memset(magic->sockets = sockets, -1, sizeof sockets);
+  memset(magic->regs = reg, 0, sizeof reg);
+  memset(magic->wakeups = wakeups, 0, sizeof wakeups);
+
+  su_root_size_hint = 16;
+
+  TEST_1(port = su_port_create());
+  TEST(su_port_threadsafe(port), 0);
+  SU_PORT_INCREF(port, __func__);
+
+  TEST_1(test_sup_indices(port));
+
+  for (i = N0; i < N; i++) {
+    sockets[i] = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(sockets[i] != -1);
+
+    if (bind(sockets[i], &su->su_sa, sizeof su->su_sin) != 0)
+      perror("bind"), assert(0);
+    
+    TEST(su_wait_create(wait + i, sockets[i], SU_WAIT_IN), 0);
+
+    reg[i] = su_port_register(port, root, wait + i, callback, (void*)i, 0);
+
+    TEST_1(reg[i] > 0);
+  }
+
+  TEST(port->sup_indices[0], -I);
+  TEST_1(test_sup_indices(port));
+  TEST(test_wakeup(port, magic), 0);
+
+  for (i = 1; i < N; i += 2) {
+    TEST(su_port_deregister(port, reg[i]), reg[i]);
+    TEST_1(test_sup_indices(port));
+  }
+
+  TEST_1(test_sup_indices(port));
+
+  prioritized = 0;
+
+  for (i = N - 1; i >= N0; i -= 2) {
+    TEST(su_wait_create(wait + i, sockets[i], SU_WAIT_IN), 0);
+    reg[i] = su_port_register(port, root, wait + i, callback, (void *)i, 1);
+    TEST_1(reg[i] > 0);
+    prioritized++;		/* Count number of prioritized registrations */
+#if HAVE_EPOLL
+    /* With epoll we do not bother to prioritize the wait list */
+    if (port->sup_epoll != -1) {
+      int N = port->sup_n_waits;
+      TEST_M(wait + i, port->sup_waits + N - 1, sizeof wait[0]);
+    }
+    else
+#endif
+    TEST_M(wait + i, port->sup_waits, sizeof wait[0]);
+  }
+
+  TEST(port->sup_indices[0], -I);
+
+#if 0
+#if HAVE_EPOLL
+  /* With epoll we do not bother to prioritize the wait list */
+  if (port->sup_epoll != -1) {
+    TEST_M(wait + 15, port->sup_waits + 8, sizeof wait[0]);
+    TEST_M(wait + 13, port->sup_waits + 9, sizeof wait[0]);
+    TEST_M(wait + 11, port->sup_waits + 10, sizeof wait[0]);
+    TEST_M(wait + 9, port->sup_waits + 11, sizeof wait[0]);
+    TEST_M(wait + 7, port->sup_waits + 12, sizeof wait[0]);
+    TEST_M(wait + 5, port->sup_waits + 13, sizeof wait[0]);
+    TEST_M(wait + 3, port->sup_waits + 14, sizeof wait[0]);
+    TEST_M(wait + 1, port->sup_waits + 15, sizeof wait[0]);
+  }
+  else
+#endif
+  {
+  TEST_M(wait + 15, port->sup_waits + 7, sizeof wait[0]);
+  TEST_M(wait + 13, port->sup_waits + 6, sizeof wait[0]);
+  TEST_M(wait + 11, port->sup_waits + 5, sizeof wait[0]);
+  TEST_M(wait + 9, port->sup_waits + 4, sizeof wait[0]);
+  TEST_M(wait + 7, port->sup_waits + 3, sizeof wait[0]);
+  TEST_M(wait + 5, port->sup_waits + 2, sizeof wait[0]);
+  TEST_M(wait + 3, port->sup_waits + 1, sizeof wait[0]);
+  TEST_M(wait + 1, port->sup_waits + 0, sizeof wait[0]);
+  }
+#endif
+
+  TEST_1(test_sup_indices(port));
+  TEST(test_wakeup(port, magic), 0);
+
+  for (i = 1; i <= 8; i++) {
+    TEST(su_port_deregister(port, reg[i]), reg[i]); reg[i] = 0;
+    if (i % 2 == (N - 1) % 2)
+      prioritized--;		/* Count number of prioritized registrations */
+  }
+
+#if HAVE_EPOLL
+  /* With epoll we do not bother to prioritize the wait list */
+  if (port->sup_epoll == -1) 
+#endif
+    TEST(port->sup_pri_offset, prioritized);
+
+  TEST_1(test_sup_indices(port));
+
+  TEST(su_port_deregister(port, 0), -1);
+  TEST(su_port_deregister(port, -1), -1);
+  TEST(su_port_deregister(port, 130), -1);
+
+  TEST_1(test_sup_indices(port));
+
+  for (i = 1; i <= 8; i++) {
+    TEST(su_port_deregister(port, reg[i]), -1);
+  }
+
+  TEST_VOID(su_port_decref(port, 1, __func__));
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-v]\n",
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+#if SU_HAVE_WINSOCK
+  if (N > SU_WAIT_MAX)
+    N = SU_WAIT_MAX;
+  if (I - 1 >= SU_WAIT_MAX)
+    I = (unsigned)SU_WAIT_MAX + 1;
+#endif
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  su_init();
+
+  retval |= test_register(); fflush(stdout);
+
+  su_deinit();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,362 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * 
+ * @file torture_su_root.c
+ *
+ * Test su_root_register functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * Copyright (c) 2002 Nokia Research Center.  All rights reserved.
+ *
+ * @date Created: Wed Jun 12 15:18:11 2002 ppessi
+ */
+
+#include "config.h"
+
+char const *name = "su_root_test";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TSTFLAGS rt->rt_flags
+#include <sofia-sip/tstdef.h>
+
+typedef struct root_test_s root_test_t;
+typedef struct test_ep_s   test_ep_t;
+
+#define SU_ROOT_MAGIC_T  root_test_t
+#define SU_WAKEUP_ARG_T  test_ep_t
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+
+typedef struct test_ep_s {
+  int           i;
+  int           s;
+  su_wait_t     wait[1];
+  int           registered;
+  socklen_t     addrlen;
+  su_sockaddr_t addr[1];
+} test_ep_at[1];
+
+struct root_test_s {
+  su_home_t  rt_home[1];
+  int        rt_flags;
+
+  su_root_t *rt_root;
+  short      rt_family;
+  int        rt_status;
+  int        rt_received;
+  int        rt_wakeup;
+
+  su_clone_r rt_clone;
+
+  unsigned   rt_fail_init:1;
+  unsigned   rt_fail_deinit:1;
+  unsigned   rt_success_init:1;
+  unsigned   rt_success_deinit:1;
+
+  test_ep_at rt_ep[5];
+};
+
+/** Test root initialization */
+int init_test(root_test_t *rt)
+{
+  su_sockaddr_t su[1] = {{ 0 }};
+  int i;
+
+  BEGIN();
+
+  su_init();
+
+  su->su_family = rt->rt_family;
+
+  TEST_1(rt->rt_root = su_root_create(rt));
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    ep->i = i;
+    ep->addrlen = su_sockaddr_size(su);
+    TEST_1((ep->s = su_socket(su->su_family, SOCK_DGRAM, 0)) != -1);
+    TEST_1(bind(ep->s, &su->su_sa, ep->addrlen) != -1);
+    TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+    TEST_1(getsockname(ep->s, &ep->addr->su_sa, &ep->addrlen) != -1);
+    if (SU_HAS_INADDR_ANY(ep->addr)) {
+      inet_pton(su->su_family, 
+	        su->su_family == AF_INET ? "127.0.0.1" : "::1",
+		SU_ADDR(ep->addr));
+    }
+  }
+
+  END();
+}
+
+static int deinit_test(root_test_t *rt)
+{
+  BEGIN();
+
+  TEST_VOID(su_root_destroy(rt->rt_root)); rt->rt_root = NULL;
+  TEST_VOID(su_root_destroy(NULL));
+
+  su_deinit();
+
+  END();
+}
+
+int wakeup(root_test_t *rt,
+	   su_wait_t *w,
+	   test_ep_t *ep)
+{
+  char buffer[64];
+  int n, error;
+ 
+  su_wait_events(w, ep->s);
+
+  n = recv(ep->s, buffer, sizeof(buffer), 0);
+  error = su_errno();
+ 
+  if (n < 0)
+    fprintf(stderr, "%s: %s\n", "recv", su_strerror(error));
+
+  TEST_1(n > 0);
+
+  rt->rt_received = ep->i;
+	   
+  return 0;
+}
+
+static int wakeup0(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 0;
+  return wakeup(rt, w, ep);
+}
+static int wakeup1(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 1;
+  return wakeup(rt, w, ep);
+}
+static int wakeup2(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 2;
+  return wakeup(rt, w, ep);
+}
+static int wakeup3(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 3;
+  return wakeup(rt, w, ep);
+}
+static int wakeup4(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 4;
+  return wakeup(rt, w, ep);
+}
+
+static
+su_wakeup_f wakeups[5] = { wakeup0, wakeup1, wakeup2, wakeup3, wakeup4 };
+
+
+static
+void test_run(root_test_t *rt)
+{
+  rt->rt_received = -1;
+
+  while (rt->rt_received == -1) {
+    su_root_step(rt->rt_root, 200);
+  }
+}
+
+static int register_test(root_test_t *rt)
+{
+  int i;
+  int s;
+  char *msg = "foo";
+
+  BEGIN();
+
+  TEST_1((s = su_socket(rt->rt_family, SOCK_DGRAM, 0)) != -1);
+
+  for (i = 0; i < 5; i++) {
+    rt->rt_ep[i]->registered = 
+      su_root_register(rt->rt_root, rt->rt_ep[i]->wait, 
+		       wakeups[i], rt->rt_ep[i], 0);
+    TEST(rt->rt_ep[i]->registered, i + 1 + SU_HAVE_PTHREADS);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	      sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, 
+			    wakeups[i], rt->rt_ep[i]), 
+	 rt->rt_ep[i]->registered);
+  }
+
+
+  for (i = 0; i < 5; i++) {
+    rt->rt_ep[i]->registered = 
+      su_root_register(rt->rt_root, rt->rt_ep[i]->wait, 
+		       wakeups[i], rt->rt_ep[i], 1);
+    TEST_1(rt->rt_ep[i]->registered > 0);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	      sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_deregister(rt->rt_root, rt->rt_ep[i]->registered), 
+	 rt->rt_ep[i]->registered);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+    ep->registered = 
+      su_root_register(rt->rt_root, ep->wait, 
+		       wakeups[i], ep, 1);
+    TEST_1(ep->registered > 0);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	      sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, 
+			    wakeups[i], rt->rt_ep[i]), 
+	 rt->rt_ep[i]->registered);
+  }
+
+  END();
+}
+
+int fail_init(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_fail_init = 1;
+  return -1;
+}
+
+void fail_deinit(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_fail_deinit = 1;
+}
+
+int success_init(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_success_init = 1;
+  return 0;
+}
+
+void success_deinit(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_success_deinit = 1;
+}
+
+static int clone_test(root_test_t rt[1])
+{
+  BEGIN();
+
+  rt->rt_fail_init = 0;
+  rt->rt_fail_deinit = 0;
+  rt->rt_success_init = 0;
+  rt->rt_success_deinit = 0;
+
+  TEST(su_clone_start(rt->rt_root,
+		      rt->rt_clone,
+		      rt,
+		      fail_init,
+		      fail_deinit), SU_FAILURE);
+  TEST_1(rt->rt_fail_init);
+  TEST_1(rt->rt_fail_deinit);
+
+  TEST(su_clone_start(rt->rt_root,
+		      rt->rt_clone,
+		      rt,
+		      success_init,
+		      success_deinit), SU_SUCCESS);
+  TEST_1(rt->rt_success_init);
+  TEST_1(!rt->rt_success_deinit);
+
+  TEST_VOID(su_clone_wait(rt->rt_root, rt->rt_clone));
+
+  TEST_1(rt->rt_success_deinit);
+  
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  root_test_t rt[1] = {{{ SU_HOME_INIT(rt) }}};
+  int retval = 0;
+  int i;
+
+  rt->rt_family = AF_INET;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      rt->rt_flags |= tst_verbatim;
+#if SU_HAVE_IN6
+    else if (strcmp(argv[i], "-6") == 0)
+      rt->rt_family = AF_INET6;
+#endif
+    else
+      usage();
+  }
+
+  retval |= init_test(rt);
+  retval |= register_test(rt);
+  retval |= clone_test(rt);
+  su_root_threading(rt->rt_root, 0);
+  retval |= clone_test(rt);
+  retval |= deinit_test(rt);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,364 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * 
+ * @file torture_su_root_osx.c
+ *
+ * Test su_root_register functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * Copyright (c) 2006 Nokia Research Center.  All rights reserved.
+ *
+ * @date Created: Mon Oct  9 13:25:10 EEST 2006 mela
+ */
+
+#include "config.h"
+
+char const *name = "torture_su_root_osx";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TSTFLAGS rt->rt_flags
+#include <sofia-sip/tstdef.h>
+
+typedef struct root_test_s root_test_t;
+typedef struct test_ep_s   test_ep_t;
+
+#define SU_ROOT_MAGIC_T  root_test_t
+#define SU_WAKEUP_ARG_T  test_ep_t
+
+#include <sofia-sip/su_osx_runloop.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+
+typedef struct test_ep_s {
+  int           i;
+  int           s;
+  su_wait_t     wait[1];
+  int           registered;
+  socklen_t     addrlen;
+  su_sockaddr_t addr[1];
+} test_ep_at[1];
+
+struct root_test_s {
+  su_home_t  rt_home[1];
+  int        rt_flags;
+
+  su_root_t *rt_root;
+  short      rt_family;
+  int        rt_status;
+  int        rt_received;
+  int        rt_wakeup;
+
+  su_clone_r rt_clone;
+
+  unsigned   rt_fail_init:1;
+  unsigned   rt_fail_deinit:1;
+  unsigned   rt_success_init:1;
+  unsigned   rt_success_deinit:1;
+
+  test_ep_at rt_ep[5];
+};
+
+/** Test root initialization */
+int init_test(root_test_t *rt)
+{
+  su_sockaddr_t su[1] = {{ 0 }};
+  int i;
+
+  BEGIN();
+
+  su_init();
+
+  su->su_family = rt->rt_family;
+
+  TEST_1(rt->rt_root = su_root_osx_runloop_create(rt));
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    ep->i = i;
+    ep->addrlen = su_sockaddr_size(su);
+    TEST_1((ep->s = su_socket(su->su_family, SOCK_DGRAM, 0)) != -1);
+    TEST_1(bind(ep->s, &su->su_sa, ep->addrlen) != -1);
+    TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+    TEST_1(getsockname(ep->s, &ep->addr->su_sa, &ep->addrlen) != -1);
+    if (SU_HAS_INADDR_ANY(ep->addr)) {
+      inet_pton(su->su_family, 
+	        su->su_family == AF_INET ? "127.0.0.1" : "::1",
+		SU_ADDR(ep->addr));
+    }
+  }
+
+  END();
+}
+
+static int deinit_test(root_test_t *rt)
+{
+  BEGIN();
+
+  TEST_VOID(su_root_destroy(rt->rt_root)); rt->rt_root = NULL;
+  TEST_VOID(su_root_destroy(NULL));
+
+  su_deinit();
+
+  END();
+}
+
+int wakeup(root_test_t *rt,
+	   su_wait_t *w,
+	   test_ep_t *ep)
+{
+  char buffer[64];
+  int n, error;
+ 
+  su_wait_events(w, ep->s);
+
+  n = recv(ep->s, buffer, sizeof(buffer), 0);
+  error = su_errno();
+ 
+  if (n < 0)
+    fprintf(stderr, "%s: %s\n", "recv", su_strerror(error));
+
+  TEST_1(n > 0);
+
+  rt->rt_received = ep->i;
+	   
+  return 0;
+}
+
+static int wakeup0(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 0;
+  return wakeup(rt, w, ep);
+}
+static int wakeup1(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 1;
+  return wakeup(rt, w, ep);
+}
+static int wakeup2(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 2;
+  return wakeup(rt, w, ep);
+}
+static int wakeup3(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 3;
+  return wakeup(rt, w, ep);
+}
+static int wakeup4(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+  rt->rt_wakeup = 4;
+  return wakeup(rt, w, ep);
+}
+
+static
+su_wakeup_f wakeups[5] = { wakeup0, wakeup1, wakeup2, wakeup3, wakeup4 };
+
+
+static
+void test_run(root_test_t *rt)
+{
+  rt->rt_received = -1;
+
+  while (rt->rt_received == -1) {
+    su_root_step(rt->rt_root, 200);
+  }
+}
+
+static int register_test(root_test_t *rt)
+{
+  int i;
+  int s;
+  char msg[3] = "foo";
+
+  BEGIN();
+
+  TEST_1((s = su_socket(rt->rt_family, SOCK_DGRAM, 0)) != -1);
+
+  for (i = 0; i < 5; i++) {
+    rt->rt_ep[i]->registered = 
+      su_root_register(rt->rt_root, rt->rt_ep[i]->wait, 
+		       wakeups[i], rt->rt_ep[i], 0);
+    TEST(rt->rt_ep[i]->registered, i + 1 + SU_HAVE_PTHREADS);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	 sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, 
+			    wakeups[i], rt->rt_ep[i]), 
+	 rt->rt_ep[i]->registered);
+  }
+
+
+  for (i = 0; i < 5; i++) {
+    rt->rt_ep[i]->registered = 
+      su_root_register(rt->rt_root, rt->rt_ep[i]->wait, 
+		       wakeups[i], rt->rt_ep[i], 1);
+    TEST_1(rt->rt_ep[i]->registered > 0);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	 sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_deregister(rt->rt_root, rt->rt_ep[i]->registered), 
+	 rt->rt_ep[i]->registered);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+    ep->registered = 
+      su_root_register(rt->rt_root, ep->wait, 
+		       wakeups[i], ep, 1);
+    TEST_1(ep->registered > 0);
+  }
+
+  for (i = 0; i < 5; i++) {
+    test_ep_t *ep = rt->rt_ep[i];
+    TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen), 
+	 sizeof(msg));
+    test_run(rt);
+    TEST(rt->rt_received, i);
+    TEST(rt->rt_wakeup, i);
+  }
+
+  for (i = 0; i < 5; i++) {
+    TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait, 
+			    wakeups[i], rt->rt_ep[i]), 
+	 rt->rt_ep[i]->registered);
+  }
+
+  END();
+}
+
+int fail_init(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_fail_init = 1;
+  return -1;
+}
+
+void fail_deinit(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_fail_deinit = 1;
+}
+
+int success_init(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_success_init = 1;
+  return 0;
+}
+
+void success_deinit(su_root_t *root, root_test_t *rt)
+{
+  rt->rt_success_deinit = 1;
+}
+
+static int clone_test(root_test_t rt[1])
+{
+  BEGIN();
+
+  rt->rt_fail_init = 0;
+  rt->rt_fail_deinit = 0;
+  rt->rt_success_init = 0;
+  rt->rt_success_deinit = 0;
+
+  TEST(su_clone_start(rt->rt_root,
+		      rt->rt_clone,
+		      rt,
+		      fail_init,
+		      fail_deinit), SU_FAILURE);
+  TEST_1(rt->rt_fail_init);
+  TEST_1(rt->rt_fail_deinit);
+
+  TEST(su_clone_start(rt->rt_root,
+		      rt->rt_clone,
+		      rt,
+		      success_init,
+		      success_deinit), SU_SUCCESS);
+  TEST_1(rt->rt_success_init);
+  TEST_1(!rt->rt_success_deinit);
+
+  TEST_VOID(su_clone_wait(rt->rt_root, rt->rt_clone));
+
+  TEST_1(rt->rt_success_deinit);
+  
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  root_test_t rt[1] = {{{ SU_HOME_INIT(rt) }}};
+  int retval = 0;
+  int i;
+
+  rt->rt_family = AF_INET;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      rt->rt_flags |= tst_verbatim;
+#if SU_HAVE_IN6
+    else if (strcmp(argv[i], "-6") == 0)
+      rt->rt_family = AF_INET6;
+#endif
+    else
+      usage();
+  }
+
+  retval |= init_test(rt);
+  retval |= register_test(rt);
+  retval |= clone_test(rt);
+  su_root_threading(rt->rt_root, 0);
+  retval |= clone_test(rt);
+  retval |= deinit_test(rt);
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,654 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ * 
+ * @file torture_su_tag.c
+ *
+ * Testing functions for su_tag module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * 
+ * @date Created: Tue Mar  6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+#ifndef WIN32
+#define DEVNULL "/dev/null"
+#else
+#define DEVNULL "nul"
+#endif 
+
+int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#define TAG_A(s)      tag_a, tag_str_v((s))
+#define TAG_A_REF(s)  tag_a_ref, tag_str_vr(&(s))
+#define TAG_B(s)      tag_b, tag_str_v((s))
+#define TAG_B_REF(s)  tag_b_ref, tag_str_vr(&(s))
+
+#define TAG_I(i)      tag_i, tag_int_v((i))
+#define TAG_I_REF(i)  tag_i_ref, tag_int_vr(&(i))
+#define TAG_J(i)      tag_j, tag_int_v((i))
+#define TAG_J_REF(i)  tag_j_ref, tag_int_vr(&(i))
+#define TAG_K(i)      tag_k, tag_int_v((i))
+#define TAG_K_REF(i)  tag_k_ref, tag_int_vr(&(i))
+
+#define TAG_ANY_PQ()  tag_any_pq, (tag_value_t)0
+
+#define TAG_P(i)      tag_p, tag_bool_v((i))
+#define TAG_P_REF(i)  tag_p_ref, tag_bool_vr(&(i))
+#define TAG_Q(i)      tag_q, tag_bool_v((i))
+#define TAG_Q_REF(i)  tag_q_ref, tag_bool_vr(&(i))
+
+char const *name = "su_tag_test";
+
+#if HAVE_WIN32
+typedef struct tag_type_s tag_typedef_win_t[1];
+
+tag_typedef_win_t tag_a, tag_a_ref, tag_b, tag_b_ref;
+tag_typedef_win_t tag_i, tag_i_ref, tag_j, tag_j_ref;
+tag_typedef_win_t tag_k, tag_k_ref, tag_n, tag_n_ref;
+tag_typedef_win_t tag_any_pq;
+tag_typedef_win_t tag_p, tag_p_ref, tag_q, tag_q_ref;
+
+#else
+tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+tag_typedef_t tag_a_ref = REFTAG_TYPEDEF(tag_a);
+
+tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+tag_typedef_t tag_b_ref = REFTAG_TYPEDEF(tag_b);
+
+tag_typedef_t tag_i = INTTAG_TYPEDEF(i);
+tag_typedef_t tag_i_ref = REFTAG_TYPEDEF(tag_i);
+
+tag_typedef_t tag_j = INTTAG_TYPEDEF(j);
+tag_typedef_t tag_j_ref = REFTAG_TYPEDEF(tag_j);
+
+tag_typedef_t tag_k = INTTAG_TYPEDEF(k);
+tag_typedef_t tag_k_ref = REFTAG_TYPEDEF(tag_k);
+
+tag_typedef_t tag_n = INTTAG_TYPEDEF(n);
+tag_typedef_t tag_n_ref = REFTAG_TYPEDEF(tag_n);
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "pq"
+
+tag_typedef_t tag_any_pq = NSTAG_TYPEDEF(*);
+
+tag_typedef_t tag_p = BOOLTAG_TYPEDEF(p);
+tag_typedef_t tag_p_ref = REFTAG_TYPEDEF(tag_p);
+
+tag_typedef_t tag_q = BOOLTAG_TYPEDEF(q);
+tag_typedef_t tag_q_ref = REFTAG_TYPEDEF(tag_q);
+
+#endif
+
+static void init_tags(void)
+{
+#if HAVE_WIN32
+  /* Automatic initialization with pointers from DLL does not work in WIN32 */
+
+  tag_typedef_t _tag_a = STRTAG_TYPEDEF(a);
+  tag_typedef_t _tag_a_ref = REFTAG_TYPEDEF(tag_a);
+
+  tag_typedef_t _tag_b = STRTAG_TYPEDEF(b);
+  tag_typedef_t _tag_b_ref = REFTAG_TYPEDEF(tag_b);
+ 
+  tag_typedef_t _tag_i = INTTAG_TYPEDEF(i);
+  tag_typedef_t _tag_i_ref = REFTAG_TYPEDEF(tag_i);
+ 
+  tag_typedef_t _tag_j = INTTAG_TYPEDEF(j);
+  tag_typedef_t _tag_j_ref = REFTAG_TYPEDEF(tag_j);
+ 
+  tag_typedef_t _tag_k = INTTAG_TYPEDEF(k);
+  tag_typedef_t _tag_k_ref = REFTAG_TYPEDEF(tag_k);
+  
+  tag_typedef_t _tag_n = INTTAG_TYPEDEF(n);
+  tag_typedef_t _tag_n_ref = REFTAG_TYPEDEF(tag_n);
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "pq"
+  
+  tag_typedef_t _tag_any_pq = NSTAG_TYPEDEF(*);
+
+  tag_typedef_t _tag_p = BOOLTAG_TYPEDEF(p);
+  tag_typedef_t _tag_p_ref = REFTAG_TYPEDEF(tag_p);
+  
+  tag_typedef_t _tag_q = BOOLTAG_TYPEDEF(q);
+  tag_typedef_t _tag_q_ref = REFTAG_TYPEDEF(tag_q);
+
+  *(struct tag_type_s *)tag_a = *_tag_a;
+  *(struct tag_type_s *)tag_a_ref = *_tag_a_ref;
+  *(struct tag_type_s *)tag_b = *_tag_b;
+  *(struct tag_type_s *)tag_b_ref = *_tag_b_ref;
+  *(struct tag_type_s *)tag_i = *_tag_i;
+  *(struct tag_type_s *)tag_i_ref = *_tag_i_ref;
+  *(struct tag_type_s *)tag_j = *_tag_j;
+  *(struct tag_type_s *)tag_j_ref = *_tag_j_ref;
+  *(struct tag_type_s *)tag_k = *_tag_k;
+  *(struct tag_type_s *)tag_k_ref = *_tag_k_ref;
+  *(struct tag_type_s *)tag_n = *_tag_n;
+  *(struct tag_type_s *)tag_n_ref = *_tag_n_ref;
+  *(struct tag_type_s *)tag_any_pq = *_tag_any_pq;
+  *(struct tag_type_s *)tag_p = *_tag_p;
+  *(struct tag_type_s *)tag_p_ref = *_tag_p_ref;
+  *(struct tag_type_s *)tag_q = *_tag_q;
+  *(struct tag_type_s *)tag_q_ref = *_tag_q_ref;
+#endif
+}
+
+static int test_assumptions(void)
+{
+  tagi_t tags[2], *tagi;
+
+  BEGIN();
+
+  TEST_1(sizeof (tag_value_t) >= sizeof (void *));
+
+  /* First some pointer arithmetics - this is always true, right? */
+  tagi = tags;
+  TEST_P(tagi + 1, tags + 1);
+  tagi = (tagi_t *)(sizeof(tagi_t) + (char *)tagi);
+  TEST_P(tagi, tags + 1);
+
+  END();
+}
+
+#if SU_HAVE_TAGSTACK
+
+/* Automake thing:
+
+###
+### Test if we have stack suitable for handling tags directly
+###
+AC_TRY_RUN( [
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+  va_list ap;
+  tv i, *p = &l;
+
+  va_start(ap, h);
+
+  if (*p++ != l || *p++ != h) return 1;
+
+  for (i = l; i <= h; i++) {
+    if (*p++ != i)
+      return 1;
+  }
+
+  for (i = l; i <= h; i++) {
+    if (va_arg(ap, tv) != i)
+      return 1;
+  }
+
+  va_end(ap);
+
+  return 0;
+}
+
+int main(int avc, char *av[])
+{
+  return test1((tv)1, (tv)10,
+	       (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+	       (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+], 
+SAC_SU_DEFINE(SU_HAVE_TAGSTACK, 1, [
+Define this as 1 if your compiler puts the variable argument list nicely in memory]), 
+)
+
+*/
+
+static int test_stackargs(int l, ...)
+{
+  va_list ap;  
+  int i, *p;
+
+  BEGIN();
+
+  va_start(ap, l);
+  
+  p = &l;
+
+  for (i = l; i <= 10; i++) {
+    TEST(*p++, i);
+  }
+
+  for (i = l + 1; i <= 10; i++) {
+    TEST(va_arg(ap, int), i);
+  }
+
+  va_end(ap);
+
+  END();
+}
+#else
+static int test_stackargs(int l, ...) { return 0; }
+#endif
+
+/** Test tl_list, tl_llist and tl_dup */
+static int test_dup(void)
+{
+  tagi_t const rest[] = {{ TAG_A("Foo") }, { TAG_NULL() }};
+  tagi_t *lst, *dup;
+
+  BEGIN();
+
+  lst = tl_list(TAG_A("Moro"), 
+		TAG_A("Vaan"), 
+		TAG_I(1), 
+		TAG_SKIP(2), 
+		TAG_NEXT(rest));
+
+  TEST_P(lst[0].t_tag, tag_a);
+  TEST_P(lst[1].t_tag, tag_a);
+  TEST_P(lst[2].t_tag, tag_i);
+  TEST_P(lst[3].t_tag, tag_skip);
+  TEST_P(lst[4].t_tag, tag_next);
+
+  TEST_SIZE(tl_len(lst), 5 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(lst, 0), strlen("Moro" "Vaan" "Foo") + 3);
+
+  dup = tl_adup(NULL, lst);
+
+  TEST_1(dup != NULL);
+  TEST_SIZE(tl_len(dup), 5 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(dup, 0), strlen("Moro" "Vaan" "Foo") + 3);
+
+  su_free(NULL, dup);
+
+  dup = tl_llist(TAG_B("Moi"), TAG_NEXT(lst));
+
+  TEST_P(dup[0].t_tag, tag_b);
+  TEST_P(dup[1].t_tag, tag_a);
+  TEST_P(dup[2].t_tag, tag_a);
+  TEST_P(dup[3].t_tag, tag_i);
+  TEST_P(dup[4].t_tag, tag_a);
+  TEST_P(dup[5].t_tag, NULL);
+
+  su_free(NULL, dup);
+
+  dup = tl_llist(TAG_NEXT(NULL));
+  TEST_P(dup[0].t_tag, 0);
+  su_free(NULL, dup);
+
+  dup = tl_llist(TAG_END());
+  TEST_P(dup[0].t_tag, 0);
+  su_free(NULL, dup);
+
+  dup = tl_llist(TAG_SKIP(1), TAG_NEXT(lst + 4));
+  TEST_P(dup[0].t_tag, tag_a);
+  TEST_P(dup[1].t_tag, 0);
+  su_free(NULL, dup);
+
+  tl_vfree(lst);
+
+  END();
+}
+
+/* filtering function */
+int filter(tagi_t const *filter, tagi_t const *t)
+{
+  if (!t)
+    return 0;
+
+  /* Accept even TAG_I() */
+  if (t->t_tag == tag_i)
+    return (t->t_value & 1) == 0;
+
+  /* TAG_Q(true) */
+  if (t->t_tag == tag_q)
+    return t->t_value != 0;
+
+  /* TAG_P(false) */
+  if (t->t_tag == tag_p)
+    return t->t_value == 0;
+
+  if (t->t_tag == tag_a) {
+    char const *s = (char *)t->t_value;
+    if (s && 'A' <= *s && *s <= 'Z')
+      return 1;
+  }
+
+  return 0;
+}
+
+/* Test tl_afilter() */
+static int test_filters(void)
+{
+  tagi_t *lst, *filter1, *filter2, *filter3, *filter4, *filter5, *filter6;
+  tagi_t *b, *b1, *b2, *b3, *b4;
+
+  tagi_t *nsfilter, *b5;
+  su_home_t *home;
+
+  BEGIN();
+
+  home = su_home_new(sizeof *home); TEST_1(home);
+
+  lst = tl_list(TAG_A("Moro"), 
+		TAG_I(2),
+		TAG_Q(3),
+		TAG_SKIP(2), 
+		TAG_A("vaan"), 
+		TAG_I(1), 
+		TAG_P(2),
+		TAG_NULL());
+
+  filter1 = tl_list(TAG_A(""), TAG_NULL());
+  filter2 = tl_list(TAG_I(0), TAG_NULL());
+  filter3 = tl_list(TAG_A(""), TAG_I(0), TAG_NULL());
+  filter4 = tl_list(TAG_ANY(), TAG_NULL());
+  filter5 = tl_list(TAG_FILTER(filter), TAG_NULL());
+  filter6 = tl_list(TAG_NULL());
+
+  TEST0(lst && filter1 && filter2 && filter3 && filter4 && filter5);
+
+  b1 = tl_afilter(NULL, filter1, lst);
+
+  TEST_SIZE(tl_len(b1), 3 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b1, 0), strlen("Moro" "vaan") + 2);
+
+  b2 = tl_afilter(NULL, filter2, lst);
+
+  TEST_SIZE(tl_len(b2), 3 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b2, 0), 0);
+
+  b3 = tl_afilter(NULL, filter3, lst);
+
+  TEST_SIZE(tl_len(b3), 5 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b3, 0), strlen("Moro" "vaan") + 2);
+
+  b4 = tl_afilter(NULL, filter4, lst);
+
+  TEST_SIZE(tl_len(b4), 7 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b4, 0), strlen("Moro" "vaan") + 2);
+
+  su_free(NULL, b1); su_free(NULL, b2); su_free(NULL, b3); su_free(NULL, b4);
+
+  nsfilter = tl_list(TAG_ANY_PQ(), TAG_END());
+  
+  b5 = tl_afilter(NULL, nsfilter, lst);
+  TEST_SIZE(tl_len(b5), 3 * sizeof(tagi_t));
+  TEST_SIZE(tl_xtra(b5, 0), 0);
+
+  TEST_P(b5[0].t_tag, tag_q);
+  TEST_P(b5[1].t_tag, tag_p);
+
+  b = tl_afilter(home, filter5, lst); TEST_1(b);
+  TEST_P(b[0].t_tag, tag_a);
+  TEST_P(b[1].t_tag, tag_i);
+  TEST_P(b[2].t_tag, tag_q);
+  TEST_P(b[3].t_tag, 0);
+
+  b = tl_afilter(home, filter6, lst); TEST_1(b);
+  TEST_P(b[0].t_tag, 0);
+
+  tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3); 
+  tl_vfree(filter4); tl_vfree(filter5); tl_vfree(filter6);
+
+  tl_vfree(lst);
+
+  su_home_unref(home);
+
+  END();
+}
+
+/* Test tl_print */
+static int test_print(void)
+{
+  BEGIN();
+
+  tagi_t *lst;
+  FILE *out;
+
+  lst = tl_list(TAG_A("Moro"), 
+		TAG_I(2), 
+		TAG_J(3),
+		TAG_K(5),
+		TAG_SKIP(2), 
+		TAG_A("Vaan"), 
+		TAG_B("b"),
+		TAG_I(1), 
+		TAG_NULL());
+
+  if (tstflags & tst_verbatim)
+    out = stdout;
+  else
+    out = fopen(DEVNULL, "w");
+
+  if (out) {
+    tl_print(out, "test_print: ", lst);
+
+    if ((tstflags & tst_verbatim) == 0)
+      fclose(out);
+  }
+
+  END();
+}
+
+static int test_tagargs2(tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  tagi_t const *t;
+
+  BEGIN();
+
+  ta_start(ta, tag, value);
+
+  t = ta_args(ta);
+  TEST_P(t->t_tag, tag_a);
+  TEST_S((char *)t->t_value, "a");
+
+  t = tl_next(t);
+  TEST_P(t->t_tag, tag_b);
+  TEST_S((char *)t->t_value, "b");
+
+  ta_end(ta);
+
+  END();
+}
+
+/* Test tagargs) */
+static int test_tagargs(void)
+{
+  return test_tagargs2(TAG_A("a"),
+		       TAG_B("b"),
+		       TAG_I(1),
+		       TAG_J(2),
+		       TAG_K(3),
+		       TAG_P(0),
+		       TAG_Q(-1),
+		       TAG_END());
+}
+
+/* Test tl_tgets() and tl_gets() */
+static int test_gets(void)
+{
+  tagi_t *lst, *t;
+  char const *a = "B", *b = "A";
+  int i = 1, j = 0, k = 0, p = -1;
+
+  BEGIN();
+
+  lst = tl_list(TAG_A("Moro"), 
+		TAG_I(2), 
+		TAG_J(3),
+		TAG_K(5),
+		TAG_P(3),
+		TAG_SKIP(2), 
+		TAG_A("Vaan"), 
+		TAG_B("b"),
+		TAG_I(1), 
+		TAG_NULL());
+
+  TEST_1(lst);
+
+  TEST_1(t = tl_find(lst, tag_i)); TEST(t->t_value, 2);
+  TEST_1(t = tl_find_last(lst, tag_i)); TEST(t->t_value, 1);
+
+  TEST(tl_gets(lst, 
+	       TAG_A_REF(a),
+	       TAG_B_REF(b),
+	       TAG_I_REF(i),
+	       TAG_J_REF(j),
+	       TAG_K_REF(k),
+	       TAG_P_REF(p),
+	       TAG_END()),
+       6);
+
+  /* tl_gets() semantics have changed */
+#if 0
+  TEST_S(a, "Moro");
+  TEST(i, 2);
+#else
+  TEST_S(a, "Vaan");
+  TEST(i, 1);
+#endif
+  TEST(j, 3);
+  TEST(k, 5);
+  TEST(p, 1);
+  TEST_S(b, "b");
+
+  lst = tl_list(TAG_A_REF(a),
+		TAG_I_REF(i),
+		TAG_NULL());
+  
+  TEST(tl_tgets(lst, TAG_A("Foo"), TAG_I(-1), TAG_END()), 2);
+
+  TEST_S(a, "Foo");
+  TEST(i, -1);
+
+  END();
+}
+
+static int test_scan(void)
+{
+  tag_value_t v = 0;
+
+  BEGIN();
+
+  TEST(t_scan(tag_a, NULL, NULL, &v), -1); /* Invalid case */
+
+  TEST(t_scan(tag_a, NULL, "foo", &v), 1);
+  TEST_S((char *)v, "foo");
+  su_free(NULL, (void *)v);
+
+  TEST(t_scan(tag_i, NULL, "", &v), -1); /* Invalid case */
+  TEST(t_scan(tag_i, NULL, "kukkuu-reset", &v), -1); /* Invalid case */
+
+  TEST(t_scan(tag_i, NULL, "-1234", &v), 1);
+  TEST(v, -1234);
+
+  TEST(t_scan(tag_n, NULL, "", &v), -1); /* Invalid case */
+
+  TEST(t_scan(tag_n, NULL, "3243432", &v), 1);
+  TEST(v, 3243432);
+
+  TEST(t_scan(tag_p, NULL, "kukkuu-reset", &v), -1); /* Invalid case */
+  TEST(t_scan(tag_p, NULL, "", &v), -1); /* Invalid case */
+
+  TEST(t_scan(tag_p, NULL, "true", &v), 1);
+  TEST(v, 1);
+
+  TEST(t_scan(tag_p, NULL, "true ", &v), 1);
+  TEST(v, 1);
+
+  TEST(t_scan(tag_p, NULL, "  134  ", &v), 1);
+  TEST(v, 1);
+
+  TEST(t_scan(tag_p, NULL, "false   \n\t", &v), 1);
+  TEST(v, 0);
+
+  TEST(t_scan(tag_p, NULL, "  000.000  ", &v), 1);
+  TEST(v, 0);
+
+  TEST(t_scan(tag_null, NULL, "NULL", &v), -2);
+  TEST(t_scan(tag_skip, NULL, "SKIP", &v), -2);
+  TEST(t_scan(tag_any, NULL, "any", &v), -2);
+
+  TEST(t_scan(NULL, NULL, "-1234", &v), -1);
+  TEST(t_scan(tag_a, NULL, NULL, &v), -1);
+  TEST(t_scan(tag_a, NULL, "-1234", NULL), -1);
+
+  END();
+}
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  init_tags();
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_assumptions();
+  retval |= test_stackargs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+  retval |= test_dup();
+  retval |= test_filters();
+  retval |= test_print();
+  retval |= test_tagargs();
+  retval |= test_gets();
+  retval |= test_scan();
+
+  return retval;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,218 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ * 
+ * @IFILE torture_su_time.c  
+ *
+ * Tests for su_time functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ * 
+ * @date Created: Fri May 10 16:08:18 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_time.h>
+
+#define TSTFLAGS flags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_time.c";
+
+static int test1(int flags);
+static int test2(int flags);
+static int test3(int flags);
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: %s [-v]\n", 
+	  name);
+}
+
+char *lastpart(char *path)
+{
+  if (strchr(path, '/')) 
+    return strrchr(path, '/') + 1;
+  else
+    return path;
+}
+
+int main(int argc, char *argv[])
+{
+  int flags = 0;
+  int retval = 0;
+  int i;
+
+  name = lastpart(argv[0]);  /* Set our name */
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      flags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test1(flags); fflush(stdout);
+  retval |= test2(flags); fflush(stdout);
+  retval |= test3(flags); fflush(stdout);
+
+  return retval;
+}
+
+su_time_t tv0;
+
+void su_time(su_time_t *tv)
+{
+  *tv = tv0;
+}
+
+int test1(int flags)
+{
+  uint32_t ntp_hi, ntp_lo, ntp_mw;
+  su_time_t now;
+  su_ntp_t ntp, ntp0, ntp1;
+  
+  BEGIN();
+
+  ntp_hi = 2208988800UL;
+  ntp_lo = ((su_ntp_t)500000 << 32) / 1000000;
+  ntp_mw = (ntp_hi << 16) | (ntp_lo >> 16);
+
+  tv0.tv_sec = ntp_hi;
+  tv0.tv_usec = 500000UL;
+  ntp0 = (((su_ntp_t)2208988800UL) << 32) + ntp_lo;
+  ntp1 = (((su_ntp_t)2208988800UL) << 32);
+
+  now = su_now();
+
+  TEST(now.tv_sec, 2208988800UL);
+  TEST(now.tv_usec, 500000);
+
+  ntp = su_ntp_now();
+  TEST64(ntp, ntp0);
+  TEST64(su_ntp_hi(ntp), ntp_hi);
+  TEST64(su_ntp_lo(ntp), ntp_lo);
+  TEST64(su_ntp_mw(ntp), ntp_mw);
+  TEST(su_ntp_fraq(tv0), ntp_mw);
+
+  tv0.tv_usec = 0;
+  ntp = su_ntp_now();
+  TEST64(ntp, ntp1);
+  TEST64(su_ntp_hi(ntp), ntp_hi);
+  TEST64(su_ntp_lo(ntp), 0);
+  TEST64(su_ntp_mw(ntp), (ntp_hi & 0xffff) << 16);
+  TEST(su_ntp_fraq(tv0), su_ntp_mw(ntp));
+
+  END();
+}
+
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su.h>			/* htonl() and guys */
+
+int test2(int flags)
+{
+  char buf[64];
+  su_guid_t g1[1], g2[2];
+  uint64_t tl;
+  uint16_t seq1, seq2;
+  const uint64_t granularity = 10000000U;
+  const uint64_t ntp_epoch = 
+    (uint64_t)(141427) * (24 * 60 * 60L) * granularity;
+  isize_t i;
+
+  BEGIN();
+
+  tv0.tv_sec = 268435455;
+  tv0.tv_usec = 98765;
+
+  tl = tv0.tv_sec * granularity + tv0.tv_usec * (granularity / 1000000);
+  tl += ntp_epoch;
+
+  su_guid_generate(g1);
+  seq1 = ((g1->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g1->s.clock_seq_low;
+  TEST(g1->s.time_low, htonl(tl & 0xffffFFFFU));
+  TEST(g1->s.time_mid, htons((tl >> 32) & 0xffffU));
+  TEST(g1->s.time_high_and_version, htons(((tl >> 48) & 0xfffU) | 0x1000));
+  TEST(g1->s.clock_seq_hi_and_reserved & 0xc0, 0x80);
+
+  TEST(i = su_guid_sprintf(buf, sizeof(buf), g1), su_guid_strlen);
+  TEST_SIZE(strlen(buf), i);
+
+  tv0.tv_usec++;
+  su_guid_generate(g1);
+  seq2 = ((g1->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g1->s.clock_seq_low;
+  TEST(seq1, seq2);
+
+  su_guid_generate(g2);
+  seq2 = ((g2->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g2->s.clock_seq_low;
+  TEST(g2->s.time_low, g1->s.time_low);
+  TEST(g2->s.time_mid, g1->s.time_mid);
+  TEST(g2->s.time_high_and_version, g1->s.time_high_and_version);
+  TEST((seq1 + 1) % 16384, seq2);
+
+  for (i = 0; i < 32000; i++) {
+    su_guid_generate(g2);
+    seq2 = ((g2->s.clock_seq_hi_and_reserved & 0x3f) << 8) 
+      + g2->s.clock_seq_low;
+    TEST((seq1 + i + 2) % 16384, seq2);
+  }
+
+  END();
+}
+
+int test3(int flags)
+{
+  su_time_t a = { ULONG_MAX , ULONG_MAX };
+  su_time_t b = { 0 , 0 };
+  su_time_t c = { ULONG_MAX , ULONG_MAX - 1 };
+
+  BEGIN();
+
+  TEST_1(su_time_cmp(a, b) > 0);
+  TEST_1(su_time_cmp(a, a) == 0);
+  TEST_1(su_time_cmp(b, a) < 0);
+  TEST_1(su_time_cmp(a, c) > 0);
+  TEST_1(su_time_cmp(c, c) == 0);
+  TEST_1(su_time_cmp(c, a) < 0);
+
+  TEST_1(SU_TIME_CMP(a, b) > 0);
+  TEST_1(SU_TIME_CMP(a, a) == 0);
+  TEST_1(SU_TIME_CMP(b, a) < 0);
+  TEST_1(SU_TIME_CMP(a, c) > 0);
+  TEST_1(SU_TIME_CMP(c, c) == 0);
+  TEST_1(SU_TIME_CMP(c, a) < 0);
+
+  END();
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE torture_su_timer.c
+ *
+ * @brief Test program for su timers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @internal
+ *
+ * @date Created: Fri Oct 19 08:53:55 2001 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct tester;
+
+#define SU_ROOT_MAGIC_T struct tester
+#define SU_INTERNAL_P   su_root_t *
+#define SU_TIMER_ARG_T  struct timing
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+
+struct timing
+{
+  int       t_run;
+  int       t_times;
+  su_time_t t_prev;
+};
+
+struct tester
+{
+  su_root_t *root;
+  su_timer_t *t, *t1;
+  unsigned times;
+  void *sentinel;
+};
+
+void
+print_stamp(struct tester *x, su_timer_t *t, struct timing *ti)
+{
+  su_time_t now = su_now(), prev = ti->t_prev;
+
+  ti->t_prev = now;
+
+  if (!ti->t_run)
+    su_timer_set(t, print_stamp, ti);
+
+  printf("timer interval %f\n", 1000 * su_time_diff(now, prev));
+
+  if (++ti->t_times >= 10)
+    su_timer_reset(t);
+}
+
+void
+print_X(struct tester *x, su_timer_t *t1, struct timing *ti)
+{
+  su_timer_set(t1, print_X, ti);
+  putchar('X'); fflush(stdout);
+}
+
+su_msg_r intr_msg = SU_MSG_R_INIT;
+
+static RETSIGTYPE intr_handler(int signum)
+{
+  su_msg_send(intr_msg);
+}
+
+static void test_break(struct tester *tester, su_msg_r msg, su_msg_arg_t *arg)
+{
+  su_root_break(tester->root);
+}
+
+void
+end_test(struct tester *tester, su_timer_t *t, struct timing *ti)
+{
+  su_timer_destroy(t);
+  su_timer_reset(tester->t);
+  su_timer_reset(tester->t1);
+  su_root_break(tester->root);
+}
+
+void
+increment(struct tester *tester, su_timer_t *t, struct timing *ti)
+{
+  tester->times++;
+
+  if ((void *)ti == (void*)tester->sentinel)
+    su_root_break(tester->root);
+}
+
+void
+usage(char const *name)
+{
+  fprintf(stderr, "usage: %s [-1r] [-Nnum] [interval]\n", name);
+  exit(1);
+}
+
+/*
+ * test su_timer functionality:
+ *
+ * Create a timer, executing print_stamp() in every 20 ms
+ */
+int main(int argc, char *argv[])
+{
+  su_root_t *root;
+  su_timer_t *t, *t1, *t_end;
+  su_timer_t **timers;
+  su_duration_t interval = 60;
+  char *argv0 = argv[0];
+  char *s;
+  int use_t1 = 0;
+  su_time_t now, started;
+  intptr_t i, N = 500;
+
+  struct timing timing[1] = {{ 0 }};
+  struct tester tester[1] = {{ 0 }};
+
+  while (argv[1] && argv[1][0] == '-') {
+    char *o = argv[1] + 1;
+    while (*o) {
+      if (*o == '1')
+	o++, use_t1 = 1;
+      else if (*o == 'r')
+	o++, timing->t_run = 1;
+      else if (*o == 'N') {
+	if (o[1])
+	  N = strtoul(o + 1, &o, 0);
+	else if (argv[2])
+	  N = strtoul(argv++[2], &o, 0);
+	break;
+      }
+      else
+	break;
+
+    }
+    if (*o)
+      usage(argv0);
+    argv++;
+  }
+
+  if (argv[1]) {
+    interval = strtoul(argv[1], &s, 10);
+
+    if (interval == 0 || s == argv[1])
+      usage(argv0);
+  }
+
+  su_init(); atexit(su_deinit);
+
+  tester->root = root = su_root_create(tester);
+
+  su_msg_create(intr_msg,
+		su_root_task(root),
+		su_root_task(root),
+		test_break, 0);
+
+  signal(SIGINT, intr_handler);
+#if HAVE_SIGPIPE
+  signal(SIGPIPE, intr_handler);
+  signal(SIGQUIT, intr_handler);
+  signal(SIGHUP, intr_handler);
+#endif
+
+  t = su_timer_create(su_root_task(root), interval);
+  t1 = su_timer_create(su_root_task(root), 1);
+  t_end = su_timer_create(su_root_task(root), 20 * interval);
+
+  if (t == NULL || t1 == NULL || t_end == NULL)
+    su_perror("su_timer_create"), exit(1);
+
+  tester->t = t, tester->t1 = t1;
+
+  timing->t_prev = su_now();
+
+  if (timing->t_run)
+    su_timer_run(t, print_stamp, timing);
+  else
+    su_timer_set(t, print_stamp, timing);
+
+  if (use_t1)
+    su_timer_set(t1, print_X, NULL);
+
+  su_timer_set(t_end, end_test, NULL);
+
+  su_root_run(root);
+
+  su_msg_destroy(intr_msg);
+
+  su_timer_destroy(t);
+  su_timer_destroy(t1);
+
+  if (timing->t_times != 10) {
+    fprintf(stderr, "%s: t expired %d times (expecting 10)\n",
+	    argv0, timing->t_times);
+    return 1;
+  }
+
+  /* Insert timers in order */
+  timers = calloc(N, sizeof *timers);
+  if (!timers) { perror("calloc"); exit(1); }
+
+  now = started = su_now();
+
+  for (i = 0; i < N; i++) {
+    t = su_timer_create(su_root_task(root), 1000);
+    if (!t) { perror("su_timer_create"); exit(1); }
+    if (++now.tv_usec == 0) ++now.tv_sec;
+    su_timer_set_at(t, increment, (void *)i, now);
+    timers[i] = t;
+  }
+
+  tester->sentinel = (void*)(i - 1);
+
+  su_root_run(root);
+
+  printf("Processing %u timers took %f millisec (%f expected)\n",
+	 (unsigned)i, su_time_diff(su_now(), started) * 1000, (double)i / 1000);
+
+  for (i = 0; i < N; i++) {
+    su_timer_destroy(timers[i]);
+  }
+
+  su_root_destroy(root);
+
+  su_deinit();
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+2006-10-19  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* tport.c (tport_is_shutdown, tport_is_closed): Added to 
+	public API.
+
+2006-01-15  Martti Mela  <martti.mela at nokia.com>
+
+	* tport.c: integrated initial new STUN support.
+
+2005-11-08  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Renamed tport_test.c as test_tport.c.
+
+2005-10-27  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added tls_version[] to tport/tport_tls.[hc].
+
+    M ./libsofia-sip-ua/tport/tport_tls.c -2 +4
+    M ./libsofia-sip-ua/tport/tport_tls.h -3 +2
+
+2005-10-24  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* tport.c (tport_bind_server): Avoid segfault
+	if init for a NAT traversal mechanism has failed.
+	
+2005-10-18  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+	* Feature #1326002.
+	
+  * Added stun_test(), but not running it.
+
+    M ./libsofia-sip-ua/tport/tport_test.c +32
+
+  * Passing tags to stun_engine_tcreate().
+
+    M ./libsofia-sip-ua/tport/tport.c -17 +14
+
+2005-09-08  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* tport_test.c: Fixed error when building without
+	SSL support.
+
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+PROJECT_NAME         = "tport"
+OUTPUT_DIRECTORY     = ../docs/html/tport
+
+INPUT 		     = tport.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES            += \
+	../docs/su.doxytags=../su \
+	../docs/msg.doxytags=../msg
+
+GENERATE_TAGFILE    = ../docs/tport.doxytags
+
+EXCLUDE_PATTERNS   += test_*.[hc] torture_*.[hc]
+
+ALIASES +=

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,81 @@
+#
+# Makefile.am @template@ for tport module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 		-I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../stun -I../stun \
+			-I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	libtport.la
+
+bin_PROGRAMS = 		
+
+check_PROGRAMS =	test_tport
+
+TESTS =			test_tport
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/tport.h sofia-sip/tport_tag.h \
+			sofia-sip/tport_plugins.h
+
+TLS_SRC =		tport_type_tls.c tport_tls.c tport_tls.h
+
+if HAVE_TLS
+USE_TLS_SRC = 		$(TLS_SRC)
+endif
+
+libtport_la_SOURCES = 	tport.c tport_logging.c \
+			tport_stub_stun.c tport_stub_sigcomp.c \
+			tport_type_udp.c tport_type_tcp.c tport_type_sctp.c \
+			tport_type_connect.c tport_type_stun.c \
+			tport_internal.h \
+			tport_tag.c tport_tag_ref.c $(USE_TLS_SRC)
+
+# to make sure all files end up in the dist package
+EXTRA_libtport_la_SOURCES = $(TLS_SRC) 
+
+# Disable for now
+EXTRA_libtport_la_SOURCES += tport_sigcomp.c tport_threadpool.c
+
+BUILT_SOURCES =		tport_tag_ref.c
+
+COVERAGE_INPUT = 	$(libtport_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		libtport.la \
+			../stun/libstun.la \
+			../sresolv/libsresolv.la \
+			../ipt/libipt.la \
+			../http/libhttp.la \
+			../msg/libtest_msg.a ../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_tport_LDFLAGS = 	-static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile tport.docs \
+			certificates.html agent.pem cafile.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,786 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for tport module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libtport_la_SOURCES) $(EXTRA_libtport_la_SOURCES) test_tport.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS =
+check_PROGRAMS = test_tport$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/tport
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtport_la_LIBADD =
+am__libtport_la_SOURCES_DIST = tport.c tport_logging.c \
+	tport_stub_stun.c tport_stub_sigcomp.c tport_type_udp.c \
+	tport_type_tcp.c tport_type_sctp.c tport_type_connect.c \
+	tport_type_stun.c tport_internal.h tport_tag.c tport_tag_ref.c \
+	tport_type_tls.c tport_tls.c tport_tls.h
+am__objects_1 = tport_type_tls.lo tport_tls.lo
+ at HAVE_TLS_TRUE@am__objects_2 = $(am__objects_1)
+am_libtport_la_OBJECTS = tport.lo tport_logging.lo tport_stub_stun.lo \
+	tport_stub_sigcomp.lo tport_type_udp.lo tport_type_tcp.lo \
+	tport_type_sctp.lo tport_type_connect.lo tport_type_stun.lo \
+	tport_tag.lo tport_tag_ref.lo $(am__objects_2)
+libtport_la_OBJECTS = $(am_libtport_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" \
+	"$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+test_tport_SOURCES = test_tport.c
+test_tport_OBJECTS = test_tport.$(OBJEXT)
+test_tport_LDADD = $(LDADD)
+test_tport_DEPENDENCIES = libtport.la ../stun/libstun.la \
+	../sresolv/libsresolv.la ../ipt/libipt.la ../http/libhttp.la \
+	../msg/libtest_msg.a ../msg/libmsg.la ../url/liburl.la \
+	../bnf/libbnf.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libtport_la_SOURCES) $(EXTRA_libtport_la_SOURCES) \
+	test_tport.c
+DIST_SOURCES = $(am__libtport_la_SOURCES_DIST) \
+	$(EXTRA_libtport_la_SOURCES) test_tport.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+			-I$(srcdir)/../stun -I../stun \
+			-I$(srcdir)/../ipt -I../ipt \
+			-I$(srcdir)/../msg -I../msg \
+			-I$(srcdir)/../http -I../http \
+			-I$(srcdir)/../url -I../url \
+			-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libtport.la
+TESTS = test_tport
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+			sofia-sip/tport.h sofia-sip/tport_tag.h \
+			sofia-sip/tport_plugins.h
+
+TLS_SRC = tport_type_tls.c tport_tls.c tport_tls.h
+ at HAVE_TLS_TRUE@USE_TLS_SRC = $(TLS_SRC)
+libtport_la_SOURCES = tport.c tport_logging.c \
+			tport_stub_stun.c tport_stub_sigcomp.c \
+			tport_type_udp.c tport_type_tcp.c tport_type_sctp.c \
+			tport_type_connect.c tport_type_stun.c \
+			tport_internal.h \
+			tport_tag.c tport_tag_ref.c $(USE_TLS_SRC)
+
+
+# to make sure all files end up in the dist package
+
+# Disable for now
+EXTRA_libtport_la_SOURCES = $(TLS_SRC) tport_sigcomp.c \
+	tport_threadpool.c
+BUILT_SOURCES = tport_tag_ref.c
+COVERAGE_INPUT = $(libtport_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libtport.la \
+			../stun/libstun.la \
+			../sresolv/libsresolv.la \
+			../ipt/libipt.la \
+			../http/libhttp.la \
+			../msg/libtest_msg.a ../msg/libmsg.la \
+			../url/liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_tport_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile tport.docs \
+			certificates.html agent.pem cafile.pem
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/tport/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/tport/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libtport.la: $(libtport_la_OBJECTS) $(libtport_la_DEPENDENCIES) 
+	$(LINK)  $(libtport_la_LDFLAGS) $(libtport_la_OBJECTS) $(libtport_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	     || test -f $$p1 \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_tport$(EXEEXT): $(test_tport_OBJECTS) $(test_tport_DEPENDENCIES) 
+	@rm -f test_tport$(EXEEXT)
+	$(LINK) $(test_tport_LDFLAGS) $(test_tport_OBJECTS) $(test_tport_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_tport.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_logging.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_sigcomp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_stub_sigcomp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_stub_stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_threadpool.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tls.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_connect.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_sctp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_tcp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_tls.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_udp.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-binPROGRAMS install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-binPROGRAMS \
+	uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+<title>Generating SSL/TLS certificates for SIP agents and proxies</title>
+</head>
+<body>
+<h1>Generating SSL/TLS certificates for SIP agents and proxies</h1>
+<h2>Prerequisites</h2>
+The openssl v0.96 or higher must be installed to create the certificates.
+
+<h2>To generate the random seed file</h2>
+<strong><pre>$ tport_rand tls_seed.dat
+</pre>
+</strong>
+
+<h2>To generate the root authority certificate</h2>
+<strong><pre>
+$ make_root_cert.pl \
+     -cn &lt;root common name&gt;\
+     -dns &lt;comma separated list of root dns names&gt;\
+    [-prefix &lt;prefix for the generated files&gt; (default root)]\
+    [-rand &lt;random seed file&gt; (default tls_seed.dat)]</pre></strong>
+
+This command will generate files <strong>&lt;prefix&gt;key.pem</strong> (root private key), 
+<strong>&lt;prefix&gt;cert.pem</strong> (root certificate) and <strong>&lt;prefix&gt;.pem</strong> (combination
+of the key and the certificate). The latter file will be used to sign the node certificates.
+
+<h2>To generate a certificate for a single node (user agent or proxy)</h2>
+<strong><pre>
+$ make_node_cert.pl \
+     -cn &lt;node common name&gt;\
+     -dns &lt;comma separated list of node dns names&gt;\
+    [-ca &lt;cafile&gt; (default root.pem)]\
+    [-prefix &lt;prefix for the generated files&gt; (default agent)]\
+    [-rand &lt;random seed file&gt; (default tls_seed.dat)]
+</pre></strong>
+This command will generate files <strong>&lt;prefix&gt;key.pem </strong> (node private key), 
+<strong>&lt;prefix&gt;cert.pem</strong> (node certificate) and <strong>&lt;prefix&gt;.pem</strong> (combination
+of the key and the certificate). The certificate has been signed with ca certificate
+contained in <strong>&lt;cafile&gt;</strong>.
+
+<h2>Installing the certificates to the nodes</h2>
+
+<ol>
+
+<li>Copy the root certificate file (<strong>rootcert.pem</strong> by default - <strong>not root.pem or rootkey.pem!</strong>), 
+the combined node certificate+key file (<strong>agent.pem</strong>) and <strong>tls_seed.dat</strong> to the tls configuration
+directory (default <strong>$HOME/.sip/auth</strong>)</li>
+
+<li>Rename <strong>rootcert.pem</strong> as <strong>cafile.pem</strong></li>
+</ol>
+<p>
+<strong>Note that files agent.pem and tls_seed.dat must be kept secret to
+ensure secure connection</strong>  
+</p>
+
+</ol>
+</body>
+</html>
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+use strict;
+use Getopt::Long;
+use File::Temp;
+
+my $cn;
+my @dns = ();
+my $cafile = "root.pem";
+my $prefix = "agent";
+my $rand = "tls_seed.dat";
+my $help = 0;
+
+GetOptions('help' => \$help,
+	   'cn=s' => \$cn, 
+	   'dns=s' => \@dns, 
+	   'ca=s' => \$cafile,
+	   'prefix=s' => \$prefix,
+           'rand=s' => \$rand);
+
+ at dns = split(/,/,join(',', at dns));
+
+if ($help || !$cn || !@dns) {
+  print "Usage: make_node_cert -cn <common name>\n".
+        "                      -dns <comma separated list of dns names>\n".
+        "                     [-ca cafile (default root.pem)]\n".
+        "                     [-prefix prefix (default agent)]\n".
+	"                     [-rand <random seed file>]\n";
+  exit 0;
+}
+
+$_ = "DNS:$_" for @dns;
+
+my $dnsstring = join(',', @dns);
+
+my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1);
+
+print $fh <<"EOF";
+[ req ]
+default_bits		= 1024
+prompt                  = no
+distinguished_name	= req_dn
+
+[ req_dn ]
+commonName		= $cn
+
+[ ext ]
+basicConstraints=CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+subjectAltName=$dnsstring
+keyUsage=digitalSignature:TRUE,keyEncipherment:TRUE
+EOF
+
+system("openssl req -newkey rsa -nodes -keyout ${prefix}key.pem -sha1 -out ${prefix}req.pem -config $filename -rand $rand");
+
+system("openssl x509 -req -in ${prefix}req.pem -sha1 -extensions ext -CA $cafile -CAkey $cafile -out ${prefix}cert.pem -CAcreateserial -extfile $filename");
+
+system("cat ${prefix}cert.pem ${prefix}key.pem >${prefix}.pem");

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use strict;
+use Getopt::Long;
+use File::Temp;
+
+my $cn;
+my @dns = ();
+my $prefix = "root";
+my $rand = "tls_seed.dat";
+my $help = 0;
+
+GetOptions('help' => \$help,
+	   'cn=s' => \$cn,
+	   'dns=s' => \@dns,
+	   'prefix=s' => \$prefix,
+           'rand=s' => \$rand);
+
+ at dns = split(/,/,join(',', at dns));
+
+if ($help || !$cn || !@dns) {
+  print "Usage: make_root_cert -cn <common name>\n".
+        "                      -dns <comma separated list of dns names>\n". 
+	"                     [-prefix <name prefix>]\n".
+	"                     [-rand <random seed file>\n]";
+  exit 0;
+}
+
+$_ = "DNS:$_" for @dns;
+
+my $dnsstring = join(',', @dns);
+
+my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1);
+
+print $fh <<"EOF";
+[ req ]
+default_bits		= 1024
+prompt                  = no
+distinguished_name	= req_dn
+
+[ req_dn ]
+commonName		= $cn
+
+[ ext ]
+basicConstraints = CA:TRUE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+subjectAltName=$dnsstring
+EOF
+
+system("openssl req -newkey rsa -nodes -keyout ${prefix}key.pem -sha1 -out ${prefix}req.pem -config $filename -rand $rand");
+
+system("openssl x509 -req -in ${prefix}req.pem -sha1 -extensions ext -signkey ${prefix}key.pem -out ${prefix}cert.pem -extfile $filename");
+
+system("cat ${prefix}cert.pem ${prefix}key.pem >${prefix}.pem");
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+basedir=`dirname $0`
+
+mkdir -p test/server
+mkdir -p test/client
+
+./tport_rand tls_seed.dat
+
+cp tls_seed.dat test/server
+cp tls_seed.dat test/client
+
+./make_root_cert.pl -cn test_root -dns test_root.sip.nokia.com
+cp rootcert.pem test/client/cafile.pem
+cp rootcert.pem test/server/cafile.pem
+
+./make_node_cert.pl -cn test_client -dns test_client.sip.nokia.com
+cp agent.pem test/client
+
+./make_node_cert.pl -cn test_server -dns test_server.sip.nokia.com
+cp agent.pem test/server
+
+rm agent*.pem
+rm root*.pem
+rm tls_seed.dat
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,421 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_H
+/** Defined when <sofia-sip/tport.h> has been included. */
+#define TPORT_H
+/**@file sofia-sip/tport.h
+ * @brief Transport interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef TPORT_TAG_H
+#include <sofia-sip/tport_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct tport_s;
+#ifndef TPORT_T
+#define TPORT_T struct tport_s
+typedef TPORT_T tport_t;
+#endif
+
+#ifndef TP_STACK_T
+#ifndef TP_AGENT_T
+#define TP_STACK_T struct tp_stack_s
+#else
+#define TP_STACK_T TP_AGENT_T
+#endif
+#endif
+/** Type of stack object */
+typedef TP_STACK_T tp_stack_t;
+
+#ifndef TP_MAGIC_T
+/** Type of transport-protocol-specific context.  @sa @ref tp_magic */
+#define TP_MAGIC_T struct tp_magic_s
+#endif
+/** Type of transport-protocol-specific context object. */
+typedef TP_MAGIC_T tp_magic_t;
+
+#ifndef TP_CLIENT_T
+#define TP_CLIENT_T struct tp_client_s
+#endif
+/** Transaction object given as a reference to the transport.
+ *
+ *  This type is used when transport reports errors with pending requests.
+ */
+typedef TP_CLIENT_T tp_client_t;
+
+struct sigcomp_compartment;
+struct sigcomp_udvm;
+
+/** Interface towards stack. */
+typedef struct {
+  int      tpac_size;
+
+  /** Function used to pass a received message to the protocol stack */
+  void   (*tpac_recv)(tp_stack_t *, tport_t *, msg_t *msg, tp_magic_t *magic,
+		      su_time_t received);
+
+  /** Function used to indicate an error to the protocol stack */
+  void   (*tpac_error)(tp_stack_t *, tport_t *,
+		       int errcode, char const *remote);
+
+  /** Ask stack to allocate a message. */
+  msg_t *(*tpac_alloc)(tp_stack_t *, int flags,
+		       char const [], usize_t,
+		       tport_t const *, tp_client_t *);
+
+  /** Indicate stack that address has changed */
+  void (*tpac_address)(tp_stack_t *, tport_t *);
+
+} tport_stack_class_t;
+
+/* Compatibility */
+typedef tport_stack_class_t tp_stack_class_t;
+
+/** Callback to report error by pending requests. */
+typedef void tport_pending_error_f(tp_stack_t *, tp_client_t *,
+				   tport_t *, msg_t *msg, int error);
+
+enum {
+  /** Maximum number of messages in send queue. */
+  TPORT_QUEUESIZE = 64
+};
+
+
+/* AI extension flags - these must not overlap with existing AI flags. */
+
+/** Message is to be sent/received compressed */
+#define TP_AI_COMPRESSED 0x01000
+/** Message is to be sent/received on secure connection */
+#define TP_AI_SECURE     0x02000
+
+/** Halfclose (shutdown(c, 1)) connection after sending message */
+#define TP_AI_SHUTDOWN   0x04000
+/** Close connection (shutdown(c, 2)) after sending message */
+#define TP_AI_CLOSE      0x08000
+
+/** Address was inaddr_any */
+#define TP_AI_ANY        0x80000
+
+#define TP_AI_MASK       0xff000
+
+/** Maximum size of a @e host:port string, including final NUL. */
+#define TPORT_HOSTPORTSIZE (55)
+
+/** Transport name.
+ *
+ * This structure represents the address of the transport in textual format.
+ * For primary transports, the transport name contains the local address,
+ * for secondary transports, the peer address.
+ *
+ * The tpn_ident specifies the transport identifier used to make difference
+ * between connectivity domains.
+ */
+typedef struct {
+  char const *tpn_proto;	/**< Protocol name ("udp", "tcp", etc.) */
+  char const *tpn_canon;	/**< Node DNS name (if known). */
+  char const *tpn_host;		/**< Node address in textual format */
+  char const *tpn_port;		/**< Port number in textual format. */
+  char const *tpn_comp;		/**< Compression algorithm (NULL if none) */
+  char const *tpn_ident;	/**< Transport identifier (NULL if none) */
+} tp_name_t;
+
+#define TPN_FORMAT "%s/%s:%s%s%s%s%s"
+
+#define TPN_ARGS(n)							\
+  (n)->tpn_proto, (n)->tpn_host, (n)->tpn_port,				\
+  (n)->tpn_comp ? ";comp=" : "", (n)->tpn_comp ? (n)->tpn_comp : "",    \
+  (n)->tpn_ident ? "/" : "", (n)->tpn_ident ? (n)->tpn_ident : ""
+
+/** Create first primary transport. */
+TPORT_DLL tport_t *tport_tcreate(tp_stack_t *stack,
+				 tport_stack_class_t const *tpac,
+				 su_root_t *root,
+				 tag_type_t tag, tag_value_t value, ...);
+
+/** Bind transports to network. */
+TPORT_DLL int tport_tbind(tport_t *self,
+			  tp_name_t const *tpn,
+			  char const * const transports[],
+			  tag_type_t tag, tag_value_t value, ...);
+
+/** Get transport parameters. */
+TPORT_DLL int tport_get_params(tport_t const *, tag_type_t tag, tag_value_t value, ...);
+
+/** Set transport parameters. */
+TPORT_DLL int tport_set_params(tport_t *self, tag_type_t tag, tag_value_t value, ...);
+
+/** Destroy transport(s). */
+TPORT_DLL void tport_destroy(tport_t *tport);
+
+/** Shutdown a transport connection. */
+TPORT_DLL int tport_shutdown(tport_t *tport, int how);
+
+/** Create a new reference to a transport object. */
+TPORT_DLL tport_t *tport_ref(tport_t *tp);
+
+/** Destroy reference to a transport object. */
+TPORT_DLL void tport_unref(tport_t *tp);
+
+/** Create a new transport reference. @deprecated Use tport_ref(). */
+TPORT_DLL tport_t *tport_incref(tport_t *tp);
+
+/** Destroy a transport reference. @deprecated Use tport_unref(). */
+TPORT_DLL void tport_decref(tport_t **tp);
+
+/** Send a message using transport. */
+TPORT_DLL tport_t *tport_tsend(tport_t *, msg_t *, tp_name_t const *,
+			       tag_type_t, tag_value_t, ...);
+
+/** Queue a message to transport. */
+TPORT_DLL int tport_tqueue(tport_t *, msg_t *, tag_type_t, tag_value_t, ...);
+
+/** Return number of queued messages. */
+TPORT_DLL isize_t tport_queuelen(tport_t const *self);
+
+/** Send a queued message (and queue another, if required). */
+TPORT_DLL int tport_tqsend(tport_t *, msg_t *, msg_t *, 
+			   tag_type_t, tag_value_t, ...);
+
+/** Stop reading from socket until tport_continue() is called. */
+TPORT_DLL int tport_stall(tport_t *self);
+
+/** Continue reading from socket. */
+TPORT_DLL int tport_continue(tport_t *self);
+
+/** Mark message as waiting for a response. */
+TPORT_DLL int tport_pend(tport_t *self, msg_t *msg,
+			 tport_pending_error_f *callback, tp_client_t *client);
+
+/** Do not wait for response anymore. */
+TPORT_DLL int tport_release(tport_t *self, int pendd,
+			    msg_t *msg, msg_t *reply, tp_client_t *client,
+			    int still_pending);
+
+/** Return true if transport is master. */
+TPORT_DLL int tport_is_master(tport_t const *self);
+
+/** Return true if transport is primary. */
+TPORT_DLL int tport_is_primary(tport_t const *self);
+
+/** Return nonzero if transport is public. */
+TPORT_DLL int tport_is_public(tport_t const *self);
+
+/** Return true if transport is secondary. */
+TPORT_DLL int tport_is_secondary(tport_t const *self);
+
+/** Return true if transport is reliable, false otherwise */
+TPORT_DLL int tport_is_reliable(tport_t const *tport);
+
+/** Return true if transport is a stream (no message boundaries). */
+TPORT_DLL int tport_is_stream(tport_t const *tport);
+
+/** Return true if transport is dgram-based. */
+TPORT_DLL int tport_is_dgram(tport_t const *tport);
+
+/** Return true if transport supports IPv4 */
+TPORT_DLL int tport_has_ip4(tport_t const *tport);
+
+/** Return true if transport supports IPv6 */
+TPORT_DLL int tport_has_ip6(tport_t const *tport);
+
+/** Test if transport is udp. */
+TPORT_DLL int tport_is_udp(tport_t const *self);
+
+/** Test if transport is tcp. */
+TPORT_DLL int tport_is_tcp(tport_t const *self);
+
+/** Test if transport has TLS. */
+TPORT_DLL int tport_has_tls(tport_t const *tport);
+
+/** Return true if transport is being updated. */
+TPORT_DLL int tport_is_updating(tport_t const *self);
+
+/** Test if transport has been closed (added to @VERSION_1_12_4 ) */
+TPORT_DLL int tport_is_closed(tport_t const *self);
+
+/** Test if transport has been shut down (added to @VERSION_1_12_4 ) */
+TPORT_DLL int tport_is_shutdown(tport_t const *self);
+
+/** Test if transport is connected. @NEW_1_12_5 */
+TPORT_DLL int tport_is_connected(tport_t const *self);
+
+/** Set transport magic. */
+TPORT_DLL void tport_set_magic(tport_t *self, tp_magic_t *magic);
+
+/** Get transport magic. */
+TPORT_DLL tp_magic_t *tport_magic(tport_t const *tport);
+
+/** Get transport name. */
+TPORT_DLL tp_name_t const *tport_name(tport_t const *tport);
+
+/** Get transport address list. */
+TPORT_DLL su_addrinfo_t const *tport_get_address(tport_t const *tport);
+
+/** Get transport ident. */
+TPORT_DLL char const *tport_ident(tport_t const *self);
+
+/** Get primary transport (or self, if already parent) */
+TPORT_DLL tport_t *tport_parent(tport_t const *self);
+
+/** Flush idle connections */
+TPORT_DLL int tport_flush(tport_t *);
+
+/** Get primary transports */
+TPORT_DLL tport_t *tport_primaries(tport_t const *tport);
+
+/** Get next transport */
+TPORT_DLL tport_t *tport_next(tport_t const *tport);
+
+/** Get secondary transports. */
+TPORT_DLL tport_t *tport_secondary(tport_t const *tport);
+
+/** Get a protocol corresponding to the protocol name. */
+TPORT_DLL tport_t *tport_by_protocol(tport_t const *self, char const *proto);
+
+/** Get transport by interface identifier and protocol name. */
+TPORT_DLL tport_t *tport_primary_by_name(tport_t const *self, tp_name_t const *tpn);
+
+/** Get a transport corresponding to the name */
+TPORT_DLL tport_t *tport_by_name(tport_t const *self, tp_name_t const  *);
+
+/** Create a transport name corresponding to the URL. */
+TPORT_DLL int tport_name_by_url(su_home_t *, tp_name_t *,
+				url_string_t const *us);
+
+/** Return source transport object for delivered message */
+TPORT_DLL tport_t *tport_delivered_by(tport_t const *tp, msg_t const *msg);
+
+/** Return source transport name for delivered message */
+TPORT_DLL int tport_delivered_from(tport_t *tp, msg_t const *msg,
+				   tp_name_t name[1]);
+
+/** Check if transport named is already resolved */
+TPORT_DLL int tport_name_is_resolved(tp_name_t const *);
+
+/** Duplicate a transport name. */
+TPORT_DLL int tport_name_dup(su_home_t *,
+			     tp_name_t *dst, tp_name_t const *src);
+
+/** Convert a socket address to a transport name. */
+TPORT_DLL int tport_convert_addr(su_home_t *home,
+				 tp_name_t *tpn,
+				 char const *protoname,
+				 char const *canon,
+				 su_sockaddr_t const *su);
+
+/** Print host and port separated with ':' to a string. */
+TPORT_DLL char *tport_hostport(char buf[], isize_t bufsize,
+			       su_sockaddr_t const *su, int with_port);
+
+/** Initialize STUN keepalives. */
+TPORT_DLL int tport_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+			      tag_type_t tag, tag_value_t value, ...);
+
+/* ---------------------------------------------------------------------- */
+/* SigComp-related functions */
+
+#ifndef TPORT_COMPRESSOR
+#define TPORT_COMPRESSOR struct tport_compressor
+#endif
+
+typedef TPORT_COMPRESSOR tport_compressor_t;
+
+TPORT_DLL int tport_can_send_sigcomp(tport_t const *self);
+TPORT_DLL int tport_can_recv_sigcomp(tport_t const *self);
+
+TPORT_DLL int tport_has_compression(tport_t const *self, char const *comp);
+TPORT_DLL int tport_set_compression(tport_t *self, char const *comp);
+
+/** Set SigComp option. */
+TPORT_DLL
+int tport_sigcomp_option(tport_t const *self,
+			 struct sigcomp_compartment *cc,
+			 char const *option);
+
+/** Obtain a SigComp compartment with given name. */
+TPORT_DLL struct sigcomp_compartment *
+tport_sigcomp_compartment(tport_t *self,
+			  char const *name, isize_t namelen,
+			  int create_if_needed);
+
+TPORT_DLL struct sigcomp_compartment *
+tport_compartment_incref(struct sigcomp_compartment *cc);
+
+TPORT_DLL void
+tport_compartment_decref(struct sigcomp_compartment **pointer_to_cc);
+
+/** Assign a SigComp compartment to a connection-oriented tport. */
+TPORT_DLL int
+tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *);
+
+/** Test if a SigComp compartment is assigned to a tport. */
+TPORT_DLL int tport_has_sigcomp_assigned(tport_t const *self);
+
+/** Accept SigComp message */
+TPORT_DLL int
+tport_sigcomp_accept(tport_t *self,
+		     struct sigcomp_compartment *cc,
+		     msg_t *msg);
+
+/** Get compressor context with which the request was delivered */
+TPORT_DLL int
+tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
+			  tport_compressor_t **return_compressor);
+
+/** Shutdown SigComp compartment */
+TPORT_DLL int
+tport_sigcomp_close(tport_t *self,
+		    struct sigcomp_compartment *cc,
+		    int how);
+
+/** Set SigComp compartment lifetime. */
+TPORT_DLL int
+tport_sigcomp_lifetime(tport_t *self,
+		       struct sigcomp_compartment *,
+		       unsigned lifetime_in_ms,
+		       int only_expand);
+
+
+SOFIA_END_DECLS
+
+#endif /* TPORT_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_PLUGINS_H
+/** Defined when <sofia-sip/tport_plugins.h> has been included. */
+#define TPORT_PLUGINS_H
+
+/**@file sofia-sip/tport_plugins.h
+ * @brief Transport plugin interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:22:22 EEST 2006 ppessi
+ */
+
+/* -- STUN Plugin ------------------------------------------------------- */
+
+#ifndef TPORT_STUN_SERVER_T
+#define TPORT_STUN_SERVER_T struct tport_stun_server_s
+#endif
+/** Safe type for tport server object */
+typedef TPORT_STUN_SERVER_T tport_stun_server_t;
+
+typedef struct {
+  int vst_size;
+  tport_stun_server_t *(*vst_create)(su_root_t *root, tagi_t const *tags);
+  void (*vst_destroy)(tport_stun_server_t *);
+  int (*vst_add_socket)(tport_stun_server_t *, su_socket_t socket);
+  int (*vst_remove_socket)(tport_stun_server_t *, su_socket_t socket);
+  void (*vst_request)(tport_stun_server_t *server, su_socket_t socket,
+		     void *msg, ssize_t msglen,
+		     void *addr, socklen_t addrlen);
+} tport_stun_server_vtable_t;
+
+SOFIAPUBFUN int tport_plug_in_stun_server(tport_stun_server_vtable_t const *);
+
+
+/* -- SigComp Plugin ---------------------------------------------------- */
+
+/* We already use these SigComp types in applications */
+
+struct sigcomp_udvm;
+struct sigcomp_compartment;
+
+typedef struct tport_comp_vtable_s tport_comp_vtable_t;
+
+struct tport_comp_vtable_s {
+  /* NOTE: this will change! Unstable! Do not use! */
+  int vsc_size;
+
+  char const *vsc_compname;
+  size_t vsc_sizeof_context;
+
+  int (*vsc_init_comp)(tp_stack_t *,
+		       tport_t *,
+		       tport_compressor_t *,
+		       char const *comp_name,
+		       tagi_t const *tags);
+
+  void (*vsc_deinit_comp)(tp_stack_t *,
+			  tport_t *,
+			  tport_compressor_t *);
+
+  char const *(*vsc_comp_name)(tport_compressor_t const *master_sc,
+			       char const *compression,
+			       tagi_t const *tags);
+
+  /* Mapping of public tport API */
+
+  int (*vsc_can_send_comp)(tport_compressor_t const *);
+  int (*vsc_can_recv_comp)(tport_compressor_t const *);
+
+  int (*vsc_set_comp_name)(tport_t const *self, 
+			   tport_compressor_t const *return_sc,
+			   char const *comp);
+
+  int (*vsc_sigcomp_option)(tport_t const *self,
+			    struct sigcomp_compartment *cc,
+			    char const *option);
+
+  struct sigcomp_compartment *
+  (*vsc_sigcomp_compartment)(tport_t *self,
+			     char const *name, int namelen,
+			     int create_if_needed);
+
+  struct sigcomp_compartment * 
+  (*vsc_compartment_incref)(struct sigcomp_compartment *cc);
+
+  void (*vsc_compartment_decref)(struct sigcomp_compartment **pointer_to_cc);
+
+  int (*vsc_set_compartment)(tport_t *self,
+			     tport_compressor_t *,
+			     struct sigcomp_compartment *);
+
+  struct sigcomp_compartment *
+  (*vsc_get_compartment)(tport_t const *self,
+			 tport_compressor_t const *);
+
+  int (*vsc_has_sigcomp_assigned)(tport_compressor_t const *comp);
+
+  int (*vsc_sigcomp_accept)(tport_t *self,
+			    tport_compressor_t const *comp,
+			    struct sigcomp_compartment *cc,
+			    msg_t *msg);
+
+  int (*vsc_delivered_using_udvm)(tport_t *tp,
+				  msg_t const *msg,
+				  struct sigcomp_udvm **return_pointer_to_udvm,
+				  int remove);
+
+  int (*vsc_sigcomp_close)(tport_t *self,
+			   struct sigcomp_compartment *cc,
+			   int how);
+
+  int (*vsc_sigcomp_lifetime)(tport_t *self,
+			      struct sigcomp_compartment *,
+			      unsigned lifetime_in_ms,
+			      int only_expand);
+
+  /* Internal API */
+
+  struct sigcomp_udvm **(*vsc_get_udvm_slot)(tport_t *self);
+
+  struct sigcomp_compartment *
+  (*vsc_sigcomp_assign_if_needed)(tport_t *self,
+				  struct sigcomp_compartment *cc);
+
+  void (*vsc_accept_incomplete)(tport_t const *self, 
+				tport_compressor_t *sc,
+				msg_t *msg);
+
+  int (*vsc_recv_comp)(tport_t const *self, 
+		       tport_compressor_t *sc,
+		       msg_t **in_out_msg,
+		       su_sockaddr_t *from,
+		       socklen_t fromlen);
+
+  ssize_t (*vsc_send_comp)(tport_t const *self,
+		       msg_t *msg, 
+		       msg_iovec_t iov[], 
+		       size_t iovused,
+		       struct sigcomp_compartment *cc,
+		       tport_compressor_t *sc);
+
+
+};
+
+SOFIAPUBFUN int tport_plug_in_comp(tport_comp_vtable_t const *);
+
+#endif /* !defined(TPORT_PLUGINS_H) */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_TAG_H
+/** Defined when <sofia-sip/tport_tag.h> has been included. */
+#define TPORT_TAG_H
+
+/**@file sofia-sip/tport_tag.h
+ * @brief Tags for tport module.
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Sat Oct 12 18:39:48 2002 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all tport tags. */
+TPORT_DLL extern tagi_t tport_tag_list[];
+
+/** Filter list matching any tport tag. */
+TPORT_DLL extern tagi_t tport_tags[];
+
+/** Filter tag matching any tport tag. */
+#define TPTAG_ANY()         tptag_any, ((tag_value_t)0)
+TPORT_DLL extern tag_typedef_t tptag_any;
+
+TPORT_DLL extern tag_typedef_t tptag_ident;
+/** Ident transport connection (true by default). */
+#define TPTAG_IDENT(x) tptag_ident, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_ident_ref;
+#define TPTAG_IDENT_REF(x) tptag_ident_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_reuse;
+/** Allow reusing transport connection (true by default). */
+#define TPTAG_REUSE(x) tptag_reuse, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_reuse_ref;
+#define TPTAG_REUSE_REF(x) tptag_reuse_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_fresh;
+/** Create new connection (but allow reusing new one). */
+#define TPTAG_FRESH(x) tptag_fresh, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_fresh_ref;
+#define TPTAG_FRESH_REF(x) tptag_fresh_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_server;
+/** Bind server sockets (true by default, disable with TPTAG_SERVER(0)). */
+#define TPTAG_SERVER(x) tptag_server, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_server_ref;
+#define TPTAG_SERVER_REF(x) tptag_server_ref, tag_bool_vr(&(x))
+
+/** Define how the public transport connects to Internet. 
+ *
+ * @sa TPTAG_PUBLIC(), tport_is_public().
+ */
+typedef enum tport_via {
+  tport_type_local = 0,
+  tport_type_server = 0,
+  tport_type_client = 1,
+  tport_type_stun = 2,
+  tport_type_upnp = 3,
+  tport_type_connect = 4,
+  tport_type_socks = 5,
+} tport_pri_type_t;
+
+TPORT_DLL extern tag_typedef_t tptag_public;
+/** Use a transport reaching to public Internet. */
+#define TPTAG_PUBLIC(x) tptag_public, tag_int_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_public_ref;
+#define TPTAG_PUBLIC_REF(x) tptag_public_ref, tag_int_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_mtu;
+/** Specify MTU. */
+#define TPTAG_MTU(x) tptag_mtu, tag_usize_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_mtu_ref;
+#define TPTAG_MTU_REF(x) tptag_mtu_ref, tag_usize_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_connect;
+/** Specify that tport must always use connections. */
+#define TPTAG_CONNECT(x) tptag_connect, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_connect_ref;
+#define TPTAG_CONNECT_REF(x) tptag_connect_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_queuesize;
+/** Specify the number of messages that can be queued per connection. */
+#define TPTAG_QUEUESIZE(x) tptag_queuesize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_queuesize_ref;
+#define TPTAG_QUEUESIZE_REF(x) tptag_queuesize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_error;
+/** If true, half close of a connection by remote is considered as an error. */
+#define TPTAG_SDWN_ERROR(x) tptag_sdwn_error, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_error_ref;
+#define TPTAG_SDWN_ERROR_REF(x) tptag_sdwn_error_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_after;
+/** Half-close (shutdown(c, 1) after sending the message. */
+#define TPTAG_SDWN_AFTER(x) tptag_sdwn_after, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_after_ref;
+#define TPTAG_SDWN_AFTER_REF(x) tptag_sdwn_after_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_close_after;
+/** Close of a connection after sending the message. */
+#define TPTAG_CLOSE_AFTER(x) tptag_close_after, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_close_after_ref;
+#define TPTAG_CLOSE_AFTER_REF(x) tptag_close_after_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_idle;
+/** How long transports may be idle (value in milliseconds). 
+ * If 0, zap immediately, 
+ * if UINT_MAX, leave them there (default value for now).
+ */
+#define TPTAG_IDLE(x) tptag_idle, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_idle_ref;
+#define TPTAG_IDLE_REF(x) tptag_idle_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_timeout;
+/**Timeout for incomplete incoming message  (value in milliseconds).
+ *
+ * If UINT_MAX, leave the incomplete messages there for ever.
+ * Default value for now is UINT_MAX.
+ */
+#define TPTAG_TIMEOUT(x) tptag_timeout, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_timeout_ref;
+#define TPTAG_TIMEOUT_REF(x) tptag_timeout_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sigcomp_lifetime;
+/**Default SigComp lifetime.
+ *
+ * If UINT_MAX, keep SigComp compartments around for ever.
+ *
+ * @note Experimental.
+ */
+#define TPTAG_SIGCOMP_LIFETIME(x) tptag_sigcomp_lifetime, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sigcomp_lifetime_ref;
+#define TPTAG_SIGCOMP_LIFETIME_REF(x) \
+tptag_sigcomp_lifetime_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_compartment;
+/** Pointer to SigComp compartment. */
+#define TPTAG_COMPARTMENT(x) tptag_compartment, tag_ptr_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_compartment_ref;
+#define TPTAG_COMPARTMENT_REF(x) \
+  tptag_compartment_ref, tag_ptr_vr(&(x), x)
+
+TPORT_DLL extern tag_typedef_t tptag_certificate;
+/** Path to the public key certificate directory.
+ */
+#define TPTAG_CERTIFICATE(x) tptag_certificate, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_certificate_ref;
+#define TPTAG_CERTIFICATE_REF(x) tptag_certificate_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_tls_version;
+/** Sets the TLS version (version 0 implies SSL2/SSL3).
+ */
+#define TPTAG_TLS_VERSION(x) tptag_tls_version, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_tls_version_ref;
+#define TPTAG_TLS_VERSION_REF(x) tptag_tls_version_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_trusted;
+/** Mark transport as trusted. */
+#define TPTAG_TRUSTED(x) tptag_trusted, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_trusted_ref;
+#define TPTAG_TRUSTED_REF(x) tptag_trusted_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_debug_drop;
+/** Sets the drop propability for (0..1000) incoming/outgoing packets. */
+#define TPTAG_DEBUG_DROP(x) tptag_debug_drop, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_debug_drop_ref;
+#define TPTAG_DEBUG_DROP_REF(x) tptag_debug_drop_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_rmem;
+/** Sets the maximum receive buffer in bytes for primary UDP socket. */
+#define TPTAG_UDP_RMEM(x) tptag_udp_rmem, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_rmem_ref;
+#define TPTAG_UDP_RMEM_REF(x) tptag_udp_rmem_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_wmem;
+/** Sets the maximum send buffer in bytes for primary UDP socket. */
+#define TPTAG_UDP_WMEM(x) tptag_udp_wmem, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_wmem_ref;
+#define TPTAG_UDP_WMEM_REF(x) tptag_udp_wmem_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrpsize;
+/** Determines the number of threads in the pool receiving, uncompressing,
+ * parsing, compressing, and sending messages.
+ */
+#define TPTAG_THRPSIZE(x) tptag_thrpsize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrpsize_ref;
+#define TPTAG_THRPSIZE_REF(x) tptag_thrpsize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrprqsize;
+/** Length of per-thread receive queue (as messages)
+ */
+#define TPTAG_THRPRQSIZE(x) tptag_thrprqsize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrprqsize_ref;
+#define TPTAG_THRPRQSIZE_REF(x) tptag_thrprqsize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_http_connect;
+/** Specify that tport can use HTTP connect method. */
+#define TPTAG_HTTP_CONNECT(x) tptag_http_connect, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_http_connect_ref;
+#define TPTAG_HTTP_CONNECT_REF(x) tptag_http_connect_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_stun_server;
+/** Enable STUN server. */
+#define TPTAG_STUN_SERVER(x) tptag_stun_server, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_stun_server_ref;
+#define TPTAG_STUN_SERVER_REF(x) tptag_stun_server_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_tos;
+/** Sets the IP TOS for the socket. */
+#define TPTAG_TOS(x) tptag_tos, tag_int_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_tos_ref;
+#define TPTAG_TOS_REF(x) tptag_tos_ref, tag_int_vr(&(x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined TPORT_TAG_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1402 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_test.c
+ *
+ * Test functions for transports
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Apr  3 11:25:13 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct tp_test_s tp_test_t;
+
+#define TP_STACK_T tp_test_t
+ 
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_md5.h>
+
+#include "test_class.h"
+#include "test_protos.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_addr.h"
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#include <sofia-sip/base64.h>
+
+#include <sofia-sip/su_log.h>
+
+#include "sofia-sip/tport.h"
+
+struct tp_test_s {
+  su_home_t  tt_home[1];
+  int        tt_flags;
+  su_root_t *tt_root;
+  msg_mclass_t *tt_mclass;
+  tport_t   *tt_srv_tports;
+  tport_t   *tt_tports;
+
+  tport_t   *tt_rtport;
+
+  tp_name_t tt_udp_name[1];
+  tp_name_t tt_udp_comp[1];
+
+  tp_name_t tt_tcp_name[1];
+  tp_name_t tt_tcp_comp[1];
+
+  tp_name_t tt_sctp_name[1];
+  tp_name_t tt_sctp_comp[1];
+
+  tp_name_t tt_tls_name[1];
+  tp_name_t tt_tls_comp[1];
+
+#if HAVE_SIGCOMP
+  struct sigcomp_state_handler *state_handler;
+  struct sigcomp_algorithm const *algorithm;
+  struct sigcomp_compartment *master_cc;
+
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc, TPTAG_COMPARTMENT(cc)),
+#else
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+#endif
+
+  int        tt_status;
+  int        tt_received;
+  msg_t     *tt_rmsg;
+  uint8_t    tt_digest[SU_MD5_DIGEST_SIZE];
+};
+
+int tstflags;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "tport_test";
+
+SOFIAPUBVAR su_log_t tport_log[];
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int name_test(tp_test_t *tt)
+{
+  tp_name_t tpn[1];
+
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  su_sockaddr_t su[1];
+
+  BEGIN();
+
+  memset(su, 0, sizeof su);
+
+  su->su_port = htons(5060);
+  su->su_family = AF_INET;
+
+  TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+
+  su->su_family = AF_INET;
+
+  TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+
+#if SU_HAVE_IN6
+  su->su_family = AF_INET6;
+  TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+#endif
+
+  END();
+}
+
+/* Count number of transports in chain */
+static
+int count_tports(tport_t *tp)
+{
+  int n = 0;
+
+  for (tp = tport_primaries(tp); tp; tp = tport_next(tp))
+    n++;
+  
+  return n;
+}
+
+static int check_msg(tp_test_t *tt, msg_t *msg, char const *ident)
+{
+  msg_test_t *tst;
+  msg_payload_t *pl;
+  usize_t i, len;
+
+  BEGIN();
+  
+  TEST_1(tst = msg_test_public(msg));
+  TEST_1(pl = tst->msg_payload);
+
+  if (ident) {
+    if (!tst->msg_content_location ||
+	strcmp(ident, tst->msg_content_location->g_string))
+      return 1;
+  }
+
+  len = pl->pl_len;
+
+  for (i = 0; i < len; i++) {
+    if (pl->pl_data[i] != (char) (i % 240))
+      break;
+  }
+
+  if (pl)
+  return i != len;
+
+  END();
+}
+
+static int test_create_md5(tp_test_t *tt, msg_t *msg)
+{
+  msg_test_t *tst;
+  msg_payload_t *pl;
+  su_md5_t md5[1];
+  
+  BEGIN();
+
+  TEST_1(tst = msg_test_public(msg));
+  TEST_1(pl = tst->msg_payload);
+
+  su_md5_init(md5);
+  su_md5_update(md5, pl->pl_data, pl->pl_len);
+  su_md5_digest(md5, tt->tt_digest);
+
+  END();
+}
+
+static int test_check_md5(tp_test_t *tt, msg_t *msg)
+{
+  msg_test_t *tst;
+  msg_payload_t *pl;
+  su_md5_t md5[1];
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+
+  BEGIN();
+
+  TEST_1(tst = msg_test_public(msg));
+  TEST_1(pl = tst->msg_payload);
+
+  su_md5_init(md5);
+  su_md5_update(md5, pl->pl_data, pl->pl_len);
+  su_md5_digest(md5, digest);
+
+  TEST(memcmp(digest, tt->tt_digest, sizeof digest), 0);
+
+  END();
+}
+
+static int test_msg_md5(tp_test_t *tt, msg_t *msg)
+{
+  msg_test_t *tst;
+
+  BEGIN();
+
+  TEST_1(tst = msg_test_public(msg));
+
+  if (tst->msg_content_md5) {
+    su_md5_t md5sum[1];
+    uint8_t digest[SU_MD5_DIGEST_SIZE];
+    char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
+
+    msg_payload_t *pl =tst->msg_payload;
+
+    su_md5_init(md5sum);
+    su_md5_update(md5sum, pl->pl_data, pl->pl_len);
+    su_md5_digest(md5sum, digest);
+
+    base64_e(b64, sizeof(b64), digest, sizeof(digest));
+
+    if (strcmp(b64, tst->msg_content_md5->g_string)) {
+      ;
+    }
+    
+    TEST_S(b64, tst->msg_content_md5->g_string);
+  } else {
+    TEST_1(tst->msg_content_md5);
+  }
+
+  END();
+}
+
+#define TPORT_TEST_VERSION MSG_TEST_VERSION_CURRENT
+
+static int new_test_msg(tp_test_t *tt, msg_t **retval, 
+			char const *ident,
+			int N, int len)
+{
+  msg_t *msg;
+  msg_test_t *tst;
+  su_home_t *home;
+  msg_request_t *rq;
+  msg_unknown_t *u;
+  msg_content_location_t *cl;
+  msg_content_md5_t *md5;
+  msg_content_length_t *l;
+  msg_separator_t *sep;
+  msg_payload_t payload[1];
+  msg_header_t *h;
+  int i;
+
+  su_md5_t md5sum[1];
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+  char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
+
+  BEGIN();
+
+  TEST_1(msg = msg_create(tt->tt_mclass, 0));
+  TEST_1(tst = msg_test_public(msg));
+  TEST_1(home = msg_home(msg));
+
+  TEST_SIZE(msg_maxsize(msg, 1024 + N * len), 0);
+
+  TEST_1(rq = msg_request_make(home, "DO im:foo at faa " TPORT_TEST_VERSION));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
+
+  TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+  TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+  if (ident) {
+    TEST_1(cl = msg_content_location_make(home, ident));
+    TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)cl), 0);
+  }
+
+  msg_payload_init(payload);
+
+  payload->pl_len = len;
+  TEST_1(payload->pl_data = su_zalloc(home, payload->pl_len));
+
+  for (i = 0; i < len; i++) {
+    payload->pl_data[i] = (char) (i % 240);
+  }
+
+  su_md5_init(md5sum);
+
+  for (i = 0; i < N; i++) {
+    h = msg_header_dup(home, (msg_header_t*)payload);
+    TEST_1(h);
+    TEST(msg_header_insert(msg, (void *)tst, h), 0);
+    su_md5_update(md5sum, payload->pl_data, payload->pl_len);
+  }
+
+  TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)(N * payload->pl_len)));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
+
+  su_md5_digest(md5sum, digest);
+
+  base64_e(b64, sizeof(b64), digest, sizeof(digest));
+
+  TEST_1(md5 = msg_content_md5_make(home, b64));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
+  
+  TEST_1(sep = msg_separator_create(home));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
+
+  TEST(msg_serialize(msg, (void *)tst), 0);
+
+  *retval = msg;
+
+  END();
+}
+
+static
+struct sigcomp_compartment *
+test_sigcomp_compartment(tp_test_t *tt, tport_t *tp, tp_name_t const *tpn);
+
+static void tp_test_recv(tp_test_t *tt,
+			 tport_t *tp,
+			 msg_t *msg,
+			 tp_magic_t *magic,
+			 su_time_t now)
+{
+  tp_name_t frm[1];
+
+  if (tport_delivered_from(tp, msg, frm) != -1 && frm->tpn_comp) {
+    struct sigcomp_compartment *cc = test_sigcomp_compartment(tt, tp, frm);
+   
+    tport_sigcomp_accept(tp, cc, msg);
+  }
+
+  tt->tt_status = 1;
+  tt->tt_received++;
+
+  if (test_msg_md5(tt, msg))
+    msg_destroy(msg);
+  else if (tt->tt_rmsg) 
+    msg_destroy(msg);
+  else {
+    tt->tt_rmsg = msg;
+    tt->tt_rtport = tp;
+  }
+}
+
+static void tp_test_error(tp_test_t *tt,
+			  tport_t *tp,
+			  int errcode,
+			  char const *remote)
+{
+  tt->tt_status = -1;
+  fprintf(stderr, "tp_test_error(%p): error %d (%s) from %s\n", 
+	  tp, errcode, su_strerror(errcode), 
+	  remote ? remote : "<unknown destination>");
+}
+
+msg_t *tp_test_msg(tp_test_t *tt, int flags,
+		   char const data[], usize_t size,
+		   tport_t const *tp, 
+		   tp_client_t *tpc)
+{
+  msg_t *msg = msg_create(tt->tt_mclass, flags);
+
+  msg_maxsize(msg, 2 * 1024 * 1024);
+
+  return msg;
+}
+
+
+static
+struct sigcomp_compartment *
+test_sigcomp_compartment(tp_test_t *tt, 
+			 tport_t *tp, 
+			 tp_name_t const *tpn)
+{
+  struct sigcomp_compartment *cc = NULL;
+#if HAVE_SIGCOMP
+  char name[256];
+  int namesize;
+  
+  namesize = snprintf(name, sizeof name, "TEST_%s/%s:%s",
+		     tpn->tpn_proto,
+		     tpn->tpn_host,
+		     tpn->tpn_port);
+
+  if (namesize <= 0 || namesize >= sizeof name)
+    return NULL;
+
+  cc = sigcomp_compartment_access(tt->state_handler, 
+				  0, name, namesize, NULL, 0);
+
+  if (cc == NULL) {
+    cc = sigcomp_compartment_create(tt->algorithm, tt->state_handler, 
+				    0, name, namesize, NULL, 0);
+
+    sigcomp_compartment_option(cc, "dms=32768");
+  }
+#endif
+
+  return cc;
+}
+
+/* Accept/reject early SigComp message */
+int test_sigcomp_accept(tp_stack_t *tt, tport_t *tp, msg_t *msg)
+{
+  struct sigcomp_compartment *cc = NULL;
+
+  cc = test_sigcomp_compartment(tt, tp, tport_name(tp));
+
+  if (cc)
+    tport_sigcomp_assign(tp, cc);
+
+  return tport_sigcomp_accept(tp, cc, msg);
+}
+
+
+tp_stack_class_t const tp_test_class[1] =
+  {{
+      /* tpac_size */ sizeof(tp_test_class),
+      /* tpac_recv */  tp_test_recv,
+      /* tpac_error */ tp_test_error,
+      /* tpac_alloc */ tp_test_msg,
+  }};
+
+static int init_test(tp_test_t *tt)
+{
+  tp_name_t myname[1] = {{ "*", "*", "*", "*", "sigcomp" }};
+#if HAVE_NETINET_SCTP_H
+  char const * transports[] = { "udp", "tcp", "sctp", NULL };
+#else
+  char const * transports[] = { "udp", "tcp", NULL };
+#endif
+  tp_name_t const *tpn;
+  tport_t *tp;
+  unsigned idle;
+
+  BEGIN();
+
+  int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
+
+#ifdef AI_ALL
+  mask |= AI_ALL;
+#endif
+#ifdef AI_V4MAPPED_CFG
+  mask |= AI_V4MAPPED_CFG;
+#endif
+#ifdef AI_ADDRCONFIG
+  mask |= AI_ADDRCONFIG;
+#endif
+#ifdef AI_V4MAPPED
+  mask |= AI_V4MAPPED;
+#endif
+
+  /* Test that we have no common flags with underlying getaddrinfo() */
+  TEST(mask & TP_AI_MASK, 0);
+
+  TEST_1(tt->tt_root = su_root_create(NULL));
+
+  myname->tpn_host = "127.0.0.1";
+  myname->tpn_ident = "client";
+
+  /* Create message class */
+  TEST_1(tt->tt_mclass = msg_mclass_clone(msg_test_mclass, 0, 0));
+
+  /* Try to insert Content-Length header (expecting failure) */
+  TEST(msg_mclass_insert(tt->tt_mclass, msg_content_length_href), -1);
+
+#if HAVE_SIGCOMP
+  TEST_1(tt->state_handler = sigcomp_state_handler_create());
+  TEST_1(tt->algorithm = 
+	 sigcomp_algorithm_by_name(getenv("SIGCOMP_ALGORITHM")));
+  TEST_1(tt->master_cc = 
+	 sigcomp_compartment_create(tt->algorithm, tt->state_handler, 
+				    0, "", 0, NULL, 0));
+  TEST(sigcomp_compartment_option(tt->master_cc, "stateless"), 1);
+#endif
+
+  /* Create client transport */
+  TEST_1(tt->tt_tports = 
+	 tport_tcreate(tt, tp_test_class, tt->tt_root,
+		       IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
+		       TAG_END()));
+
+  /* Bind client transports */
+  TEST(tport_tbind(tt->tt_tports, myname, transports,
+		   TPTAG_SERVER(0), TAG_END()), 
+       0);
+
+  if (getenv("TPORT_TEST_HOST"))
+    myname->tpn_host = getenv("TPORT_TEST_HOST");
+  else
+    myname->tpn_host = "*";
+
+  if (getenv("TPORT_TEST_PORT"))
+    myname->tpn_port = getenv("TPORT_TEST_PORT");
+
+  myname->tpn_ident = "server";
+
+  /* Create server transport */
+  TEST_1(tt->tt_srv_tports = 
+	 tport_tcreate(tt, tp_test_class, tt->tt_root,
+		       IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
+		       TAG_END()));
+
+  /* Bind server transports */
+  TEST(tport_tbind(tt->tt_srv_tports, myname, transports, 
+		   TPTAG_SERVER(1),
+		   TAG_END()), 
+       0);
+
+  TEST(tport_get_params(tt->tt_srv_tports,
+			TPTAG_IDLE_REF(idle),
+			TAG_END()), 1);
+
+  for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
+    TEST_S(tport_name(tp)->tpn_ident, "server");
+
+  {
+    su_sockaddr_t su[1];
+    socklen_t sulen;
+    int s;
+    int i, before, after;
+    char port[8];
+
+    tp_name_t rname[1];
+
+    *rname = *myname;
+
+    memset(su, 0, sulen = sizeof(su->su_sin));
+    s = su_socket(su->su_family = AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+    TEST_1(bind(s, &su->su_sa, sulen) != -1);
+    TEST_1(listen(s, 5) != -1);
+    TEST_1(getsockname(s, &su->su_sa, &sulen) != -1);
+
+    sprintf(port, "%u", ntohs(su->su_port));
+
+    rname->tpn_port = port;
+    rname->tpn_ident = "failure";
+    
+    before = count_tports(tt->tt_srv_tports);
+
+    /* Bind server transports to an reserved port */
+    TEST(tport_tbind(tt->tt_srv_tports, rname, transports, 
+		     TPTAG_SERVER(1),
+		     TAG_END()), 
+	 -1);
+
+    after = count_tports(tt->tt_srv_tports);
+
+    TEST(before, after);
+
+    for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
+      TEST_S(tport_name(tp)->tpn_ident, "server");
+
+    rname->tpn_port = "*";
+    rname->tpn_ident = "server2";
+
+    /* Bind server transports to another port */
+    TEST(tport_tbind(tt->tt_srv_tports, rname, transports, 
+		     TPTAG_SERVER(1),
+		     TAG_END()), 
+	 0);
+
+    tp = tport_primaries(tt->tt_srv_tports);
+
+    for (i = 0; i++ < before; tp = tport_next(tp))
+      TEST_S(tport_name(tp)->tpn_ident, "server");
+
+    for (; tp; tp = tport_next(tp))
+      TEST_S(tport_name(tp)->tpn_ident, "server2");
+  }
+
+#if HAVE_TLS
+  {
+    tp_name_t tlsname[1] = {{ "tls", "*", "*", "*", NULL }};
+    char const * transports[] = { "tls", NULL };
+
+    char const *srcdir = getenv("srcdir");
+
+    if (srcdir == NULL)
+      srcdir = ".";
+
+    tlsname->tpn_host = myname->tpn_host;
+    tlsname->tpn_ident = "server";
+
+    /* Bind client transports */
+    TEST(tport_tbind(tt->tt_tports, tlsname, transports,
+		     TPTAG_SERVER(0), 
+		     TPTAG_CERTIFICATE(srcdir),
+		     TAG_END()), 
+	 0);
+
+    /* Bind tls server transport */
+    TEST(tport_tbind(tt->tt_srv_tports, tlsname, transports, 
+		     TPTAG_SERVER(1),
+		     TPTAG_CERTIFICATE(srcdir),
+		     TAG_END()), 
+	 0);
+  }
+#endif
+
+  for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp)) {
+    TEST_1(tpn = tport_name(tp));
+
+    if (1 || tt->tt_flags & tst_verbatim) {
+      char const *host = tpn->tpn_host != tpn->tpn_canon ? tpn->tpn_host : "";
+      printf("bound transport to %s/%s:%s%s%s%s%s\n",
+	     tpn->tpn_proto, tpn->tpn_canon, tpn->tpn_port, 
+	     host[0] ? ";maddr=" : "", host,
+	     tpn->tpn_comp ? ";comp=" : "", 
+	     tpn->tpn_comp ? tpn->tpn_comp : "");
+    }
+
+    /* Ignore server2 tports for now */
+    if (strcmp(tpn->tpn_ident, "server"))
+      continue;
+
+    if (strcmp(tpn->tpn_proto, "udp") == 0) {
+      *tt->tt_udp_name = *tpn;
+      tt->tt_udp_name->tpn_comp = NULL;
+      tt->tt_udp_name->tpn_ident = NULL;
+      *tt->tt_udp_comp = *tpn;
+      tt->tt_udp_comp->tpn_ident = NULL;
+    }
+    else if (strcmp(tpn->tpn_proto, "tcp") == 0) {
+      *tt->tt_tcp_name = *tpn;
+      tt->tt_tcp_name->tpn_comp = NULL;
+      tt->tt_tcp_name->tpn_ident = NULL;
+      *tt->tt_tcp_comp = *tpn;
+      tt->tt_tcp_comp->tpn_ident = NULL;
+    } 
+    else if (strcmp(tpn->tpn_proto, "sctp") == 0) {
+      *tt->tt_sctp_name = *tpn;
+      tt->tt_sctp_name->tpn_ident = NULL;
+    }
+    else if (strcmp(tpn->tpn_proto, "tls") == 0) {
+      *tt->tt_tls_name = *tpn;
+      tt->tt_tls_name->tpn_ident = NULL;
+    }
+  }
+
+  END();
+}
+
+char const payload[] = 
+"Some data\n"
+"More data\n";
+
+#include <time.h>
+
+int 
+tport_test_run(tp_test_t *tt, unsigned timeout)
+{
+  time_t now = time(NULL);
+
+  tt->tt_status = 0;
+
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  tt->tt_rtport = NULL;
+
+  while (!tt->tt_status) {
+    if (tt->tt_flags & tst_verbatim) {
+      fputs(".", stdout); fflush(stdout);
+    }
+    su_root_step(tt->tt_root, 500L);
+
+    if (!getenv("TPORT_TEST_DEBUG") && 
+	time(NULL) > (time_t)(now + timeout))
+      return 0;
+  }
+
+  return tt->tt_status;
+}
+
+static int udp_test(tp_test_t *tt)
+{
+  tport_t *tp;
+  msg_t *msg;
+  msg_test_t *tst;
+  su_home_t *home;
+  msg_request_t *rq;
+  msg_unknown_t *u;
+  msg_content_length_t *l;
+  msg_content_md5_t *md5;
+  msg_separator_t *sep;
+  msg_payload_t *pl;
+
+  BEGIN();
+
+  TEST_1(msg = msg_create(tt->tt_mclass, 0));
+  TEST_1(tst = msg_test_public(msg));
+  TEST_1(home = msg_home(msg));
+
+  TEST_1(rq = msg_request_make(home, "DO im:foo at faa " TPORT_TEST_VERSION));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
+
+  TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+  TEST_1(pl = msg_payload_make(home, payload));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)pl), 0);
+
+  TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)pl->pl_len));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
+
+  TEST_1(md5 = msg_content_md5_make(home, "R6nitdrtJFpxYzrPaSXfrA=="));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
+  
+  TEST_1(sep = msg_separator_create(home));
+  TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
+
+  TEST(msg_serialize(msg, (void *)tst), 0);
+
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_udp_name, TAG_END()));
+
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+
+  TEST(tport_test_run(tt, 5), 1);
+
+  msg_destroy(msg);
+
+#if 0
+  tp_name_t tpn[1] = {{ NULL }};
+
+  TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
+
+  TEST_1(home = msg_home(msg));
+
+  TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
+
+  tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
+
+  /* reply */
+  TEST_1(tport_tsend(tt->tt_rtport, msg, tpn, TAG_END()) != NULL);
+
+  msg_destroy(msg);
+
+  TEST(tport_test_run(tt, 5), 1);
+
+  msg_destroy(msg);
+#endif
+
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  END();
+}
+
+static int tcp_test(tp_test_t *tt)
+{
+  msg_t *msg = NULL;
+  int i;
+  tport_t *tp, *tp0;
+  char ident[16];
+
+  BEGIN();
+
+  /* Create a large message, just to force queueing in sending end */
+  TEST(new_test_msg(tt, &msg, "tcp-0", 1, 16 * 64 * 1024), 0);
+  test_create_md5(tt, msg);
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  tp0 = tport_incref(tp);
+  msg_destroy(msg);
+
+  /* Fill up the queue */
+  for (i = 1; i < TPORT_QUEUESIZE; i++) {
+    snprintf(ident, sizeof ident, "tcp-%u", i);
+
+    TEST(new_test_msg(tt, &msg, ident, 1, 64 * 1024), 0);
+    TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+    TEST_S(tport_name(tp)->tpn_ident, "client");
+    TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
+    msg_destroy(msg);
+  }
+
+  /* This overflows the queue */
+  TEST(new_test_msg(tt, &msg, "tcp-overflow", 1, 1024), 0);
+  TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+  msg_destroy(msg);
+
+  tt->tt_received = 0;
+
+  TEST(tport_test_run(tt, 60), 1);
+  TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-0"));
+  test_check_md5(tt, tt->tt_rmsg);
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  if (tt->tt_received < TPORT_QUEUESIZE) { /* We have not received it all */
+    snprintf(ident, sizeof ident, "tcp-%u", tt->tt_received);
+    TEST(tport_test_run(tt, 5), 1);
+    TEST_1(!check_msg(tt, tt->tt_rmsg, ident));
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+
+  /* This uses a new connection */
+  TEST_1(!new_test_msg(tt, &msg, "tcp-no-reuse", 1, 1024));
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, 
+			  TPTAG_REUSE(0), TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tport_incref(tp) != tp0); tport_decref(&tp);
+  msg_destroy(msg);
+
+  /* This uses the old connection */
+  TEST_1(!new_test_msg(tt, &msg, "tcp-reuse", 1, 1024));
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, 
+			  TPTAG_REUSE(1), TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tport_incref(tp) == tp0); tport_decref(&tp);
+  msg_destroy(msg);
+
+  /* Receive every message from queue */
+  while (tt->tt_received < TPORT_QUEUESIZE + 2) {
+    TEST(tport_test_run(tt, 5), 1);
+    /* Validate message */
+    TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+
+  /* Try to send a single message */
+  TEST_1(!new_test_msg(tt, &msg, "tcp-last", 1, 1024));
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
+  msg_destroy(msg);
+
+  TEST(tport_test_run(tt, 5), 1);
+
+  TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-last"));
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  tport_decref(&tp0);
+
+  END();
+}
+
+static int reuse_test(tp_test_t *tt)
+{
+  msg_t *msg = NULL;
+  int i, reuse = -1;
+  tport_t *tp, *tp0, *tp1;
+  tp_name_t tpn[1];
+
+  BEGIN();
+
+  /* Flush existing connections */
+  *tpn = *tt->tt_tcp_name;
+  tpn->tpn_port = "*";
+  TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
+  TEST_1(tport_is_primary(tp));
+  TEST(tport_flush(tp), 0);
+  
+  for (i = 0; i < 10; i++)
+    su_root_step(tt->tt_root, 10L);
+
+  TEST(tport_set_params(tp, TPTAG_REUSE(0), TAG_END()), 1);
+
+  /* Send two messages */
+  TEST(new_test_msg(tt, &msg, "reuse-1", 1, 1024), 0);
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tp0 = tport_incref(tp));
+  TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+  TEST(reuse, 0);
+  msg_destroy(msg), msg = NULL;
+
+  TEST(new_test_msg(tt, &msg, "reuse-2", 1, 1024), 0);
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tp1 = tport_incref(tp)); TEST_1(tp0 != tp1);
+  TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+  TEST(reuse, 0);
+  msg_destroy(msg), msg = NULL;
+
+  /* Receive every message from queue */
+  for (tt->tt_received = 0;
+       tt->tt_received < 2;) {
+    TEST(tport_test_run(tt, 5), 1);
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+
+  /* Enable reuse on single connection */
+  TEST(tport_set_params(tp1, TPTAG_REUSE(1), TAG_END()), 1);
+  TEST(new_test_msg(tt, &msg, "reuse-3", 1, 1024), 0);
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, 
+			  TPTAG_REUSE(1),
+			  TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tp1 == tp);
+  TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+  TEST(reuse, 1);
+  msg_destroy(msg), msg = NULL;
+
+  TEST(tport_test_run(tt, 5), 1);
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
+  TEST_1(tport_is_primary(tp));
+  TEST(tport_set_params(tp, TPTAG_REUSE(1), TAG_END()), 1);
+
+  /* Send a single message with different connection */
+  TEST_1(!new_test_msg(tt, &msg, "fresh-1", 1, 1024));
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, 
+			  TPTAG_FRESH(1),
+			  TPTAG_REUSE(1),
+			  TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  TEST_1(tport_incref(tp) != tp1);  tport_decref(&tp);
+  msg_destroy(msg);
+
+  TEST(tport_test_run(tt, 5), 1);
+
+  TEST_1(!check_msg(tt, tt->tt_rmsg, "fresh-1"));
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  TEST_1(tport_shutdown(tp0, 2) >= 0);
+  TEST_1(tport_shutdown(tp1, 2) >= 0);
+  TEST_1(tport_shutdown(tp0, 1) >= 0);
+
+  TEST(tport_shutdown(NULL, 0), -1);
+
+  tport_decref(&tp0);
+  tport_decref(&tp1);
+
+  END();
+}
+
+static int sctp_test(tp_test_t *tt)
+{
+  BEGIN();
+
+  msg_t *msg = NULL;
+  int i, n;
+  tport_t *tp;
+  char buffer[32];
+
+  if (!tt->tt_sctp_name->tpn_proto) 
+    return 0;
+
+  /* Just a small and nice message first */
+  TEST_1(!new_test_msg(tt, &msg, "sctp-small", 1, 1024));
+  test_create_md5(tt, msg);
+  TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+  TEST_S(tport_name(tp)->tpn_ident, "client");
+  msg_destroy(msg);
+  
+  TEST(tport_test_run(tt, 5), 1);
+    
+  TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+  test_check_md5(tt, tt->tt_rmsg);
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  if (1)
+    return 0;			/* SCTP does not work reliably. Really. */
+
+  /* Create large messages, just to force queueing in sending end */
+  for (n = 0; !tport_queuelen(tp); n++) {
+    snprintf(buffer, sizeof buffer, "cid:sctp-%u", n);
+    TEST_1(!new_test_msg(tt, &msg, buffer, 1, 32000));
+    test_create_md5(tt, msg);
+    TEST_1(tport_tsend(tp, msg, tt->tt_sctp_name, TAG_END()));
+    TEST_S(tport_name(tp)->tpn_ident, "client");
+    msg_destroy(msg);
+  }
+  
+  /* Fill up the queue */
+  for (i = 1; i < TPORT_QUEUESIZE; i++) {
+    snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
+    TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
+    TEST_1(tport_tsend(tp, msg, tt->tt_sctp_name, TAG_END()));
+    msg_destroy(msg);
+  }
+
+  /* This overflows the queue */
+  snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
+  TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
+  TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+  msg_destroy(msg);
+  
+  TEST(tport_test_run(tt, 5), 1);
+    
+  TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+  test_check_md5(tt, tt->tt_rmsg);
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  /* This uses a new connection */
+  TEST_1(!new_test_msg(tt, &msg, "cid-sctp-new", 1, 1024));
+  TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, 
+		     TPTAG_REUSE(0), TAG_END()));
+  msg_destroy(msg);
+
+  /* Receive every message from queue */
+  for (tt->tt_received = 0; tt->tt_received < TPORT_QUEUESIZE + n;) {
+    TEST(tport_test_run(tt, 10), 1);
+    /* Validate message */
+    TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+  
+  /* Try to send a single message */
+  TEST_1(!new_test_msg(tt, &msg, "cid:sctp-final", 1, 1024));
+  TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+  msg_destroy(msg);
+  
+  TEST(tport_test_run(tt, 10), 1);
+  
+  TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  END();
+}
+
+static int tls_test(tp_test_t *tt)
+{
+  BEGIN(); 
+
+#if HAVE_TLS
+  tp_name_t const *dst = tt->tt_tls_name;
+  msg_t *msg = NULL;
+  int i;
+  char ident[16];
+
+  TEST_S(dst->tpn_proto, "tls");
+
+  tt->tt_received = 0;
+
+  /* Create a large message, just to force queueing in sending end */
+  TEST_1(!new_test_msg(tt, &msg, "tls-0", 16, 64 * 1024));
+  test_create_md5(tt, msg);
+  TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+  msg_destroy(msg);
+
+  /* Fill up the queue */
+  for (i = 1; i < TPORT_QUEUESIZE; i++) {
+    snprintf(ident, sizeof ident, "tls-%u", i);
+
+    TEST_1(!new_test_msg(tt, &msg, ident, 2, 512));
+    TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+    msg_destroy(msg);
+  }
+
+  /* This overflows the queue */
+  TEST_1(!new_test_msg(tt, &msg, "tls-overflow", 1, 1024));
+  TEST_1(!tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+  msg_destroy(msg);
+
+  TEST(tport_test_run(tt, 60), 1);
+
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+  /* This uses a new connection */
+  TEST_1(!new_test_msg(tt, &msg, "tls-no-reuse", 1, 1024));
+  TEST_1(tport_tsend(tt->tt_tports, msg, dst, 
+		     TPTAG_REUSE(0), TAG_END()));
+  msg_destroy(msg);
+
+  /* Receive every message from queue */
+  while (tt->tt_received < TPORT_QUEUESIZE + 1) {
+    TEST(tport_test_run(tt, 5), 1);
+    /* Validate message */
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+
+  /* Try to send a single message */
+  TEST_1(!new_test_msg(tt, &msg, "tls-last", 1, 1024));
+  TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+  msg_destroy(msg);
+
+  TEST(tport_test_run(tt, 5), 1);
+
+  TEST_1(!check_msg(tt, tt->tt_rmsg, "tls-last"));
+  msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+#endif
+
+  END();
+}
+
+static int sigcomp_test(tp_test_t *tt)
+{
+  BEGIN();
+
+#if HAVE_SIGCOMP
+  su_home_t *home;
+  tp_name_t tpn[1] = {{ NULL }};
+  struct sigcomp_compartment *cc;
+  
+  if (tt->tt_udp_comp->tpn_comp) {
+    msg_t *msg = NULL;
+
+    TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tt->tt_udp_comp));
+
+    TEST_1(!new_test_msg(tt, &msg, "udp-sigcomp", 1, 1200));
+    test_create_md5(tt, msg);
+    TEST_1(tport_tsend(tt->tt_tports, 
+		       msg, 
+		       tt->tt_udp_comp,
+		       TPTAG_COMPARTMENT(cc),
+		       TAG_END()));
+    msg_destroy(msg);
+
+    TEST(tport_test_run(tt, 5), 1);
+
+    TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+
+    test_check_md5(tt, tt->tt_rmsg);
+
+    TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
+    
+    TEST_1(home = msg_home(msg));
+    
+    TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
+    
+    tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
+    
+    /* reply */
+    TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
+    TEST_1(tport_tsend(tt->tt_rtport, msg, tpn, 
+		       TPTAG_COMPARTMENT(cc),
+		       TAG_END()) != NULL);
+    
+    msg_destroy(msg);
+    
+    TEST(tport_test_run(tt, 5), 1);
+
+    TEST_1(!check_msg(tt, tt->tt_rmsg, NULL)); 
+    test_check_md5(tt, tt->tt_rmsg); 
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+  }
+
+  if (tt->tt_tcp_comp->tpn_comp) {
+    tport_t *tp;
+    msg_t *msg = NULL;
+
+    *tpn = *tt->tt_tcp_comp;
+
+    TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp", 1, 1500));
+    test_create_md5(tt, msg);
+
+    tport_log->log_level = 9;
+
+    TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
+    TEST_1(tp = tport_tsend(tt->tt_tports, 
+			    msg, 
+			    tpn, 
+			    TPTAG_COMPARTMENT(cc),
+			    TAG_END()));
+    TEST_1(tport_incref(tp)); tport_decref(&tp);
+    msg_destroy(msg);
+
+    TEST(tport_test_run(tt, 5), 1);
+
+    TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp"));
+    test_check_md5(tt, tt->tt_rmsg);
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+    TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-2", 1, 3000));
+    test_create_md5(tt, msg);
+    TEST_1(tp = tport_tsend(tt->tt_tports, 
+			    msg, 
+			    tt->tt_tcp_comp, 
+			    TPTAG_COMPARTMENT(cc),
+			    TAG_END()));
+    TEST_1(tport_incref(tp)); tport_decref(&tp);
+    msg_destroy(msg);
+
+    TEST(tport_test_run(tt, 5), 1);
+
+    TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-2"));
+    test_check_md5(tt, tt->tt_rmsg); 
+
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+    TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-3", 1, 45500));
+    test_create_md5(tt, msg);
+    TEST_1(tp = tport_tsend(tt->tt_tports, 
+			    msg, 
+			    tt->tt_tcp_comp, 
+			    TPTAG_COMPARTMENT(cc),
+			    TAG_END()));
+    TEST_1(tport_incref(tp));
+    msg_destroy(msg);
+
+    TEST(tport_test_run(tt, 5), 1);
+
+    tport_decref(&tp);
+    TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-3"));
+    test_check_md5(tt, tt->tt_rmsg);
+    msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+    {
+      tp_name_t tpn[1];
+      tport_t *ctp, *rtp;
+
+      *tpn = *tt->tt_tcp_comp; tpn->tpn_comp = NULL;
+
+      TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-4", 1, 1000));
+      test_create_md5(tt, msg);
+      TEST_1(tp = tport_tsend(tt->tt_tports, 
+			      msg, 
+			      tpn, 
+			      TPTAG_COMPARTMENT(cc),
+			      TPTAG_FRESH(1),
+			      TAG_END()));
+      TEST_1(ctp = tport_incref(tp));
+      msg_destroy(msg);
+
+      TEST(tport_test_run(tt, 5), 1);
+      
+      TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-4"));
+      test_check_md5(tt, tt->tt_rmsg);
+      TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) == 0);
+      msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+      TEST_1(rtp = tport_incref(tt->tt_rtport));
+
+      TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-5", 1, 1000));
+      test_create_md5(tt, msg);
+      {
+	/* Mess with internal data structures in order to 
+	   force tport to use SigComp on this connection */
+	tp_name_t *tpn = (tp_name_t *)tport_name(rtp);
+	tpn->tpn_comp = "sigcomp";
+      }
+      TEST_1(tp = tport_tsend(rtp, 
+			      msg, 
+			      tt->tt_tcp_comp, 
+			      TPTAG_COMPARTMENT(cc),
+			      TAG_END()));
+      TEST_1(tport_incref(tp));
+      msg_destroy(msg);
+
+      TEST(tp, rtp);
+
+      TEST(tport_test_run(tt, 5), 1);
+
+      tport_decref(&tp);
+      TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-5"));
+      test_check_md5(tt, tt->tt_rmsg);
+      TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) != 0);
+      msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+      TEST(ctp, tt->tt_rtport);
+      tport_decref(&ctp);
+    }
+  }
+#endif
+
+  END();
+}
+
+#if HAVE_SOFIA_STUN
+
+#include <sofia-sip/stun_tag.h>
+
+static int stun_test(tp_test_t *tt)
+{
+  BEGIN();
+
+  tport_t *mr;
+  tp_name_t tpn[1] = {{ "*", "*", "*", "*", NULL }};
+#if HAVE_NETINET_SCTP_H
+  char const * transports[] = { "udp", "tcp", "sctp", NULL };
+#else
+  char const * transports[] = { "udp", "tcp", NULL };
+#endif
+
+  TEST_1(mr = tport_tcreate(tt, tp_test_class, tt->tt_root, TAG_END()));
+  
+  TEST(tport_tbind(tt->tt_tports, tpn, transports, TPTAG_SERVER(1), 
+		   STUNTAG_SERVER("999.999.999.999"),
+		   TAG_END()), -1);
+
+  tport_destroy(mr);
+
+  END();
+}
+#else
+static int stun_test(tp_test_t *tt)
+{
+  return 0;
+}
+#endif
+
+static int deinit_test(tp_test_t *tt)
+{
+  BEGIN();
+
+  /* Destroy client transports */
+  tport_destroy(tt->tt_tports), tt->tt_tports = NULL;
+
+  /* Destroy server transports */
+  tport_destroy(tt->tt_srv_tports), tt->tt_srv_tports = NULL;
+
+#if HAVE_SIGCOMP
+  sigcomp_state_handler_free(tt->state_handler); tt->state_handler = NULL;
+#endif
+
+  END();
+}
+
+/* Test tport_tags filter */
+static int filter_test(tp_test_t *tt)
+{
+  tagi_t *lst, *result;
+
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  BEGIN();
+
+  lst = tl_list(TSTTAG_HEADER_STR("X: Y"),
+		TAG_SKIP(2), 
+		TPTAG_IDENT("foo"),
+		TSTTAG_HEADER_STR("X: Y"),
+		TPTAG_IDENT("bar"),
+		TAG_NULL());
+
+  TEST_1(lst);
+
+  result = tl_afilter(home, tport_tags, lst);
+
+  TEST_1(result);
+  TEST_P(result[0].t_tag, tptag_ident);
+  TEST_P(result[1].t_tag, tptag_ident);
+
+  free(lst);
+  su_home_deinit(home);
+
+  END();
+}
+
+int main(int argc, char *argv[])
+{
+  int flags = 0;	/* XXX */
+  int retval = 0;
+  int i;
+  tp_test_t tt[1] = {{{ SU_HOME_INIT(tt) }}};
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  /* Use log */
+  if (flags & tst_verbatim)
+    tport_log->log_default = 9;
+  else
+    tport_log->log_default = 1;
+
+  su_init();
+
+  retval |= name_test(tt); fflush(stdout);
+  retval |= filter_test(tt); fflush(stdout);
+
+  retval |= init_test(tt); fflush(stdout);
+  if (retval == 0) {
+    retval |= sigcomp_test(tt); fflush(stdout);
+    retval |= sctp_test(tt); fflush(stdout);
+    retval |= udp_test(tt); fflush(stdout);
+    retval |= tcp_test(tt); fflush(stdout);
+    retval |= reuse_test(tt); fflush(stdout);
+    retval |= tls_test(tt); fflush(stdout);
+    if (0)			/* Not yet working... */
+      retval |= stun_test(tt); fflush(stdout);
+    retval |= deinit_test(tt); fflush(stdout);
+  }
+
+  su_deinit();
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "ssl.h"
+#include "tls.h"
+
+void write_file(FILE *fp, int size);
+
+int tls_setblocking(int s, int blocking)
+{
+  unsigned mode = fcntl(s, F_GETFL, 0);
+
+  if (mode < 0)
+     return -1;
+
+  if (blocking) 
+    mode &= ~(O_NDELAY | O_NONBLOCK);
+  else
+    mode |= O_NDELAY | O_NONBLOCK;
+
+  return fcntl(s, F_SETFL, mode);
+}
+
+void tls_write_buffer(TLS_CONTEXT ctx, unsigned char *buf, int size)
+{
+  int ret, err;
+  int pos = 0;
+
+  while (pos < size) {
+    int bytes = pos + 30000 < size ? 30000 : size - pos;
+
+    printf("writing %d bytes\n", bytes);
+
+    ret = tls_write(ctx, buf + pos, bytes);
+    err = tls_get_error(ctx, ret);
+
+    switch(err) {
+    case SSL_ERROR_NONE:
+      pos += ret;
+      printf("%d bytes written\n", ret);
+      break;
+    
+    case SSL_ERROR_WANT_WRITE:
+      printf("want write\n");
+      break;
+
+    case SSL_ERROR_WANT_READ:
+      printf("want read\n");
+      break;
+
+    default:
+      printf("TLS error code %d\n", err);
+    }
+  }
+}
+
+int main (int argc, char *argv[])
+{
+  int i, pid;
+  FILE *fp;
+  struct stat stats;
+
+  if (argc != 2) {
+    printf("Usage: tls_test_client <file>\n");
+  }
+
+  for (i = 0; i < 10; i++) {
+    pid = fork();
+    if (pid == 0)
+      break;
+  }
+
+  fp = fopen(argv[1], "r");
+
+  if (fp == NULL) {
+    perror("fopen");
+    exit(1);
+  }
+  
+  if (fstat(fileno(fp), &stats) < 0) {
+    perror("fstat");
+    exit(1);
+  }
+
+  for (i = 0; i < 20; i++)
+    write_file(fp, stats.st_size);
+
+  return 0;
+}
+
+void write_file(FILE *fp, int size)
+{
+  TLS_ISSUES  tls_issues = {0};
+  TLS_CONTEXT ctx;
+  int sock, posFile = 0;
+
+  printf("tls_client connecting\n");
+
+  sock = init_tls_client(tls_issues, &ctx);
+
+  printf("tls_client initialized\n");
+
+  if (sock < 0)
+    exit (1);
+
+  tls_setblocking(sock, 0);
+
+  rewind(fp);
+
+  while (posFile < size) {
+    int posBuffer = 0;
+    char buf[150000];
+
+    while (posBuffer < sizeof(buf)) {
+      int bytes;
+      
+      bytes = read(fileno(fp), buf + posBuffer, sizeof(buf));
+
+      if (bytes == 0)
+        break;
+
+      if (bytes < 0) {
+        perror("read");
+      }
+      
+      else {
+        printf("writing %d buffer\n", bytes);
+        tls_write_buffer(ctx, buf, bytes);
+        printf("wrote %d buffer\n", bytes);
+        posBuffer += bytes;
+        posFile += bytes;
+      }
+
+      if (posFile >= size)
+        break;
+    }
+  }
+
+  printf("wrote total %d bytes\n", posFile);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,264 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ssl.h"
+#include "tls.h"
+
+typedef int (*IO_HANDLER)(int i);
+
+typedef struct __tls_mngr {
+  int         sock;
+  TLS_CONTEXT ctx;
+  IO_HANDLER  handler;
+} TLS_MNGR;
+
+static TLS_MNGR tls_mngr[100] = {{0}};
+static int mngr_size = 0;
+static int width = 0;
+static char *file_prefix = "";
+static fd_set regifds;
+static int master_socket = 0;
+
+void init_event_mngr (void)
+{
+  mngr_size = 0;
+  FD_ZERO (&regifds);
+}
+
+int tls_setblocking(int s, int blocking)
+{
+  unsigned mode = fcntl(s, F_GETFL, 0);
+
+  if (mode < 0)
+     return -1;
+
+  if (blocking) 
+    mode &= ~(O_NDELAY | O_NONBLOCK);
+  else
+    mode |= O_NDELAY | O_NONBLOCK;
+
+  return fcntl(s, F_SETFL, mode);
+}
+
+void regi_sock (int sock, TLS_CONTEXT ctx, IO_HANDLER handler)
+{
+  FD_SET (sock, &regifds);
+
+  if (sock + 1 > width)
+    width = sock + 1;
+
+  tls_mngr[mngr_size].sock = sock;
+  tls_mngr[mngr_size].ctx = ctx;
+  tls_mngr[mngr_size].handler = handler;
+  mngr_size++;
+
+  tls_setblocking(sock, 0);
+
+  printf("socket %d registered, ctx = %p, mngr_size = %d, width = %d\n", 
+         sock, ctx, mngr_size, width);
+}
+
+int get_width (void)
+{
+  int i;
+  int lwidth = 1;
+
+  for (i = 0; i < mngr_size; i++) {
+    if (tls_mngr[i].sock + 1 > lwidth)
+      lwidth = tls_mngr[i].sock + 1;
+  }
+
+  return lwidth;
+}
+
+int tls_read_buffer(TLS_MNGR mngr, char *buf, int size)
+{
+  int bytes = 0;
+  TLS_CONTEXT ctx = mngr.ctx;
+
+  do {
+    int ret = tls_read(ctx, buf + bytes, size - bytes);
+    int err = tls_get_error(ctx, ret);
+
+    printf("tls_read returned %d\n", ret);
+
+    switch (err) {
+    case SSL_ERROR_NONE:
+      bytes += ret;
+      break;
+
+    case SSL_ERROR_WANT_READ:
+      printf("ssl error want read\n");
+      return bytes;
+      break;
+      
+    case SSL_ERROR_WANT_WRITE:
+      break;
+
+    case SSL_ERROR_ZERO_RETURN:
+      printf("shutdown\n");
+      tls_shutdown(ctx);
+      return bytes;
+      
+    case SSL_ERROR_SYSCALL:
+      perror("tls_syscall");
+      tls_shutdown(ctx);
+      FD_CLR(mngr.sock, &regifds);
+      return bytes;
+
+    default:
+      printf("TLS error code %d\n", err);
+      return bytes;
+    }
+    
+    if (tls_pending(ctx)) {
+      printf("read pending\n");
+    }
+
+  } while (tls_pending(ctx));
+
+  printf("normal read %d bytes\n", bytes);
+  return bytes;
+}
+
+int tls_slave_handler(int i)
+{
+  unsigned char buf[50000];
+  char fname[100];
+  FILE *fp;
+
+  int bytes = tls_read_buffer(tls_mngr[i], buf, sizeof(buf));
+
+  printf("buffer read %d bytes\n", bytes);
+
+  if (bytes > 0) {
+    sprintf(fname, "%s%02d.txt", file_prefix, i);
+    fp = fopen(fname, "a");
+  
+    if (fp == NULL)
+      perror("tls_slave_handler fopen");
+
+    else {
+      int ret = fwrite(buf, sizeof(char), bytes, fp);
+
+      if (ret != bytes)
+        perror("tls_slave_handler write");
+
+      fclose(fp);
+    }
+  }
+  
+  return 0;
+}
+
+int tls_master_handler(int i)
+{
+  TLS_CONTEXT ctx_slave;
+  TLS_ISSUES tls_issues = {0};
+  int         sock;
+
+  printf("tls_master_handler\n");
+
+  tls_issues.master_socket = master_socket;
+
+  sock = init_tls_slave(tls_issues, tls_mngr[i].ctx, &ctx_slave);
+  
+  if (sock < 0) {
+    perror("init_tls_slave");
+    return -1;
+  }
+
+  regi_sock(sock, ctx_slave, tls_slave_handler);
+
+  return 0;
+}
+
+int event_mngr ()
+{
+  struct timeval tv;
+  int            retv;
+  int            i;
+  fd_set readfds;
+
+  tv.tv_sec = 5;
+  tv.tv_usec = 0;
+
+  readfds = regifds;
+
+  retv = select(width, &readfds, NULL, NULL, &tv);
+  printf("select returned %d\n", retv);
+
+  if (retv > 0) {
+    for (i=0; i < mngr_size; i++) {
+      if (FD_ISSET(tls_mngr[i].sock, &readfds)) {
+        tls_mngr[i].handler(i);
+      }
+    }
+  }
+
+  if (retv < 0)
+    perror("select");
+
+  return retv;
+}
+
+int main (int argc, char *argv[])
+{
+  TLS_ISSUES  tls_issues = {0};
+  TLS_CONTEXT ctx;
+  fd_set readfds;
+
+  if (argc != 2) {
+    printf("Usage: tls_test_server <file prefix>\n");
+    exit(0);
+  }
+
+  file_prefix = strdup(argv[1]);
+
+  init_event_mngr();
+
+  if (init_tls_master(&master_socket, 
+                      tls_issues,
+                      &ctx) < 0) {
+    printf("init_tls_master failed\n");
+    exit (1);
+  }
+  
+  regi_sock(master_socket, ctx, tls_master_handler);
+
+  for (;;) {
+    readfds = regifds;
+    event_mngr();
+    usleep(100000L);
+  }
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4530 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport.c Transport interface implementation.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Ismo Puustinen <Ismo.H.Puustinen at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+
+typedef struct tport_nat_s tport_nat_t;
+
+#define SU_WAKEUP_ARG_T         struct tport_s
+#define SU_TIMER_ARG_T          struct tport_master
+#define SU_MSG_ARG_T            union tport_su_msg_arg
+
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/msg.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP (132)
+#endif
+
+#include "sofia-sip/tport.h"
+#include "sofia-sip/su_uniqueid.h"
+#include <sofia-sip/rbtree.h>
+
+#include "tport_internal.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "tport";
+#endif
+
+#define STACK_RECV(tp, msg, now)		       \
+  (tp)->tp_master->mr_tpac->tpac_recv((tp)->tp_master->mr_stack, (tp), \
+				      (msg), (tp)->tp_magic, (now))
+
+#define STACK_ERROR(tp, errcode, dstname) \
+  (tp)->tp_master->mr_tpac->tpac_error((tp)->tp_master->mr_stack, (tp), \
+				       (errcode), (dstname))
+
+#define STACK_ADDRESS(tp)		       \
+  (tp)->tp_master->mr_tpac->tpac_address((tp)->tp_master->mr_stack, (tp))
+
+#define TP_STACK   tp_master->mr_stack
+
+/* Define macros for rbtree implementation */
+#define TP_LEFT(tp) ((tp)->tp_left)
+#define TP_RIGHT(tp) ((tp)->tp_right)
+#define TP_PARENT(tp) ((tp)->tp_dad)
+#define TP_SET_RED(tp) ((tp)->tp_black = 0)
+#define TP_SET_BLACK(tp) ((tp)->tp_black = 1)
+#define TP_IS_RED(tp) ((tp) && (tp)->tp_black == 0)
+#define TP_IS_BLACK(tp) (!(tp) || (tp)->tp_black == 1)
+#define TP_COPY_COLOR(dst, src) ((dst)->tp_black = (src)->tp_black)
+#define TP_INSERT(tp) ((void)0)
+#define TP_REMOVE(tp) ((tp)->tp_left = (tp)->tp_right = (tp)->tp_dad = NULL)
+
+static inline int tp_cmp(tport_t const *a, tport_t const *b)
+{
+  if (a == b)
+    return 0;
+  
+  if (a->tp_addrlen != b->tp_addrlen)
+    return (int)(a->tp_addrlen - b->tp_addrlen);
+
+  return memcmp(a->tp_addr, b->tp_addr, a->tp_addrlen);
+}
+
+static inline int tprb_is_inserted(tport_t const *a)
+{
+  return a->tp_dad != 0 || a->tp_left != 0 || a->tp_right != 0;
+}
+
+RBTREE_PROTOS(static inline, tprb, tport_t);
+
+RBTREE_BODIES(static inline, tprb, tport_t, 
+	      TP_LEFT, TP_RIGHT, TP_PARENT,
+	      TP_IS_RED, TP_SET_RED, TP_IS_BLACK, TP_SET_BLACK, TP_COPY_COLOR,
+	      tp_cmp, TP_INSERT, TP_REMOVE);
+
+enum {
+  /** Default per-thread read queue length */
+  THRP_PENDING = 8
+};
+
+struct tport_pending_s {
+  /* tport_pending_t       *p_left, *p_right, *p_parent; */
+  void               *p_client;
+  tport_pending_error_f *p_callback;
+  msg_t              *p_msg;
+  unsigned short      p_reported;
+  unsigned short      p_on_success;
+};
+
+/** Return true if transport is master. */
+int tport_is_master(tport_t const *self)
+{
+  return 
+    self && 
+    self->tp_master->mr_master == self;
+}
+
+/** Return true if transport is primary. */
+int tport_is_primary(tport_t const *self)
+{
+  return 
+    self && 
+    self->tp_pri->pri_primary == self;
+}
+
+/** Return true if transport is secondary. */
+int tport_is_secondary(tport_t const *self)
+{
+  return 
+    self && 
+    self->tp_master->mr_master != self && 
+    self->tp_pri->pri_primary != self;
+}
+
+/** Test if transport has been registered */
+int tport_is_registered(tport_t const *self)
+{
+  return self->tp_index != 0;
+}
+
+/** Test if transport is stream. */
+int tport_is_stream(tport_t const *self)
+{
+  return self->tp_addrinfo->ai_socktype == SOCK_STREAM;
+}
+ 
+/** Test if transport is dgram. */
+int tport_is_dgram(tport_t const *self)
+{
+  return self->tp_addrinfo->ai_socktype == SOCK_DGRAM;
+}
+ 
+/** Test if transport is udp. */
+int tport_is_udp(tport_t const *self)
+{
+  return self->tp_addrinfo->ai_protocol == IPPROTO_UDP;
+}
+ 
+/** Test if transport is tcp. */
+int tport_is_tcp(tport_t const *self)
+{
+  return self->tp_addrinfo->ai_protocol == IPPROTO_TCP;
+}
+ 
+/** Return 1 if transport is reliable, 0 otherwise.
+ *
+ * (Note that this is part of external API).
+ */
+int tport_is_reliable(tport_t const *self)
+{
+  return self != NULL && 
+    (self->tp_addrinfo->ai_socktype == SOCK_STREAM || 
+     self->tp_addrinfo->ai_socktype == SOCK_SEQPACKET);
+}
+
+/** Return 0 if self is local, nonzero otherwise.
+ *
+ * The return valu is the 
+ *
+ * @sa TPTAG_PUBLIC(), enum #tport_via.
+ */
+int tport_is_public(tport_t const *self)
+{
+  return self->tp_pri->pri_public;
+}
+
+/** Return true if transport supports IPv4 */
+int tport_has_ip4(tport_t const *self)
+{
+  return self && 
+    (self->tp_addrinfo->ai_family == 0 || 
+     self->tp_addrinfo->ai_family == AF_INET);
+}
+
+
+#if SU_HAVE_IN6
+/** Return true if transport supports IPv6 */
+int tport_has_ip6(tport_t const *self)
+{
+  return self && 
+    (self->tp_addrinfo->ai_family == 0 || 
+     self->tp_addrinfo->ai_family == AF_INET6);
+}
+#endif
+
+/** Return true if transport supports TLS. */
+int tport_has_tls(tport_t const *self)
+{
+  return self && self->tp_pri->pri_has_tls;
+
+}
+
+/** Return true if transport is being updated. */
+int tport_is_updating(tport_t const *self)
+{
+  tport_primary_t *pri;
+
+  if (tport_is_master(self)) {
+    for (pri = self->tp_master->mr_primaries; pri; pri = pri->pri_next) 
+      if (pri->pri_updating)
+	return 1;
+  }
+  else if (tport_is_primary(self)) {
+    return self->tp_pri->pri_updating;
+  }
+
+  return 0;
+}
+
+/** Test if transport has been closed.
+ *
+ * @since New in @VERSION_1_12_4
+ */
+inline int tport_is_closed(tport_t const *self)
+{
+  return self->tp_closed;
+}
+
+/** Test if transport has been shut down.
+ *
+ * @since New in @VERSION_1_12_4
+ */
+inline int tport_is_shutdown(tport_t const *self)
+{
+  return self->tp_closed || self->tp_send_close || self->tp_recv_close;
+}
+
+/** Test if transport is bound */
+static inline int tport_is_bound(tport_t const *self)
+{
+  return self->tp_protoname != NULL;
+}
+
+/** Test if transport connection has been established. @NEW_1_12_5 */
+inline int tport_is_connected(tport_t const *self)
+{
+  return self->tp_is_connected;
+}
+
+/** MTU for transport  */
+static inline unsigned tport_mtu(tport_t const *self)
+{
+  return self->tp_params->tpp_mtu;
+}
+
+static inline
+int tport_has_sigcomp(tport_t const *self)
+{
+  return self->tp_name->tpn_comp != NULL;
+}
+
+/** Set IP TOS for socket */
+void tport_set_tos(su_socket_t socket, su_addrinfo_t *ai, int tos)
+{
+  if (tos >= 0 && 
+      ai->ai_family == AF_INET && 
+      setsockopt(socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
+    SU_DEBUG_3(("tport: setsockopt(IP_TOS): %s\n",
+		su_strerror(su_errno())));
+  }
+}
+
+static 
+tport_t *tport_connect(tport_primary_t *pri, su_addrinfo_t *ai, 
+		       tp_name_t const *tpn);
+
+static int bind6only_check(tport_master_t *mr);
+
+static
+int tport_server_addrinfo(tport_master_t *mr,
+			  char const *canon,
+			  int family,
+			  char const *host, 
+			  char const *service,
+			  char const *protocol,
+			  char const * const transports[],
+			  su_addrinfo_t **res);
+
+static int tport_get_local_addrinfo(tport_master_t *mr, 
+				    char const *port,
+				    su_addrinfo_t const *hints,
+				    su_addrinfo_t **return_ai);
+
+int tport_getaddrinfo(char const *node, char const *service,
+		      su_addrinfo_t const *hints,
+		      su_addrinfo_t **res);
+
+static void tport_freeaddrinfo(su_addrinfo_t *ai);
+
+static
+int tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen,
+			su_addrinfo_t const *src);
+
+static int
+  tport_bind_client(tport_master_t *self, tp_name_t const *tpn,
+		    char const * const transports[], enum tport_via public,
+		    tagi_t *tags),
+  tport_bind_server(tport_master_t *, tp_name_t const *tpn,
+		    char const * const transports[],  enum tport_via public,
+		    tagi_t *tags),
+
+  tport_setname(tport_t *, char const *, su_addrinfo_t const *, char const *),
+  tport_wakeup_pri(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+  tport_wakeup(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+  tport_base_wakeup(tport_t *self, int events),
+  tport_connected(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+  tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn),
+  tport_send_error(tport_t *, msg_t *, tp_name_t const *),
+  tport_queue(tport_t *self, msg_t *msg),
+  tport_queue_rest(tport_t *self, msg_t *msg, msg_iovec_t iov[], size_t iovused),
+  tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error),
+  tport_pending_errmsg(tport_t *self, msg_t *msg, int error);
+
+static ssize_t tport_vsend(tport_t *self, msg_t *msg, tp_name_t const *tpn,
+			   msg_iovec_t iov[], size_t iovused,
+			   struct sigcomp_compartment *cc);
+
+tport_t *tport_by_addrinfo(tport_primary_t const *pri,
+			   su_addrinfo_t const *ai,
+			   tp_name_t const *tpn);
+
+void tport_peer_address(tport_t *self, msg_t *msg);
+static unsigned long tport_now(void);
+
+static void tport_tick(su_root_magic_t *, su_timer_t *, tport_master_t *mr);
+
+static void tport_parse(tport_t *self, int complete, su_time_t now);
+
+static tport_primary_t *tport_alloc_primary(tport_master_t *mr,
+					    tport_vtable_t const *vtable,
+					    tp_name_t tpn[1],
+					    su_addrinfo_t *ai, 
+					    tagi_t const *tags,
+					    char const **return_culprit);
+
+static tport_primary_t *tport_listen(tport_master_t *mr,
+				     tport_vtable_t const *vtable,
+				     tp_name_t tpn[1],
+				     su_addrinfo_t *ai,
+				     tagi_t *tags);
+static void tport_zap_primary(tport_primary_t *);
+
+static char *localipname(int pf, char *buf, size_t bufsiz);
+static int getprotohints(su_addrinfo_t *hints,
+			 char const *proto, int flags);
+static void tport_send_queue(tport_t *self);
+
+
+/* Stack class used when transports are being destroyed */
+static
+void tport_destroy_recv(tp_stack_t *stack, tport_t *tp, 
+			msg_t *msg, tp_magic_t *magic, 
+			su_time_t received)
+{
+  msg_destroy(msg);
+}
+
+static
+void tport_destroy_error(tp_stack_t *stack, tport_t *tp, 
+			 int errcode, char const *remote)
+{
+}
+
+static
+msg_t *tport_destroy_alloc(tp_stack_t *stack, int flags, 
+			   char const data[], usize_t len,
+			   tport_t const *tp,
+			   tp_client_t *tpc)
+{
+  return NULL;
+}
+
+/** Name for "any" transport. @internal */
+static char const tpn_any[] = "*";
+
+/** Create the master transport. */
+tport_t *tport_tcreate(tp_stack_t *stack,
+		       tp_stack_class_t const *tpac,
+		       su_root_t *root, 
+		       tag_type_t tag, tag_value_t value, ...)
+{
+  tport_master_t *mr;
+  tp_name_t *tpn;
+  tport_params_t *tpp;
+  unsigned tick;
+  ta_list ta;
+
+  if (!stack || !tpac || !root) {
+    su_seterrno(EINVAL);
+    return NULL;
+  }
+
+  mr = su_home_clone(NULL, sizeof *mr);
+  if (!mr)
+    return NULL;
+
+  SU_DEBUG_7(("%s(): %p\n", "tport_create", mr));
+
+  mr->mr_stack = stack;
+  mr->mr_tpac = tpac;
+  mr->mr_root = root;
+
+  mr->mr_master->tp_master = mr;
+  mr->mr_master->tp_params = tpp = mr->mr_params;
+
+  mr->mr_master->tp_reusable = 1;
+  tpp->tpp_mtu = UINT_MAX;
+  tpp->tpp_thrprqsize = THRP_PENDING;
+  tpp->tpp_qsize = TPORT_QUEUESIZE;
+  tpp->tpp_sdwn_error = 1;
+  tpp->tpp_idle = UINT_MAX;
+  tpp->tpp_timeout = UINT_MAX;
+  tpp->tpp_sigcomp_lifetime = UINT_MAX;
+  tpp->tpp_stun_server = 1;
+  tpp->tpp_tos = -1;                  /* set invalid, valid values are 0-255 */
+
+  tpn = mr->mr_master->tp_name;
+  tpn->tpn_proto = "*";
+  tpn->tpn_host = "*";
+  tpn->tpn_canon = "*";
+  tpn->tpn_port = "*";
+
+  ta_start(ta, tag, value);
+
+  tport_set_params(mr->mr_master, ta_tags(ta));
+  tport_open_log(mr, ta_args(ta));
+
+  tick = 5000; /* For testing, usually 30000 is enough */  
+  if (tpp->tpp_idle < 4 * tick)
+    tick = tpp->tpp_idle / 4;
+  if (tpp->tpp_timeout < 4 * tick)
+    tick = tpp->tpp_timeout / 4;
+  if (tick < 200)
+    tick = 200;
+
+  tport_init_stun_server(mr, ta_args(ta));
+
+  mr->mr_timer = su_timer_create(su_root_task(root), tick);
+  su_timer_set(mr->mr_timer, tport_tick, mr);
+
+  ta_end(ta);
+
+  return mr->mr_master;
+}
+
+/** Destroy the master transport. */
+void tport_destroy(tport_t *self)
+{
+  tport_master_t *mr;
+
+  static tp_stack_class_t tport_destroy_tpac[1] = 
+    {{
+	sizeof tport_destroy_tpac,
+	/* tpac_recv */ tport_destroy_recv,
+	/* tpac_error */ tport_destroy_error,
+	/* tpac_alloc */ tport_destroy_alloc,
+	/* tpac_address */ NULL
+      }};
+
+  SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+  if (self == NULL)
+    return;
+  
+  assert(tport_is_master(self));
+  if (!tport_is_master(self))
+    return;
+
+  mr = (tport_master_t *)self;
+  mr->mr_tpac = tport_destroy_tpac;
+
+  while (mr->mr_primaries)
+    tport_zap_primary(mr->mr_primaries);
+
+  tport_deinit_stun_server(mr);
+
+  if (mr->mr_dump_file)
+    fclose(mr->mr_dump_file), mr->mr_dump_file = NULL;
+
+  if (mr->mr_timer)
+    su_timer_destroy(mr->mr_timer), mr->mr_timer = NULL;
+
+  su_home_zap(mr->mr_home);
+}
+
+
+/** Allocate a primary transport */
+static 
+tport_primary_t *tport_alloc_primary(tport_master_t *mr,
+				     tport_vtable_t const *vtable,
+				     tp_name_t tpn[1],
+				     su_addrinfo_t *ai,
+				     tagi_t const *tags,
+				     char const **return_culprit)
+{
+  tport_primary_t *pri, **next;
+  tport_t *tp;
+  int save_errno;
+
+  for (next = &mr->mr_primaries; *next; next = &(*next)->pri_next)
+    ;
+  
+  assert(vtable->vtp_pri_size >= sizeof *pri);
+
+  if ((pri = su_home_clone(mr->mr_home, vtable->vtp_pri_size))) {
+    tport_t *tp = pri->pri_primary;
+    pri->pri_vtable = vtable;
+    pri->pri_public = vtable->vtp_public;
+
+    tp->tp_master = mr;
+    tp->tp_pri = pri;
+    tp->tp_socket = INVALID_SOCKET;
+
+    tp->tp_magic = mr->mr_master->tp_magic;
+
+    tp->tp_params = pri->pri_params;
+    memcpy(tp->tp_params, mr->mr_params, sizeof (*tp->tp_params));
+    tp->tp_reusable = mr->mr_master->tp_reusable;
+
+    if (!pri->pri_public)
+      tp->tp_addrinfo->ai_addr = &tp->tp_addr->su_sa;
+
+    SU_DEBUG_5(("%s(%p): new primary tport %p\n", __func__, mr, pri));
+  }
+
+  *next = pri; 
+  tp = pri->pri_primary;
+  
+  if (!tp)
+    *return_culprit = "alloc";
+  else if (tport_set_params(tp, TAG_NEXT(tags)) < 0)
+    *return_culprit = "tport_set_params";
+  else if (vtable->vtp_init_primary &&
+	   vtable->vtp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+    ;
+  else if (tport_setname(tp, vtable->vtp_name, ai, tpn->tpn_canon) == -1) 
+    *return_culprit = "tport_setname";
+  else if (tpn->tpn_ident && 
+	   !(tp->tp_name->tpn_ident = su_strdup(tp->tp_home, tpn->tpn_ident)))
+    *return_culprit = "alloc ident";
+  else
+    return pri;			/* Success */
+
+  save_errno = su_errno();
+  tport_zap_primary(pri);
+  su_seterrno(save_errno);
+
+  return NULL;
+}
+
+
+/** Destroy a primary transport and its secondary transports. @internal */
+static 
+void tport_zap_primary(tport_primary_t *pri)
+{
+  tport_primary_t **prip;
+
+  if (pri == NULL)
+    return;
+
+  assert(tport_is_primary(pri->pri_primary));
+
+  if (pri->pri_vtable->vtp_deinit_primary)
+    pri->pri_vtable->vtp_deinit_primary(pri);
+
+  while (pri->pri_secondary)
+    tport_zap_secondary(pri->pri_secondary);
+
+  /* We have just a single-linked list for primary transports */
+  for (prip = &pri->pri_master->mr_primaries;
+       *prip != pri;
+       prip = &(*prip)->pri_next)
+    assert(*prip);
+
+  *prip = pri->pri_next;
+
+  tport_zap_secondary(pri->pri_primary);
+}
+
+/**Create a primary transport object with socket.
+ *
+ * Creates a primary transport object with a server socket, and then
+ * registers the socket with suitable events to the root.
+ *
+ * @param dad   parent (master or primary) transport object
+ * @param ai    pointer to addrinfo structure
+ * @param canon canonical name of node
+ * @param protoname name of the protocol
+ */
+static
+tport_primary_t *tport_listen(tport_master_t *mr,
+			      tport_vtable_t const *vtable,
+			      tp_name_t tpn[1],
+			      su_addrinfo_t *ai, 
+			      tagi_t *tags)
+{
+  tport_primary_t *pri = NULL;
+
+  int err;
+  int errlevel = 3;
+  char buf[TPORT_HOSTPORTSIZE];
+
+  char const *protoname = vtable->vtp_name;
+  char const *culprit = "unknown";
+
+  su_sockaddr_t *su = (void *)ai->ai_addr;
+
+  /* Log an error, return error */
+#define TPORT_LISTEN_ERROR(errno, what)				     \
+  ((void)(err = errno,						     \
+	  ((err == EADDRINUSE || err == EAFNOSUPPORT ||		     \
+	    err == ESOCKTNOSUPPORT || err == EPROTONOSUPPORT ||	     \
+	    err == ENOPROTOOPT ? 7 : 3) < SU_LOG_LEVEL ?	     \
+	     su_llog(tport_log, errlevel,			     \
+		     "%s(%p): %s(pf=%d %s/%s): %s\n",		     \
+		     __func__, pri ? (void *)pri : (void *)mr, what, \
+		     ai->ai_family, protoname,			     \
+		     tport_hostport(buf, sizeof(buf), su, 2),	     \
+		     su_strerror(err)) : (void)0),		     \
+	    tport_zap_primary(pri),		                     \
+	    su_seterrno(err)),					     \
+     (void *)NULL)
+
+  /* Create a primary transport object for another transport. */
+  pri = tport_alloc_primary(mr, vtable, tpn, ai, tags, &culprit);
+  if (pri == NULL)
+    return TPORT_LISTEN_ERROR(errno, culprit);
+
+  if (pri->pri_primary->tp_socket != INVALID_SOCKET) {
+    int index = 0;
+    tport_t *tp = pri->pri_primary;
+    su_wait_t wait[1] = { SU_WAIT_INIT };
+
+    if (su_wait_create(wait, tp->tp_socket, tp->tp_events) == -1)
+      return TPORT_LISTEN_ERROR(su_errno(), "su_wait_create");
+
+    /* Register receiving or accepting function with events specified above */
+    index = su_root_register(mr->mr_root, wait, tport_wakeup_pri, tp, 0); 
+    if (index == -1) {
+      su_wait_destroy(wait);
+      return TPORT_LISTEN_ERROR(su_errno(), "su_root_register");
+    }
+
+    tp->tp_index = index;
+  }
+
+  pri->pri_primary->tp_has_connection = 0;
+
+  SU_DEBUG_5(("%s(%p): %s " TPN_FORMAT "\n", 
+	      __func__, pri, "listening at",
+	      TPN_ARGS(pri->pri_primary->tp_name)));
+
+  return pri;
+}
+
+int tport_bind_socket(int socket,
+		      su_addrinfo_t *ai,
+		      char const **return_culprit)
+{
+  su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr;
+  socklen_t sulen = (socklen_t)(ai->ai_addrlen);
+
+  if (bind(socket, ai->ai_addr, sulen) == -1) {
+    return *return_culprit = "bind", -1;
+  }
+
+  if (getsockname(socket, &su->su_sa, &sulen) == SOCKET_ERROR) {
+    return *return_culprit = "getsockname", -1;
+  }
+
+  ai->ai_addrlen = sulen;
+
+#if defined (__linux__) && defined (SU_HAVE_IN6)
+  if (ai->ai_family == AF_INET6) {
+    if (!SU_SOCKADDR_INADDR_ANY(su) &&
+	(IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) ||
+	 IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))) {
+      su_sockaddr_t su0[1];
+      
+      memcpy(su0, su, sizeof su0);
+      
+      memset(su, 0, ai->ai_addrlen = sizeof su->su_sin);
+      su->su_family = ai->ai_family = AF_INET;
+      su->su_port = su0->su_port;
+      
+#ifndef IN6_V4MAPPED_TO_INADDR
+#define IN6_V4MAPPED_TO_INADDR(in6, in4) \
+      memcpy((in4), 12 + (uint8_t *)(in6), sizeof(struct in_addr))
+#endif
+      IN6_V4MAPPED_TO_INADDR(&su0->su_sin6.sin6_addr, &su->su_sin.sin_addr);
+    }
+  }
+#endif
+
+  return 0;
+}
+
+
+/** Indicate stack that a transport has been updated */
+void tport_has_been_updated(tport_t *self)
+{
+  self->tp_pri->pri_updating = 0;
+
+  if (self->tp_master->mr_tpac->tpac_address)
+    self->tp_master->mr_tpac->tpac_address(self->tp_master->mr_stack, self);
+}
+
+
+static
+int tport_set_events(tport_t *self, int set, int clear)
+{
+  int events;
+
+  if (self == NULL)
+    return -1;
+
+  events = (self->tp_events | set) & ~clear;
+  self->tp_events = events;
+
+  if (self->tp_pri->pri_vtable->vtp_set_events)
+    return self->tp_pri->pri_vtable->vtp_set_events(self);
+
+  SU_DEBUG_7(("tport_set_events(%p): events%s%s%s\n", self,
+	      (events & SU_WAIT_IN) ? " IN" : "",
+	      (events & SU_WAIT_OUT) ? " OUT" : "",
+	      SU_WAIT_CONNECT != SU_WAIT_OUT &&
+	      (events & SU_WAIT_CONNECT) ? " CONNECT" : ""));
+  
+  return 
+    su_root_eventmask(self->tp_master->mr_root, 
+		      self->tp_index, 
+		      self->tp_socket, 
+		      self->tp_events = events);
+}
+
+/**Allocate a secondary transport. @internal
+ *
+ * The function tport_alloc_secondary() creates a secondary transport
+ * object. The new transport initally shares parameters structure with the
+ * original transport.
+ *
+ * @param pri    primary transport
+ * @param socket socket for transport
+ * @parma accepted true if the socket was accepted from server socket
+ *
+ * @return
+ * Pointer to the newly created transport, or NULL upon an error.
+ *
+ * @note The socket is always closed upon error.
+ */
+tport_t *tport_alloc_secondary(tport_primary_t *pri, 
+			       int socket,
+			       int accepted,
+			       char const **return_reason)
+{
+  tport_master_t *mr = pri->pri_master;
+  tport_t *self;
+
+  self = su_home_clone(mr->mr_home, pri->pri_vtable->vtp_secondary_size);
+
+  if (self) {
+    SU_DEBUG_7(("%s(%p): new secondary tport %p\n", __func__, pri, self));
+
+    self->tp_refs = -1;			/* Freshly allocated  */
+    self->tp_master = mr;
+    self->tp_pri = pri;
+    self->tp_params = pri->pri_params;
+    self->tp_accepted = accepted != 0;
+    self->tp_reusable = pri->pri_primary->tp_reusable;
+
+    self->tp_magic = pri->pri_primary->tp_magic;
+
+    self->tp_addrinfo->ai_addr = (void *)self->tp_addr;
+
+    self->tp_socket = socket;
+    
+    if (pri->pri_vtable->vtp_init_secondary &&
+	pri->pri_vtable->vtp_init_secondary(self, socket, accepted,
+					    return_reason) < 0) {
+      if (pri->pri_vtable->vtp_deinit_secondary)
+	pri->pri_vtable->vtp_deinit_secondary(self);
+      su_home_zap(self->tp_home);
+      return NULL;
+    }
+
+    /* Set IP TOS if it is set in primary */
+    tport_set_tos(socket,
+		  pri->pri_primary->tp_addrinfo,
+		  pri->pri_params->tpp_tos);
+  }
+  else {
+    su_close(socket);
+    *return_reason = "malloc";
+  }
+
+  return self;
+}
+
+
+/** Create a connected transport object with socket.
+ *
+ * The function tport_connect() creates a secondary transport with a
+ * connected socket. It registers the socket with suitable events to the
+ * root.
+ *
+ * @param pri   primary transport object
+ * @param ai    pointer to addrinfo structure
+ * @param tpn   canonical name of node
+ */
+static
+tport_t *tport_connect(tport_primary_t *pri, 
+		       su_addrinfo_t *ai,
+		       tp_name_t const *tpn)
+{
+  if (ai == NULL || ai->ai_addrlen > sizeof (pri->pri_primary->tp_addr))
+    return NULL;
+
+  if (pri->pri_vtable->vtp_connect)
+    return pri->pri_vtable->vtp_connect(pri, ai, tpn);
+  else
+    return tport_base_connect(pri, ai, ai, tpn);
+}
+
+/**Create a connected transport object with socket.
+ *
+ * The function tport_connect() creates a secondary transport with a
+ * connected socket. It registers the socket with suitable events to the
+ * root.
+ *
+ * @param pri   primary transport object
+ * @param ai    pointer to addrinfo structure describing socket
+ * @param real_ai  pointer to addrinfo structure describing real target
+ * @param tpn   canonical name of node
+ */
+tport_t *tport_base_connect(tport_primary_t *pri,
+			    su_addrinfo_t *ai,
+			    su_addrinfo_t *real_ai,
+			    tp_name_t const *tpn)
+{
+  tport_master_t *mr = pri->pri_master;
+  tport_t *self = NULL;
+
+  su_socket_t s, server_socket;
+  su_wait_t wait[1] = { SU_WAIT_INIT };
+  su_wakeup_f wakeup = tport_wakeup;
+  int index = 0;
+  int events = SU_WAIT_IN | SU_WAIT_ERR;
+
+  int err;
+  unsigned errlevel = 3;
+  char buf[TPORT_HOSTPORTSIZE];
+  char const *what;
+
+  /* Log an error, return error */
+#define TPORT_CONNECT_ERROR(errno, what)			     \
+  return							     \
+    ((void)(err = errno,					     \
+	    su_wait_destroy(wait),				     \
+	    (SU_LOG_LEVEL >= errlevel ?				     \
+	     su_llog(tport_log, errlevel,			     \
+		     "%s(%p): %s(pf=%d %s/%s): %s\n",		     \
+		     __func__, pri, #what, ai->ai_family,	     \
+		     tpn->tpn_proto,				     \
+		     tport_hostport(buf, sizeof(buf),		     \
+				    (void *)ai->ai_addr, 2),	     \
+		     su_strerror(err)) : (void)0),		     \
+	    tport_zap_secondary(self),				     \
+	    su_seterrno(err)),					     \
+     (void *)NULL)
+
+  s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+  if (s == INVALID_SOCKET)
+    TPORT_CONNECT_ERROR(su_errno(), "socket");
+
+  what = "tport_alloc_secondary";
+  if ((self = tport_alloc_secondary(pri, s, 0, &what)) == NULL)
+    TPORT_CONNECT_ERROR(errno, what);
+
+  self->tp_conn_orient = 1;
+
+  if ((server_socket = pri->pri_primary->tp_socket) != INVALID_SOCKET) {
+    su_sockaddr_t susa;
+    socklen_t susalen = sizeof(susa);
+
+    /* Bind this socket to same IP address as the primary server socket */
+    if (getsockname(server_socket, &susa.su_sa, &susalen) < 0) {
+      SU_DEBUG_3(("tport_connect: getsockname(): %s\n", 
+		  su_strerror(su_errno())));
+    }
+    else {
+      susa.su_port = 0;
+      if (bind(s, &susa.su_sa, susalen) < 0) {
+	SU_DEBUG_3(("tport_connect: bind(local-ip): %s\n", 
+		    su_strerror(su_errno())));
+      }
+    }
+  }
+
+  /* Set sockname for the tport */
+  if (tport_setname(self, tpn->tpn_proto, real_ai, tpn->tpn_canon) == -1) 
+    TPORT_CONNECT_ERROR(su_errno(), tport_setname);
+
+  if (connect(s, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == SOCKET_ERROR) {
+    err = su_errno();
+    if (!su_is_blocking(err))
+      TPORT_CONNECT_ERROR(err, connect);
+    events = SU_WAIT_CONNECT | SU_WAIT_ERR;
+    wakeup = tport_connected;
+    what = "connecting";
+  }
+  else {
+    what = "connected";
+    self->tp_is_connected = 1;
+  }
+
+  if (su_wait_create(wait, s, self->tp_events = events) == -1)
+    TPORT_CONNECT_ERROR(su_errno(), su_wait_create);
+
+  /* Register receiving function with events specified above */
+  if ((index = su_root_register(mr->mr_root, wait, wakeup, self, 0)) == -1)
+    TPORT_CONNECT_ERROR(su_errno(), su_root_register);
+
+  self->tp_index = index;
+
+  if (ai == real_ai) {
+    SU_DEBUG_5(("%s(%p): %s to " TPN_FORMAT "\n", 
+		__func__, self, what, TPN_ARGS(self->tp_name)));
+  }
+  else {
+    SU_DEBUG_5(("%s(%p): %s via %s to " TPN_FORMAT "\n",
+		__func__, self, what,
+		tport_hostport(buf, sizeof(buf), (void *)ai->ai_addr, 2),
+		TPN_ARGS(self->tp_name)));
+  }
+  
+  tprb_append(&pri->pri_secondary, self);
+
+  return self;
+}
+
+/** Destroy a secondary transport. @internal */
+void tport_zap_secondary(tport_t *self)
+{
+  tport_master_t *mr;
+
+  if (self == NULL)
+    return;
+
+  /* Remove from rbtree */
+  tprb_remove(&self->tp_pri->pri_secondary, self);
+
+  /* Do not deinit primary as secondary! */
+  if (tport_is_secondary(self) &&
+      self->tp_pri->pri_vtable->vtp_deinit_secondary)
+    self->tp_pri->pri_vtable->vtp_deinit_secondary(self);
+
+  if (self->tp_msg) {
+    msg_destroy(self->tp_msg), self->tp_msg = NULL;
+    SU_DEBUG_3(("%s(%p): zapped partially received message\n", 
+		__func__, self));
+  }
+
+  if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+    size_t n = 0, i, N = self->tp_params->tpp_qsize;
+    for (i = self->tp_qhead; self->tp_queue[i]; i = (i + 1) % N) {
+      msg_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+      n++;
+    }
+    SU_DEBUG_3(("%s(%p): zapped %lu queued messages\n", 
+		__func__, self, (LU)n));
+  }
+
+  if (self->tp_pused) {
+    SU_DEBUG_3(("%s(%p): zapped with pending requests\n", __func__, self));
+  }
+
+  mr = self->tp_master;
+
+  tport_stun_server_remove_socket(self);
+
+  if (self->tp_index)
+    su_root_deregister(mr->mr_root, self->tp_index);
+  self->tp_index = 0;
+  if (self->tp_socket != INVALID_SOCKET)
+    su_close(self->tp_socket);
+  self->tp_socket = INVALID_SOCKET;
+
+  su_home_zap(self->tp_home);
+}
+
+/** Create a new reference to a transport object. */
+tport_t *tport_ref(tport_t *tp)
+{
+  if (tp) {
+    if (tp->tp_refs >= 0)
+      tp->tp_refs++;
+    else if (tp->tp_refs == -1)
+      tp->tp_refs = 1;
+  }
+  return tp;
+}
+
+/** Destroy reference to a transport object. */
+void tport_unref(tport_t *tp)
+{
+  if (tp && tp->tp_refs > 0)
+    if (--tp->tp_refs == 0 && tp->tp_params->tpp_idle == 0)
+      if (!tport_is_closed(tp))
+	tport_close(tp);
+}
+
+/** Create a new reference to transport object. */
+tport_t *tport_incref(tport_t *tp)
+{
+  return tport_ref(tp);
+}
+
+/** Destroy a transport reference. */
+void tport_decref(tport_t **ttp)
+{
+  assert(ttp);
+
+  if (*ttp) {
+    tport_unref(*ttp);
+    *ttp = NULL;
+  }
+}
+
+/** Get transport parameters.
+ *
+ * @param self          pointer to a transport object
+ * @param tag,value,... list of tags
+ */
+int tport_get_params(tport_t const *self,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int n;
+  tport_params_t const *tpp;
+  tport_primary_t const *pri = self->tp_pri;
+  int connect;
+
+  if (self == NULL)
+    return su_seterrno(EINVAL);
+
+  tpp = self->tp_params;
+  ta_start(ta, tag, value);
+
+  connect = tpp->tpp_conn_orient 
+    /* Only dgram primary is *not* connection-oriented */
+    || !tport_is_primary(self) || !tport_is_dgram(self);
+
+  n = tl_tgets(ta_args(ta),
+	       TPTAG_MTU(tpp->tpp_mtu),
+	       TPTAG_REUSE(self->tp_reusable),
+	       TPTAG_CONNECT(connect),
+	       TPTAG_QUEUESIZE(tpp->tpp_qsize),
+	       TPTAG_IDLE(tpp->tpp_idle),
+	       TPTAG_TIMEOUT(tpp->tpp_timeout),
+	       TPTAG_SDWN_ERROR(tpp->tpp_sdwn_error),
+	       TPTAG_DEBUG_DROP(tpp->tpp_drop),
+	       TPTAG_THRPSIZE(tpp->tpp_thrpsize),
+	       TPTAG_THRPRQSIZE(tpp->tpp_thrprqsize),
+	       TAG_IF(pri, TPTAG_PUBLIC(pri ? pri->pri_public : 0)),
+	       TPTAG_TOS(tpp->tpp_tos),
+	       TAG_END());
+
+  ta_end(ta);
+
+  return n;
+}
+
+/** Set transport parameters.
+ *
+ * @param self          pointer to a transport object
+ * @param tag,value,... list of tags
+ */
+int tport_set_params(tport_t *self,
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int n;
+  tport_params_t tpp[1], *tpp0;
+
+  int connect, sdwn_error, reusable, stun_server;
+
+  struct sigcomp_compartment *cc = NONE;
+
+  if (self == NULL)
+    return su_seterrno(EINVAL);
+
+  memcpy(tpp, tpp0 = self->tp_params, sizeof *tpp);
+
+  connect = tpp->tpp_conn_orient;
+  sdwn_error = tpp->tpp_sdwn_error;
+  reusable = self->tp_reusable;
+  stun_server = tpp->tpp_stun_server;
+
+  ta_start(ta, tag, value);
+
+  n = tl_gets(ta_args(ta),
+	      TPTAG_MTU_REF(tpp->tpp_mtu),
+	      TAG_IF(!self->tp_queue, TPTAG_QUEUESIZE_REF(tpp->tpp_qsize)),
+	      TPTAG_IDLE_REF(tpp->tpp_idle),
+	      TPTAG_TIMEOUT_REF(tpp->tpp_timeout),
+	      TPTAG_DEBUG_DROP_REF(tpp->tpp_drop),
+	      TPTAG_THRPSIZE_REF(tpp->tpp_thrpsize),
+	      TPTAG_THRPRQSIZE_REF(tpp->tpp_thrprqsize),
+	      TPTAG_SIGCOMP_LIFETIME_REF(tpp->tpp_sigcomp_lifetime),
+	      TPTAG_CONNECT_REF(connect),
+	      TPTAG_SDWN_ERROR_REF(sdwn_error),
+	      TPTAG_REUSE_REF(reusable),
+	      TPTAG_COMPARTMENT_REF(cc),
+	      TPTAG_STUN_SERVER_REF(stun_server),
+	      TPTAG_TOS_REF(tpp->tpp_tos),
+	      TAG_END());
+
+  ta_end(ta);
+
+  if (n == 0)
+    return 0;
+
+  if (tpp->tpp_idle > 0 && tpp->tpp_idle < 2000)
+    tpp->tpp_idle = 2000;
+  if (tpp->tpp_timeout < 1000)
+    tpp->tpp_timeout = 1000;
+  if (tpp->tpp_drop > 1000)
+    tpp->tpp_drop = 1000;
+  if (tpp->tpp_thrprqsize > 0)
+    tpp->tpp_thrprqsize = tpp0->tpp_thrprqsize;
+  if (tpp->tpp_sigcomp_lifetime != 0 && tpp->tpp_sigcomp_lifetime < 30)
+    tpp->tpp_sigcomp_lifetime = 30;
+  if (tpp->tpp_qsize >= 1000)
+    tpp->tpp_qsize = 1000;
+
+  /* Currently only primary UDP transport can *not* be connection oriented */ 
+  tpp->tpp_conn_orient = connect; 
+  tpp->tpp_sdwn_error = sdwn_error;
+  self->tp_reusable = reusable;
+  tpp->tpp_stun_server = stun_server;
+
+  if (tport_is_secondary(self) && 
+      self->tp_params == self->tp_pri->pri_primary->tp_params) {
+    tpp0 = su_zalloc(self->tp_home, sizeof *tpp0); if (!tpp0) return -1;
+  }
+
+  memcpy(tpp0, tpp, sizeof *tpp);
+
+  return n;
+}
+
+extern tport_vtable_t const tport_udp_vtable;
+extern tport_vtable_t const tport_tcp_vtable;
+extern tport_vtable_t const tport_tls_vtable;
+extern tport_vtable_t const tport_sctp_vtable;
+extern tport_vtable_t const tport_udp_client_vtable;
+extern tport_vtable_t const tport_tcp_client_vtable;
+extern tport_vtable_t const tport_sctp_client_vtable;
+extern tport_vtable_t const tport_tls_client_vtable;
+extern tport_vtable_t const tport_http_connect_vtable;
+extern tport_vtable_t const tport_threadpool_vtable;
+
+#define TPORT_NUMBER_OF_TYPES 64
+
+tport_vtable_t const *tport_vtables[TPORT_NUMBER_OF_TYPES + 1] =
+{
+  &tport_http_connect_vtable,
+#if HAVE_TLS
+  &tport_tls_client_vtable,
+  &tport_tls_vtable,
+#endif
+#if HAVE_SCTP		/* SCTP is broken */
+  &tport_sctp_client_vtable,
+  &tport_sctp_vtable,
+#endif
+  &tport_tcp_client_vtable,
+  &tport_tcp_vtable,
+  &tport_udp_client_vtable,
+  &tport_udp_vtable,
+#if 0
+  &tport_threadpool_vtable,
+#endif
+#if HAVE_SOFIA_STUN
+  &tport_stun_vtable,
+#endif
+};
+
+/** Register new transport vtable */
+int tport_register_type(tport_vtable_t const *vtp)
+{
+  int i;
+
+  for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+    if (tport_vtables[i] == NULL) {
+      tport_vtables[i] = vtp;
+      return 0;
+    }
+  }
+
+  su_seterrno(ENOMEM);
+  return -1;
+}
+
+/**Get a vtable for given protocol */
+tport_vtable_t const *tport_vtable_by_name(char const *protoname,
+					   enum tport_via public) 
+{
+  int i;
+
+  for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+    tport_vtable_t const *vtable = tport_vtables[i];
+
+    if (vtable == NULL)
+      continue;
+    if (vtable->vtp_public != public)
+      continue;
+    if (strcasecmp(vtable->vtp_name, protoname))
+      continue;
+
+    assert(vtable->vtp_pri_size >= sizeof (tport_primary_t));
+    assert(vtable->vtp_secondary_size >= sizeof (tport_t));
+    
+    return vtable;
+  }
+
+  return NULL;
+}
+
+#if 0
+tport_set_f const *tport_set_methods[TPORT_NUMBER_OF_TYPES + 1] = 
+  {
+    tport_server_bind_set,
+    tport_client_bind_set,
+    tport_threadpool_set,
+    tport_http_connect_set,
+#if HAVE_TLS
+    tport_tls_set,
+#endif
+    NULL
+  };
+
+int tport_bind_set(tport_master_t *mr, 
+		   tp_name_t const *tpn,
+		   char const * const transports[],
+		   tagi_t const *taglist,
+		   tport_set_t **return_set,
+		   int set_size)
+{
+  int i;
+
+  for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+    tport_set_f const *perhaps = tport_vtables[i];
+    int result;
+
+    if (perhaps == NULL)
+      continue;
+
+    result = perhaps(mr, tpn, transports, taglist, return_set, set_size);
+    if (result != 0)
+      return result;
+  }
+
+  return 0;
+}
+#endif
+
+/** Bind transport objects.
+ *
+ * @param self        pointer to a transport object
+ * @param tpn         desired transport address
+ * @param transports  list of protocol names supported by stack
+ * @param tag,value,... tagged argument list
+ */
+int tport_tbind(tport_t *self,
+		tp_name_t const *tpn,
+		char const * const transports[],
+		tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta;
+  int server = 1, retval, public = 0;
+  tp_name_t mytpn[1];
+  tport_master_t *mr;
+  char const *http_connect = NULL;
+  
+  if (self == NULL || tport_is_secondary(self) ||
+      tpn == NULL || transports == NULL) {
+    su_seterrno(EINVAL);
+    return -1;
+  }
+
+  *mytpn = *tpn;
+
+  if (mytpn->tpn_ident == NULL)
+    mytpn->tpn_ident = self->tp_ident;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  TPTAG_SERVER_REF(server),
+	  TPTAG_PUBLIC_REF(public),
+	  TPTAG_IDENT_REF(mytpn->tpn_ident),
+	  TPTAG_HTTP_CONNECT_REF(http_connect),
+	  TAG_END());
+
+  mr = self->tp_master; assert(mr);
+
+  if (http_connect && public == 0)
+    public = tport_type_connect;
+    
+  if (public && public != tport_type_stun)
+    server = 0;
+
+  if (server)
+    retval = tport_bind_server(mr, mytpn, transports, public, ta_args(ta));
+  else
+    retval = tport_bind_client(mr, mytpn, transports, public, ta_args(ta));
+
+  ta_end(ta);
+
+  return retval;
+}
+
+
+/** Bind primary transport objects used by a client-only application.
+ * @internal
+ */
+int tport_bind_client(tport_master_t *mr,
+                      tp_name_t const *tpn,
+                      char const * const transports[],
+		      enum tport_via public,
+		      tagi_t *tags)
+{
+  int i;
+  tport_primary_t *pri = NULL, **tbf;
+  tp_name_t tpn0[1] = {{ "*", "*", "*", "*", NULL, NULL }};
+  char const *why = "unknown";
+
+  tport_vtable_t const *vtable;
+
+  if (public == tport_type_local)
+    public = tport_type_client;
+
+  SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn)));
+
+  memset(tpn0, 0, sizeof(tpn0));
+
+  for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
+    ;
+
+  for (i = 0; transports[i]; i++) {
+    su_addrinfo_t hints[1];
+    char const *proto = transports[i];
+    
+    if (strcmp(proto, tpn->tpn_proto) != 0 && 
+        strcmp(tpn->tpn_proto, tpn_any) != 0)
+      continue;
+
+    vtable = tport_vtable_by_name(proto, public);
+    if (!vtable)
+      continue;
+
+    /* Resolve protocol, skip unknown transport protocols */
+    if (getprotohints(hints, proto, AI_PASSIVE) < 0)
+      continue;
+
+    tpn0->tpn_proto = proto;
+    tpn0->tpn_comp = tpn->tpn_comp;
+    tpn0->tpn_ident = tpn->tpn_ident;
+
+    hints->ai_canonname = "*";
+
+    if (!(pri = tport_alloc_primary(mr, vtable, tpn0, hints, tags, &why)))
+      break;
+
+    pri->pri_public = tport_type_client; /* XXX */
+  }
+
+  if (!pri) {
+    SU_DEBUG_3(("tport_alloc_primary: %s failed\n", why));
+    tport_zap_primary(*tbf);
+  }
+
+  return pri ? 0 : -1;
+}
+
+/** Bind primary transport objects used by a server application. */
+int tport_bind_server(tport_master_t *mr,
+                      tp_name_t const *tpn,
+                      char const * const transports[],
+		      enum tport_via public,
+		      tagi_t *tags)
+{
+  char hostname[256];
+  char const *canon = NULL, *host, *service;
+  int error = 0, not_supported, family = 0;
+  tport_primary_t *pri = NULL, **tbf;
+  su_addrinfo_t *ai, *res = NULL;
+  unsigned port, port0, port1, old;
+  unsigned short step = 0;
+
+  bind6only_check(mr);
+
+  SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn)));
+
+  if (tpn->tpn_host == NULL || strcmp(tpn->tpn_host, tpn_any) == 0) {
+    /* Use a local IP address */
+    host = NULL;
+  }
+#ifdef SU_HAVE_IN6
+  else if (tpn->tpn_host && tpn->tpn_host[0] == '[') {
+    /* Remove [] around IPv6 addresses. */
+    host = strcpy(hostname, tpn->tpn_host + 1);
+    hostname[strlen(hostname) - 1] = '\0';
+  }
+#endif
+  else
+    host = tpn->tpn_host;
+
+  if (tpn->tpn_port != NULL && strlen(tpn->tpn_port) > 0 &&
+      strcmp(tpn->tpn_port, tpn_any) != 0)
+    service = tpn->tpn_port;
+  else 
+    service = "";
+
+  if (host && (strcmp(host, "0.0.0.0") == 0 || strcmp(host, "0") == 0))
+    host = NULL, family = AF_INET;
+#if SU_HAVE_IN6
+  else if (host && strcmp(host, "::") == 0)
+    host = NULL, family = AF_INET6;
+#endif
+
+  if (tpn->tpn_canon && strcmp(tpn->tpn_canon, tpn_any) &&
+      (host || tpn->tpn_canon != tpn->tpn_host))
+    canon = tpn->tpn_canon;
+
+  if (tport_server_addrinfo(mr, canon, family, 
+			    host, service, tpn->tpn_proto,
+			    transports, &res) < 0)
+    return -1;
+
+  for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
+    ;
+
+  port = port0 = port1 = ntohs(((su_sockaddr_t *)res->ai_addr)->su_port);
+  error = EPROTONOSUPPORT;
+
+  /* 
+   * Loop until we can bind all the transports requested 
+   * by the transport user to the same port. 
+   */
+  for (;;) {
+    for (ai = res; ai; ai = ai->ai_next) {
+      tp_name_t tpname[1];
+      su_addrinfo_t ainfo[1];
+      su_sockaddr_t su[1];
+      tport_vtable_t const *vtable;
+
+      vtable = tport_vtable_by_name(ai->ai_canonname, public);
+      if (!vtable)
+	continue;
+
+      tport_addrinfo_copy(ainfo, su, sizeof su, ai);
+      ainfo->ai_canonname = (char *)canon;
+      su->su_port = htons(port);
+
+      memcpy(tpname, tpn, sizeof tpname);
+      tpname->tpn_canon = canon;
+      tpname->tpn_host = host;
+
+      SU_DEBUG_9(("%s(%p): calling tport_listen for %s\n", 
+		  __func__, mr, ai->ai_canonname));
+
+      pri = tport_listen(mr, vtable, tpname, ainfo, tags);
+      if (!pri) {
+	switch (error = su_errno()) {
+	case EADDRNOTAVAIL:	/* Not our address */
+	case ENOPROTOOPT:	/* Protocol not supported */
+	case ESOCKTNOSUPPORT:	/* Socket type not supported */
+	  continue;
+	default:
+	  break;
+	}
+	break;
+      }
+
+      not_supported = 0;
+
+      if (port0 == 0 && port == 0) {
+	port = port1 = ntohs(su->su_port);
+	assert(public != tport_type_server || port != 0);
+      }
+    }
+
+    if (ai == NULL)
+      break;
+
+    while (*tbf)
+      tport_zap_primary(*tbf);
+
+    if (error != EADDRINUSE || port0 != 0 || port == 0)
+      break;
+
+    while (step == 0) {
+      /* step should be relative prime to 65536 - 1024 */
+      /* 65536 - 1024 = 7 * 3 * 3 * 1024 */
+      step = su_randint(1, 65535 - 1024 - 1) | 1;
+      if (step % 3 == 0)
+	step = (step + 2) % (65536 - 1024);
+      if (step % 7 == 0)
+	step = (step + 2) % (65536 - 1024);
+    }
+    old = port; port += step; if (port >= 65536) port -= (65536 - 1024);
+
+    if (port == port1)		/* All ports in use! */
+      break;
+
+    SU_DEBUG_3(("%s(%p): cannot bind all transports to port %u, trying %u\n", 
+		__func__, mr, old, port));
+  }
+
+  tport_freeaddrinfo(res);
+
+  if (!*tbf) {
+    su_seterrno(error);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/** Check if we can bind to IPv6 separately from IPv4 bind */
+static
+int bind6only_check(tport_master_t *mr)
+{
+  int retval = 0;
+#if SU_HAVE_IN6
+  su_sockaddr_t su[1], su4[1];
+  socklen_t sulen, su4len;
+  int s6, s4;
+
+  if (mr->mr_boundserver)
+    return 0;
+
+  s4 = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  s6 = su_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+  
+  memset(su, 0, sizeof *su);
+  su->su_len = sulen = (sizeof su->su_sin6);
+  su->su_family = AF_INET6;
+  
+  memset(su4, 0, sizeof *su4);
+  su4->su_len = su4len = (sizeof su->su_sin);
+  su4->su_family = AF_INET;
+  
+  if (bind(s6, &su->su_sa, sulen) < 0)
+    ;
+  else if (getsockname(s6, &su->su_sa, &sulen) < 0)
+    ;
+  else if ((su4->su_port = su->su_port) != 0 && 
+	   bind(s4, &su4->su_sa, su4len) == 0)
+    retval = 1;
+
+  su_close(s6), su_close(s4);
+
+  mr->mr_bindv6only = retval;
+  mr->mr_boundserver = 1;
+#endif
+
+  return retval;
+}
+
+/* Number of supported transports */
+#define TPORT_N (8)
+
+/** Return list of addrinfo structures matching to 
+ * canon/host/service/protocol
+ */
+static
+int tport_server_addrinfo(tport_master_t *mr,
+			  char const *canon,
+			  int family,
+			  char const *host, 
+			  char const *service,
+			  char const *protocol,
+			  char const * const transports[],
+			  su_addrinfo_t **return_addrinfo)
+{
+  int i, N;
+  su_addrinfo_t hints[TPORT_N + 1];
+
+  *return_addrinfo = NULL;
+
+  /* 
+   * Resolve all the transports requested by the protocol
+   */
+  for (i = 0, N = 0; transports[i] && N < TPORT_N; i++) {
+    su_addrinfo_t *ai = &hints[N];
+
+    if (strcasecmp(transports[i], protocol) != 0 && 
+	strcmp(protocol, tpn_any) != 0)
+      continue;
+
+    /* Resolve protocol, skip unknown transport protocols. */
+    if (getprotohints(ai, transports[i], AI_PASSIVE) < 0)
+      continue;
+
+    ai->ai_family = family;
+    ai->ai_next = &hints[++N];
+  }
+
+  if (N == 0)
+    return su_seterrno(EPROTONOSUPPORT);
+  if (transports[i] /* Too many protocols */) 
+    return su_seterrno(ENOMEM);
+
+  hints[N - 1].ai_next = NULL;
+
+  if (host) {
+    int error = tport_getaddrinfo(host, service, hints, return_addrinfo);
+    if (error || !*return_addrinfo) {
+      SU_DEBUG_3(("%s(%p): su_getaddrinfo(%s, %s) for %s: %s\n", 
+		  __func__, mr, host ? host : "\"\"", service, protocol,
+		  su_gai_strerror(error)));
+      return su_seterrno(error != EAI_MEMORY ? ENOENT : ENOMEM);
+    }
+    return 0;
+  }
+
+  return tport_get_local_addrinfo(mr, service, hints, return_addrinfo);
+}
+
+/** Convert localinfo into addrinfo */
+static
+int
+tport_get_local_addrinfo(tport_master_t *mr, 
+			 char const *port,
+			 su_addrinfo_t const *hints,
+			 su_addrinfo_t **return_ai)
+{
+  int error, family;
+  su_localinfo_t lihints[1] = {{ 0 }};
+  su_localinfo_t *li, *li_result;
+  su_addrinfo_t const *h;
+  su_addrinfo_t *ai, **prev;
+  su_sockaddr_t *su;
+  unsigned long lport = 0;
+  char *rest;
+
+  prev = return_ai, *prev = NULL;
+
+  if (port) {
+    lport = strtoul(port, &rest, 10);
+    if (lport >= 65536) {
+      su_seterrno(EINVAL);
+      return -1;
+    }
+  }
+
+  family = hints->ai_family;
+
+  for (h = hints->ai_next; h && family; h = h->ai_next)
+    if (h->ai_family != family)
+      family = 0;
+
+  lihints->li_flags = 0;
+  lihints->li_family = family;
+  lihints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE | LI_SCOPE_HOST;
+
+  error = su_getlocalinfo(lihints, &li_result);
+  if (error) {
+#if SU_HAVE_IN6
+    SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n", 
+		__func__, mr, 
+		family == AF_INET6 ? "ip6" 
+		: family == AF_INET ? "ip4" : "ip",
+		su_gli_strerror(error)));
+#else
+    SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n", 
+		__func__, mr, 
+		family == AF_INET ? "ip4" : "ip",
+		su_gli_strerror(error)));
+#endif
+    su_seterrno(ENOENT);
+    return -1;
+  }
+
+  for (li = li_result; li; li = li->li_next) {
+    for (h = hints; h; h = h->ai_next) {
+      if (h->ai_family && h->ai_family != li->li_family)
+	continue;
+
+      ai = calloc(1, sizeof *ai + li->li_addrlen);
+      if (ai == NULL)
+	break;
+    
+      *prev = ai, prev = &ai->ai_next;
+
+      ai->ai_flags = AI_PASSIVE | TP_AI_ANY;
+      ai->ai_family = li->li_family;
+      ai->ai_socktype = h->ai_socktype;
+      ai->ai_protocol = h->ai_protocol;
+      ai->ai_canonname = h->ai_canonname;
+      ai->ai_addr = memcpy(ai + 1, li->li_addr, 
+			   ai->ai_addrlen = li->li_addrlen);
+      su = (void *)ai->ai_addr;
+      su->su_port = htons(lport);
+    }
+  }
+
+  su_freelocalinfo(li_result);
+
+  if (li) {
+    tport_freeaddrinfo(*return_ai);
+    su_seterrno(ENOMEM);
+    return -1;
+  }
+
+  if (*return_ai == NULL) {
+    su_seterrno(ENOENT);
+    return -1;
+  }
+
+  return 0;
+}
+
+static inline su_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all);
+
+/** Translate address and service.
+ *
+ * This is a getaddrinfo() supporting multiple hints in a list.
+ */
+int tport_getaddrinfo(char const *node, char const *service,
+		      su_addrinfo_t const *hints,
+		      su_addrinfo_t **res)
+{
+  su_addrinfo_t const *h0;
+  su_addrinfo_t *tbf, **prev;
+  int error = EAI_SOCKTYPE;
+  int i, N;
+  su_addrinfo_t *all[TPORT_N + 1]; /* Lists for all supported transports */
+  su_addrinfo_t *results[TPORT_N + 1]; 
+  void *addr;
+  int addrlen;
+
+  *res = NULL;
+
+  for (N = 0, h0 = hints; h0; h0 = h0->ai_next) {
+    su_addrinfo_t h[1];
+
+    *h = *h0, h->ai_next = NULL, h->ai_canonname = NULL;
+
+    error = su_getaddrinfo(node, service, h, &all[N]);
+    results[N] = all[N];
+    if (error == EAI_SOCKTYPE) {
+      SU_DEBUG_7(("%s(): su_getaddrinfo(%s, %s) for %s: %s\n", 
+		  __func__, node ? node : "\"\"", service,
+		  h0->ai_canonname, su_gai_strerror(error)));
+      continue;
+    }
+
+    if (error || !all[N])
+      break;
+    N++;
+  }
+
+  if (h0)
+    for (i = 0; i < N; i++)
+      su_freeaddrinfo(all[i]);
+  if (error)
+    return error;
+
+  /* Combine all the valid addrinfo structures to a single list */
+  prev = &tbf, tbf = NULL;
+
+  for (;;) {
+    su_addrinfo_t *ai = NULL, *ai0;
+
+    for (i = 0, h0 = hints; i < N; i++, h0 = h0->ai_next) {
+      if ((ai = get_next_addrinfo(&results[i])))
+	break;
+    }
+    if (i == N)
+      break;
+
+    assert(ai);
+    addr = SU_ADDR((su_sockaddr_t *)ai->ai_addr);
+    addrlen = SU_ADDRLEN((su_sockaddr_t *)ai->ai_addr);
+
+    /* Copy all the addrinfo structures with same address to the list */
+    for (; i < N; i++, h0 = h0->ai_next) {
+      while ((ai0 = get_next_addrinfo(&results[i]))) {
+	void *a = SU_ADDR((su_sockaddr_t *)ai0->ai_addr);
+
+	if (memcmp(addr, a, addrlen)) /* Different address */
+	  break;
+	
+	results[i] = ai0->ai_next;
+
+	ai = calloc(1, sizeof *ai + ai0->ai_addrlen);
+	if (ai == NULL) 
+	  goto error;
+	*prev = memcpy(ai, ai0, sizeof *ai); prev = &ai->ai_next; *prev = NULL;
+	ai->ai_addr = memcpy(ai + 1, ai0->ai_addr, ai0->ai_addrlen);
+	ai->ai_canonname = h0->ai_canonname;
+      }
+    }
+  }    
+
+  for (i = 0; i < N; i++)
+    su_freeaddrinfo(all[i]);
+  
+  *res = tbf;
+  return 0;
+
+ error:
+  for (i = 0; i < N; i++)
+    su_freeaddrinfo(all[i]);
+  tport_freeaddrinfo(tbf);
+  return EAI_MEMORY;
+}
+
+static inline
+su_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all)
+{
+  su_addrinfo_t *ai;
+
+  while ((ai = *all)) {
+    if (ai->ai_family == AF_INET)
+      return ai;
+#if SU_HAVE_IN6
+    if (ai->ai_family == AF_INET6)
+      return ai;
+#endif
+    *all = ai->ai_next;
+  }
+  return ai;
+}
+
+static
+void tport_freeaddrinfo(su_addrinfo_t *ai)
+{
+  su_addrinfo_t *ai_next;
+
+  while (ai) {
+    ai_next = ai->ai_next;
+    free(ai);
+    ai = ai_next;
+  }
+}
+
+static
+int tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen,
+			su_addrinfo_t const *src)
+{
+  if (addrlen < src->ai_addrlen)
+    return -1;
+
+  memcpy(dst, src, sizeof *dst);
+
+  if (src->ai_addrlen < addrlen)
+    memset(addr, 0, addrlen);
+
+  dst->ai_addr = memcpy(addr, src->ai_addr, src->ai_addrlen);
+  dst->ai_next = NULL;
+
+  return 0;
+}
+
+/** Close a transport. 
+ * 
+ * The function tport_close() closes a socket associated with a transport
+ * object.
+ */
+void tport_close(tport_t *self)
+{
+  SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", "tport_close", self,
+	      TPN_ARGS(self->tp_name)));
+
+  self->tp_closed = 1;
+  self->tp_send_close = 3;
+  self->tp_recv_close = 3;
+
+  if (self->tp_params->tpp_sdwn_error && self->tp_pused)
+    tport_error_report(self, -1, NULL);
+
+  if (self->tp_pri->pri_vtable->vtp_shutdown)
+    self->tp_pri->pri_vtable->vtp_shutdown(self, 2);
+  else if (self->tp_socket != -1)
+    shutdown(self->tp_socket, 2);
+
+  if (self->tp_index)
+    su_root_deregister(self->tp_master->mr_root, self->tp_index);
+  self->tp_index = 0;
+#if SU_HAVE_BSDSOCK
+  if (self->tp_socket != -1)
+    su_close(self->tp_socket);
+  self->tp_socket = -1;
+#endif
+
+  /* Zap the queued messages */
+  if (self->tp_queue) {
+    unsigned short i, N = self->tp_params->tpp_qsize;
+    for (i = 0; i < N; i++) {
+      if (self->tp_queue[i])
+	msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+    }
+  }
+
+  self->tp_index = 0;
+  self->tp_events = 0;
+}
+
+/** Shutdown a transport.
+ *
+ * The tport_shutdown() shuts down a full-duplex transport connection
+ * partially or completely. If @a how is 0, the further incoming data is
+ * shut down. If @a how is 1, further outgoing data is shut down. If @a how
+ * is 2, both incoming and outgoing traffic is shut down.
+ *
+ */
+int tport_shutdown(tport_t *self, int how)
+{
+  if (!tport_is_secondary(self))
+    return -1;
+
+  SU_DEBUG_7(("%s(%p, %d)\n", "tport_shutdown", self, how));
+
+  if (!tport_is_tcp(self) ||
+      how < 0 || 
+      (how == 0 && self->tp_send_close) ||
+      (how == 1 && self->tp_recv_close > 1) || 
+      how >= 2) {
+    tport_close(self);
+    return 1;
+  }
+
+  if (self->tp_pri->pri_vtable->vtp_shutdown)
+    self->tp_pri->pri_vtable->vtp_shutdown(self, how);
+  else
+    shutdown(self->tp_socket, how);
+
+  if (how == 0) {
+    self->tp_recv_close = 2;
+    tport_set_events(self, 0, SU_WAIT_IN);
+    if (self->tp_params->tpp_sdwn_error && self->tp_pused)
+      tport_error_report(self, -1, NULL);
+  }
+  else if (how == 1) {
+    self->tp_send_close = 2;
+    tport_set_events(self, 0, SU_WAIT_OUT);
+    if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+      unsigned short i, N = self->tp_params->tpp_qsize;
+      for (i = 0; i < N; i++) {
+	if (self->tp_queue[i]) {
+	  tport_pending_errmsg(self, self->tp_queue[i], EPIPE);
+	  msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+	}
+      }
+    }
+  }
+
+
+  return 0;
+}
+
+static inline
+unsigned long tport_now(void)
+{
+  return su_now().tv_sec;
+}
+
+/** Transport timer function. */
+static
+void tport_tick(su_root_magic_t *magic, su_timer_t *t, tport_master_t *mr)
+{
+  tport_primary_t *dad;
+  tport_t *tp, *tp_next;
+  su_time_t now = su_now();
+  int ts = (int)su_time_ms(now);
+
+  /* Go through all primary transports */
+  for (dad = mr->mr_primaries; dad; dad = dad->pri_next) {
+    if (dad->pri_primary->tp_addrinfo->ai_protocol == IPPROTO_SCTP) {
+      /* Go through all SCTP connections */
+
+      tp = dad->pri_secondary;
+
+      for (tp = tprb_first(tp); tp; tp = tp_next) {
+	tp_next = tprb_succ(tp);
+	if (tp->tp_queue && tp->tp_queue[tp->tp_qhead]) {
+	  SU_DEBUG_9(("tport_tick(%p) - trying to send to %s/%s:%s\n", 
+		      tp, tp->tp_protoname, tp->tp_host, tp->tp_port));
+	  tport_send_queue(tp);
+	}
+      }      
+    }
+
+    /* Go through all secondary transports with incomplete messages */
+    for (tp = tprb_first(dad->pri_secondary); tp; tp = tp_next) {
+      msg_t *msg = tp->tp_msg;
+      int closed;
+
+      if (msg &&
+	  tp->tp_params->tpp_timeout < INT_MAX && 
+	  (int)tp->tp_params->tpp_timeout < ts - (int)tp->tp_time &&
+	  !msg_is_streaming(msg)) {
+	SU_DEBUG_5(("tport_tick(%p): incomplete message idle for %d ms\n",
+		    tp, ts - (int)tp->tp_time));
+	msg_set_streaming(msg, 0);
+	msg_set_flags(msg, MSG_FLG_ERROR | MSG_FLG_TRUNC | MSG_FLG_TIMEOUT);
+	tport_deliver(tp, msg, NULL, NULL, now);
+	tp->tp_msg = NULL;
+      }
+
+      tp_next = tprb_succ(tp);
+
+      if (tp->tp_refs)
+	continue;
+
+      closed = tport_is_closed(tp);
+
+      if (!closed &&
+	  !(tp->tp_params->tpp_idle > 0 
+	    && (int)tp->tp_params->tpp_idle < ts - (int)tp->tp_time)) {
+	continue;
+      }
+
+      if (closed) {
+	SU_DEBUG_5(("tport_tick(%p): closed, zapping\n", tp));
+      } else {
+	SU_DEBUG_5(("tport_tick(%p): unused for %d ms, closing and zapping\n",
+		    tp, ts - (int)tp->tp_time));
+	if (!tport_is_closed(tp))
+	  tport_close(tp);
+      }
+
+      tport_zap_secondary(tp);
+    }
+  }
+
+  su_timer_set(t, tport_tick, mr);
+}
+
+/** Flush idle connections. */
+int tport_flush(tport_t *tp)
+{
+  tport_t *tp_next;
+
+  if (tp == NULL)
+    return -1;
+
+  /* Go through all secondary transports, zap idle ones */
+  for (tp = tprb_first(tp->tp_pri->pri_secondary); tp; tp = tp_next) {
+    tp_next = tprb_succ(tp);
+
+    if (tp->tp_refs != 0)
+      continue;
+
+    SU_DEBUG_1(("tport_flush(%p): %szapping\n",
+		tp, tport_is_closed(tp) ? "" : "closing and "));
+    if (!tport_is_closed(tp))
+      tport_close(tp);
+    tport_zap_secondary(tp);
+  }
+
+  return 0;
+}
+
+/**Convert sockaddr_t to a transport name.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int tport_convert_addr(su_home_t *home,
+		       tp_name_t *tpn,
+		       char const *protoname,
+		       char const *canon,
+		       su_sockaddr_t const *su)
+{
+  tp_name_t name[1] = {{ NULL }};
+  char const *host;
+  char buf[TPORT_HOSTPORTSIZE];
+  char port[8];
+  size_t canonlen = canon ? strlen(canon) : 0;
+
+  if (su == NULL)
+    host = "*";
+  else if (!SU_SOCKADDR_INADDR_ANY(su))
+    host = tport_hostport(buf, sizeof(buf), su, 0);
+  else if (canonlen && su->su_family == AF_INET && 
+	   strspn(canon, "0123456789.") == canonlen)
+    host = canon;
+#if SU_HAVE_IN6
+  else if (canonlen && su->su_family == AF_INET6 && 
+	   strspn(canon, "0123456789abcdefABCDEF:.") == canonlen)
+    host = canon;
+#endif
+  else
+    host = localipname(su->su_family, buf, sizeof(buf));
+
+  if (host == NULL)
+    return -1;
+
+  if (su == NULL)
+    strcpy(port, "*");
+  else
+    snprintf(port, sizeof(port), "%u", ntohs(su->su_port));
+  
+  name->tpn_proto = protoname;
+  name->tpn_host = host;
+  name->tpn_canon = canon ? canon : host;
+  name->tpn_port = port;
+
+  return tport_name_dup(home, tpn, name);
+}
+
+/** Set transport object name. @internal
+ */
+static
+int tport_setname(tport_t *self,
+		  char const *protoname,
+		  su_addrinfo_t const *ai,
+		  char const *canon)
+{
+  su_addrinfo_t *selfai = self->tp_addrinfo;
+
+  if (tport_convert_addr(self->tp_home, self->tp_name, 
+			 protoname, canon, 
+			 (su_sockaddr_t *)ai->ai_addr) < 0)
+    return -1;
+
+  if (tport_is_secondary(self))
+    self->tp_ident = self->tp_pri->pri_primary->tp_ident;
+
+  selfai->ai_flags = ai->ai_flags & TP_AI_MASK;
+
+  selfai->ai_family = ai->ai_family;     
+  selfai->ai_socktype = ai->ai_socktype; 
+  selfai->ai_protocol = ai->ai_protocol; 
+  selfai->ai_canonname = (char *)self->tp_name->tpn_canon;
+
+  if (ai->ai_addr) {
+    assert(ai->ai_family), assert(ai->ai_socktype), assert(ai->ai_protocol);
+    memcpy(self->tp_addr, ai->ai_addr, selfai->ai_addrlen = ai->ai_addrlen);
+  }
+
+  return 0;
+}
+
+/**Resolve protocol name.
+ *
+ * Convert a protocol name to IP protocol number and socket type used by
+ * su_getaddrinfo().
+ *
+ * @param hints hints with the protocol number and socktype [OUT]
+ * @param proto protocol name [IN]
+ * @param flags hint flags      
+ */
+static
+int getprotohints(su_addrinfo_t *hints, 
+		  char const *proto,
+		  int flags)
+{
+  memset(hints, 0, sizeof *hints);
+
+  hints->ai_flags = flags;
+  hints->ai_canonname = (char *)proto;
+
+#if HAVE_TLS
+  if (strcasecmp(proto, "tls") == 0)
+    proto = "tcp";
+#endif
+
+#if HAVE_SCTP  
+  if (strcasecmp(proto, "sctp") == 0) {
+    hints->ai_protocol = IPPROTO_SCTP;
+    hints->ai_socktype = SOCK_STREAM;
+    return 0;
+  }
+#endif
+
+  if (strcasecmp(proto, "udp") == 0) {
+    hints->ai_protocol = IPPROTO_UDP;
+    hints->ai_socktype = SOCK_DGRAM;
+    return 0;
+  }
+  
+  if (strcasecmp(proto, "tcp") == 0) {
+    hints->ai_protocol = IPPROTO_TCP;
+    hints->ai_socktype = SOCK_STREAM;
+    return 0;
+  }
+
+  return -1;
+}
+
+/** Get local IP.
+ *
+ * Get primary local IP address in URI format (IPv6 address will be
+ * []-quoted).
+ */
+static
+char *localipname(int pf, char *buf, size_t bufsiz)
+{
+  su_localinfo_t *li = NULL, hints[1] = {{ LI_NUMERIC | LI_CANONNAME }};
+  size_t n;
+  int error;
+
+  hints->li_family = pf;
+
+#if SU_HAVE_IN6
+  if (pf == AF_INET6) {
+    /* Link-local addresses are not usable on IPv6 */
+    hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_HOST */;
+  }
+#endif
+
+  if ((error = su_getlocalinfo(hints, &li))) {
+#if SU_HAVE_IN6
+    if (error == ELI_NOADDRESS && pf == AF_INET6) {
+      hints->li_family = AF_INET;
+      error = su_getlocalinfo(hints, &li);
+      if (error == ELI_NOADDRESS) {
+	hints->li_family = AF_INET6; hints->li_scope |= LI_SCOPE_HOST;
+	error = su_getlocalinfo(hints, &li);
+      }
+      if (error == ELI_NOADDRESS) {
+	hints->li_family = AF_INET;
+	error = su_getlocalinfo(hints, &li);
+      }
+    }
+#endif
+    if (error) {
+      SU_DEBUG_1(("tport: su_getlocalinfo: %s\n", su_gli_strerror(error)));
+      return NULL;
+    }
+  }
+
+  assert(li); assert(li->li_canonname);
+
+  n = strlen(li->li_canonname);
+
+  if (li->li_family == AF_INET) {
+    if (n >= bufsiz)
+      return NULL;
+    
+    memcpy(buf, li->li_canonname, n + 1);
+  }
+  else {
+    if (n + 2 >= bufsiz)
+      return NULL;
+
+    memcpy(buf + 1, li->li_canonname, n);
+    buf[0] = '['; buf[++n] = ']'; buf[++n] = '\0';
+  }
+      
+  su_freelocalinfo(li);
+  
+  return buf;
+}
+
+/** Process errors from transport. */
+void tport_error_report(tport_t *self, int errcode, 
+			su_sockaddr_t const *addr)
+{
+  char const *errmsg;
+
+  if (errcode == 0)
+    return;
+  else if (errcode > 0)
+    errmsg = su_strerror(errcode);
+  else
+    errcode = 0, errmsg = "stream closed";
+
+  if (addr && addr->su_family == AF_UNSPEC)
+    addr = NULL;
+
+  /* Mark this connection as unusable */
+  if (errcode > 0 && tport_has_connection(self))
+    self->tp_reusable = 0;
+
+  if (addr == NULL && tport_is_connection_oriented(self))
+    addr = self->tp_addr;
+
+  /* Report error */
+  if (addr && tport_pending_error(self, addr, errcode))
+    ;
+  else if (self->tp_master->mr_tpac->tpac_error) {
+    char *dstname = NULL;
+    char hp[TPORT_HOSTPORTSIZE];
+
+    if (addr)
+      dstname = tport_hostport(hp, sizeof hp, addr, 1);
+
+    STACK_ERROR(self, errcode, dstname);
+  }
+  else {
+    if (tport_is_primary(self))
+      SU_DEBUG_3(("%s(%p): %s (with %s)\n", __func__, self, 
+		  errmsg, self->tp_protoname));
+    else
+      SU_DEBUG_3(("%s(%p): %s (with %s/%s:%s)\n", __func__, self, 
+		  errmsg, self->tp_protoname, self->tp_host, self->tp_port));
+  }
+
+  /* Close connection */
+  if (!self->tp_closed && errcode > 0 && tport_has_connection(self))
+    tport_close(self);
+}
+
+/** Accept a new connection.
+ * 
+ * The function tport_accept() accepts a new connection and creates a
+ * secondary transport object for the new socket.
+ */
+int tport_accept(tport_primary_t *pri, int events)
+{
+  tport_t *self;
+  su_addrinfo_t ai[1];
+  su_sockaddr_t su[1]; 
+  socklen_t sulen = sizeof su;
+  su_socket_t s = INVALID_SOCKET, l = pri->pri_primary->tp_socket;
+  char const *reason = "accept";
+
+  if (events & SU_WAIT_ERR)
+    tport_error_event(pri->pri_primary);
+
+  if (!(events & SU_WAIT_ACCEPT))
+    return 0;
+
+  memcpy(ai, pri->pri_primary->tp_addrinfo, sizeof ai);
+  ai->ai_canonname = NULL;
+
+  s = accept(l, &su->su_sa, &sulen);
+
+  if (s < 0) {
+    tport_error_report(pri->pri_primary, su_errno(), NULL);
+    return 0;
+  }
+
+  ai->ai_addr = &su->su_sa, ai->ai_addrlen = sulen;
+
+  /* Alloc a new transport object, then register socket events with it */ 
+  self = tport_alloc_secondary(pri, s, 1, &reason);
+
+  if (self) {
+    int i;
+    su_root_t *root = self->tp_master->mr_root;
+    su_wakeup_f wakeup = tport_wakeup;
+    int events = SU_WAIT_IN|SU_WAIT_ERR|SU_WAIT_HUP;
+    su_wait_t wait[1] = { SU_WAIT_INIT };
+
+    SU_CANONIZE_SOCKADDR(su);
+
+    if (/* Create wait object with appropriate events. */
+	su_wait_create(wait, s, events) != -1 
+	/* Register socket to root */
+	&&
+	(i = su_root_register(root, wait, wakeup, self, 0)) != -1) {
+
+      self->tp_index     = i;
+      self->tp_conn_orient = 1;
+      self->tp_is_connected = 1;
+      self->tp_events = events;
+
+      if (tport_setname(self, pri->pri_protoname, ai, NULL) != -1) {
+	SU_DEBUG_5(("%s(%p): new connection from " TPN_FORMAT "\n", 
+		    __func__,  self, TPN_ARGS(self->tp_name)));
+
+	tprb_append(&pri->pri_secondary, self);
+
+	/* Return succesfully */
+	return 0;
+      }
+    }
+    else
+      su_wait_destroy(wait);
+
+    /* Failure: shutdown socket,  */
+    tport_close(self);
+    tport_zap_secondary(self);
+  }
+
+  /* XXX - report error ? */
+
+  return 0;
+}
+
+/** Allocate a new message object */
+msg_t *tport_msg_alloc(tport_t const *self, usize_t size)
+{
+  if (self) {
+    tport_master_t *mr = self->tp_master;
+    msg_t *msg = mr->mr_tpac->tpac_alloc(mr->mr_stack, mr->mr_log,
+					 NULL, size, self, NULL);
+    if (msg) {
+      su_addrinfo_t *mai = msg_addrinfo(msg);
+      su_addrinfo_t const *tai = self->tp_addrinfo;
+
+      mai->ai_family =   tai->ai_family;
+      mai->ai_protocol = tai->ai_protocol;
+      mai->ai_socktype = tai->ai_socktype;
+    }
+
+    return msg;
+  }
+  else {
+    return NULL;
+  }
+}
+
+/** Process events for socket waiting to be connected
+ */
+static int tport_connected(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
+{
+  int events = su_wait_events(w, self->tp_socket);
+  tport_master_t *mr = self->tp_master;
+  su_wait_t wait[1] =  { SU_WAIT_INIT };
+
+  int error;
+
+  SU_DEBUG_7(("tport_connected(%p): events%s%s\n", self,
+	      events & SU_WAIT_CONNECT ? " CONNECTED" : "",
+	      events & SU_WAIT_ERR ? " ERR" : ""));
+
+#if HAVE_POLL
+  assert(w->fd == self->tp_socket);
+#endif
+
+  if (events & SU_WAIT_ERR)
+    tport_error_event(self);
+
+  if (!(events & SU_WAIT_CONNECT) || self->tp_closed) {
+    return 0;
+  }
+
+  error = su_soerror(self->tp_socket);
+  if (error) {
+    tport_error_report(self, error, NULL);
+    return 0;
+  }
+
+  self->tp_is_connected = 1;
+
+  su_root_deregister(mr->mr_root, self->tp_index);
+  self->tp_index = -1;
+  self->tp_events = SU_WAIT_IN | SU_WAIT_ERR;
+  if (su_wait_create(wait, self->tp_socket, self->tp_events) == -1 ||
+      (self->tp_index = su_root_register(mr->mr_root, 
+					 wait, tport_wakeup, self, 0))
+      == -1) {
+    tport_close(self);
+  }
+  else if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+    tport_send_event(self);
+  }
+
+  return 0;
+}
+
+/** Process events for primary socket  */
+static int tport_wakeup_pri(su_root_magic_t *m, su_wait_t *w, tport_t *self)
+{
+  tport_primary_t *pri = self->tp_pri;
+  int events = su_wait_events(w, self->tp_socket);
+
+#if HAVE_POLL
+  assert(w->fd == self->tp_socket);
+#endif
+
+  SU_DEBUG_7(("%s(%p): events%s%s%s%s%s%s\n", 
+	      "tport_wakeup_pri", self,
+	      events & SU_WAIT_IN ? " IN" : "",
+	      SU_WAIT_ACCEPT != SU_WAIT_IN && 
+	      (events & SU_WAIT_ACCEPT) ? " ACCEPT" : "",
+	      events & SU_WAIT_OUT ? " OUT" : "",
+	      events & SU_WAIT_HUP ? " HUP" : "",
+	      events & SU_WAIT_ERR ? " ERR" : "",
+	      self->tp_closed ? " (closed)" : ""));
+
+
+  if (pri->pri_vtable->vtp_wakeup_pri)
+    return pri->pri_vtable->vtp_wakeup_pri(pri, events);
+  else
+    return tport_base_wakeup(self, events);
+}
+
+/** Process events for connected socket  */
+static int tport_wakeup(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
+{
+  int events = su_wait_events(w, self->tp_socket);
+
+#if HAVE_POLL
+  assert(w->fd == self->tp_socket);
+#endif
+
+  SU_DEBUG_7(("%s(%p): events%s%s%s%s%s\n", 
+	      "tport_wakeup", self,
+	      events & SU_WAIT_IN ? " IN" : "",
+	      events & SU_WAIT_OUT ? " OUT" : "",
+	      events & SU_WAIT_HUP ? " HUP" : "",
+	      events & SU_WAIT_ERR ? " ERR" : "",
+	      self->tp_closed ? " (closed)" : ""));
+
+  if (self->tp_pri->pri_vtable->vtp_wakeup)
+    return self->tp_pri->pri_vtable->vtp_wakeup(self, events);
+  else
+    return tport_base_wakeup(self, events);
+}
+
+static int tport_base_wakeup(tport_t *self, int events)
+{
+  int error = 0;
+
+  if (events & SU_WAIT_ERR)
+    error = tport_error_event(self);
+
+  if ((events & SU_WAIT_OUT) && !self->tp_closed)
+    tport_send_event(self);
+
+  if ((events & SU_WAIT_IN) && !self->tp_closed)
+    tport_recv_event(self);
+  
+  if ((events & SU_WAIT_HUP) && !self->tp_closed)
+    tport_hup_event(self);
+
+  if (error)
+    tport_error_report(self, error, NULL);
+
+  return 0;
+}
+
+/** Stop reading from socket until tport_continue() is called. */
+int tport_stall(tport_t *self)
+{
+  return tport_set_events(self, 0, SU_WAIT_IN);
+}
+
+/** Continue reading from socket. */
+int tport_continue(tport_t *self)
+{
+  if (self == NULL || self->tp_recv_close)
+    return -1;
+  return tport_set_events(self, SU_WAIT_IN, 0);
+}
+
+/** Process "hangup" event.
+ *
+ */
+void tport_hup_event(tport_t *self)
+{
+  SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+  if (self->tp_msg) {
+    su_time_t now = su_now();
+    msg_recv_commit(self->tp_msg, 0, 1);
+    tport_parse(self, 1, now);
+  }
+
+  /* End of stream */
+  tport_shutdown(self, 0);
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream  
+ * @retval 1  normal receive
+ * @retval 2  incomplete recv, recv again
+ * @retval 3  STUN keepalive, ignore
+ */
+static inline
+int tport_recv_data(tport_t *self)
+{
+  return self->tp_pri->pri_vtable->vtp_recv(self);
+}
+
+/** Process "ready to receive" event.
+ *
+ */
+void tport_recv_event(tport_t *self)
+{
+  su_time_t now;
+  int again;
+
+  SU_DEBUG_7(("%s(%p)\n", "tport_recv_event", self));
+
+  do {
+    now = su_now(); 
+
+    /* Receive data from socket */
+    again = tport_recv_data(self);
+
+    self->tp_time = su_time_ms(now);
+
+    if (again == 3) /* STUN keepalive */
+      return;
+
+    if (again < 0) {
+      int error = su_errno();
+
+      if (!su_is_blocking(error)) {
+	tport_error_report(self, error, NULL);
+	/* Failure: shutdown socket */
+	if (tport_has_connection(self))
+	  tport_close(self);
+	return;
+      } 
+      else {
+	SU_DEBUG_3(("%s: recvfrom(): %s (%d)\n", __func__, 
+		    su_strerror(EAGAIN), EAGAIN));
+      }
+    }
+
+    if (again >= 0)
+      tport_parse(self, !again, now);
+  } 
+  while (again > 1);
+
+  if (again == 0 && !tport_is_dgram(self)) {
+    /* End of stream */
+    if (!self->tp_closed) {
+      /* Don't shutdown completely if there are queued messages */
+      tport_shutdown(self, self->tp_queue && self->tp_queue[self->tp_qhead] ? 0 : 2);
+    }
+  }
+}
+
+/* 
+ * Parse the data and feed complete messages to the stack 
+ */
+static void tport_parse(tport_t *self, int complete, su_time_t now)
+{
+  msg_t *msg, *next = NULL;
+  int n, streaming, stall = 0;
+
+  for (msg = self->tp_msg; msg; msg = next) {
+    n = msg_extract(msg);	/* Parse message */
+
+    streaming = 0;
+
+    if (n == 0) {
+      if (complete)
+	msg_mark_as_complete(msg, MSG_FLG_ERROR), n = -1;
+      else if (!(streaming = msg_is_streaming(msg))) {
+	tport_sigcomp_accept_incomplete(self, msg);
+	break;
+      }
+    } 
+
+    if (msg_get_flags(msg, MSG_FLG_TOOLARGE))
+      SU_DEBUG_3(("%s(%p): too large message from " TPN_FORMAT "\n",
+		  __func__, self, TPN_ARGS(self->tp_name)));
+
+    /* Do not try to read anymore from this connection? */
+    if (tport_is_stream(self) && 
+	msg_get_flags(msg, MSG_FLG_TOOLARGE | MSG_FLG_ERROR))
+      self->tp_recv_close = stall = 1;
+    
+    if (n == -1)
+      next = NULL;
+    else if (streaming)
+      msg_ref_create(msg);	/* Keep a reference */
+    else if (tport_is_stream(self))
+      next = msg_next(msg);
+    else
+      next = NULL;
+
+    tport_deliver(self, msg, next, self->tp_comp, now);
+
+    if (streaming && next == NULL)
+      break;
+  }
+
+  if (stall)
+    tport_stall(self);
+
+  if (self->tp_rlogged != msg)
+    self->tp_rlogged = NULL;
+  
+  self->tp_msg = msg;
+}
+
+/** Deliver message to the protocol stack */
+void tport_deliver(tport_t *self,
+		   msg_t *msg,
+		   msg_t *next,
+		   tport_compressor_t *sc,
+		   su_time_t now)
+{
+  tport_t *ref;
+  int error;
+  struct tport_delivery *d;
+
+  assert(msg);
+
+  d = self->tp_master->mr_delivery;
+
+  d->d_tport = self;
+  d->d_msg = msg;
+  *d->d_from = *self->tp_name;
+
+  if (tport_is_primary(self)) {
+    char ipaddr[SU_ADDRSIZE + 2];
+    su_sockaddr_t const *su = msg_addr(msg);
+
+#if SU_HAVE_IN6
+    if (su->su_family == AF_INET6) {
+      ipaddr[0] = '[';
+      inet_ntop(su->su_family, SU_ADDR(su), ipaddr + 1, sizeof(ipaddr) - 1);
+      strcat(ipaddr, "]");
+    }
+    else {
+      inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr));
+    }
+#else
+    inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr));
+#endif
+
+    d->d_from->tpn_canon = ipaddr;
+    d->d_from->tpn_host = ipaddr;    
+  }
+
+  d->d_comp = sc;
+  if (!sc)
+    d->d_from->tpn_comp = NULL;
+
+  error = msg_has_error(msg);
+
+  if (error && !*msg_chain_head(msg)) {
+    /* This is badly damaged packet */
+  }
+  else if (self->tp_master->mr_log && msg != self->tp_rlogged) {
+    char const *via = "recv";
+    tport_log_msg(self, msg, via, "from", now);
+    self->tp_rlogged = msg;
+  }
+
+  SU_DEBUG_7(("%s(%p): %smsg %p ("MOD_ZU" bytes)"
+	      " from " TPN_FORMAT " next=%p\n", 
+	      __func__, self, error ? "bad " : "",
+	      msg, (size_t)msg_size(msg),
+	      TPN_ARGS(d->d_from), next));
+
+  ref = tport_incref(self);
+
+  if (self->tp_pri->pri_vtable->vtp_deliver) {
+    self->tp_pri->pri_vtable->vtp_deliver(self, msg, now);
+  }
+  else
+    tport_base_deliver(self, msg, now);
+
+  tport_decref(&ref);
+
+  d->d_msg = NULL;
+}
+
+/** Pass message to the protocol stack */
+void
+tport_base_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+  STACK_RECV(self, msg, now);
+}
+
+/** Return source transport object for delivered message */
+tport_t *tport_delivered_by(tport_t const *tp, msg_t const *msg)
+{
+  if (tp && msg && msg == tp->tp_master->mr_delivery->d_msg)
+    return tp->tp_master->mr_delivery->d_tport;
+  else
+    return NULL;
+}
+
+
+/** Return source transport name for delivered message */
+int tport_delivered_from(tport_t *tp, msg_t const *msg, tp_name_t name[1])
+{
+  if (name == NULL)
+    return -1;
+  
+  if (tp == NULL || msg == NULL || msg != tp->tp_master->mr_delivery->d_msg) {
+    memset(name, 0, sizeof *name);
+    return -1;
+  }
+  else {
+    *name = *tp->tp_master->mr_delivery->d_from;
+    return 0;
+  }
+}
+
+/** Return UDVM used to decompress the message. */
+int
+tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
+			  tport_compressor_t **return_compressor)
+{
+  if (tp == NULL || msg == NULL || msg != tp->tp_master->mr_delivery->d_msg)
+    return -1;
+
+  if (return_compressor)
+    *return_compressor = tp->tp_master->mr_delivery->d_comp;
+
+  return 0;
+}
+
+/** Allocate message for N bytes,
+ *  return message buffer as a iovec 
+ */
+ssize_t tport_recv_iovec(tport_t const *self, 
+			 msg_t **in_out_msg,
+			 msg_iovec_t iovec[msg_n_fragments],
+			 size_t N, 
+			 int exact)
+{
+  msg_t *msg = *in_out_msg;
+  ssize_t i, veclen;
+  int fresh;
+
+  if (N == 0)
+    return 0;
+
+  fresh = !msg;
+
+  /*
+   * Allocate a new message if needed 
+   */
+  if (!msg) {
+    if (!(*in_out_msg = msg = tport_msg_alloc(self, N))) {
+      SU_DEBUG_7(("%s(%p): cannot allocate msg for "MOD_ZU" bytes "
+		  "from (%s/%s:%s)\n", 
+		  __func__, self, N, 
+		  self->tp_protoname, self->tp_host, self->tp_port));
+      return -1;
+    }
+  }
+
+  /*
+   * Get enough buffer space for the incoming data
+   */
+  veclen = msg_recv_iovec(msg, iovec, msg_n_fragments, N, exact);
+  if (veclen < 0) {
+    int err = su_errno();
+    if (fresh && err == ENOBUFS && msg_get_flags(msg, MSG_FLG_TOOLARGE))
+      veclen = msg_recv_iovec(msg, iovec, msg_n_fragments, 4096, 1);
+  }
+  if (veclen < 0) {
+    int err = su_errno();
+    SU_DEBUG_7(("%s(%p): cannot get msg %p buffer for "MOD_ZU" bytes "
+		"from (%s/%s:%s): %s\n", 
+		__func__, self, msg, N, 
+		self->tp_protoname, self->tp_host, self->tp_port,
+		su_strerror(err)));
+    su_seterrno(err);
+    return veclen;
+  }
+
+  assert(veclen <= msg_n_fragments);
+
+  SU_DEBUG_7(("%s(%p) msg %p from (%s/%s:%s) has "MOD_ZU" bytes, "
+	      "veclen = "MOD_ZD"\n",
+              __func__, self, 
+	      msg, self->tp_protoname, self->tp_host, self->tp_port, 
+	      N, veclen));
+
+  for (i = 0; veclen > 1 && i < veclen; i++) {
+    SU_DEBUG_7(("\tiovec[%lu] = %lu bytes\n", (LU)i, (LU)iovec[i].mv_len));
+  }
+
+  return veclen;
+}
+
+int tport_recv_error_report(tport_t *self)
+{
+  if (su_is_blocking(su_errno()))
+    return 1;
+
+  /* Report error */
+  tport_error_report(self, su_errno(), NULL);
+
+  return -1;
+}
+
+/** Send a message. 
+ *
+ * The function tport_tsend() sends a message using the transport @a self.
+ *
+ * @TAGS
+ * TPTAG_MTU(), TPTAG_REUSE(), TPTAG_CLOSE_AFTER(), TPTAG_SDWN_AFTER(), 
+ */
+tport_t *tport_tsend(tport_t *self, 
+		     msg_t *msg, 
+		     tp_name_t const *_tpn, 
+		     tag_type_t tag, tag_value_t value, ...)
+{
+  ta_list ta; 
+  tagi_t const *t;
+  int reuse, sdwn_after, close_after, resolved = 0, fresh;
+  unsigned mtu;
+  su_addrinfo_t *ai;
+  tport_primary_t *primary;
+  tp_name_t tpn[1];
+  struct sigcomp_compartment *cc;
+
+  assert(self);
+
+  if (!self || !msg || !_tpn) {
+    msg_set_errno(msg, EINVAL);
+    return NULL;
+  }
+
+  *tpn = *_tpn;
+
+  SU_DEBUG_7(("tport_tsend(%p) tpn = " TPN_FORMAT "\n", self, TPN_ARGS(tpn)));
+
+  if (tport_is_master(self)) {
+    primary = (tport_primary_t *)tport_primary_by_name(self, tpn);
+    if (!primary) {
+      msg_set_errno(msg, EPROTONOSUPPORT);
+      return NULL;
+    }
+  }
+  else {
+    primary = self->tp_pri;
+  }
+
+  ta_start(ta, tag, value);
+
+  reuse = primary->pri_primary->tp_reusable && self->tp_reusable;
+  fresh = 0;
+  sdwn_after = 0;
+  close_after = 0;
+  mtu = 0;
+  cc = NULL;
+
+  /* tl_gets() is a bit too slow here... */
+  for (t = ta_args(ta); t; t = tl_next(t)) {
+    tag_type_t tt = t->t_tag; 
+    
+    if (tptag_reuse == tt)
+      reuse = t->t_value != 0;
+    else if (tptag_mtu == tt)
+      mtu = t->t_value;
+    else if (tptag_sdwn_after == tt)
+      sdwn_after = t->t_value != 0;
+    else if (tptag_close_after == tt)
+      close_after = t->t_value != 0;
+    else if (tptag_fresh == tt)
+      fresh = t->t_value != 0;
+    else if (tptag_compartment == tt)
+      cc = (struct sigcomp_compartment *)t->t_value;
+  }    
+
+  ta_end(ta);
+
+  fresh = fresh || !reuse;
+
+  ai = msg_addrinfo(msg);
+
+  ai->ai_flags = 0;
+
+  tpn->tpn_comp = tport_canonize_comp(tpn->tpn_comp);
+  if (tpn->tpn_comp) {
+    ai->ai_flags |= TP_AI_COMPRESSED;
+    SU_DEBUG_9(("%s: compressed msg(%p) with %s\n", 
+		__func__, msg, tpn->tpn_comp));
+  } 
+
+  if (!tpn->tpn_comp || cc == NONE)
+    cc = NULL;
+
+  if (sdwn_after)
+    ai->ai_flags |= TP_AI_SHUTDOWN;
+  if (close_after)
+    ai->ai_flags |= TP_AI_CLOSE;
+
+  if (fresh) {
+    /* Select a primary protocol, make a fresh connection */
+    self = primary->pri_primary;
+  }
+  else {
+    if (tport_is_secondary(self) && 
+	tport_is_registered(self) && 
+	self->tp_reusable &&
+	!self->tp_closed &&
+	!self->tp_send_close) {
+      self = self;
+    }
+    /*
+     * Try to find an already open connection to the destination, 
+     * or get a primary protocol 
+     */
+    else {
+      /* If primary, resolve the destination address, store it in the msg */
+      if (tport_resolve(primary->pri_primary, msg, tpn) < 0) {
+	return NULL;
+      }
+      resolved = 1;
+
+      self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn);
+
+      if (!self)
+	self = primary->pri_primary;
+    }
+  }
+
+  if (tport_is_primary(self)) {
+    /* If primary, resolve the destination address, store it in the msg */
+    if (!resolved && tport_resolve(self, msg, tpn) < 0) {
+      return NULL;
+    }
+
+    if (tport_is_connection_oriented(self)
+	|| self->tp_params->tpp_conn_orient) {
+#if 0 && HAVE_UPNP /* We do not want to use UPnP with secondary transports! */
+      if (upnp_register_upnp_client(1) != 0) { 
+	upnp_check_for_nat();
+      }
+#endif
+
+      tpn->tpn_proto = self->tp_protoname;
+
+      if (!cc)
+	tpn->tpn_comp = NULL;
+
+      /* Create a secondary transport which is connected to the destination */
+      self = tport_connect(primary, msg_addrinfo(msg), tpn);
+
+#if 0 && HAVE_UPNP /* We do not want to use UPnP with secondary transports! */
+      upnp_deregister_upnp_client(0, 0);
+#endif
+
+      if (!self) {
+	msg_set_errno(msg, su_errno());
+        SU_DEBUG_9(("tport_socket failed in tsend\n"));
+	return NULL;
+      }
+
+      if (cc)
+	tport_sigcomp_assign(self, cc);
+    }
+  }
+  else if (tport_is_secondary(self)) {
+    cc = tport_sigcomp_assign_if_needed(self, cc);
+  }
+
+  if (cc == NULL)
+    tpn->tpn_comp = NULL;
+
+  if (tport_is_secondary(self)) {
+    /* Set the peer address to msg */
+    tport_peer_address(self, msg);
+    if (sdwn_after || close_after)
+      self->tp_reusable = 0;
+  }
+
+  if (self->tp_pri->pri_vtable->vtp_prepare
+      ? self->tp_pri->pri_vtable->vtp_prepare(self, msg, tpn, cc, mtu) < 0 
+      : tport_prepare_and_send(self, msg, tpn, cc, mtu) < 0)
+    return NULL;
+  else
+    return self;
+}
+
+int tport_prepare_and_send(tport_t *self, msg_t *msg, 
+			   tp_name_t const *tpn, 
+			   struct sigcomp_compartment *cc,
+			   unsigned mtu)
+{
+  /* Prepare message for sending - i.e., encode it */
+  if (msg_prepare(msg) < 0) {
+    msg_set_errno(msg, errno);
+    return -1;
+  }
+
+  if (msg_size(msg) > (mtu ? mtu : tport_mtu(self))) {
+    msg_set_errno(msg, EMSGSIZE);
+    return -1;
+  }
+
+  /*
+   * If there is already an queued message, 
+   * put this message straight in the queue
+   */
+  if ((self->tp_queue && self->tp_queue[self->tp_qhead]) ||
+      /* ...or we are connecting */
+      (self->tp_events & (SU_WAIT_CONNECT | SU_WAIT_OUT))) {
+    if (tport_queue(self, msg) < 0) {
+      SU_DEBUG_9(("tport_queue failed in tsend\n"));
+      return -1;
+    }
+    return 0;
+  }
+  
+  return tport_send_msg(self, msg, tpn, cc);
+}
+
+
+/** Send a message.
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int tport_send_msg(tport_t *self, msg_t *msg, 
+		   tp_name_t const *tpn, 
+		   struct sigcomp_compartment *cc)
+{
+  msg_iovec_t *iov, auto_iov[40];
+  size_t iovlen, iovused, i, total;
+  size_t n;
+  ssize_t nerror;
+  int sdwn_after, close_after;
+  su_time_t now;
+  su_addrinfo_t *ai;
+
+  assert(self->tp_queue == NULL || 
+	 self->tp_queue[self->tp_qhead] == NULL ||
+	 self->tp_queue[self->tp_qhead] == msg);
+
+  if (self->tp_iov)
+    /* Use the heap-allocated I/O vector */
+    iov = self->tp_iov, iovlen = self->tp_iovlen;
+  else
+    /* Use the stack I/O vector */
+    iov = auto_iov, iovlen = sizeof(auto_iov)/sizeof(auto_iov[0]);
+
+  /* Get a iovec for message contents */
+  for (;;) {
+    iovused = msg_iovec(msg, iov, iovlen);
+    if (iovused <= iovlen) 
+      break;
+
+    iov = su_realloc(self->tp_home, self->tp_iov, sizeof(*iov) * iovused);
+
+    if (iov == NULL) {
+      msg_set_errno(msg, errno);
+      return -1;
+    }
+    
+    self->tp_iov = iov, self->tp_iovlen = iovlen = iovused;
+  }
+
+  assert(iovused > 0);
+
+  self->tp_time = su_time_ms(now = su_now());
+
+  nerror = tport_vsend(self, msg, tpn, iov, iovused, cc);
+  SU_DEBUG_9(("tport_vsend returned "MOD_ZD"\n", nerror));
+
+  if (nerror == -1)
+    return -1;
+
+  n = (size_t)nerror;
+
+  self->tp_unsent = NULL, self->tp_unsentlen = 0;
+  
+  if (n > 0 && self->tp_master->mr_log && self->tp_slogged != msg) {
+    tport_log_msg(self, msg, "send", "to", now);
+    self->tp_slogged = msg;
+  }
+
+  for (i = 0, total = 0; i < iovused; i++) {
+    if (total + (size_t)iov[i].mv_len > n) {
+      if (tport_is_connection_oriented(self)) {
+	iov[i].mv_len -= (su_ioveclen_t)(n - total);
+	iov[i].mv_base = (char *)iov[i].mv_base + (n - total);
+	if (tport_queue_rest(self, msg, &iov[i], iovused - i) >= 0)
+	  return 0;
+      }
+      else {
+	char const *comp = tpn->tpn_comp;
+
+	SU_DEBUG_1(("tport(%p): send truncated for %s/%s:%s%s%s\n", 
+		    self, tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
+		    comp ? ";comp=" : "", comp ? comp : ""));
+
+	su_seterrno(EIO);
+      }
+
+      return -1;
+    }
+    total += iov[i].mv_len;
+  }
+
+  /* We have sent a complete message */
+
+  self->tp_slogged = NULL;
+
+  ai = msg_addrinfo(msg); assert(ai);
+  close_after = (ai->ai_flags & TP_AI_CLOSE) == TP_AI_CLOSE;
+  sdwn_after = (ai->ai_flags & TP_AI_SHUTDOWN) == TP_AI_SHUTDOWN ||
+    self->tp_send_close;
+
+  if (close_after || sdwn_after)
+    tport_shutdown(self, close_after ? 2 : 1);
+
+  return 0;
+}
+
+static 
+ssize_t tport_vsend(tport_t *self, 
+		    msg_t *msg, 
+		    tp_name_t const *tpn,
+		    msg_iovec_t iov[], 
+		    size_t iovused,
+		    struct sigcomp_compartment *cc)
+{ 
+  ssize_t n;
+  su_addrinfo_t *ai = msg_addrinfo(msg);
+
+  if (cc) {
+    n = tport_send_comp(self, msg, iov, iovused, cc, self->tp_comp);
+  }
+  else {
+    ai->ai_flags &= ~TP_AI_COMPRESSED;
+    n = self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused);
+  }
+
+  if (n == 0)
+    return 0;
+
+  if (n == -1) 
+    return tport_send_error(self, msg, tpn);
+
+  self->tp_stats.sent_bytes += n;
+
+  if (n > 0 && self->tp_master->mr_dump_file)
+    tport_dump_iovec(self, msg, n, iov, iovused, "sent", "to");
+    
+  if (tport_log->log_level >= 7) {
+    size_t i, m = 0;
+
+    for (i = 0; i < iovused; i++)
+      m += iov[i].mv_len;
+
+    if (tpn == NULL || tport_is_connection_oriented(self))
+      tpn = self->tp_name;
+
+    SU_DEBUG_7(("tport_vsend(%p): "MOD_ZU" bytes of "MOD_ZU" to %s/%s:%s%s\n", 
+		self, n, m, tpn->tpn_proto, tpn->tpn_host, 
+		tpn->tpn_port, 
+		(ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : ""));
+  }
+
+  return n;
+}
+
+static
+int tport_send_error(tport_t *self, msg_t *msg, 
+		     tp_name_t const *tpn)
+{
+  int error = su_errno();
+  su_addrinfo_t *ai = msg_addrinfo(msg);
+  char const *comp = (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : "";
+
+  if (error == EPIPE) {
+    /*Xyzzy*/
+  }
+
+  if (su_is_blocking(error)) {
+    SU_DEBUG_5(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n", 
+		self, "EAGAIN", (int)self->tp_socket, 
+		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
+    return 0;
+  }
+
+  msg_set_errno(msg, error);
+
+  if (self->tp_addrinfo->ai_family == AF_INET) {
+    SU_DEBUG_3(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n", 
+		self, su_strerror(error), (int)self->tp_socket, 
+		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
+  }
+#if SU_HAVE_IN6
+  else if (self->tp_addrinfo->ai_family == AF_INET6) {
+    su_sockaddr_t const *su = (su_sockaddr_t const *)ai->ai_addr;
+    SU_DEBUG_3(("tport_vsend(%p): %s with "
+		"(s=%d, IP6=%s/%s:%s%s (scope=%i) addrlen=%u)\n", 
+		self, su_strerror(error), (int)self->tp_socket, 
+		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp,
+		su->su_scope_id, (unsigned)ai->ai_addrlen));
+  }
+#endif
+  else {
+    SU_DEBUG_3(("\ttport_vsend(%p): %s with "
+		"(s=%d, AF=%u addrlen=%u)%s\n", 
+		self, su_strerror(error), 
+		(int)self->tp_socket, ai->ai_family, (unsigned)ai->ai_addrlen, comp));
+  }
+
+#if 0
+  int i;
+  for (i = 0; i < iovused; i++)
+    SU_DEBUG_7(("\t\tiov[%d] = { %d bytes @ %p }\n", 
+		i, iov[i].siv_len, iov[i].siv_base));
+#endif
+
+  if (tport_is_connection_oriented(self)) {
+    tport_error_report(self, error, NULL);
+    if (tport_has_connection(self))
+      tport_close(self);
+  }
+
+  return -1;
+}
+
+
+static
+int tport_queue_rest(tport_t *self, 
+		     msg_t *msg, 
+		     msg_iovec_t iov[], 
+		     size_t iovused)
+{
+  size_t iovlen = self->tp_iovlen;
+
+  assert(tport_is_connection_oriented(self));
+  assert(self->tp_queue == NULL || 
+	 self->tp_queue[self->tp_qhead] == NULL || 
+	 self->tp_queue[self->tp_qhead] == msg);
+
+  if (tport_queue(self, msg) < 0)
+    return -1;
+
+  assert(self->tp_queue[self->tp_qhead] == msg);
+
+  if (self->tp_iov == NULL) {
+    if (iovlen < 40) iovlen = 40;
+    if (iovlen < iovused) iovlen = iovused;
+    self->tp_iov = su_alloc(self->tp_home, iovlen * sizeof(iov[0]));
+    self->tp_iovlen = iovlen;
+
+    if (!self->tp_iov) {
+      msg_set_errno(msg, errno);
+      return -1;
+    }
+
+    memcpy(self->tp_iov, iov, iovused * sizeof(iov[0]));
+
+    iov = self->tp_iov;
+  }
+
+  self->tp_unsent = iov;
+  self->tp_unsentlen = iovused;
+
+  /* the POLLOUT event is far too unreliable with SCTP */
+  if (self->tp_addrinfo->ai_protocol == IPPROTO_SCTP)
+    return 0;
+
+  /* Ask for a send event */
+  tport_set_events(self, SU_WAIT_OUT, 0);
+
+  return 0;
+}
+
+/** Queue a message to transport. 
+ *
+ * The tport_tqueue() function queues a message in the send queue. It is
+ * used by an (server) application that is required to send (response)
+ * messages in certain order. For example, a HTTP server or proxy may
+ * receive multiple requests from a single TCP connection. The server is
+ * required to answer to the requests in same order as they are received. 
+ * The responses are, however, sometimes generated asynchronously, that is,
+ * a response to a later request may be ready earlier. For that purpose, the
+ * HTTP protocol stack queues an empty response message immediately upon
+ * receiving a request. Other messages cannot be sent before the queued one.
+ *
+ * The function tport_tqsend() is used to send the completed response message. 
+ *
+ * @param self pointer to transport object
+ * @param msg  message to be inserted into queue
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * @par Currently none.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+
+ * @ERRORS
+ * @ERROR EINVAL  Invalid argument(s).
+ * @ERROR ENOMEM  Memory was exhausted.
+ * @ERROR ENOBUFS The transport object queue was full.
+ *
+ * @deprecated Alternative interface will be provided in near future.
+ *
+ * @sa tport_tqsend()
+ */
+int tport_tqueue(tport_t *self, msg_t *msg, 
+		 tag_type_t tag, tag_value_t value, ...)
+{
+  msg_unprepare(msg);
+
+  return tport_queue(self, msg);
+}
+
+/** Return number of queued messages. */
+isize_t tport_queuelen(tport_t const *self)
+{
+  isize_t retval = 0;
+
+  if (self && self->tp_queue) {
+    unsigned short i, N = self->tp_params->tpp_qsize;
+
+    for (i = self->tp_qhead; self->tp_queue[i]; i = (i + 1) % N)
+      retval++;
+  }
+
+  return retval;
+}
+
+static
+int tport_queue(tport_t *self, msg_t *msg)
+{
+  unsigned short qhead = self->tp_qhead;
+  unsigned short N = self->tp_params->tpp_qsize;
+
+  SU_DEBUG_7(("tport_queue(%p): queueing %p for %s/%s:%s\n", 
+	      self, msg, self->tp_protoname, self->tp_host, self->tp_port));
+
+  if (self->tp_queue == NULL) {
+    assert(N > 0);
+    assert(qhead == 0);
+    self->tp_queue = su_zalloc(self->tp_home, N * sizeof(msg));
+    if (!self->tp_queue) {
+      msg_set_errno(msg, errno);
+      return -1;
+    }
+  }
+
+  if (self->tp_queue[qhead] == msg)
+    return 0;
+
+  while (self->tp_queue[qhead]) {
+    qhead = (qhead + 1) % N;
+    if (qhead == self->tp_qhead) {
+      msg_set_errno(msg, ENOBUFS);
+      return -1;
+    }
+  }
+
+  self->tp_queue[qhead] = msg_ref_create(msg);
+
+  return 0;
+}
+
+/** Send a queued message (and queue another, if required).
+ * 
+ * The function tport_tqsend() sends a message to the transport. 
+ *
+ * @deprecated Alternative interface will be provided in near future.
+ */
+int tport_tqsend(tport_t *self, msg_t *msg, msg_t *next,
+		 tag_type_t tag, tag_value_t value, ...)
+{
+  unsigned short qhead;
+  ta_list ta;
+  int reuse, sdwn_after, close_after;
+  unsigned short N;
+  su_addrinfo_t *ai;
+
+  if (self == NULL)
+    return -1;
+
+  qhead = self->tp_qhead;
+  N = self->tp_params->tpp_qsize;
+  reuse = self->tp_reusable;
+  sdwn_after = 0;
+  close_after = 0;
+
+  ta_start(ta, tag, value);
+
+  tl_gets(ta_args(ta),
+	  TPTAG_REUSE_REF(reuse),
+	  TPTAG_SDWN_AFTER_REF(sdwn_after),
+	  TPTAG_CLOSE_AFTER_REF(close_after),
+	  TAG_END());
+
+  ta_end(ta);
+
+  /* If "next", make sure we can queue it */
+  if (next && self->tp_queue[qhead == 0 ? N - 1 : qhead - 1]) {
+    msg_set_errno(next, ENOBUFS);
+    return -1;
+  }
+
+  /* Prepare message for sending - i.e., encode it */
+  if (msg_prepare(msg) < 0) {
+    msg_set_errno(msg, errno);
+    return -1;
+  }
+
+  tport_peer_address(self, msg);  /* Set addrinfo */
+  if (next == NULL) {
+    ai = msg_addrinfo(msg);
+
+    if (sdwn_after)
+      ai->ai_flags |= TP_AI_SHUTDOWN;
+    if (close_after)
+      ai->ai_flags |= TP_AI_CLOSE;
+
+    if (self->tp_queue[qhead] == msg)
+      tport_send_queue(self);
+    return 0;
+  }
+
+  ai = msg_addrinfo(next);
+
+  if (sdwn_after)
+    ai->ai_flags |= TP_AI_SHUTDOWN;
+  if (close_after)
+    ai->ai_flags |= TP_AI_CLOSE;
+
+  if (self->tp_queue[qhead] == msg) {
+    /* XXX - what about errors? */
+    tport_send_msg(self, msg, self->tp_name, NULL);
+    if (!self->tp_unsent) {
+      msg_destroy(self->tp_queue[qhead]);
+      if ((self->tp_queue[qhead] = msg_ref_create(next)))
+	msg_unprepare(next);
+      return 0; 
+    }
+  }
+
+  while (self->tp_queue[qhead] && self->tp_queue[qhead] != msg) {
+    qhead = (qhead + 1) % N;
+    if (qhead == self->tp_qhead)
+      break;
+  }
+
+  if (self->tp_queue[qhead] != msg) {
+    msg_set_errno(next, EINVAL);
+    return -1;
+  }
+
+  msg = msg_ref_create(next);
+
+  do {
+    qhead = (qhead + 1) % N;
+    next = self->tp_queue[qhead]; self->tp_queue[qhead] = msg; msg = next;
+    /* Above we made sure that there is an empty slot */
+    assert(!next || qhead != self->tp_qhead); 
+  } while (next);
+
+  return 0;
+}
+
+/** Send event.
+ *
+ * Process SU_WAIT_OUT event.
+ */ 
+void tport_send_event(tport_t *self)
+{
+  assert(tport_is_connection_oriented(self));
+
+  SU_DEBUG_7(("tport_send_event(%p) - ready to send to (%s/%s:%s)\n", 
+	      self, self->tp_protoname, self->tp_host, self->tp_port));
+  tport_send_queue(self);
+}
+
+/** Send queued messages */
+static
+void tport_send_queue(tport_t *self)
+{
+  msg_t *msg;
+  msg_iovec_t *iov;
+  size_t i, iovused, n, total;
+  unsigned short qhead = self->tp_qhead, N = self->tp_params->tpp_qsize;
+  su_time_t now;
+
+  assert(self->tp_queue && self->tp_queue[qhead]);
+
+  self->tp_time = su_time_ms(now = su_now());
+
+  msg = self->tp_queue[qhead];
+
+  iov = self->tp_unsent, self->tp_unsent = NULL;
+  iovused = self->tp_unsentlen, self->tp_unsentlen = 0;
+
+  if (iov && iovused) {
+    ssize_t e;
+    e = tport_vsend(self, msg, self->tp_name, iov, iovused, NULL);
+
+    if (e == -1)				/* XXX */
+      return;
+
+    n = (size_t)e;
+
+    if (n > 0 && self->tp_master->mr_log && self->tp_slogged != msg) {
+      tport_log_msg(self, msg, "send", "to", now);
+      self->tp_slogged = msg;
+    }
+    
+    for (i = 0, total = 0; i < iovused; i++) {
+      if (total + (size_t)iov[i].mv_len > n) {
+	iov[i].mv_len -= (su_ioveclen_t)(n - total);
+	iov[i].mv_base = (char *)iov[i].mv_base + (n - total);
+
+	self->tp_unsent = iov + i;
+	self->tp_unsentlen = iovused - i;
+
+	return;
+      }
+      total += iov[i].mv_len;
+    }
+    assert(total == n);
+
+    self->tp_queue[qhead] = NULL;
+    msg_destroy(msg);
+    self->tp_slogged = NULL;
+
+    qhead = (qhead + 1) % N;
+  }
+
+  while (msg_is_prepared(msg = self->tp_queue[self->tp_qhead = qhead])) {
+    /* XXX - what about errors? */
+    tport_send_msg(self, msg, self->tp_name, NULL); 
+    if (self->tp_unsent) 
+      return;
+
+    msg = self->tp_queue[qhead]; /* tport_send_msg() may flush queue! */
+    self->tp_queue[qhead] = NULL;
+    msg_destroy(msg);
+    qhead = (qhead + 1) % N;
+  }
+
+  /* No more send event(s)? */
+  tport_set_events(self, 0, SU_WAIT_OUT);
+}
+
+static int msg_select_addrinfo(msg_t *msg, su_addrinfo_t *res);
+
+static int
+tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn)
+{
+  int error;
+  char ipaddr[TPORT_HOSTPORTSIZE];
+  su_addrinfo_t *res, hints[1] = {{ 0 }};
+  char const *host;
+  su_sockaddr_t *su;
+
+  hints->ai_socktype = self->tp_addrinfo->ai_socktype;
+  hints->ai_protocol = self->tp_addrinfo->ai_protocol;
+
+  if (tpn->tpn_host[0] == '[') {
+    /* Remove [] around IPv6 address */
+    char *end;
+    hints->ai_flags |= AI_NUMERICHOST;
+    host = strncpy(ipaddr, tpn->tpn_host +  1, sizeof(ipaddr) - 1);
+    ipaddr[sizeof(ipaddr) - 1] = '\0';
+
+    if ((end = strchr(host, ']'))) {
+      *end = 0;
+    }
+    else {
+      SU_DEBUG_3(("tport_resolve: bad IPv6 address\n"));
+      msg_set_errno(msg, EINVAL);
+      return -1;
+    }
+  }
+  else 
+    host = tpn->tpn_host;
+
+  if ((error = su_getaddrinfo(host, tpn->tpn_port, hints, &res))) {
+    SU_DEBUG_3(("tport_resolve: getaddrinfo(\"%s\":%s): %s\n",
+		tpn->tpn_host, tpn->tpn_port,
+		su_gai_strerror(error)));
+    msg_set_errno(msg, ENXIO);
+    return -1;
+  }
+
+  error = msg_select_addrinfo(msg, res);
+
+  su = (su_sockaddr_t *) msg_addrinfo(msg)->ai_addr;
+
+#if SU_HAVE_IN6
+  SU_DEBUG_9(("tport_resolve addrinfo = %s%s%s:%d\n", 
+	      su->su_family == AF_INET6 ? "[" : "",
+              inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr)),
+	      su->su_family == AF_INET6 ? "]" : "",
+              htons(su->su_port)));
+#else
+  SU_DEBUG_9(("tport_resolve addrinfo = %s%s%s:%d\n", 
+	      "",
+              inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr)),
+	      "",
+              htons(su->su_port)));
+#endif
+
+  su_freeaddrinfo(res);
+
+  return error;
+}
+
+static int
+msg_select_addrinfo(msg_t *msg, su_addrinfo_t *res)
+{
+  su_addrinfo_t *ai, *mai = msg_addrinfo(msg);
+  su_sockaddr_t *su = (su_sockaddr_t *)mai->ai_addr;
+
+  for (ai = res; ai; ai = ai->ai_next) {
+#if SU_HAVE_IN6
+    if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+      continue;
+#else
+    if (ai->ai_family != AF_INET)
+      continue;
+#endif
+
+    if (ai->ai_addrlen > sizeof(su_sockaddr_t))
+      continue;
+    mai->ai_family = ai->ai_family;
+    mai->ai_socktype = ai->ai_socktype;
+    mai->ai_protocol = ai->ai_protocol;
+    if (ai->ai_addrlen < sizeof(su_sockaddr_t))
+      memset(su, 0, sizeof(su_sockaddr_t));
+    memcpy(su, ai->ai_addr, ai->ai_addrlen);
+    if (su_sockaddr_size(su))
+      mai->ai_addrlen = su_sockaddr_size(su);
+    else
+      mai->ai_addrlen = ai->ai_addrlen;
+    return 0;
+  }
+
+  msg_set_errno(msg, EAFNOSUPPORT);
+   
+  return -1;
+}
+
+/** Copy peer address to msg */
+void
+tport_peer_address(tport_t *self, msg_t *msg)
+{
+  su_addrinfo_t *mai = msg_addrinfo(msg);
+  su_addrinfo_t const *tai = self->tp_addrinfo;
+  void *maddr = mai->ai_addr;
+  int flags = mai->ai_flags;
+
+  memcpy(mai, tai, sizeof *mai);
+  mai->ai_addr = memcpy(maddr, tai->ai_addr, tai->ai_addrlen);
+  mai->ai_flags = flags;
+}
+
+/** Process error event. 
+ *
+ * Return events that can be processed afterwards.
+ */
+int tport_error_event(tport_t *self)
+{
+  int errcode;
+  su_sockaddr_t name[1] = {{ 0 }};
+
+  name->su_family = AF_UNSPEC; /* 0 */
+
+  if (tport_is_udp(self)) {
+    errcode = tport_udp_error(self, name);
+  }
+  else {
+    /* Process error event for basic transport. */
+    errcode = su_soerror(self->tp_socket);
+  }
+
+  if (errcode == 0 || errcode == EPIPE)
+    return errcode;
+
+  tport_error_report(self, errcode, name);
+
+  return 0;
+}
+
+/** Mark message as waiting for a response.
+ *
+ * @return Positive integer, or -1 upon an error.
+ */
+int tport_pend(tport_t *self, 
+	       msg_t *msg, 
+	       tport_pending_error_f *callback, 
+	       tp_client_t *client)
+{
+  tport_pending_t *pending;
+
+  if (self == NULL || msg == NULL || callback == NULL || client == NULL)
+    return -1;
+
+  SU_DEBUG_7(("tport_pend(%p): pending %p for %s/%s:%s (already %u)\n", 
+	      self, msg, 
+	      self->tp_protoname, self->tp_host, self->tp_port,
+	      self->tp_pused));
+
+  if (self->tp_released == NULL) {
+    unsigned i, len = 8;
+    if (self->tp_plen)
+      len = 2 * self->tp_plen;
+    pending = su_realloc(self->tp_home, 
+			 self->tp_pending, len * sizeof(*pending));
+    if (!pending) {
+      msg_set_errno(msg, errno);
+      return -1;
+    }
+
+    memset(pending + self->tp_plen, 0, (len - self->tp_plen) * sizeof(*pending));
+
+    for (i = self->tp_plen; i + 1 < len; i++)
+      pending[i].p_client = pending + i + 1;
+      
+    self->tp_released = pending + self->tp_plen;
+    self->tp_pending = pending;
+    self->tp_plen = len;
+  }
+
+  pending = self->tp_released;
+  self->tp_released = pending->p_client;
+
+  pending->p_callback = callback;
+  pending->p_client = client;
+  pending->p_msg = msg;
+  pending->p_reported = self->tp_reported;
+
+  self->tp_pused++;
+
+  return (pending - self->tp_pending) + 1;
+}
+
+/** Mark message as no more pending */
+int tport_release(tport_t *self, 
+		  int pendd,
+		  msg_t *msg, 
+		  msg_t *reply, 
+		  tp_client_t *client, 
+		  int still_pending)
+{
+  tport_pending_t *pending;
+
+  if (self == NULL || msg == NULL || pendd <= 0 || pendd > (int)self->tp_plen)
+    return su_seterrno(EINVAL), -1;
+
+  pending = self->tp_pending + (pendd - 1);
+
+  if (pending->p_client != client || 
+      pending->p_msg != msg) {
+    SU_DEBUG_1(("tport_release(%p): %u %p by %p not pending\n", self, 
+		pendd, msg, client));
+    return su_seterrno(EINVAL), -1;
+  }
+
+  SU_DEBUG_7(("tport_release(%p): %p by %p with %p%s\n", 
+	      self, msg, client, reply,
+	      still_pending ? " (preliminary)" : ""));
+
+  /* sigcomp can here associate request (msg) with response (reply) */
+
+  if (still_pending)
+    return 0;
+	    
+  /* Just to make sure nobody uses stale data */
+  memset(pending, 0, sizeof(*pending));
+  pending->p_client = self->tp_released;
+  self->tp_released = pending;
+  self->tp_pused--;
+  return 0;
+}
+
+/** Report error to pending messages with destination */
+int
+tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error)
+{
+  unsigned i, reported, callbacks;
+  tport_pending_t *pending;
+  msg_t *msg;
+  su_addrinfo_t const *ai;
+
+  assert(self); assert(dst);
+
+  callbacks = 0;
+  reported = ++self->tp_reported;
+
+  if (self->tp_pused == 0)
+    return 0;
+
+  for (i = 0; i < self->tp_plen; i++) {
+    pending = self->tp_pending + i;
+
+    if (!pending->p_callback || !pending->p_msg)
+      continue;
+
+    if (pending->p_reported == reported)
+      continue;
+
+    msg = pending->p_msg;
+    ai = msg_addrinfo(msg);
+
+    if (su_cmp_sockaddr(dst, (su_sockaddr_t *)ai->ai_addr) != 0)
+      continue;
+
+    pending->p_reported = reported;
+
+    msg_set_errno(msg, error);
+
+    pending->p_callback(self->TP_STACK, pending->p_client, self, msg, error);
+
+    callbacks++;
+  }
+
+  return callbacks;
+}
+
+
+/** Report error via pending message */
+int
+tport_pending_errmsg(tport_t *self, msg_t *msg, int error)
+{
+  unsigned i, reported, callbacks;
+  tport_pending_t *pending;
+
+  assert(self); assert(msg);
+
+  callbacks = 0;
+  reported = ++self->tp_reported;
+
+  msg_set_errno(msg, error);
+
+  if (self->tp_pused == 0)
+    return 0;
+
+  for (i = 0; i < self->tp_plen; i++) {
+    pending = self->tp_pending + i;
+
+    if (!pending->p_client || 
+	pending->p_msg != msg ||
+	pending->p_reported == reported)
+      continue;
+    
+    pending->p_reported = reported;
+
+    pending->p_callback(self->TP_STACK, pending->p_client, self, msg, error);
+
+    callbacks++;
+  }
+
+  return callbacks;
+}
+
+
+/** Set transport magic. */
+void tport_set_magic(tport_t *self, tp_magic_t *magic)
+{
+  self->tp_magic = magic;
+}
+
+/** Get transport magic. */
+tp_magic_t *tport_magic(tport_t const *self)
+{
+  return self ? self->tp_magic : NULL;
+}
+
+/** Get primary transport (or self, if primary) */
+tport_t *tport_parent(tport_t const *self)
+{
+  return self ? self->tp_pri->pri_primary : NULL;
+}
+
+/** Get list of primary transports */
+tport_t *tport_primaries(tport_t const *self)
+{
+  if (self)
+    return self->tp_master->mr_primaries->pri_primary;
+  else
+    return NULL;
+}
+
+/** Get next transport */
+tport_t *tport_next(tport_t const *self)
+{
+  if (self == NULL)
+    return NULL;
+  else if (tport_is_master(self))
+    return ((tport_master_t *)self)->mr_primaries->pri_primary;
+  else if (tport_is_primary(self))
+    return ((tport_primary_t *)self)->pri_next->pri_primary;
+  else
+    return tprb_succ(self);
+}
+
+/** Get secondary transports. */
+tport_t *tport_secondary(tport_t const *self)
+{
+  if (tport_is_primary(self))
+    return self->tp_pri->pri_secondary;
+  else
+    return NULL;
+}
+
+#if 0
+void tport_hints(tport_t const *self, su_addrinfo_t *hints)
+{
+  hints->ai_protocol = self->tp_addrinfo->ai_protocol;
+  hints->ai_socktype = self->tp_addrinfo->ai_socktype;
+}
+#endif
+
+/** Get transport address list. */
+su_addrinfo_t const *tport_get_address(tport_t const *self)
+{
+  return self ? self->tp_addrinfo : NULL;
+}
+
+/** Get transport name. */
+tp_name_t const *tport_name(tport_t const *self)
+{
+  return self->tp_name;
+}
+
+/** Get transport identifier. */ 
+char const *tport_ident(tport_t const *self)
+{
+  return self ? self->tp_ident : NULL;
+}
+
+/** Get transport by protocol name. */
+tport_t *tport_by_protocol(tport_t const *self, char const *proto) 
+{
+  if (proto && strcmp(proto, tpn_any) != 0) {
+    for (; self; self = tport_next(self))
+      if (strcasecmp(proto, self->tp_protoname) == 0)
+	break;
+  }
+
+  return (tport_t *)self;
+}
+
+/** Get transport by protocol name. */
+tport_t *tport_primary_by_name(tport_t const *tp, tp_name_t const *tpn)
+{
+  char const *ident = tpn->tpn_ident;
+  char const *proto = tpn->tpn_proto;
+  char const *comp = tpn->tpn_comp;
+  int family = 0;
+
+  tport_primary_t const *self, *nocomp = NULL;
+
+  self = tp ? tp->tp_master->mr_primaries : NULL;
+
+  if (ident && strcmp(ident, tpn_any) == 0)
+    ident = NULL;
+
+  if (tpn->tpn_host == NULL)
+    family = 0;
+#if SU_HAVE_IN6
+  else if (host_is_ip6_address(tpn->tpn_host))
+    family = AF_INET6;
+#endif
+  else if (host_is_ip4_address(tpn->tpn_host))
+    family = AF_INET;
+  else 
+    family = 0;
+
+  if (proto && strcmp(proto, tpn_any) == 0)
+    proto = NULL;
+
+  if (!ident && !proto && !family && !comp)
+    return (tport_t *)self;		/* Anything goes */
+
+  comp = tport_canonize_comp(comp);
+
+  for (; self; self = self->pri_next) {
+    tp = self->pri_primary;
+
+    if (ident && strcmp(ident, tp->tp_ident))
+      continue;
+    if (family) {
+      if (family == AF_INET && !tport_has_ip4(tp))
+	continue;
+#if SU_HAVE_IN6
+      if (family == AF_INET6 && !tport_has_ip6(tp))
+	continue;
+#endif
+    }
+    if (proto && strcasecmp(proto, tp->tp_protoname))
+      continue;
+    
+    if (comp && comp != tp->tp_name->tpn_comp) {
+      if (tp->tp_name->tpn_comp == NULL && nocomp == NULL)
+	nocomp = self;
+      continue;
+    }
+
+    break;
+  }
+
+  if (self)
+    return (tport_t *)self;
+  else
+    return (tport_t *)nocomp;
+}
+
+
+/** Get transport by name. */
+tport_t *tport_by_name(tport_t const *self, tp_name_t const *tpn)
+{
+  tport_t const *sub, *next;
+  char const *canon, *host, *port, *comp;
+#if SU_HAVE_IN6
+  char *end, ipaddr[TPORT_HOSTPORTSIZE];
+#endif
+
+  assert(self); assert(tpn);
+
+  assert(tpn->tpn_proto); assert(tpn->tpn_host); assert(tpn->tpn_port);
+  assert(tpn->tpn_canon);
+
+  if (!tport_is_primary(self))
+    self = tport_primary_by_name(self, tpn);
+
+  host = strcmp(tpn->tpn_host, tpn_any) ? tpn->tpn_host : NULL;
+  port = strcmp(tpn->tpn_port, tpn_any) ? tpn->tpn_port : NULL;
+  canon = tpn->tpn_canon;
+  comp = tport_canonize_comp(tpn->tpn_comp);
+
+  if (self && host && port) {
+    int resolved = 0, cmp;
+    socklen_t sulen;
+    su_sockaddr_t su[1];
+
+    sub = self->tp_pri->pri_secondary;
+
+    memset(su, 0, sizeof su);
+
+#if SU_HAVE_IN6
+    if (host_is_ip6_reference(host)) {
+      /* Remove [] around IPv6 address */
+      host = strncpy(ipaddr, host +  1, sizeof(ipaddr) - 1);
+      ipaddr[sizeof(ipaddr) - 1] = '\0';
+      if ((end = strchr(host, ']')))
+	*end = 0;
+      su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
+      su->su_family = AF_INET6;
+    }
+    else if (host_is_ip_address(host)) {
+      su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
+      su->su_family = AF_INET6;
+    }
+    else
+#endif
+    {
+      su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in);
+      su->su_family = AF_INET;
+    }
+
+    su->su_port = htons(strtoul(port, NULL, 10));
+    
+    if (inet_pton(su->su_family, host, SU_ADDR(su)) > 0) {
+      resolved = 1;
+      next = NULL;
+
+      /* Depth-first search */
+      while (sub) {
+	cmp = (int)((size_t)sub->tp_addrlen - (size_t)sulen);
+
+	if (cmp == 0)
+	  cmp = memcmp(sub->tp_addr, su, sulen);
+
+	if (cmp == 0) {
+	  if (sub->tp_left) {
+	    next = sub;
+	    sub = sub->tp_left;
+	    continue;
+	  }
+	  break;
+	}
+	else if (next) {
+	  sub = next;
+	  break;
+	}
+	else if (cmp > 0) {
+	  sub = sub->tp_left;
+	  continue;
+	}
+	else /* if (cmp < 0) */ {
+	  sub = sub->tp_right;
+	  continue;
+	}
+      }
+    }
+    else {
+      SU_DEBUG_7(("tport(%p): EXPENSIVE unresolved " TPN_FORMAT "\n",
+		  self, TPN_ARGS(tpn)));
+
+      sub = tprb_first(sub);
+    }
+
+    for (; sub; sub = tprb_succ(sub)) {
+      if (!sub->tp_reusable)
+	continue;
+      if (!tport_is_registered(sub))
+	continue;
+      if (tport_is_shutdown(sub))
+	continue;
+
+      if (comp != sub->tp_name->tpn_comp)
+	continue;
+
+      if (resolved) {
+	if ((socklen_t)sub->tp_addrlen != sulen ||
+	    memcmp(sub->tp_addr, su, sulen)) {
+	  SU_DEBUG_7(("tport(%p): not found by name " TPN_FORMAT "\n",
+		      self, TPN_ARGS(tpn)));
+	  break;
+	}
+	SU_DEBUG_7(("tport(%p): found %p by name " TPN_FORMAT "\n",
+		    self, sub, TPN_ARGS(tpn)));
+      }
+      else if ((strcasecmp(canon, sub->tp_canon) &&
+		strcasecmp(host, sub->tp_host)) ||
+	       strcmp(port, sub->tp_port))
+	continue;
+
+      return (tport_t *)sub;
+    }
+  }
+
+  return (tport_t *)self;
+}
+
+/** Get transport from primary by addrinfo. */
+tport_t *tport_by_addrinfo(tport_primary_t const *pri, 
+			   su_addrinfo_t const *ai,
+			   tp_name_t const *tpn)
+{
+  tport_t const *sub, *maybe;
+  struct sockaddr const *sa;
+  int cmp;
+  char const *comp;
+
+  assert(pri); assert(ai);
+
+  sa = ai->ai_addr;
+
+  sub = pri->pri_secondary, maybe = NULL;
+
+  comp = tport_canonize_comp(tpn->tpn_comp);
+
+  /* Find leftmost (prevmost) matching tport */
+  while (sub) {
+    cmp = (int)(sub->tp_addrlen - ai->ai_addrlen); 
+    if (cmp == 0)
+      cmp = memcmp(sub->tp_addr, sa, ai->ai_addrlen);
+
+    if (cmp == 0) {
+      if (sub->tp_left) {
+	maybe = sub;
+	sub = sub->tp_left;
+	continue;
+      }
+      break;
+    }
+    else if (maybe) {
+      sub = maybe;
+      break;
+    }
+    else if (cmp > 0) {
+      sub = sub->tp_left;
+      continue;
+    }
+    else /* if (cmp < 0) */ {
+      sub = sub->tp_right;
+      continue;
+    }
+  }
+
+  for (; sub; sub = tprb_succ(sub)) {
+    if (!sub->tp_reusable)
+      continue;
+    if (!tport_is_registered(sub))
+      continue;
+    if (tport_is_shutdown(sub))
+      continue;
+
+    if (comp != sub->tp_name->tpn_comp)
+      continue;
+    
+    if (sub->tp_addrlen != ai->ai_addrlen 
+	|| memcmp(sub->tp_addr, sa, ai->ai_addrlen)) {
+      sub = NULL;
+      break;
+    }
+    break;
+  }
+
+  if (sub)
+    SU_DEBUG_7(("%s(%p): found %p by name " TPN_FORMAT "\n",
+		__func__, pri, sub, TPN_ARGS(tpn)));
+  else
+    SU_DEBUG_7(("%s(%p): not found by name " TPN_FORMAT "\n",
+		__func__, pri, TPN_ARGS(tpn)));
+
+  return (tport_t *)sub;
+}
+
+
+/** Get transport name from URL. */
+int tport_name_by_url(su_home_t *home, 
+		      tp_name_t *tpn,
+		      url_string_t const *us)
+{
+  size_t n;
+  url_t url[1];
+  char *b;
+
+  n = url_xtra(us->us_url);
+  b = su_alloc(home, n);
+
+  if (b == NULL || url_dup(b, n, url, us->us_url) < 0) {
+    su_free(home, b);
+    return -1;
+  }
+
+  tpn->tpn_proto = url_tport_default(url->url_type);
+  tpn->tpn_canon = url->url_host;
+  tpn->tpn_host = url->url_host;
+  tpn->tpn_port = url_port(url);
+
+  if (tpn->tpn_host == NULL || tpn->tpn_host[0] == '\0' ||
+      tpn->tpn_port == NULL || tpn->tpn_port[0] == '\0') {
+    su_free(home, b);
+    return -1;
+  }
+
+  if (url->url_params) {
+    for (b = (char *)url->url_params; b[0]; b += n) {
+      n = strcspn(b, ";");
+
+      if (n > 10 && strncasecmp(b, "transport=", 10) == 0)
+	tpn->tpn_proto = b + 10;
+      else if (n > 6 && strncasecmp(b, "maddr=", 6) == 0)
+	tpn->tpn_host = b + 6;
+
+      if (b[n])
+	b[n++] = '\0';
+    }
+  }
+
+  return 0;
+}
+
+/** Check if transport named is already resolved */
+int tport_name_is_resolved(tp_name_t const *tpn)
+{
+  size_t n;
+
+  if (!tpn->tpn_host)
+    return 0;
+  
+  if (tpn->tpn_host[0] == '[')
+    return 1;
+
+  n = strspn(tpn->tpn_host, ".0123456789");
+
+  if (tpn->tpn_host[n] == '\0')
+    return 1;
+
+  if (strchr(tpn->tpn_host, ':')) {
+    n = strspn(tpn->tpn_host, ":0123456789abcdefABCDEF");
+
+    if (tpn->tpn_host[n] == '\0')
+      return 1;
+  }
+
+  return 0;
+}
+
+/** Duplicate name.
+ *
+ * The tport_name_dup() function copies strings belonging to the transport
+ * name. It returns the copied strings via the @a dst transport name
+ * structure. The memory block required for copies is allocated from the
+ * memory @a home. Please note that only one memory block is allocated, so
+ * the memory can be reclainmed only by deinitializing the memory home
+ * itself.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int tport_name_dup(su_home_t *home, 
+		   tp_name_t *dst,
+		   tp_name_t const *src)
+{
+  size_t n_proto, n_host, n_port, n_canon, n_comp = 0;
+  char *s;
+
+  if (strcmp(src->tpn_proto, tpn_any)) 
+    n_proto = strlen(src->tpn_proto) + 1;
+  else
+    n_proto = 0;
+
+  n_host = strlen(src->tpn_host) + 1;
+
+  n_port = strlen(src->tpn_port) + 1;
+
+  if (src->tpn_comp != NULL)
+    n_comp = strlen(src->tpn_comp) + 1;
+
+  if (src->tpn_canon != src->tpn_host &&
+      strcmp(src->tpn_canon, src->tpn_host))
+    n_canon = strlen(src->tpn_canon) + 1;
+  else
+    n_canon = 0;
+
+  s = su_alloc(home, n_proto + n_canon + n_host + n_port + n_comp);
+  
+  if (n_proto)
+    dst->tpn_proto = memcpy(s, src->tpn_proto, n_proto), s += n_proto;
+  else
+    dst->tpn_proto = tpn_any;
+
+  dst->tpn_host = memcpy(s, src->tpn_host, n_host), s += n_host;
+  dst->tpn_port = memcpy(s, src->tpn_port, n_port), s += n_port;
+
+  if (n_canon)
+    dst->tpn_canon = memcpy(s, src->tpn_canon, n_canon), s += n_canon;
+  else
+    dst->tpn_canon = dst->tpn_host;
+
+  if (n_comp)
+    dst->tpn_comp = memcpy(s, src->tpn_comp, n_comp), s += n_comp;
+  else
+    dst->tpn_comp = NULL;
+  
+  return 0;
+}
+
+/** Convert a sockaddr structure into printable form. */
+char *tport_hostport(char buf[], isize_t bufsize, 
+		     su_sockaddr_t const *su,
+		     int with_port_and_brackets)
+{
+  char *b = buf;
+  size_t n;
+
+#if SU_HAVE_IN6
+  if (with_port_and_brackets > 1 || su->su_family == AF_INET6) {
+    *b++ = '['; bufsize--; 
+  }
+#endif
+
+  if (inet_ntop(su->su_family, SU_ADDR(su), b, bufsize) == NULL)
+    return NULL;
+  n = strlen(b); 
+  if (bufsize < n + 2)
+    return NULL;
+
+  bufsize -= n; b += n;
+
+#if SU_HAVE_IN6
+  if (with_port_and_brackets > 1 || su->su_family == AF_INET6) {
+    *b++ = ']'; bufsize--; 
+  }
+  if (with_port_and_brackets) {
+    unsigned short port = ntohs(su->su_port);
+    if (port != 0) {
+      n = snprintf(b, bufsize, ":%u", port);
+      if (n <= 0)
+        return NULL;
+      b += n; 
+      if (bufsize > n)
+        bufsize -= n;
+      else
+        bufsize = 0;
+    }
+  }
+#endif
+
+  if (bufsize)
+    *b++ = 0;
+
+  return buf;
+}
+
+/* ----------------------------------------------------------------------  */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,193 @@
+/**@MODULEPAGE "tport" - Transport Module
+
+ at section tport_meta Module Information
+
+The @b tport module contains a generic transport interface used by SIP,
+RTSP, and HTTP protocols. It is an abstraction layer between a protocol
+stack and a transport protocol implementation. The interface is
+implemented via transport objects.
+
+ at CONTACT Pekka.Pessi at nokia.com
+
+ at LICENSE LGPL
+
+ at section tp_primary Master, Primary and Secondary Transport Objects
+
+A transport object can be used in three roles. Master transport object
+represents all available transport. It is used to store stack and root
+interface as well as common data such as SigComp state handler. The primary
+transport objects represent available transports. The secondary transports
+represent actual transport connections.
+
+A protocol stack first creates a @e master @e transport object and binds a
+number of primary transport objects (each representing a transport protocol
+such as UDP, TCP, TLS/TCP, SCTP, etc). The binding process creates a new
+primary transport object for each transport supported. If the protocol stack
+is used as a server, the binding process also creates the necessary server
+sockets and binds them to the specified server ports.
+
+Secondary transport objects are created for each transport-level
+connection. The @b tport module takes care of automatically creating them
+and discarding them when they are no more used. The secondary transport
+objects are required to transmit messages when a connection-oriented
+transport protocol is used.
+
+A secondary transport object can be created for two reasons. A server may
+accept a new connection from a client, or a client may connect to a
+server. When the connection belonging to a secondary transport has been
+established, the protocol stack can send or receive messages through it.
+
+ at section tp_init Initializing Transports
+
+When the primary transport object is created with tport_tcreate(), the
+protocol stack must pass a #tport_stack_class_t structure containing
+function pointers to the new transport object. These function pointers
+are used to
+
+-# create new message objects used to store received messages
+-# pass received messages to the protocol stack, and
+-# report transport errors to the protocol stack.
+
+The transport protocols are bound to the primary transport objects with
+the method tport_tbind(). The protocol stack gives the desired server
+transport name (transport name is a structure containing a text-formatted
+socket address along with transport name) along with the list of
+transport protocols supported by the stack. The function tport_tbind()
+can be called multiple times, if, for example, the server port(s) used by
+transport protocol differ (for example, default TCP port for SIP is 5060,
+and default TLS port is 5061).
+
+ at subsection tp_connect Connection-Oriented and Connection-Less Transports
+
+A secondary transport objects is created for each transport-level
+connection. The tport module takes care of automatically creating them,
+and discarding them when they are no more used. The secondary transport
+objects are required to transmit messages when a connection-oriented
+transport protocol is used.
+
+A secondary transport can be created for two reasons. A server may accept
+a new connection from a client, or a client may connect to a server. When
+the connection belonging to a secondary transport has been established,
+the protocol stack can send or receive messages through it.
+
+ at par Connection-Oriented and Connection-Less Transports
+
+A transport can be connection-oriented (TCP, SCTP) or connectionless
+(UDP). A connection-oriented transport needs a connection to be
+established before messages can be sent. It can also send messages only
+to a single destination. For a connectionless transport, a destination
+address must always be given.
+
+A connectionless transport can be used to send messages to several
+distinct destinations. The destination address must be given to the
+kernel whenever a message is sent using connectionless transport.
+
+Note that UDP can be used in connection-oriented manner (client does not
+use sendto(), but connect() and then send()), if tport_set_params() is
+called with TPTAG_CONNECT(1) argument.
+
+ at subsection tp_stream Stream and Datagram Transports
+
+A connection-oriented transport can also be stream-based (TCP, SCTP) or
+packet-based (UDP, SCTP). A stream-based transport protocol takes care of
+ordering the data within a stream, a data chunk sent earlier is always
+delivered before chunks sent after it. A packet-based transport delivers
+data chunks independent of each other and does not maintain the relative
+order, for instance, if a data chunk is lost by the network and then
+retransmitted, application can receive it later than a data chunk that
+was sent after lost one but did not need any retransmissions.
+
+ at subsection tp_magic Transport Magic 
+
+Transport magic is a cookie, a piece of data specified by stack that can
+be associated with a transport (e.g., a Via header). The protocol stack
+can change the type of transport magic by defining the macro
+#TP_MAGIC_T before including <tport.h>.
+
+ at section tp_op Transport Operations
+
+ at subsection tp_send Sending Messages
+
+A message can be sent by the tport_tsend() method. The method can be
+called either from the primary or from the secondary transport. If a
+secondary transport is needed to send the message, it is created and
+connected automatically.
+
+The transport gets the data to be sent from the message object with
+msg_iovec() call. The transport tries to send all the data using one
+su_vsend() call. If the call would fail, for instance, because the send
+buffer is too short, the transport object would create a reference to the
+message and queue it in its own queue.
+
+ at subsection tp_recv Receiving Messages
+
+When a primary connectionless transport object or a secondary transport
+object receives new data, it allocates a new message object. The message
+object is created using the factory function tpac_alloc() provided by the
+protocl stack. The incoming data is passed to the message object, data is
+parsed and when a message is complete, it is passed to the application
+using the tpac_recv() function provided when the transport was created.
+
+ at subsection tp_refcnt Reference Counting
+
+In order to destroy unused connections, each secondary transport object
+needs to know if there is a reference to it from the stack. A protocol
+stack creates a reference to a transport when it receives an incoming
+request and needs to send the response using the same transport, or when
+it expects a reply from the server coming on the connection used to send
+the request.
+
+ at note While the reference counting has been implemented in the tport
+module, the transport objects are not destroyed by timers by default as
+all the protocol stacks do @b not properly handle the reference counting. 
+Timers are activated when the tag TPTAG_IDLE() is used.
+
+ at subsection tp_pend Pending Requests
+
+The protocol stack can mark requests as @e pending using tport_pend()
+function. The tport_pend() function associates a request message with a
+callback and a handle to a client object. When a transport error occurs,
+it is reported to the client object using the associated callback
+function.
+
+When the stack receives a response to the request it has marked as
+pending, it calls tport_release(). The request can be still considered
+pending, if the response was a preliminary one. In this case, the @a
+still_pending argument is true. The function tport_release() is also
+called without response message, if the stack is no more interested in
+the response, for instance, after a timeout.
+
+ at subsection tp_queue Send Queue
+
+Each stream-based transport also supports send queue. The queue can be
+used either to queue messages during congestion, or to maintain the
+relative ordering of responses. Usually, queue is used implicitly for the
+first purpose, e.g., if a transport is busy sending a message it queues
+further messages when tport_tsend() is called.
+
+Explicit queueing is needed when the protocol (like HTTP/1.1) requires
+that the relative order of responses is maintained. When the protocol
+stack receives a request, it queues an empty response message to the
+transport with tport_tqueue(). Such an empty response is marked as
+incomplete, not ready to send. When application responds to the request
+via tport_tqsend(), the transport object marks the message ready to send
+and, if there are no other queued responses before it, sends it.
+
+ at section tp_debug Logging and Dumping Messages
+
+Seeing message contents and network events is extremely useful when
+debugging protocols. There are environment variables that are used to
+activate message logging within @b tport module.
+<dl compact>
+<dt>@b #TPORT_LOG
+   <dd>if set, tport module prints out the message contents 
+       after parsing
+<dt>@b #TPORT_DUMP
+   <dd>contains dump file name - incoming data is written
+       dump file @e before parsing 
+<dt>@b #TPORT_DEBUG
+   <dd>integer in range -1..9 controlling amount of
+       debugging printout from @b tport module. See also #tport_log.
+</dl>
+ */
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,529 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_INTERNAL_H
+/** Defined when <tport_internal.h> has been included. */
+#define TPORT_INTERNAL_H
+
+/**@file tport_internal.h
+ * @brief Transport interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+#include <sofia-sip/su_uniqueid.h>
+
+#ifndef MSG_ADDR_H
+#include <sofia-sip/msg_addr.h>
+#endif
+#ifndef TPORT_H
+#include <sofia-sip/tport.h>
+#endif
+
+#if HAVE_SOFIA_STUN
+#include "sofia-sip/stun.h"
+#include "sofia-sip/stun_tag.h"
+#endif
+
+#include <sofia-sip/tport_plugins.h>
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+#define SU_LOG   tport_log
+
+#include <sofia-sip/su_debug.h>
+
+#if !defined(MSG_NOSIGNAL) || defined(__CYGWIN__)
+#undef MSG_NOSIGNAL
+#define MSG_NOSIGNAL (0)
+#endif
+
+#if !HAVE_MSG_TRUNC
+#define MSG_TRUNC (0)
+#endif
+
+#ifndef NONE
+#define NONE ((void *)-1)
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct tport_master tport_master_t;
+typedef struct tport_pending_s tport_pending_t;
+typedef struct tport_primary tport_primary_t;
+typedef struct tport_vtable tport_vtable_t;
+
+struct sigcomp_state_handler;
+struct sigcomp_algorithm;
+struct sigcomp_udvm;
+struct sigcomp_magic;
+struct sigcomp_compartment;
+
+typedef long unsigned LU; 	/* for printf() and friends */
+
+/** Transport parameters */
+typedef struct {
+  usize_t  tpp_mtu;		/**< Maximum packet size */
+  unsigned tpp_idle;		/**< Allowed connection idle time. */
+  unsigned tpp_timeout;		/**< Allowed idle time for message. */
+  unsigned tpp_sigcomp_lifetime;  /**< SigComp compartment lifetime  */
+  unsigned tpp_thrpsize;	/**< Size of thread pool */
+
+  unsigned tpp_thrprqsize;	/**< Length of per-thread recv queue */
+  unsigned tpp_qsize;		/**< Size of queue */
+
+  unsigned tpp_drop;		/**< Packet drop probablity */
+  int      tpp_tos;         	/**< IP TOS */
+
+  unsigned tpp_conn_orient:1;   /**< Connection-orienteded */
+  unsigned tpp_sdwn_error:1;	/**< If true, shutdown is error. */
+  unsigned tpp_stun_server:1;	/**< If true, use stun server */
+
+  unsigned :0;
+
+} tport_params_t;
+
+
+/** Transport object.
+ *
+ * A transport object can be used in three roles, to represent transport
+ * list (aka master transport), to represent available transports (aka
+ * primary transport) and to represent actual transport connections (aka
+ * secondary transport).
+ */
+struct tport_s {
+  su_home_t           tp_home[1];       /**< Memory home */
+
+  int                 tp_refs;		/**< Number of references to tport */
+
+  unsigned            tp_black:1;       /**< Used by red-black-tree */
+  
+  unsigned            tp_accepted:1;    /**< Originally server? */
+  unsigned            tp_conn_orient:1;	/**< Is connection-oriented */
+  unsigned            tp_has_connection:1; /**< Has real connection */
+  unsigned            tp_reusable:1;    /**< Can this connection be reused */
+  unsigned            tp_closed : 1;    /**< This transport is closed */
+  /**< Remote end has sent FIN (2) or we should not just read */
+  unsigned            tp_recv_close:2;
+  /** We will send FIN (1) or have sent FIN (2) */
+  unsigned            tp_send_close:2; 
+  unsigned            tp_has_keepalive:1;
+  unsigned            tp_has_stun_server:1;
+  unsigned            tp_trunc:1;
+  unsigned            tp_is_connected:1; /**< Connection is established */
+  unsigned:0;
+
+  tport_t *tp_left, *tp_right, *tp_dad; /**< Links in tport tree */
+
+  tport_master_t     *tp_master;        /**< Master transport */
+  tport_primary_t    *tp_pri;           /**< Primary transport */
+
+  tport_params_t     *tp_params;        /**< Transport parameters */
+
+  tp_magic_t         *tp_magic; 	/**< Context provided by consumer */
+
+  msg_t const        *tp_rlogged;       /**< Last logged when receiving */
+  msg_t const        *tp_slogged;       /**< Last logged when sending */
+
+  unsigned            tp_time;	        /**< When this transport was last used */
+
+  tp_name_t           tp_name[1];	/**< Transport name.
+					 * 
+					 * This is either our name (if primary)
+					 * or peer name (if secondary).
+					 */
+
+#define tp_protoname tp_name->tpn_proto
+#define tp_canon     tp_name->tpn_canon
+#define tp_host      tp_name->tpn_host
+#define tp_port      tp_name->tpn_port
+#define tp_ident     tp_name->tpn_ident
+
+  su_socket_t  	      tp_socket;	/**< Socket of this tport*/
+  int                 tp_index;		/**< Root registration index */
+  int                 tp_events;        /**< Subscribed events */
+
+  su_addrinfo_t       tp_addrinfo[1];   /**< Peer/own address info */
+  su_sockaddr_t       tp_addr[1];	/**< Peer/own address */
+#define tp_addrlen tp_addrinfo->ai_addrlen
+
+  /* ==== Receive queue ================================================== */
+
+  msg_t   	     *tp_msg;		/**< Message being received */
+
+  /* ==== Pending messages =============================================== */
+
+  tport_pending_t    *tp_pending;       /**< Pending requests */
+  tport_pending_t    *tp_released;      /**< Released pends */
+  unsigned            tp_plen;          /**< Size of tp_pending */
+  unsigned            tp_pused;         /**< Used pends */
+  unsigned short      tp_reported;      /**< Report counter */
+  unsigned short      tp_pad;
+
+  /* ==== Send queue ===================================================== */
+
+  msg_t             **tp_queue;		/**< Messages being sent */
+  unsigned short      tp_qhead;		/**< Head of queue */
+
+  msg_iovec_t        *tp_unsent;	/**< Pointer to first unsent iovec */
+  size_t              tp_unsentlen;	/**< Number of unsent iovecs */
+
+  msg_iovec_t        *tp_iov;		/**< Iovecs allocated for sending */
+  size_t              tp_iovlen;	/**< Number of allocated iovecs */
+
+  /* ==== Extensions  ===================================================== */
+
+  tport_compressor_t *tp_comp;
+
+  /* ==== Statistics  ===================================================== */
+  
+  struct {
+    uint64_t sent_bytes, sent_on_line, recv_bytes, recv_on_line;
+    uint64_t sent_msgs, recv_msgs;
+  } tp_stats;
+};
+
+/** Primary structure */
+struct tport_primary {
+  tport_t             pri_primary[1];   /**< Transport part */
+#if DOXYGEN_ONLY
+  su_home_t           pri_home[1];
+#else
+#define pri_home      pri_primary->tp_home
+#define pri_master    pri_primary->tp_master
+#define pri_protoname pri_primary->tp_name->tpn_proto
+#endif
+  tport_vtable_t const
+                     *pri_vtable;
+  int                 pri_public;       /**< Type of primary transport; 
+					 * tport_type_local,
+					 * tport_type_stun, etc. 
+					 */
+
+  char                pri_ident[16];
+  tport_primary_t    *pri_next;	        /**< Next primary tport */
+
+  tport_t            *pri_secondary;	/**< Secondary tports */
+
+  unsigned            pri_updating:1;   /**< Currently updating address */
+  unsigned            pri_natted:1;	/**< Using natted address  */
+  unsigned            pri_has_tls:1;	/**< Supports tls  */
+  unsigned:0;
+
+  void               *pri_stun_handle;
+
+  tport_params_t      pri_params[1];      /**< Transport parameters */
+
+};
+
+/** Master structure */
+struct tport_master {
+  tport_t             mr_master[1];
+#if DOXYGEN_ONLY
+  su_home_t           mr_home[1];
+#else
+#define mr_home mr_master->tp_home
+#endif
+
+  int                 mr_stun_step_ready; /**< for stun's callback */
+
+  tp_stack_t  	     *mr_stack;         /**< Transport consumer */
+  tp_stack_class_t 
+               const *mr_tpac;		/**< Methods provided by stack */
+  int                 mr_log;	        /**< Do logging of parsed messages */
+  su_root_t    	     *mr_root;		/**< SU root pointer */
+
+  /**< Timer reclaiming unused connections and compartment */
+  su_timer_t         *mr_timer;		
+  /** File to dump received and sent data */
+  FILE               *mr_dump_file;	
+
+  tport_primary_t    *mr_primaries;        /**< List of primary contacts */
+
+  tport_params_t      mr_params[1];
+  
+  unsigned            mr_boundserver:1; /**< Server has been bound */
+  unsigned            mr_bindv6only:1; /**< We can bind separately to IPv6/4 */
+  unsigned :0;
+
+  /* Delivery context */
+  struct tport_delivery {
+    tport_t              *d_tport;
+    msg_t                *d_msg;
+    tp_name_t             d_from[1];
+    tport_compressor_t   *d_comp;
+  } mr_delivery[1];
+
+  tport_stun_server_t *mr_stun_server;
+
+#if 0
+  struct tport_nat_s {
+    int initialized;
+    int bound;
+    int stun_enabled;
+    char *external_ip_address;
+#if HAVE_UPNP || HAVE_SOFIA_STUN
+    int try_stun;
+#endif
+#if HAVE_UPNP
+#endif
+#if HAVE_SOFIA_STUN
+    tport_master_t *tport;
+    char *stun_server;
+    /* stun_socket_t *stun_socket; */
+    stun_handle_t *stun;
+    su_socket_t stun_socket;
+    su_sockaddr_t sockaddr;
+#endif
+  }                   mr_nat[1];
+#endif
+};
+
+/** Virtual funtion table for transports */
+struct tport_vtable
+{
+  char const *vtp_name;
+  enum tport_via vtp_public;
+
+  size_t vtp_pri_size;		/* Size of primary tport */
+  int (*vtp_init_primary)(tport_primary_t *pri,
+			  tp_name_t tpn[1],
+			  su_addrinfo_t *ai, tagi_t const *,
+			  char const **return_culprit);
+  void (*vtp_deinit_primary)(tport_primary_t *pri);
+  int (*vtp_wakeup_pri)(tport_primary_t *pri, int events);
+  tport_t *(*vtp_connect)(tport_primary_t *pri, su_addrinfo_t *ai, 
+			  tp_name_t const *tpn);
+
+  size_t vtp_secondary_size;	/* Size of secondary tport */
+
+  int (*vtp_init_secondary)(tport_t *, int socket, int accepted,
+			    char const **return_reason);
+  void (*vtp_deinit_secondary)(tport_t *);
+  void (*vtp_shutdown)(tport_t *, int how);
+  int (*vtp_set_events)(tport_t const *self);
+  int (*vtp_wakeup)(tport_t *self, int events);
+  int (*vtp_recv)(tport_t *self);
+  ssize_t (*vtp_send)(tport_t const *self, msg_t *msg,
+		      msg_iovec_t iov[], size_t iovused);
+  void (*vtp_deliver)(tport_t *self,  msg_t *msg, su_time_t now);
+  int (*vtp_prepare)(tport_t *self, msg_t *msg, 
+		     tp_name_t const *tpn, 
+		     struct sigcomp_compartment *cc,
+		     unsigned mtu);
+  int (*vtp_keepalive)(tport_t *self, su_addrinfo_t const *ai,
+		       tagi_t const *taglist);
+  int (*vtp_stun_response)(tport_t const *self,
+			   void *msg, size_t msglen,
+			   void *addr, socklen_t addrlen);
+};
+
+int tport_register_type(tport_vtable_t const *vtp);
+
+/** Test if transport is needs connect() before sending. */
+static inline int tport_is_connection_oriented(tport_t const *self)
+{
+  return self->tp_conn_orient;
+}
+
+/** Test if transport involves connection. @NEW_1_12_5 */
+static inline int tport_has_connection(tport_t const *self)
+{
+  return self->tp_has_connection;
+}
+
+void tport_has_been_updated(tport_t *tport);
+
+int tport_primary_compression(tport_primary_t *pri,
+			      char const *compression,
+			      tagi_t const *tl);
+
+void tport_set_tos(su_socket_t socket, su_addrinfo_t *ai, int tos);
+
+tport_t *tport_base_connect(tport_primary_t *pri, 
+			    su_addrinfo_t *ai,
+			    su_addrinfo_t *name,
+			    tp_name_t const *tpn);
+
+int tport_stream_init_primary(tport_primary_t *pri, 
+			      su_socket_t socket,
+			      tp_name_t tpn[1],
+			      su_addrinfo_t *ai,
+			      tagi_t const *tags,
+			      char const **return_reason);
+
+tport_t *tport_alloc_secondary(tport_primary_t *pri,
+			       int socket,
+			       int accepted,
+			       char const **return_reason);
+
+int tport_accept(tport_primary_t *pri, int events);
+void tport_zap_secondary(tport_t *self);
+
+int tport_bind_socket(int socket,
+		      su_addrinfo_t *ai,
+		      char const **return_culprit);
+void tport_close(tport_t *self);
+
+
+int tport_error_event(tport_t *self);
+void tport_recv_event(tport_t *self);
+void tport_send_event(tport_t *self);
+void tport_hup_event(tport_t *self);
+
+ssize_t tport_recv_iovec(tport_t const *self, 
+			 msg_t **mmsg,
+			 msg_iovec_t iovec[msg_n_fragments], size_t N, 
+			 int exact);
+
+msg_t *tport_msg_alloc(tport_t const *self, usize_t size);
+
+int tport_prepare_and_send(tport_t *self, msg_t *msg, 
+			   tp_name_t const *tpn, 
+			   struct sigcomp_compartment *cc,
+			   unsigned mtu);
+int tport_send_msg(tport_t *self, msg_t *msg, 
+		   tp_name_t const *tpn, 
+		   struct sigcomp_compartment *cc);
+
+void tport_deliver(tport_t *self, msg_t *msg, msg_t *next, 
+		   tport_compressor_t *comp,
+		   su_time_t now);
+void tport_base_deliver(tport_t *self, msg_t *msg, su_time_t now);
+
+int tport_recv_error_report(tport_t *self);
+void tport_error_report(tport_t *self, int errcode, 
+			su_sockaddr_t const *addr);
+
+void tport_open_log(tport_master_t *mr, tagi_t *tags);
+void tport_log_msg(tport_t *tp, msg_t *msg, char const *what, 
+		   char const *via, su_time_t now);
+void tport_dump_iovec(tport_t const *self, msg_t *msg, 
+		      size_t n, su_iovec_t const iov[], size_t iovused,
+		      char const *what, char const *how);
+
+extern tport_vtable_t const tport_udp_vtable;
+extern tport_vtable_t const tport_udp_client_vtable;
+
+int tport_udp_init_primary(tport_primary_t *, 
+			   tp_name_t tpn[1], 
+			   su_addrinfo_t *, 
+			   tagi_t const *,
+			   char const **return_culprit);
+void tport_udp_deinit_primary(tport_primary_t *);
+int tport_recv_dgram(tport_t *self);
+ssize_t tport_send_dgram(tport_t const *self, msg_t *msg,
+			 msg_iovec_t iov[], size_t iovused);
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1]);
+
+extern tport_vtable_t const tport_tcp_vtable;
+extern tport_vtable_t const tport_tcp_client_vtable;
+
+int tport_tcp_init_primary(tport_primary_t *, 
+ 			  tp_name_t  tpn[1], 
+ 			  su_addrinfo_t *, tagi_t const *,
+ 			  char const **return_culprit);
+int tport_tcp_init_client(tport_primary_t *, 
+ 			 tp_name_t tpn[1], 
+ 			 su_addrinfo_t *, tagi_t const *,
+ 			 char const **return_culprit);
+int tport_tcp_init_secondary(tport_t *self, int socket, int accepted,
+			     char const **return_reason);
+int tport_recv_stream(tport_t *self);
+ssize_t tport_send_stream(tport_t const *self, msg_t *msg,
+			  msg_iovec_t iov[], size_t iovused);
+
+extern tport_vtable_t const tport_sctp_vtable;
+extern tport_vtable_t const tport_sctp_client_vtable;
+extern tport_vtable_t const tport_tls_vtable;
+extern tport_vtable_t const tport_tls_client_vtable;
+extern tport_vtable_t const tport_stun_vtable;
+extern tport_vtable_t const tport_http_connect_vtable;
+extern tport_vtable_t const tport_threadpool_vtable;
+
+typedef struct tport_descriptor_s {
+  char const *tpd_name;
+  tport_vtable_t *tpd_vtable;
+  su_addrinfo_t *tpd_hints;
+  int tpd_is_client_only;
+} tport_descriptor_t;
+
+typedef int const *(tport_set_f)(tport_master_t *mr, 
+				 tp_name_t const *tpn,
+				 tagi_t const *taglist,
+				 tport_descriptor_t **return_set,
+				 int return_set_size);
+
+/* STUN plugin */
+
+int tport_init_stun_server(tport_master_t *mr, tagi_t const *tags);
+void tport_deinit_stun_server(tport_master_t *mr);
+int tport_recv_stun_dgram(tport_t const *self, msg_t **in_out_msg,
+			  su_sockaddr_t *from, socklen_t fromlen);
+
+int tport_stun_server_add_socket(tport_t *tp);
+int tport_stun_server_remove_socket(tport_t *tp);
+
+/* ---------------------------------------------------------------------- */
+/* Compressor plugin */
+extern tport_comp_vtable_t const *tport_comp_vtable;
+
+char const *tport_canonize_comp(char const *comp);
+
+int tport_init_compressor(tport_t *,
+			  char const *comp_name,
+			  tagi_t const *tags);
+void tport_deinit_compressor(tport_t *);
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+			       struct sigcomp_compartment *cc);
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self);
+
+void tport_sigcomp_accept_incomplete(tport_t *self, msg_t *msg);
+
+int tport_recv_comp_dgram(tport_t const *self,
+			  tport_compressor_t *sc,
+			  msg_t **in_out_msg,
+			  su_sockaddr_t *from,
+			  socklen_t fromlen);
+
+ssize_t tport_send_comp(tport_t const *self,
+		    msg_t *msg, 
+		    msg_iovec_t iov[], 
+		    size_t iovused,
+		    struct sigcomp_compartment *cc,
+		    tport_compressor_t *sc);
+
+SOFIA_END_DECLS
+
+#endif /* TPORT_INTERNAL_H */

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_logging.c Logging transported messages.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <sofia-sip/string0.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/**@var TPORT_LOG
+ *
+ * Environment variable determining if parsed message contents are logged.
+ *
+ * If the TPORT_LOG environment variable is set, the tport module logs the
+ * contents of parsed messages. This eases debugging the signaling greatly.
+ * 
+ * @sa TPORT_DUMP, TPORT_DEBUG, tport_log
+ */
+extern char const TPORT_LOG[];	/* dummy declaration for Doxygen */
+
+/**@var TPORT_DUMP
+ *
+ * Environment variable for transport data dump.
+ *
+ * The received and sent data is dumped to the file specified by TPORT_DUMP
+ * environment variable. This can be used to save message traces and help
+ * hairy debugging tasks.
+ * 
+ * @sa TPORT_LOG, TPORT_DEBUG, tport_log
+ */
+extern char const TPORT_DUMP[];	/* dummy declaration for Doxygen */
+
+/**@var TPORT_DEBUG
+ *
+ * Environment variable determining the debug log level for @b tport module.
+ *
+ * The TPORT_DEBUG environment variable is used to determine the debug logging
+ * level for @b tport module. The default level is 3.
+ * 
+ * @sa <su_debug.h>, tport_log, SOFIA_DEBUG
+ */
+extern char const TPORT_DEBUG[]; /* dummy declaration for Doxygen */
+
+/**Debug log for @b tport module. 
+ * 
+ * The tport_log is the log object used by @b tport module. The level of
+ * #tport_log is set using #TPORT_DEBUG environment variable.
+ */
+su_log_t tport_log[] = { 
+  SU_LOG_INIT("tport", "TPORT_DEBUG", SU_DEBUG)
+};
+
+
+/** Initialize logging. */
+void tport_open_log(tport_master_t *mr, tagi_t *tags)
+{
+  char const *log;
+  
+  mr->mr_log = 
+    getenv("MSG_STREAM_LOG") != NULL ||
+    getenv("TPORT_LOG") != NULL 
+    ? MSG_DO_EXTRACT_COPY : 0;
+    
+  if ((log = getenv("TPORT_DUMP")) || (log = getenv("MSG_DUMP"))) {
+    time_t now;
+
+    if (strcmp(log, "-")) 
+      mr->mr_dump_file = fopen(log, "ab"); /* XXX */
+    else
+      mr->mr_dump_file = stdout;
+
+    if (mr->mr_dump_file) {
+      time(&now);
+      fprintf(mr->mr_dump_file, "dump started at %s\n\n", ctime(&now));
+    }
+  }
+}
+
+/** Create log stamp */
+void tport_stamp(tport_t const *self, msg_t *msg, 
+		 char stamp[128], char const *what, 
+		 size_t n, char const *via,
+		 su_time_t now)
+{
+  char label[24] = "";
+  char *comp = "";
+  char name[SU_ADDRSIZE] = "";
+  su_sockaddr_t const *su = msg_addr(msg);
+  unsigned short second, minute, hour;
+
+  second = (unsigned short)(now.tv_sec % 60);
+  minute = (unsigned short)((now.tv_sec / 60) % 60);
+  hour = (unsigned short)((now.tv_sec / 3600) % 24);
+
+#if SU_HAVE_IN6
+  if (su->su_family == AF_INET6) {
+    if (su->su_sin6.sin6_flowinfo)
+      snprintf(label, sizeof(label), "/%u", ntohl(su->su_sin6.sin6_flowinfo));
+  }
+#endif
+
+  if (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED)
+    comp = ";comp=sigcomp";
+
+  inet_ntop(su->su_family, SU_ADDR(su), name, sizeof(name));
+
+  snprintf(stamp, 128,
+	   "%s "MOD_ZU" bytes %s %s/[%s]:%u%s%s at %02u:%02u:%02u.%06lu:\n",
+	   what, (size_t)n, via, self->tp_name->tpn_proto,
+	   name, ntohs(su->su_port), label[0] ? label : "", comp,
+	   hour, minute, second, now.tv_usec);
+}
+
+/** Dump the data from the iovec */
+void tport_dump_iovec(tport_t const *self, msg_t *msg, 
+		      size_t n, su_iovec_t const iov[], size_t iovused,
+		      char const *what, char const *how)
+{
+  tport_master_t *mr = self->tp_master;
+  char stamp[128];
+  size_t i;
+
+  if (!mr->mr_dump_file)
+    return;
+
+  tport_stamp(self, msg, stamp, what, n, how, su_now());
+  fputs(stamp, mr->mr_dump_file);
+
+  for (i = 0; i < iovused && n > 0; i++) {
+    size_t len = iov[i].mv_len;
+    if (len > n)
+      len = n;
+    if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != len)
+      break;
+    n -= len;
+  }
+
+  fputs("\v\n", mr->mr_dump_file);
+  fflush(mr->mr_dump_file);
+}
+
+/** Log the message. */
+void tport_log_msg(tport_t *self, msg_t *msg, 
+		   char const *what, char const *via,
+		   su_time_t now)
+{
+  char stamp[128];
+  msg_iovec_t iov[80];
+  size_t i, iovlen = msg_iovec(msg, iov, 80);
+  size_t linelen = 0, n, logged = 0, truncated = 0;
+  int skip_lf = 0;
+
+#define MSG_SEPARATOR \
+  "------------------------------------------------------------------------\n"
+#define MAX_LINELEN 2047
+
+  for (i = n = 0; i < iovlen && i < 80; i++)
+    n += iov[i].mv_len;
+
+  tport_stamp(self, msg, stamp, what, n, via, now);
+  su_log(stamp);
+  su_log("   " MSG_SEPARATOR);
+ 
+  for (i = 0; truncated == 0 && i < iovlen && i < 80; i++) {
+    char *s = iov[i].mv_base, *end = s + iov[i].mv_len;
+
+    if (skip_lf && s < end && s[0] == '\n') { s++; logged++; skip_lf = 0; }
+
+    while (s < end) {
+      if (s[0] == '\0') {
+	truncated = logged;
+	break;
+      }
+
+      n = strncspn(s, end - s, "\r\n");
+
+      if (linelen + n > MAX_LINELEN) {
+	n = MAX_LINELEN - n - linelen;
+	truncated = logged + n;
+      }
+
+      su_log("%s%.*s", linelen > n ? "" : "   ", (int)n, s);
+      s += n, linelen += n, logged += n;
+
+      if (truncated)
+	break;
+      if (s == end)
+	continue;
+
+      linelen = 0;
+      su_log("\n");
+
+      /* Skip eol */
+      if (s[0] == '\r') {
+	s++, logged++;
+	if (s == end) {
+	  skip_lf = 1;
+	  continue;
+	}
+      }
+      if (s[0] == '\n')
+	s++, logged++;
+    }
+  }
+
+  su_log("%s   " MSG_SEPARATOR, linelen > 0 ? "\n" : "");
+
+  if (!truncated && i == 80)
+    truncated = logged;
+
+  if (truncated)
+    su_log("   *** message truncated at "MOD_ZU" ***\n", truncated);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <openssl/rand.h>
+
+int main(int argc, char **argv)
+{
+  int nb;
+
+  if (argc != 2) {
+    printf("Usage: tport_rand <output seed file>\n");
+    exit(0);
+  }
+
+  printf("Please move mouse for until the application stops\n");
+
+  RAND_load_file("/dev/random", 1024);
+  RAND_write_file(argv[1]);
+
+  nb = RAND_load_file(argv[1], -1);
+
+  printf("Wrote %d bytes to the seed file\n", nb);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,885 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_sigcomp.c Transport using SigComp.
+ *
+ * Incomplete.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport.h"
+
+#include <sofia-sip/string0.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sigcomp.h>
+
+/* ---------------------------------------------------------------------- */
+/* SigComp */
+
+typedef struct tport_sigcomp_handler tport_sigcomp_handler_t;
+
+/** Per end-point SigComp data */
+struct tport_compressor {
+  struct sigcomp_state_handler *msc_state_handler;
+  struct sigcomp_compartment *msc_compartment;
+};
+
+/** Per-socket SigComp data */
+struct tport_comp {
+  struct sigcomp_udvm          *sc_udvm;
+  struct sigcomp_compartment   *sc_cc;
+  struct sigcomp_compressor    *sc_compressor;
+  struct sigcomp_buffer        *sc_output;
+  unsigned                      sc_compressed; 
+
+  struct sigcomp_buffer        *sc_input;
+  unsigned                      sc_copied;
+  
+  enum {
+    format_is_unknown,
+    format_is_sigcomp,
+    format_is_noncomp
+  } sc_infmt, sc_outfmt;
+};
+
+
+tport_compressor_t *vsc_master_init_sigcomp(tport_t *mr,
+					     char const *algorithm)
+{
+  tport_compressor_t *retval =  NLL;
+  stuct sigcomp_state_handler *sh = NULL;
+  struct sigcomp_algorithm *a = NULL;
+  struct sigcomp_compartment *cc = NULL;
+
+  if (algorithm == NULL)
+    algorithm = getenv("SIGCOMP_ALGORITHM");
+
+  retval = su_zalloc((su_home_t *)mr, sizeof *retval);
+  if (retval == NULL)
+    return retval;
+
+  sh = sigcomp_state_handler_create();
+
+  if (sh == NULL) {
+    SU_DEBUG_1(("tport: initializing SigComp state handler: %s\n", 
+		strerror(errno)));
+    vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
+    return retval;
+  }
+  retval->msc_state_handler = sh;
+
+  a = sigcomp_algorithm_by_name(algorithm);
+  cc = sigcomp_compartment_create(a, sh, 0, "", 0, NULL, 0);
+
+  if (cc == NULL) {
+    SU_DEBUG_1(("tport: initializing SigComp master compartment: %s\n", 
+		strerror(errno)));
+    vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
+    return retval;
+  }
+
+  self->msc_compartment = cc;
+
+  return retval;
+}
+
+  if (self->sa_compartment) {
+    agent_sigcomp_options(self, self->sa_compartment);
+    sigcomp_compartment_option(self->sa_compartment, "stateless");
+  }
+  else
+
+  if (mr->mr_compartment)
+    sigcomp_compartment_unref(mt->mr_compartment);
+  mr->mr_compartment = sigcomp_compartment_ref(cc);
+
+  return cc;
+}
+
+
+void vsc_master_deinit_sigcomp(tport_master_t *mr)
+{
+  tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
+
+  if (mr->mr_compartment)
+    sigcomp_compartment_unref(mr->mr_compartment), mr->mr_compartment = NULL;
+
+}
+
+char const *vsc_comp_name(tport_sigcomp_t const *master_sc,
+			  char const *proposed_name,
+			  tagi_t const *tags)
+{
+  if (master_sc == NULL ||
+      master_sc->sc_cc == NULL ||
+      compression == NULL || 
+      strcasecmp(compression, tport_sigcomp_name))
+    return NULL;
+
+  return tport_sigcomp_name;
+}
+
+/** Check if transport can receive compressed messages */
+int vsc_can_recv_sigcomp(tport_sigcomp_t const *sc)
+{
+  return sc && sc->sc_infmt != format_is_noncomp;
+}
+
+/** Check if transport can send compressed messages */
+int vsc_can_send_sigcomp(tport_sigcomp_t const *sc)
+{
+  return sc && sc->sc_outfmt != format_is_noncomp;
+}
+
+/** Set/reset compression */
+int vsc_set_compression(tport_t *self, 
+			tport_sigcomp_t *sc,
+			char const *comp)
+{
+  if (self == NULL)
+    ;
+  else if (comp == NULL) {
+    if (sc == NULL || sc->sc_outfmt != format_is_sigcomp) {
+      self->tp_name->tpn_comp = NULL;
+      return 0;
+    }
+  }
+  else {
+    comp = tport_canonize_comp(comp);
+
+    if (comp && sc && sc->sc_outfmt != format_is_noncomp) {
+      self->tp_name->tpn_comp = comp;
+      return 0;
+    }
+  }
+  
+  return -1;
+}
+
+
+/** Assign a SigComp compartment (to a possibly connected tport). */
+int tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *cc)
+{
+  if (tport_is_connection_oriented(self) && 
+      tport_is_secondary(self) &&
+      self->tp_socket != INVALID_SOCKET) {
+
+    if (self->tp_sigcomp->sc_cc) {
+      if (cc == self->tp_sigcomp->sc_cc)
+	return 0;
+
+      /* Remove old assignment */
+      sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
+    }
+    
+    self->tp_sigcomp->sc_cc = sigcomp_compartment_ref(cc);
+
+    return 0;
+  }
+
+  return su_seterrno(EINVAL);
+}
+
+
+void vsc_sigcomp_shutdown(tport_t *self, int how)
+{
+  if (self->tp_socket != -1)
+    shutdown(self->tp_socket, how - 1);
+
+  if (how >= 2 && self->tp_sigcomp->sc_cc) {
+    sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
+    self->tp_sigcomp->sc_cc = NULL;
+  }  
+}
+
+static int vsc_recv_sigcomp_r(tport_t*, msg_t**, struct sigcomp_udvm*, int);
+static struct sigcomp_compartment *vsc_primary_compartment(tport_master_t *);
+
+
+static int tport_sigcomp_init_secondary()
+{
+  if (accept) {
+    if (!pri->pri_primary->tp_name->tpn_comp)
+      self->tp_sigcomp->sc_infmt = format_is_noncomp;
+  }
+  else {
+    /* XXX - no tpn here */
+    if (tpn->tpn_comp == pri->pri_primary->tp_name->tpn_comp)
+      self->tp_name->tpn_comp = pri->pri_primary->tp_name->tpn_comp;
+    if (!pri->pri_primary->tp_name->tpn_comp)
+      self->tp_sigcomp->sc_infmt = format_is_noncomp;
+  }
+}
+
+static int tport_sigcomp_deinit_secondary(tport_t *self)
+{
+  if (self->tp_sigcomp) {
+    tport_sigcomp_t *sc = self->tp_sigcomp;
+
+    if (sc->sc_udvm)
+      sigcomp_udvm_free(sc->sc_udvm), sc->sc_udvm = NULL;
+    if (sc->sc_compressor)
+      sigcomp_compressor_free(sc->sc_compressor), sc->sc_compressor = NULL;
+  }
+}
+
+#if 0
+#if HAVE_SIGCOMP
+  if (tport_can_recv_sigcomp(self))
+    return tport_recv_sigcomp_stream(self);
+#endif
+#endif
+
+/** Try to receive stream data using SigComp. */
+static int tport_recv_sigcomp_stream(tport_t *self)
+{
+  struct sigcomp_udvm *udvm;
+  int retval;
+
+  SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+  /* Peek for first byte in stream,
+     determine if this is a compressed stream or not */
+  if (self->tp_sigcomp->sc_infmt == format_is_unknown) {
+    unsigned char sample;
+    int n;
+
+    n = recv(self->tp_socket, &sample, 1, MSG_PEEK);
+    if (n < 0)
+      return n;
+
+    if (n == 0) {
+      recv(self->tp_socket, &sample, 1, 0);
+      return 0;			/* E-o-S from first message */
+    }
+
+    if ((sample & 0xf8) != 0xf8) {
+      /* Not SigComp, receive as usual */
+      if (tport_is_primary(self)) {
+	SU_DEBUG_1(("%s(%p): receive semantics not implemented\n",
+		    __func__, self));
+	su_seterrno(EINVAL);		/* Internal error */
+	return -1;
+      }
+
+      /* Do not try to receive with sigcomp from this socket */
+      self->tp_sigcomp->sc_infmt = format_is_noncomp;
+
+      return tport_recv_stream(self);
+    }
+
+    /* SigComp, receive using UDVM */
+    self->tp_sigcomp->sc_infmt = format_is_sigcomp;
+
+    /* Initialize UDVM */
+    self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
+    if (!self->tp_sigcomp->sc_udvm) {
+      int save = su_errno();
+      recv(self->tp_socket, &sample, 1, 0); /* remove msg from socket */
+      return su_seterrno(save);
+    }
+  }
+
+  udvm = self->tp_sigcomp->sc_udvm; assert(udvm);
+
+  retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
+
+  if (retval < 0)
+    sigcomp_udvm_reject(udvm);
+
+  return retval;
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream
+ * @retval 1  normal receive
+ * @retval 2  incomplete recv, recv again
+ */
+static int tport_recv_sigcomp_r(tport_t *self,
+				msg_t **mmsg,
+				struct sigcomp_udvm *udvm,
+				int N)
+{
+  msg_t *msg;
+  size_t n, m, i;
+  int eos, complete;
+  ssize_t veclen;
+  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+  su_sockaddr_t su[1];
+  socklen_t su_size = sizeof(su);
+  struct sigcomp_buffer *input, *output;
+  void *data;
+  size_t dlen;
+
+  SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+  assert(udvm);
+
+  if (sigcomp_udvm_has_input(udvm)) {
+    input = sigcomp_udvm_input_buffer(udvm, n = N = 0); assert(input);
+  }
+  else {
+    if (N == 0) {
+      assert(self->tp_addrinfo->ai_socktype != SOCK_DGRAM);
+      if (self->tp_addrinfo->ai_socktype == SOCK_DGRAM) {
+	recv(self->tp_socket, (void *)su, 1, 0);
+	return 1;
+      }
+    }
+
+    input = sigcomp_udvm_input_buffer(udvm, N); assert(input);
+    if (input == NULL)
+      return su_seterrno(EIO);
+
+    data = input->b_data + input->b_avail;
+    dlen = input->b_size - input->b_avail;
+    
+    if (tport_is_stream(self)) {
+      n = recv(self->tp_socket, data, dlen, 0);
+    } 
+    else if (dlen >= N) {
+      n = recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
+      SU_CANONIZE_SOCKADDR(su);
+    } 
+    else {
+      recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
+      SU_CANONIZE_SOCKADDR(su);
+      su_seterrno(EMSGSIZE);		/* Protocol error */
+      return -1;
+    }
+  
+    if (n == (unsigned)-1) {
+      char const *pn = self->tp_protoname;
+      int err = su_errno();
+    
+      if (su_is_blocking(err)) {
+	SU_DEBUG_7(("%s(%p): recv from %s: EAGAIN\n", __func__, self, pn));
+	return 1;
+      }
+    
+      SU_DEBUG_1(("%s(%p): recv from %s: %s (%d)\n", __func__, self, pn,
+		  su_strerror(err), err));
+      return -1;
+    }
+  
+    /* XXX - in case of stream, use message buffers for output? */
+    
+    input->b_avail += n;
+    input->b_complete = (n == 0) || !tport_is_stream(self);
+  }
+
+  for (complete = eos = 0; !complete;) {
+    output = sigcomp_udvm_output_buffer(udvm, 16384);
+    
+    if (sigcomp_udvm_decompress(udvm, output, input) < 0) {
+      int error = sigcomp_udvm_errno(udvm);
+      
+      SU_DEBUG_3(("%s: UDVM error %d: %s\n", __func__,
+		  error, sigcomp_udvm_strerror(udvm)));
+      
+      su_seterrno(EREMOTEIO);
+
+      return -1;
+    }
+
+    data = output->b_data + output->b_used;
+    dlen = output->b_avail - output->b_used;
+    complete = output->b_complete;
+    eos = complete && input->b_complete;
+
+    veclen = tport_recv_iovec(self, mmsg, iovec, dlen, eos);
+    
+    if (dlen ? veclen <= 0 : veclen < 0) {
+      return -1;
+    }
+
+    for (i = 0, n = 0; i < veclen; i++) {
+      m = iovec[i].mv_len; assert(dlen >= n + m);
+      memcpy(iovec[i].mv_base, data + n, m);
+      n += m;
+    }
+    assert(dlen == n);
+
+    msg = *mmsg;
+    
+    if (msg) {
+      /* Message address */
+      if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
+	msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+      else
+	msg_set_address(msg, su, su_size);
+      
+      SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self, 
+		  N, dlen, eos ? " (complete)" : ""));
+
+      msg_mark_as_compressed(msg);
+      
+      /* Write the received data to the message dump file */
+      if (self->tp_master->mr_dump_file && !self->tp_pri->pri_threadpool)
+	tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+      
+      msg_recv_commit(msg, dlen, eos);    /* Mark buffer as used */
+    }
+    else {
+      SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self, 
+		  N, dlen, eos ? " (complete)" : ""));
+      if (complete || !tport_is_stream(self)) {
+	sigcomp_udvm_reject(udvm); /* Reject empty message */
+      }
+    }
+
+    if (self->tp_addrinfo->ai_socktype == SOCK_STREAM) {
+      if (eos)
+	return 0;
+    
+      if (output->b_complete)
+	return n < N || sigcomp_udvm_has_pending_data(udvm) ? 2 : 1;
+
+      if (!sigcomp_udvm_has_input(udvm))
+	return 1;
+    }
+  }
+
+  return eos ? 0 : 2;
+}
+
+static
+int vsc_send_sigcomp(tport_t const *self,
+		     msg_t *msg, 
+		     msg_iovec_t iov[], 
+		     int iovused,
+		     struct sigcomp_compartment *cc,
+		     tport_sigcomp_t *sc)
+{
+  struct sigcomp_compressor *c = sc->sc_compressor;
+  struct sigcomp_buffer *input = sc->sc_input;
+  struct sigcomp_buffer *output = sc->sc_output;
+  msg_iovec_t ciov[1];
+
+  int i, n, m, k, stream = tport_is_stream(self);
+  char const *ccname;
+  int ccnamelen;
+
+  su_addrinfo_t *ai = msg_addrinfo(msg);
+
+  int compress = (cc || (cc = sc->sc_cc)) && ai->ai_flags & TP_AI_COMPRESSED;
+
+  if (!compress) {
+    if (stream)
+      sc->sc_outfmt = format_is_noncomp;
+    ai->ai_flags &= ~TP_AI_COMPRESSED;
+    return self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused, NULL);
+  }
+
+  if (stream)
+    sc->sc_outfmt = format_is_sigcomp;
+
+  assert(cc);
+  
+  if (c == NULL) {
+    assert(input == NULL);
+    if (stream)
+      c = sigcomp_compressor_create_for_stream(cc);
+    else
+      c = sigcomp_compressor_create(cc);
+    sc->sc_compressor = c;
+  } 
+
+  ccname = sigcomp_compartment_name(cc, &ccnamelen);
+
+  if (sc->sc_compressed != 0) {
+    input = NONE;
+  }
+  else if (input == NULL) {
+    int input_size = -1;
+
+    if (tport_is_udp(self)) {
+      input_size = 0;
+
+      for (i = 0; i < iovused; i++)
+	input_size += iov[i].siv_len;
+    }
+
+    sc->sc_input = input = sigcomp_compressor_input_buffer(c, input_size);
+
+    assert(input->b_avail == 0 && input->b_used == 0);
+  } 
+  else if (!input->b_complete) {
+    int input_size = 0;
+
+    for (i = 0; i < iovused; i++)
+      input_size += iov[i].siv_len;
+
+    if (input_size > input->b_size - input->b_avail)
+      sigcomp_buffer_align_available(input, 0);
+  }
+
+  if (output == NULL)
+    sc->sc_output = output = sigcomp_compressor_output_buffer(c, NULL);
+    
+  if (!c || !input || !output) {
+    SU_DEBUG_3(("%s(%p): %s (%u)%s%s%s\n", 
+		__func__, self, strerror(errno), errno,
+		c ? "" : " (comp)",
+		input ? "" : " (input)",
+		output ? "" : " (output)"));
+    sigcomp_compressor_free(c);
+    sc->sc_compressor = NULL; 
+    sc->sc_output = NULL; sc->sc_input = NULL;
+    sc->sc_compressed = 0; sc->sc_copied = 0;
+    return -1;
+  }
+
+  if (sc->sc_compressed == 0) {
+    k = sc->sc_copied;
+
+    if (!input->b_complete) {
+      int m = sc->sc_copied;
+
+      for (i = 0, n = 0; i < iovused; i++) {
+	char *b = iov[i].siv_base;
+	int l = iov[i].siv_len;
+
+	if (m >= l) {
+	  m -= l;
+	  continue;
+	}
+
+	b += m; l -= m;
+
+	if (input->b_size == input->b_avail)
+	  break;
+
+	if (l > input->b_size - input->b_avail)
+	  l = input->b_size - input->b_avail;
+
+	memcpy(input->b_data + input->b_avail, b, l);
+	input->b_avail += l; n += l; sc->sc_copied += l;
+
+	if (l != iov[i].siv_len)
+	  break;
+      }
+      input->b_complete = i == iovused;
+      assert(stream || input->b_complete); (void)stream;
+    }
+    
+    m = output->b_avail - output->b_used;
+
+    n = sigcomp_compressor_compress(c, output, input);
+    
+    if (n < 0) {
+      SU_DEBUG_3(("%s(%p): %s (%u)\n", __func__, self,
+		  sigcomp_compressor_strerror(c), 
+		  sigcomp_compressor_errno(c)));
+      sigcomp_compressor_free(c);
+      sc->sc_compressor = NULL; 
+      sc->sc_output = NULL; sc->sc_input = NULL;
+      sc->sc_compressed = 0;
+      return -1;
+    }
+
+    assert(input->b_complete || sc->sc_copied - k > 0);
+
+    SU_DEBUG_5(("%s: input %u (%u new) compressed %u to %u with '%.*s'\n", 
+		__func__, sc->sc_copied, k, n, 
+		(output->b_avail - output->b_used) - m, 
+		ccnamelen, ccname));
+
+    sc->sc_compressed = n;
+
+    assert(stream || output->b_complete);
+  } 
+  else {
+    assert(tport_is_connection_oriented(self));
+    n = sc->sc_compressed;
+  }
+
+  assert(input && cc && c && output);
+
+  ciov->siv_base = output->b_data + output->b_used;
+  ciov->siv_len = output->b_avail - output->b_used;
+
+  m = self->tp_pri->pri_vtable->vtp_send(self, msg, ciov, 1);
+  
+  if (m == -1) {
+    int error = su_errno();
+
+    if (su_is_blocking(error)) {
+      sigcomp_compressor_free(c);
+      sc->sc_compressor = NULL;
+      sc->sc_output = NULL; sc->sc_input = NULL;
+      sc->sc_compressed = 0; sc->sc_copied = 0;
+      su_seterrno(error);
+    }
+
+    return -1;
+  }
+  
+  output->b_used += m;
+  
+  if (output->b_used < output->b_avail)
+    return 0;
+
+  if (output->b_complete) {
+    sigcomp_compressor_accept(c, cc), sc->sc_output = output = NULL;
+  }
+
+  if (input != NONE && input->b_avail == input->b_used && input->b_complete)
+    sigcomp_buffer_reset(input, -1), sc->sc_input = input = NULL;
+
+  if (!input && !output) {
+    sigcomp_compressor_free(c);
+    sc->sc_compressor = NULL;
+  }
+
+  assert(sc->sc_compressed >= n); assert(sc->sc_copied >= n); 
+
+  sc->sc_compressed -= n;
+  sc->sc_copied -= n;
+
+  return n;
+}
+
+/** Initialize UDVM */
+static 
+struct sigcomp_udvm *tport_init_udvm(tport_t *self)
+{
+  struct sigcomp_compartment *cc;
+  struct sigcomp_udvm *udvm;
+
+  if (self->tp_sigcomp->sc_udvm)
+    return self->tp_sigcomp->sc_udvm;
+
+  cc = tport_primary_compartment(self->tp_master);
+
+  if (!cc)
+    return NULL;
+
+  if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
+    udvm = sigcomp_udvm_create_for_stream(cc);
+  else
+    udvm = sigcomp_udvm_create_for_compartment(cc);
+
+  return udvm;
+}
+
+
+/** Get primary compartment */
+static 
+struct sigcomp_compartment *
+tport_primary_compartment(tport_master_t *mr)
+{
+  return mr->mr_compartment;
+}
+
+/** Test if tport has a SigComp compartment is assigned to it. */
+int vsc_has_sigcomp_assigned(tport_sigcomp_t const *sc)
+{
+  return sc && sc->sc_udvm != NULL;
+}
+
+static
+void vsc_try_accept_sigcomp(tport_t *self, msg_t *msg)
+{
+  struct sigcomp_udvm *udvm;
+
+  udvm = self->tp_sigcomp->sc_udvm;
+  if (udvm && sigcomp_udvm_is_complete(udvm)) {
+    if (self->tp_master->mr_tpac->tpac_sigcomp_accept && 
+	self->tp_sigcomp->sc_cc == NULL) {
+      tport_t *ref;
+      struct tport_delivery *d;
+
+      d = self->tp_master->mr_delivery;
+
+      d->d_tport = self; 
+      d->d_msg = msg;
+      d->d_udvm = &self->tp_sigcomp->sc_udvm;
+      *d->d_from = *self->tp_name;
+
+      ref = tport_incref(self);
+      STACK_SIGCOMP_ACCEPT(self, msg);
+      /* Reject by default */
+      if (self->tp_sigcomp->sc_udvm)
+	sigcomp_udvm_accept(self->tp_sigcomp->sc_udvm, NULL);
+      tport_decref(&ref);
+
+      d->d_msg = NULL;
+    }
+    else {
+      if (tport_log->log_level >= 5) {
+	char const *name; 
+	int namelen;
+      
+	name = sigcomp_compartment_name(self->tp_sigcomp->sc_cc, &namelen);
+	SU_DEBUG_5(("tport(%p): msg %p SigComp implicit accept '%.*s'\n", 
+		    self, msg, namelen, name));
+      }
+      sigcomp_udvm_accept(udvm, self->tp_sigcomp->sc_cc);
+    }
+  }
+}
+
+
+/** Accept a SigComp message */
+int 
+tport_sigcomp_accept(tport_t *self, 
+		     struct sigcomp_compartment *cc, 
+		     msg_t *msg)
+{
+  struct sigcomp_udvm *udvm;
+
+  if (self == NULL || msg != self->tp_master->mr_delivery->d_msg)
+    return su_seterrno(EINVAL);
+
+  if (!self->tp_master->mr_delivery->d_udvm || cc == NONE)
+    return 0;
+
+  udvm = *self->tp_master->mr_delivery->d_udvm;
+
+  if (udvm) {
+    if (tport_log->log_level >= 5) {
+      char const *name; 
+      int namelen;
+   
+      if (cc) {
+	name = sigcomp_compartment_name(cc, &namelen);
+	SU_DEBUG_5(("tport(%p): msg %p SigComp accept '%.*s'\n", 
+		    self, msg, namelen, name));
+      }
+      else {
+	SU_DEBUG_5(("tport(%p): msg %p SigComp reject\n", self, msg));
+      }
+    }
+    sigcomp_udvm_accept(udvm, cc);
+  }
+
+  self->tp_master->mr_delivery->d_udvm = NULL;
+
+  return 0;
+}
+
+
+/** Pass message to the protocol stack */
+void
+tport_sigcomp_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+  /* XXX - no d */
+
+  STACK_RECV(self, msg, now);
+
+  if (d->d_udvm && *d->d_udvm)
+    sigcomp_udvm_accept(*d->d_udvm, NULL); /* reject */
+}
+
+
+#if HAVE_SIGCOMP && 0
+
+static inline
+int msg_is_compressed(msg_t *msg)
+{
+  return msg && 
+    (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED) == TP_AI_COMPRESSED;
+}
+
+static inline
+void msg_mark_as_compressed(msg_t *msg)
+{
+  if (msg)
+    msg_addrinfo(msg)->ai_flags |= TP_AI_COMPRESSED;
+}
+
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self)
+{
+  tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
+
+  if (vsc)
+
+#if HAVE_SIGCOMP
+  return &self->tp_sigcomp->sc_udvm;
+#else
+  return NULL;
+#endif
+}
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+			       struct sigcomp_compartment *cc)
+{
+  if (self->tp_name->tpn_comp) {
+    if (cc)
+      tport_sigcomp_assign(self, cc);
+    else if (self->tp_sigcomp->sc_cc)
+      cc = self->tp_sigcomp->sc_cc;
+    else
+      /* Use default compartment */
+      cc = self->tp_master->mr_compartment;
+  }
+  else 
+    cc = NULL;
+  
+  return cc;
+}			   
+
+/** Receive data from datagram using SigComp. */
+int tport_recv_sigcomp_dgram(tport_t *self, int N)
+{
+  char dummy[1];
+  int error = EBADMSG;
+#if HAVE_SIGCOMP
+  struct sigcomp_udvm *udvm;
+
+  if (self->tp_sigcomp->sc_udvm == 0)
+    self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
+
+  udvm = self->tp_sigcomp->sc_udvm;
+
+  if (udvm) {
+    retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
+    if (retval < 0)
+      sigcomp_udvm_reject(udvm);
+    return retval;
+  }
+  error = su_errno();
+#endif
+  recv(self->tp_socket, dummy, 1, 0); /* remove msg from socket */
+  /* XXX - send NACK ? */
+  return su_seterrno(error);     
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_stub_sigcomp.c Stub interface for SigComp
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:31:36 EEST 2006
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+tport_comp_vtable_t const *tport_comp_vtable = NULL;
+
+int tport_plug_in_compress(tport_comp_vtable_t const *vsc)
+{
+  return -1;
+}
+
+char const tport_sigcomp_name[] = "sigcomp";
+
+/** Canonize compression string */
+char const *tport_canonize_comp(char const *comp)
+{
+  if (tport_comp_vtable && comp && strcasecmp(comp, tport_sigcomp_name) == 0)
+    return tport_sigcomp_name;
+  return NULL;
+}
+
+int tport_init_compressor(tport_t *tp,
+			  char const *comp_name,
+			  tagi_t const *tags)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+  tport_master_t *mr = tp ? tp->tp_master : NULL;
+  tport_compressor_t *tcc;
+
+  if (vsc == NULL)
+    return -1;
+  if (mr == NULL)
+    return -1;
+
+  if (tp->tp_comp)
+    return 0;
+
+  comp_name = tport_canonize_comp(comp_name);
+  if (comp_name == NULL)
+    return 0;
+
+  tcc = su_zalloc(tp->tp_home, vsc->vsc_sizeof_context);
+
+  if (tcc == NULL)
+    return -1;
+
+  if (vsc->vsc_init_comp(mr->mr_stack, tp, tcc, comp_name, tags) < 0) {
+    vsc->vsc_deinit_comp(mr->mr_stack, tp, tcc);
+    return -1;
+  }
+
+  tp->tp_comp = tcc;
+
+  return 0;
+}
+
+void tport_deinit_compressor(tport_t *tp)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+  tport_master_t *mr = tp ? tp->tp_master : NULL;
+
+  if (vsc && mr && tp->tp_comp) {
+    vsc->vsc_deinit_comp(mr->mr_stack, tp, tp->tp_comp);
+    su_free(tp->tp_home, tp->tp_comp), tp->tp_comp = NULL;
+  }
+}
+
+
+char const *tport_comp_name(tport_primary_t *pri,
+			    char const *name,
+			    tagi_t const *tags)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+  tport_compressor_t const *comp = pri->pri_master->mr_master->tp_comp;
+
+  if (vsc)
+    return vsc->vsc_comp_name(comp, name, tags);
+
+  return NULL;
+}
+
+
+/** Check if transport can receive compressed messages */
+int tport_can_recv_sigcomp(tport_t const *self)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    return vsc->vsc_can_recv_comp(self->tp_comp);
+
+  return 0;
+}
+
+/** Check if transport can send compressed messages */
+int tport_can_send_sigcomp(tport_t const *self)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    return vsc->vsc_can_send_comp(self->tp_comp);
+
+  return 0;
+}
+
+/** Check if transport supports named compression */
+int tport_has_compression(tport_t const *self, char const *comp)
+{
+  return
+    self && comp && 
+    self->tp_name->tpn_comp == tport_canonize_comp(comp);
+}
+
+int tport_set_compression(tport_t *self, char const *comp)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    return vsc->vsc_set_comp_name(self, self->tp_comp, comp);
+
+  return (self == NULL || comp) ? -1 : 0;
+}
+
+/** Set options to SigComp */
+int tport_sigcomp_option(tport_t const *self,
+			 struct sigcomp_compartment *cc,
+			 char const *option)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    return vsc->vsc_sigcomp_option(self, cc, option);
+
+  return -1;
+}
+
+
+/** Assign a SigComp compartment (to a possibly connected tport). 
+ *
+ * @related tport_s
+ */
+int tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *cc)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (!vsc)
+    return 0;
+
+  if (tport_is_connection_oriented(self) && 
+      tport_is_secondary(self) &&
+      self->tp_socket != INVALID_SOCKET) {
+    return vsc->vsc_set_compartment(self, self->tp_comp, cc);
+  }
+
+  return 0;
+}
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+			       struct sigcomp_compartment *cc)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (!vsc)
+    return NULL;
+
+  if (!self->tp_name->tpn_comp)
+    return NULL;
+
+  if (cc) {
+    tport_sigcomp_assign(self, cc);
+    return cc;
+  }
+
+  return vsc->vsc_get_compartment(self, self->tp_comp);
+}			   
+
+
+/** Test if tport has a SigComp compartment assigned to it. */
+int tport_has_sigcomp_assigned(tport_t const *self)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc && self)
+    return vsc->vsc_has_sigcomp_assigned(self->tp_comp);
+    
+  return 0;
+}
+
+int 
+tport_sigcomp_accept(tport_t *self, 
+		     struct sigcomp_compartment *cc, 
+		     msg_t *msg)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (self == NULL)
+    return su_seterrno(EFAULT);
+
+  if (vsc)
+    return vsc->vsc_sigcomp_accept(self, self->tp_comp, cc, msg);
+
+  return 0;
+}
+
+/* Internal API */
+
+/** This function is called when the application message is still incomplete
+    but a complete SigComp message could have been received */
+void tport_sigcomp_accept_incomplete(tport_t *self, msg_t *msg)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc && self->tp_comp)
+    vsc->vsc_accept_incomplete(self, self->tp_comp, msg);
+}
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc && self)
+    return vsc->vsc_get_udvm_slot(self);
+
+  return NULL;
+}
+
+/** Receive data from datagram using SigComp. */
+int tport_recv_comp_dgram(tport_t const *self, 
+			  tport_compressor_t *sc,
+			  msg_t **in_out_msg,
+			  su_sockaddr_t *from,
+			  socklen_t fromlen)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    return vsc->vsc_recv_comp(self, sc, in_out_msg, from, fromlen);
+
+  msg_destroy(*in_out_msg), *in_out_msg = NULL;
+
+  return su_seterrno(EBADMSG);     
+}
+
+
+ssize_t tport_send_comp(tport_t const *self,
+			msg_t *msg, 
+			msg_iovec_t iov[], 
+			size_t iovused,
+			struct sigcomp_compartment *cc,
+			tport_compressor_t *comp)
+{
+  tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+  if (vsc)
+    vsc->vsc_send_comp(self, msg, iov, iovused, cc, comp);
+
+  msg_addrinfo(msg)->ai_flags &= ~TP_AI_COMPRESSED;
+  return self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_stub_stun.c Stub interface for STUN
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:31:36 EEST 2006
+ */
+
+#include "config.h"
+
+#include <sofia-sip/stun.h>
+#include <sofia-sip/su_tagarg.h>
+
+#define TPORT_STUN_SERVER_T stun_mini_t
+#include "tport_internal.h"
+#include "sofia-sip/msg_buffer.h"
+#include "sofia-sip/msg_addr.h"
+
+#include <assert.h>
+
+/* ---------------------------------------------------------------------- */
+/* Plugin pointer */
+
+tport_stun_server_vtable_t const *tport_stun_server_vtable = NULL;
+
+
+static
+tport_stun_server_t *vst_create(su_root_t *root, tagi_t const *tags)
+{
+  return stun_mini_create();
+}
+
+static
+tport_stun_server_vtable_t const stun_mini_vtable = 
+  {
+    sizeof stun_mini_vtable,
+    vst_create, 
+    stun_mini_destroy,
+    stun_mini_add_socket, 
+    stun_mini_remove_socket, 
+    stun_mini_request
+  };
+
+/** Initialize stun server */
+int tport_init_stun_server(tport_master_t *mr, tagi_t const *tags)
+{
+  tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+
+  if (vst == NULL)
+    /* Nobody has plugged better server in, use miniserver */
+    tport_stun_server_vtable = vst = &stun_mini_vtable;
+
+  if (!vst)
+    return 0;
+
+  if (mr->mr_params->tpp_stun_server)
+    mr->mr_stun_server = vst->vst_create(mr->mr_root, tags);
+  mr->mr_master->tp_has_stun_server = mr->mr_stun_server != NULL;
+  return 0;
+}
+
+/** Deinit stun server */
+void tport_deinit_stun_server(tport_master_t *mr)
+{
+  tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+
+  if (mr->mr_stun_server) {
+    assert(vst);
+    vst->vst_destroy(mr->mr_stun_server), mr->mr_stun_server = NULL;
+  }
+}
+
+int tport_stun_server_add_socket(tport_t *tp)
+{
+  tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
+
+  if (tport_stun_server_vtable && 
+      stun_server &&
+      tp->tp_params->tpp_stun_server) {
+    if (tport_stun_server_vtable->vst_add_socket(stun_server, 
+						 tp->tp_socket) == 0)
+      tp->tp_has_stun_server = 1;
+  }
+  return 0;
+}
+
+int tport_stun_server_remove_socket(tport_t *tp)
+{
+  tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
+
+  if (tport_stun_server_vtable &&
+      stun_server &&
+      tp->tp_has_stun_server) {
+    tport_stun_server_vtable->vst_remove_socket(stun_server, tp->tp_socket);
+    tp->tp_has_stun_server = 0;
+  }
+  return 0;
+}
+
+/**Process stun messagee.
+ *
+ * @retval -1 error
+ * @retval 3  stun message received, ignore  
+ */
+int tport_recv_stun_dgram(tport_t const *self,
+			  msg_t **in_out_msg,
+			  su_sockaddr_t *from,
+			  socklen_t fromlen)
+{
+  int retval = -1;
+  msg_t *msg;
+  uint8_t *request;
+  size_t n;
+
+  assert(in_out_msg); assert(*in_out_msg);
+
+  msg = *in_out_msg;
+
+  request = msg_buf_committed_data(msg);
+  n = msg_buf_committed(msg);
+
+  if (n < 20 || request == NULL) {
+    su_seterrno(EBADMSG);
+    retval = -1;
+  }
+  else if (request[0] == 1) {
+    /* This is a response. */
+    if (self->tp_pri->pri_vtable->vtp_stun_response) {
+      if (self->tp_pri->pri_vtable->vtp_stun_response(self, request, n, 
+						      from, fromlen) < 0)
+	retval = -1;
+    }
+    else
+      SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
+		  "ignoring request with "MOD_ZU" bytes\n", self, n));
+  }
+  else if (request[0] == 0 && self->tp_master->mr_stun_server) {
+    tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+    vst->vst_request(self->tp_master->mr_stun_server,
+		     self->tp_socket, request, n, 
+		     (void *)from, fromlen);
+  }
+  else if (request[0] == 0) {
+    /* Respond to stun request with a simple error message. */
+    int const status = 600;
+    char const *error = "Not Implemented";
+    size_t unpadded = strlen(error);
+    uint16_t elen;
+    uint8_t dgram[128];
+
+    if (unpadded > sizeof(dgram) - 28)
+      unpadded = sizeof(dgram) - 28;
+
+    elen = (uint16_t)unpadded;
+    elen = (elen + 3) & -4;	/* Round up to 4 */
+
+    SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
+		"responding %u %s\n", self, status, error));
+  /*
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      STUN Message Type        |         Message Length        |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                             Transaction ID
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                                                    |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    */
+
+#define set16(b, offset, value)			\
+  (((b)[(offset) + 0] = ((value) >> 8) & 255),	\
+   ((b)[(offset) + 1] = (value) & 255))
+
+    /* Respond to request */
+    dgram[0] = 1; /* Mark as response */
+    dgram[1] = request[1] | 0x10; /* Mark as error response */
+    set16(dgram, 2, elen + 4 + 4);
+
+    /* TransactionID is there at bytes 4..19 */
+    memcpy(dgram + 4, request + 4, 16);
+
+    /*
+    TLV At 20:
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |         Type                  |            Length             |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    */
+    set16(dgram, 20, 0x0009); /* ERROR-CODE */
+    set16(dgram, 22, elen + 4);
+    /*
+    ERROR-CODE at 24:
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                   0                     |Class|     Number    |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      Reason Phrase (variable)                                ..
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     */
+    dgram[24] = 0, dgram[25] = 0;
+    dgram[26] = status / 100, dgram[27] = status % 100;
+    memcpy(dgram + 28, error, unpadded);
+    memset(dgram + 28 + unpadded, 0, elen - unpadded);
+
+    sendto(self->tp_socket, (void *)dgram, 28 + elen, 0,
+	   (void *)from, fromlen);
+#undef set16
+  }
+  else {
+    SU_DEBUG_0(("tport(%p): recv_stun_dgram(): internal error\n", self));
+    su_seterrno(EBADMSG);
+    retval = -1;
+  }
+
+  *in_out_msg = NULL, msg_destroy(msg);
+
+  return retval;
+}
+
+
+/** Activate (STUN) keepalive for transport */
+int tport_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+		    tag_type_t tag, tag_value_t value, ...)
+{
+  if (tp && tp->tp_pri && tp->tp_pri->pri_vtable->vtp_keepalive) {
+    int retval;
+    ta_list ta;
+    ta_start(ta, tag, value);
+    retval = tp->tp_pri->pri_vtable->vtp_keepalive(tp, ai, ta_args(ta));
+    ta_end(ta);
+    return retval;
+  }
+  return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Plugin interface */
+
+/** Plug in stun server.
+ *
+ * @note This function @b must be called before any transport is initialized.
+ */
+int tport_plug_in_stun_server(tport_stun_server_vtable_t const *vtable)
+{
+  if (!vtable)
+    return 0;
+
+  if (vtable->vst_size <= (int)sizeof *vtable)
+    return su_seterrno(EINVAL);
+
+  if (!vtable->vst_create || 
+      !vtable->vst_destroy ||
+      !vtable->vst_add_socket ||
+      !vtable->vst_remove_socket ||
+      !vtable->vst_request)
+    return su_seterrno(EFAULT);
+
+  if (tport_stun_server_vtable)
+    return su_seterrno(EEXIST);
+
+  tport_stun_server_vtable = vtable;
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_tag.c
+ * @brief Tags for transport module
+ *
+ * @note This file is used to automatically generate 
+ * tport_tag_ref.c and tport_tag_dll.c
+ *
+ * Copyright (c) 2002 Nokia Research Center.  All rights reserved.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun  6 00:38:07 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "tp"
+
+#include "sofia-sip/tport.h"
+#include <sofia-sip/su_tag_class.h>
+
+/* ==== Globals ========================================================== */
+
+/** Filter for tport tags. */
+tagi_t tport_tags[] = { { tptag_any, 0 }, { TAG_END() } };
+
+tag_typedef_t tptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t tptag_ident = CSTRTAG_TYPEDEF(ident);
+tag_typedef_t tptag_reuse = BOOLTAG_TYPEDEF(reuse);
+tag_typedef_t tptag_fresh = BOOLTAG_TYPEDEF(fresh);
+tag_typedef_t tptag_server = BOOLTAG_TYPEDEF(server);
+tag_typedef_t tptag_public = INTTAG_TYPEDEF(public);
+tag_typedef_t tptag_mtu = USIZETAG_TYPEDEF(mtu);
+tag_typedef_t tptag_connect = BOOLTAG_TYPEDEF(connect);
+tag_typedef_t tptag_sdwn_error = BOOLTAG_TYPEDEF(sdwn_error);
+tag_typedef_t tptag_sdwn_after = BOOLTAG_TYPEDEF(sdwn_after);
+tag_typedef_t tptag_close_after = BOOLTAG_TYPEDEF(sdwn_after);
+tag_typedef_t tptag_idle = UINTTAG_TYPEDEF(idle);
+tag_typedef_t tptag_timeout = UINTTAG_TYPEDEF(timeout);
+tag_typedef_t tptag_sigcomp_lifetime = UINTTAG_TYPEDEF(sigcomp_lifetime);
+tag_typedef_t tptag_certificate = STRTAG_TYPEDEF(certificate);
+tag_typedef_t tptag_compartment = PTRTAG_TYPEDEF(compartment);
+
+tag_typedef_t tptag_tls_version = UINTTAG_TYPEDEF(tls_version);
+tag_typedef_t tptag_queuesize = UINTTAG_TYPEDEF(queuesize);
+tag_typedef_t tptag_debug_drop = UINTTAG_TYPEDEF(debug_drop);
+tag_typedef_t tptag_udp_rmem = UINTTAG_TYPEDEF(udp_rmem);
+tag_typedef_t tptag_udp_wmem = UINTTAG_TYPEDEF(udp_wmem);
+tag_typedef_t tptag_thrpsize = UINTTAG_TYPEDEF(thrpsize);
+tag_typedef_t tptag_thrprqsize = UINTTAG_TYPEDEF(thrprqsize);
+tag_typedef_t tptag_http_connect = STRTAG_TYPEDEF(http_connect);
+tag_typedef_t tptag_stun_server = BOOLTAG_TYPEDEF(stun_server);
+tag_typedef_t tptag_tos = INTTAG_TYPEDEF(tos);

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,812 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_threadpool.c Multithreading transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#undef HAVE_SIGCOMP 
+
+#define SU_ROOT_MAGIC_T         struct tport_threadpool
+#define SU_WAKEUP_ARG_T         struct tport_s
+#define SU_MSG_ARG_T            union tport_su_msg_arg
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "tport_threadpool";
+#endif
+
+/* ==== Thread pools =================================================== */
+
+typedef struct threadpool threadpool_t;
+
+typedef struct {
+  tport_primary_t tptp_primary;
+  threadpool_t   *tptp_pool;   /**< Worker threads */
+  unsigned        tptp_poolsize;
+} tport_threadpool_t;
+
+struct threadpool
+{
+  /* Shared */
+  su_clone_r thrp_clone;
+  tport_threadpool_t *thrp_tport;
+
+  int        thrp_killing; /* Threadpool is being killed */
+
+  /* Private variables */
+  su_root_t    *thrp_root;
+  int           thrp_reg;
+  struct sigcomp_compartment *thrp_compartment;
+  su_msg_r   thrp_rmsg;
+
+  /* Slave thread counters */
+  int        thrp_r_sent;
+  int        thrp_s_recv;
+
+  unsigned   thrp_rcvd_msgs;
+  unsigned   thrp_rcvd_bytes;
+
+  /* Master thread counters */
+  int        thrp_s_sent;
+  int        thrp_r_recv;
+
+  int        thrp_yield;
+};
+
+typedef struct 
+{
+  threadpool_t *tpd_thrp;
+  int  tpd_errorcode;
+  msg_t *tpd_msg;
+  su_time_t tpd_when;
+  unsigned tpd_mtu;
+#if HAVE_SIGCOMP
+  struct sigcomp_compartment *tpd_cc;
+#endif
+  struct sigcomp_udvm *tpd_udvm;
+  socklen_t tpd_namelen;
+  su_sockaddr_t tpd_name[1];
+} thrp_udp_deliver_t;
+
+union tport_su_msg_arg
+{
+  threadpool_t   *thrp;
+  thrp_udp_deliver_t thrp_udp_deliver[1];
+};
+
+int tport_threadpool_init_primary(tport_primary_t *, 
+				  tp_name_t tpn[1], 
+				  su_addrinfo_t *, 
+				  tagi_t const *,
+				  char const **return_culprit);
+static void tport_threadpool_deinit_primary(tport_primary_t *pri);
+
+static int tport_thread_send(tport_t *tp,
+			     msg_t *msg,
+			     tp_name_t const *tpn, 
+			     struct sigcomp_compartment *cc,
+			     unsigned mtu);
+
+tport_vtable_t const tport_threadpool_vtable =
+{
+  "udp", tport_type_local,
+  sizeof (tport_threadpool_t),
+  tport_threadpool_init_primary,
+  tport_threadpool_deinit_primary,
+  NULL,
+  NULL,
+  0,				/* No secondary transports! */
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_dgram,
+  tport_send_dgram,
+  NULL,
+  tport_thread_send
+};
+
+static int thrp_udp_init(su_root_t *, threadpool_t *);
+static void thrp_udp_deinit(su_root_t *, threadpool_t *);
+static int thrp_udp_event(threadpool_t *thrp, 
+			    su_wait_t *w, 
+			    tport_t *_tp);
+static int thrp_udp_recv_deliver(threadpool_t *thrp, 
+				 tport_t const *tp, 
+				 thrp_udp_deliver_t *tpd,
+				 int events);
+static int thrp_udp_recv(threadpool_t *thrp, thrp_udp_deliver_t *tpd);
+#if HAVE_SIGCOMP
+static int thrp_udvm_decompress(threadpool_t *thrp, 
+				thrp_udp_deliver_t *tpd);
+#endif
+static void thrp_udp_deliver(threadpool_t *thrp,
+			     su_msg_r msg,
+			     union tport_su_msg_arg *arg);
+static void thrp_udp_deliver_report(threadpool_t *thrp,
+				    su_msg_r m,
+				    union tport_su_msg_arg *arg);
+static void thrp_udp_send(threadpool_t *thrp,
+			  su_msg_r msg,
+			  union tport_su_msg_arg *arg);
+static void thrp_udp_send_report(threadpool_t *thrp,
+				 su_msg_r msg,
+				 union tport_su_msg_arg *arg);
+
+
+/** Launch threads in the tport pool. */
+int tport_threadpool_init_primary(tport_primary_t *pri, 
+				  tp_name_t tpn[1], 
+				  su_addrinfo_t *ai,
+				  tagi_t const *tags,
+				  char const **return_culprit)
+{
+  tport_threadpool_t *tptp = (tport_threadpool_t *)pri;
+  tport_t *tp = pri->pri_primary;
+  threadpool_t *thrp;
+  int i, N = tp->tp_params->tpp_thrpsize;
+
+  assert(ai->ai_socktype == SOCK_DGRAM);
+
+  if (tport_udp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+    return -1;
+
+  if (N == 0)
+    return 0;
+
+  thrp = su_zalloc(tp->tp_home, (sizeof *thrp) * N);
+  if (!thrp)
+    return -1;
+
+  su_setblocking(tp->tp_socket, 0);
+
+  tptp->tptp_pool = thrp;
+  tptp->tptp_poolsize = N;
+
+  for (i = 0; i < N; i++) {
+#if HAVE_SIGCOMP
+    if (tport_has_sigcomp(tp))
+      thrp[i].thrp_compartment = tport_primary_compartment(tp->tp_master);
+#endif
+    thrp[i].thrp_tport = tptp;
+    if (su_clone_start(pri->pri_master->mr_root, 
+		       thrp[i].thrp_clone,
+		       thrp + i,
+		       thrp_udp_init,
+		       thrp_udp_deinit) < 0)
+      goto error;
+  }
+
+  tp->tp_events = 0;
+  
+  return 0;
+
+ error:
+  assert(!"tport_launch_threadpool");
+  return -1;
+}
+
+/** Kill threads in the tport pool.
+ *
+ * @note Executed by stack thread only.
+ */
+static 
+void tport_threadpool_deinit_primary(tport_primary_t *pri)
+{
+  tport_threadpool_t *tptp = (tport_threadpool_t *)pri;
+  threadpool_t *thrp = tptp->tptp_pool;
+  int i, N = pri->tptp_poolsize;
+
+  if (!thrp)
+    return;
+
+  /* Prevent application from using these. */
+  for (i = 0; i < N; i++)
+    thrp[i].thrp_killing = 1;
+
+  /* Stop every task in the threadpool. */
+  for (i = 0; i < N; i++) 
+    su_clone_wait(pri->pri_master->mr_root, thrp[i].thrp_clone);
+
+  su_free(pri->pri_home, tptp), tptp->tptp_pool = NULL;
+  tptp->tptp_poolsize = 0;
+
+  SU_DEBUG_3(("%s(%p): zapped threadpool\n", __func__, pri));
+}
+
+static int thrp_udp_init(su_root_t *root, threadpool_t *thrp)
+{
+  tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+  su_wait_t wait[1];
+
+  assert(tp);
+
+  thrp->thrp_root = root;
+
+  if (su_wait_create(wait, tp->tp_socket, SU_WAIT_IN | SU_WAIT_ERR) < 0)
+    return -1;
+
+  thrp->thrp_reg = su_root_register(root, wait, thrp_udp_event, tp, 0);
+
+  if (thrp->thrp_reg  == -1)
+    return -1;
+
+  return 0;
+}
+
+static void thrp_udp_deinit(su_root_t *root, threadpool_t *thrp)
+{
+  if (thrp->thrp_reg)
+    su_root_deregister(root, thrp->thrp_reg), thrp->thrp_reg = 0;
+  su_msg_destroy(thrp->thrp_rmsg);
+}
+
+static inline void
+thrp_yield(threadpool_t *thrp)
+{
+  tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+  su_root_eventmask(thrp->thrp_root, thrp->thrp_reg, tp->tp_socket, 0);
+  thrp->thrp_yield = 1;
+}
+
+static inline void
+thrp_gain(threadpool_t *thrp)
+{
+  tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+  int events = SU_WAIT_IN | SU_WAIT_ERR;
+  su_root_eventmask(thrp->thrp_root, thrp->thrp_reg, tp->tp_socket, events);
+  thrp->thrp_yield = 0;
+}
+
+static int thrp_udp_event(threadpool_t *thrp, 
+			  su_wait_t *w, 
+			  tport_t *tp)
+{
+#if HAVE_POLL
+  assert(w->fd == tp->tp_socket);
+#endif
+
+  for (;;) {
+    thrp_udp_deliver_t *tpd;
+    int events;
+
+    if (!*thrp->thrp_rmsg) {
+      if (su_msg_create(thrp->thrp_rmsg,
+			su_root_parent(thrp->thrp_root),
+			su_root_task(thrp->thrp_root),
+			thrp_udp_deliver,
+			sizeof (*tpd)) == -1) {
+	SU_DEBUG_1(("thrp_udp_event(%p): su_msg_create(): %s\n", thrp, 
+		    strerror(errno)));
+	return 0;
+      }
+    }
+
+    tpd = su_msg_data(thrp->thrp_rmsg)->thrp_udp_deliver; assert(tpd);
+    tpd->tpd_thrp = thrp;
+
+    events = su_wait_events(w, tp->tp_socket);
+    if (!events)
+      return 0;
+
+    thrp_udp_recv_deliver(thrp, tp, tpd, events);
+
+    if (*thrp->thrp_rmsg) {
+      SU_DEBUG_7(("thrp_udp_event(%p): no msg sent\n", thrp));
+      tpd = su_msg_data(thrp->thrp_rmsg)->thrp_udp_deliver;
+      memset(tpd, 0, sizeof *tpd);
+      return 0;
+    } 
+
+    if (thrp->thrp_yield || (thrp->thrp_s_sent - thrp->thrp_s_recv) > 0)
+      return 0;
+
+    su_wait(w, 1, 0);
+  }
+}
+
+static int thrp_udp_recv_deliver(threadpool_t *thrp, 
+				 tport_t const *tp, 
+				 thrp_udp_deliver_t *tpd,
+				 int events)
+{
+  unsigned qlen = thrp->thrp_r_sent - thrp->thrp_r_recv;
+
+  SU_DEBUG_7(("thrp_udp_event(%p): events%s%s%s%s for %p\n", thrp,
+	      events & SU_WAIT_IN ? " IN" : "",
+	      events & SU_WAIT_HUP ? " HUP" : "",
+	      events & SU_WAIT_OUT ? " OUT" : "",
+	      events & SU_WAIT_ERR ? " ERR" : "",
+	      tpd));
+
+  if (events & SU_WAIT_ERR) {
+    tpd->tpd_errorcode = tport_udp_error(tp, tpd->tpd_name);
+    if (tpd->tpd_errorcode) {
+      if (thrp->thrp_yield)
+	su_msg_report(thrp->thrp_rmsg, thrp_udp_deliver_report);
+      tpd->tpd_when = su_now();
+      su_msg_send(thrp->thrp_rmsg);
+      thrp->thrp_r_sent++;
+      return 0;
+    }
+  }
+
+  if (events & SU_WAIT_IN) {
+    if (thrp_udp_recv(thrp, tpd) < 0) {
+      tpd->tpd_errorcode = su_errno();
+      assert(tpd->tpd_errorcode);
+      if (su_is_blocking(tpd->tpd_errorcode))
+	return 0;
+    } 
+    else if (tpd->tpd_msg) {
+      int n = msg_extract(tpd->tpd_msg); (void)n;
+      
+      thrp->thrp_rcvd_msgs++;
+      thrp->thrp_rcvd_bytes += msg_size(tpd->tpd_msg);
+    }
+
+#if HAVE_SIGCOMP
+    if (tpd->tpd_udvm && !tpd->tpd_msg)
+      sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+#endif
+
+    assert(!tpd->tpd_msg || !tpd->tpd_errorcode);
+
+    if (tpd->tpd_msg || tpd->tpd_errorcode) {
+      if (qlen >= tp->tp_params->tpp_thrprqsize) {
+	SU_DEBUG_7(("tport recv queue %i: %u\n", 
+		    (int)(thrp - tp->tp_pri->tptp_pool), qlen));
+	thrp_yield(thrp);
+      }
+
+      if (qlen >= tp->tp_params->tpp_thrprqsize / 2)
+	su_msg_report(thrp->thrp_rmsg, thrp_udp_deliver_report);
+      tpd->tpd_when = su_now();
+      su_msg_send(thrp->thrp_rmsg);
+      thrp->thrp_r_sent++;
+      return 0;
+    }
+  }
+
+  return 0;
+}
+
+#include <pthread.h>
+
+/** Mutex for reading from socket */
+static pthread_mutex_t mutex[1] = { PTHREAD_MUTEX_INITIALIZER };
+
+/** Receive a UDP packet by threadpool. */
+static
+int thrp_udp_recv(threadpool_t *thrp, thrp_udp_deliver_t *tpd)
+{
+  tport_t const *tp = thrp->thrp_tport->pri_primary;
+  unsigned char sample[2];
+  int N;
+  int s = tp->tp_socket;
+
+  pthread_mutex_lock(mutex);
+
+  /* Simulate packet loss */
+  if (tp->tp_params->tpp_drop && 
+      su_randint(0, 1000) < tp->tp_params->tpp_drop) {
+    recv(s, sample, 1, 0);
+    pthread_mutex_unlock(mutex);
+    SU_DEBUG_3(("tport(%p): simulated packet loss!\n", tp));
+    return 0;
+  }
+
+  /* Peek for first two bytes in message:
+     determine if this is stun, sigcomp or sip
+  */
+  N = recv(s, sample, sizeof sample, MSG_PEEK | MSG_TRUNC);
+
+  if (N < 0) {
+    if (su_is_blocking(su_errno()))
+      N = 0;
+  }
+  else if (N <= 1) {
+    SU_DEBUG_1(("%s(%p): runt of %u bytes\n", "thrp_udp_recv", thrp, N));
+    recv(s, sample, sizeof sample, 0);
+    N = 0;
+  }
+#if !HAVE_MSG_TRUNC
+  else if ((N = su_getmsgsize(tp->tp_socket)) < 0)
+    ;
+#endif
+  else if ((sample[0] & 0xf8) == 0xf8) {
+#if HAVE_SIGCOMP
+    if (thrp->thrp_compartment) {
+      struct sigcomp_buffer *input;
+      void *data;
+      int dlen;
+
+      tpd->tpd_udvm = 
+	sigcomp_udvm_create_for_compartment(thrp->thrp_compartment);
+      input = sigcomp_udvm_input_buffer(tpd->tpd_udvm, N); assert(input);
+
+      data = input->b_data + input->b_avail;
+      dlen = input->b_size - input->b_avail;
+
+      if (dlen < N)
+	dlen = 0;
+
+      tpd->tpd_namelen = sizeof(tpd->tpd_name);
+    
+      dlen = recvfrom(tp->tp_socket, data, dlen, 0, 
+		      &tpd->tpd_name->su_sa, &tpd->tpd_namelen);
+
+      SU_CANONIZE_SOCKADDR(tpd->tpd_name);
+      
+      if (dlen < N) {
+	su_seterrno(EMSGSIZE);		/* Protocol error */
+	N = -1;
+      } else if (dlen == -1) 
+	N = -1;
+      else {
+	input->b_avail += dlen; 
+	input->b_complete = 1;
+	
+	pthread_mutex_unlock(mutex);
+      
+	N = thrp_udvm_decompress(thrp, tpd);
+
+	if (N == -1)
+	  /* Do not report decompression errors as ICMP errors */
+	  memset(tpd->tpd_name, 0, tpd->tpd_namelen);
+
+	return N;
+      }
+      pthread_mutex_unlock(mutex);
+      return N;
+    }
+#endif
+    recv(s, sample, 1, 0);
+    pthread_mutex_unlock(mutex);
+    /* XXX - send NACK ? */
+    su_seterrno(EBADMSG);
+    N = -1;
+  }
+  else {
+    /* receive as usual */
+    N = tport_recv_dgram_r(tp, &tpd->tpd_msg, N);
+  } 
+  
+  pthread_mutex_unlock(mutex);
+
+  return N;
+}
+
+#if HAVE_SIGCOMP
+static
+int thrp_udvm_decompress(threadpool_t *thrp, thrp_udp_deliver_t *tpd)
+{
+  struct sigcomp_udvm *udvm = tpd->tpd_udvm;
+  struct sigcomp_buffer *output;
+  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+  su_addrinfo_t *ai;
+  tport_t *tp = thrp->thrp_tport->pri_primary;
+  size_t n, m, i, dlen;
+  int eos;
+  void *data;
+  ssize_t veclen;
+
+  output = sigcomp_udvm_output_buffer(udvm, -1);
+  
+  if (sigcomp_udvm_decompress(udvm, output, NULL) < 0) {
+    int error = sigcomp_udvm_errno(udvm);
+    SU_DEBUG_3(("%s: UDVM error %d: %s\n", __func__,
+		error, sigcomp_udvm_strerror(udvm)));
+    su_seterrno(EREMOTEIO);
+    return -1;
+  } 
+
+  data = output->b_data + output->b_used;
+  dlen = output->b_avail - output->b_used;
+  /* XXX - if a message is larger than default output size... */
+  eos = output->b_complete; assert(output->b_complete);
+    
+  veclen = tport_recv_iovec(tp, &tpd->tpd_msg, iovec, dlen, eos);
+    
+  if (veclen <= 0) {
+    n = -1;
+  } else {
+    for (i = 0, n = 0; i < veclen; i++) {
+      m = iovec[i].mv_len; assert(dlen >= n + m);
+      memcpy(iovec[i].mv_base, data + n, m);
+      n += m;
+    }
+    assert(dlen == n);
+
+    msg_recv_commit(tpd->tpd_msg, dlen, eos);    /* Mark buffer as used */
+    
+    /* Message address */
+    ai = msg_addrinfo(tpd->tpd_msg);
+    ai->ai_flags |= TP_AI_COMPRESSED;
+    ai->ai_family = tpd->tpd_name->su_sa.sa_family;
+    ai->ai_socktype = SOCK_DGRAM;
+    ai->ai_protocol = IPPROTO_UDP;
+    memcpy(ai->ai_addr, tpd->tpd_name, ai->ai_addrlen = tpd->tpd_namelen);
+
+    SU_DEBUG_9(("%s(%p): sigcomp msg sz = %d\n", __func__, tp, n));
+  }
+
+  return n;
+}
+#endif
+
+/** Deliver message from threadpool to the stack
+ *
+ * @note Executed by stack thread only.
+ */
+static 
+void thrp_udp_deliver(su_root_magic_t *magic,
+		      su_msg_r m,
+		      union tport_su_msg_arg *arg)
+{
+  thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+  threadpool_t *thrp = tpd->tpd_thrp;
+  tport_t *tp = thrp->thrp_tport->pri_primary;
+  su_time_t now = su_now();
+
+  assert(magic != thrp);
+
+  thrp->thrp_r_recv++;
+
+  if (thrp->thrp_killing) {
+#if HAVE_SIGCOMP
+    sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+#endif
+    msg_destroy(tpd->tpd_msg);
+    return;
+  }
+
+  SU_DEBUG_7(("thrp_udp_deliver(%p): got %p delay %f\n", 
+	      thrp, tpd, 1000 * su_time_diff(now, tpd->tpd_when)));
+
+  if (tpd->tpd_errorcode)
+    tport_error_report(tp, tpd->tpd_errorcode, tpd->tpd_name);
+  else if (tpd->tpd_msg) {
+    tport_deliver(tp, tpd->tpd_msg, NULL, &tpd->tpd_udvm, tpd->tpd_when);
+    tp->tp_rlogged = NULL;
+  }
+
+#if HAVE_SIGCOMP 
+  if (tpd->tpd_udvm) {
+    sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+  }
+#endif
+}
+
+static 
+void thrp_udp_deliver_report(threadpool_t *thrp,
+			     su_msg_r m,
+			     union tport_su_msg_arg *arg)
+{
+  if (thrp->thrp_yield) {
+    int qlen = thrp->thrp_r_sent - thrp->thrp_r_recv;
+    int qsize = thrp->thrp_tport->pri_params->tpp_thrprqsize;
+    if (qlen == 0 || qlen < qsize / 2)
+      thrp_gain(thrp);
+  }
+}
+
+/** Send a message to network using threadpool.
+ *
+ * @note Executed by stack thread only.
+ */
+static
+int tport_thread_send(tport_t *tp,
+		      msg_t *msg,
+		      tp_name_t const *tpn, 
+		      struct sigcomp_compartment *cc,
+		      unsigned mtu)
+{
+  
+  threadpool_t *thrp = tp->tp_pri->tptp_pool;
+  thrp_udp_deliver_t *tpd;
+  int i, N = tp->tp_pri->tptp_poolsize;
+  su_msg_r m;
+  unsigned totalqlen = 0;
+  unsigned qlen;
+
+  if (!tp->tp_pri->tptp_pool)
+    return tport_prepare_and_send(tp, msg, tpn, cc, mtu);
+
+  SU_DEBUG_9(("tport_thread_send()\n"));
+
+  if (thrp->thrp_killing)
+    return (su_seterrno(ECHILD)), -1;
+
+  qlen = totalqlen = thrp->thrp_s_sent - thrp->thrp_s_recv;
+
+  /* Select thread with shortest queue */ 
+  for (i = 1; i < N; i++) {
+    threadpool_t *other = tp->tp_pri->tptp_pool + i;
+    unsigned len = other->thrp_s_sent - other->thrp_s_recv;
+
+    if (len < qlen || 
+	(len == qlen && (other->thrp_s_sent - thrp->thrp_s_sent) < 0))
+      thrp = other, qlen = len;
+
+    totalqlen += len;
+  }
+
+  if (totalqlen >= N * tp->tp_params->tpp_qsize)
+    SU_DEBUG_3(("tport send queue: %u (shortest %u)\n", totalqlen, qlen));
+
+  if (su_msg_create(m,
+		    su_clone_task(thrp->thrp_clone),
+		    su_root_task(tp->tp_master->mr_root),
+		    thrp_udp_send,
+		    sizeof (*tpd)) != su_success) {
+    SU_DEBUG_1(("thrp_udp_event(%p): su_msg_create(): %s\n", thrp, 
+		strerror(errno)));
+    return -1;
+  }
+
+  tpd = su_msg_data(m)->thrp_udp_deliver;
+  tpd->tpd_thrp = thrp;
+  tpd->tpd_when = su_now();
+  tpd->tpd_mtu = mtu;
+  tpd->tpd_msg = msg_ref_create(msg);
+
+#if HAVE_SIGCOMP
+  tpd->tpd_cc = cc;
+#endif
+
+  su_msg_report(m, thrp_udp_send_report);
+
+  if (su_msg_send(m) == su_success) {
+    thrp->thrp_s_sent++;
+    return 0;
+  }
+
+  msg_ref_destroy(msg);
+  return -1;
+}
+
+/** thrp_udp_send() is run by threadpool to send the message. */
+static 
+void thrp_udp_send(threadpool_t *thrp,
+		   su_msg_r m,
+		   union tport_su_msg_arg *arg)
+{
+  thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+  tport_t *tp = thrp->thrp_tport->pri_primary;
+  msg_t *msg = tpd->tpd_msg;
+  msg_iovec_t *iov, auto_iov[40], *iov0 = NULL;
+  int iovlen, iovused, n;
+
+  assert(thrp == tpd->tpd_thrp);
+
+  thrp->thrp_s_recv++;
+
+  { 
+    double delay = 1000 * su_time_diff(su_now(), tpd->tpd_when);
+    if (delay > 100)
+      SU_DEBUG_3(("thrp_udp_deliver(%p): got %p delay %f\n", thrp, tpd, delay));
+    else
+      SU_DEBUG_7(("thrp_udp_deliver(%p): got %p delay %f\n", thrp, tpd, delay));
+  }
+
+  if (!msg) {
+    tpd->tpd_errorcode = EINVAL;
+    return;
+  }
+
+  /* Prepare message for sending - i.e., encode it */
+  if (msg_prepare(msg) < 0) {
+    tpd->tpd_errorcode = errno;
+    return;
+  }
+
+  if (tpd->tpd_mtu != 0 && msg_size(msg) > tpd->tpd_mtu) {
+    tpd->tpd_errorcode = EMSGSIZE;
+    return;
+  }
+
+  /* Use initially the I/O vector from stack */
+  iov = auto_iov, iovlen = sizeof(auto_iov)/sizeof(auto_iov[0]);
+
+  /* Get a iovec for message contents */
+  for (;;) {
+    iovused = msg_iovec(msg, iov, iovlen);
+    if (iovused <= iovlen) 
+      break;
+
+    iov = iov0 = realloc(iov0, sizeof(*iov) * iovused);
+    iovlen = iovused;
+
+    if (iov0 == NULL) {
+      tpd->tpd_errorcode = errno;
+      return;
+    }
+  }
+
+  assert(iovused > 0);
+
+  tpd->tpd_when = su_now();
+
+  if (0)
+    ;
+#if HAVE_SIGCOMP
+  else if (tpd->tpd_cc) {
+    tport_sigcomp_t sc[1] = {{ NULL }};
+
+    n = tport_sigcomp_vsend(tp, msg, iov, iovused, tpd->tpd_cc, sc);
+  } 
+#endif
+  else 
+    n = tport_send_dgram(tp, msg, iov, iovused);
+
+  if (n == -1)
+    tpd->tpd_errorcode = su_errno();
+
+  if (iov0)
+    free(iov0);
+}
+
+static 
+void thrp_udp_send_report(su_root_magic_t *magic,
+			  su_msg_r msg,
+			  union tport_su_msg_arg *arg)
+{
+  thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+  threadpool_t *thrp = tpd->tpd_thrp;
+  tport_t *tp = thrp->thrp_tport->pri_primary;
+
+  assert(magic != thrp);
+
+  SU_DEBUG_7(("thrp_udp_send_report(%p): got %p delay %f\n", 
+	      thrp, tpd, 1000 * su_time_diff(su_now(), tpd->tpd_when)));
+
+  if (tp->tp_master->mr_log)
+    tport_log_msg(tp, tpd->tpd_msg, "sent", "to", tpd->tpd_when);
+
+  if (tpd->tpd_errorcode)
+    tport_error_report(tp, tpd->tpd_errorcode, msg_addr(tpd->tpd_msg));
+
+  msg_ref_destroy(tpd->tpd_msg);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,763 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_tls.c
+ * @brief TLS interface
+ * 
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>
+ * @author Pekka Pessi <ext-Pekka.Pessi at nokia.com>
+ *
+ * Copyright 2001, 2002 Nokia Research Center.  All rights reserved.
+ *
+ */
+
+#include "config.h"
+
+#define OPENSSL_NO_KRB5 oh-no
+
+#include <openssl/lhash.h>
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/bio.h>
+#include <openssl/opensslv.h>
+
+#include <sofia-sip/su_types.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_wait.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "tport_tls.h"
+
+char const tls_version[] = OPENSSL_VERSION_TEXT;
+
+enum  { tls_master, tls_slave };
+
+struct tls_s {
+  SSL_CTX *ctx;
+  SSL *con;
+  BIO *bio_con;
+  BIO *bio_err;
+  int type;
+  int verified;
+
+  /* Receiving */
+  int read_events;
+  void *read_buffer;
+  size_t read_buffer_len;
+
+  /* Sending */
+  int   write_events;
+  void *write_buffer;
+  size_t write_buffer_len;
+
+  /* Host names */
+  char *hosts[TLS_MAX_HOSTS + 1];
+};
+
+enum { tls_buffer_size = 16384 };
+
+static
+tls_t *tls_create(int type)
+{
+  tls_t *tls = calloc(1, sizeof(*tls));
+
+  if (tls)
+    tls->type = type;
+
+  return tls;
+}
+
+static
+void tls_set_default(tls_issues_t *i)
+{
+  i->verify_depth = i->verify_depth == 0 ? 2 : i->verify_depth;
+  i->cert = i->cert ? i->cert : "agent.pem";
+  i->key = i->key ? i->key : i->cert;
+  i->randFile = i->randFile ? i->randFile : "tls_seed.dat";
+  i->CAfile = i->CAfile ? i->CAfile : "cafile.pem";
+  i->cipher = i->cipher ? i->cipher : "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
+  /* Default SIP cipher */
+  /* "RSA-WITH-AES-128-CBC-SHA"; */
+  /* RFC-2543-compatibility ciphersuite */
+  /* TLS_RSA_WITH_3DES_EDE_CBC_SHA; */
+}
+
+static
+int tls_verify_cb(int ok, X509_STORE_CTX *store)
+{
+  char data[256];
+
+  X509 *cert = X509_STORE_CTX_get_current_cert(store);
+  int  depth = X509_STORE_CTX_get_error_depth(store);
+  int  err = X509_STORE_CTX_get_error(store);
+
+#if nomore 
+  509_NAME_oneline(X509_get_subject_name(cert), data, 256);
+  fprintf(stderr,"depth=%d %s\n",depth,data);
+#endif
+
+  if (!ok)
+  {
+    fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
+    X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
+    fprintf(stderr, "  issuer   = %s\n", data);
+    X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
+    fprintf(stderr, "  subject  = %s\n", data);
+    fprintf(stderr, "  err %i:%s\n", err, X509_verify_cert_error_string(err));
+  }
+ 
+  return 1;			/* Always return "ok" */
+}
+
+static
+int tls_init_context(tls_t *tls, tls_issues_t const *ti)
+{
+  static int initialized = 0;
+
+  if (!initialized) {
+    initialized = 1;
+    SSL_library_init();
+    SSL_load_error_strings();
+
+    if (ti->randFile &&
+	!RAND_load_file(ti->randFile, 1024 * 1024)) {
+      if (ti->configured > 1) {
+	BIO_printf(tls->bio_err, "%s: cannot open randFile %s\n", 
+		   "tls_init_context", ti->randFile);
+	ERR_print_errors(tls->bio_err);
+      }
+      /* errno = EIO; */
+      /* return -1; */
+    }
+  }
+
+  /* Avoid possible SIGPIPE when sending close_notify */
+  signal(SIGPIPE, SIG_IGN);
+
+  if (tls->bio_err == NULL)
+    tls->bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+  if (tls->ctx == NULL) {
+    SSL_METHOD *meth;
+
+    /* meth = SSLv3_method(); */
+    /* meth = SSLv23_method(); */
+
+    if (ti->version)
+      meth = TLSv1_method();
+    else
+      meth = SSLv23_method();
+
+    tls->ctx = SSL_CTX_new(meth);
+  }
+
+  if (tls->ctx == NULL) {
+    ERR_print_errors(tls->bio_err);
+    errno = EIO;
+    return -1;
+  }
+
+  if (!SSL_CTX_use_certificate_file(tls->ctx, 
+				    ti->cert,
+				    SSL_FILETYPE_PEM)) {
+    if (ti->configured > 0) {
+      BIO_printf(tls->bio_err, "%s: invalid certificate: %s\n",
+		 "tls_init_context", ti->cert);
+      ERR_print_errors(tls->bio_err);
+#if require_client_certificate
+      errno = EIO;
+      return -1;
+#endif
+    }
+  }
+
+  if (!SSL_CTX_use_PrivateKey_file(tls->ctx, 
+                                   ti->key, 
+                                   SSL_FILETYPE_PEM)) {
+    if (ti->configured > 0) {
+      ERR_print_errors(tls->bio_err);
+#if require_client_certificate
+      errno = EIO;
+      return -1;
+#endif
+    }
+  }
+
+  if (!SSL_CTX_check_private_key(tls->ctx)) {
+    if (ti->configured > 0) {
+      BIO_printf(tls->bio_err,
+		 "Private key does not match the certificate public key\n");
+    }
+#if require_client_certificate
+    errno = EIO;
+    return -1;
+#endif
+  }
+
+  if (!SSL_CTX_load_verify_locations(tls->ctx, 
+                                     ti->CAfile, 
+                                     ti->CApath)) {
+    if (ti->configured > 0)
+      ERR_print_errors(tls->bio_err);
+    errno = EIO;
+    return -1;
+  }
+
+  SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
+
+  SSL_CTX_set_verify(tls->ctx, 
+		     getenv("SSL_VERIFY_PEER") ? SSL_VERIFY_PEER : SSL_VERIFY_NONE
+		     /* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */,
+                     tls_verify_cb);
+
+  if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) {
+    BIO_printf(tls->bio_err,"error setting cipher list\n");
+    ERR_print_errors(tls->bio_err);
+    errno = EIO;
+    return -1;
+  }
+
+  return 0;
+}
+
+void tls_free(tls_t *tls)
+{
+  int k;
+
+  if (!tls)
+    return;
+
+  if (tls->read_buffer)
+    free(tls->read_buffer), tls->read_buffer = NULL;
+
+  if (tls->con != NULL)
+    SSL_shutdown(tls->con);
+
+  if (tls->ctx != NULL && tls->type != tls_slave)
+    SSL_CTX_free(tls->ctx);
+
+  if (tls->bio_con != NULL)
+    BIO_free(tls->bio_con);
+
+  if (tls->bio_err != NULL && tls->type != tls_slave)
+    BIO_free(tls->bio_err);
+
+  for (k = 0; k < TLS_MAX_HOSTS; k++)
+    free(tls->hosts[k]), tls->hosts[k] = NULL;
+
+  free(tls);
+}
+
+int tls_get_socket(tls_t *tls)
+{
+  int sock = -1;
+
+  if (tls != NULL && tls->bio_con != NULL)
+    BIO_get_fd(tls->bio_con, &sock);
+
+  return sock;
+}
+
+tls_t *tls_init_master(tls_issues_t *ti)
+{
+  /* Default id in case RAND fails */ 
+  unsigned char sessionId[32] = "sofia/tls"; 
+  tls_t *tls;
+
+  signal(SIGPIPE, SIG_IGN);  /* Ignore spurios SIGPIPE from OpenSSL */
+
+  tls_set_default(ti);
+
+  if (!(tls = tls_create(tls_master)))
+    return NULL;
+
+  if (tls_init_context(tls, ti) < 0) {
+    int err = errno;
+    tls_free(tls);
+    errno = err;
+    return NULL;
+  }
+
+  RAND_pseudo_bytes(sessionId, sizeof(sessionId));
+
+  SSL_CTX_set_session_id_context(tls->ctx,
+                                 (void*) sessionId,
+				 sizeof(sessionId)); 
+  
+  if (ti->CAfile != NULL)
+    SSL_CTX_set_client_CA_list(tls->ctx,
+                               SSL_load_client_CA_file(ti->CAfile));
+
+#if 0
+  if (sock != -1) {
+    tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE);
+
+    if (tls->bio_con == NULL) {
+      BIO_printf(tls->bio_err, "tls_init_master: BIO_new_socket failed\n");
+      ERR_print_errors(tls->bio_err);
+      tls_free(tls);
+      errno = EIO;
+      return NULL;
+    }
+  }
+#endif
+
+  return tls;
+}
+
+#if 0
+#include <poll.h>
+
+static 
+int tls_accept(tls_t *tls)
+{
+  int ret = SSL_accept(tls->con);
+  int verify_result;
+
+  if (ret <= 0) {
+    int err = SSL_get_error(tls->con, ret);
+    switch(err) {
+    case SSL_ERROR_WANT_READ:
+      return errno = EAGAIN, tls->read_events = SU_WAIT_IN, 0;
+    case SSL_ERROR_WANT_WRITE:
+      return errno = EAGAIN, tls->read_events = SU_WAIT_OUT, 0;
+
+    default:    
+      BIO_printf(tls->bio_err, "SSL_connect failed: %d %s\n", 
+                 err,
+                 ERR_error_string(err, NULL));
+      ERR_print_errors(tls->bio_err);
+      return -1;
+    }
+  }
+
+  verify_result = SSL_get_verify_result(tls->con);
+
+  if (verify_result != X509_V_OK) {
+    BIO_printf(tls->bio_err, 
+               "Client certificate doesn't verify: %s\n",
+               X509_verify_cert_error_string(verify_result));
+#if 0
+    tls_free(tls);
+    return NULL;
+#endif
+  }
+
+  if (SSL_get_peer_certificate(tls->con) == NULL) {
+    BIO_printf(tls->bio_err, "Client didn't send certificate\n");
+#if 0
+    tls_free(tls);
+    return NULL;
+#endif
+  }
+
+  return 1;
+}
+#endif
+
+tls_t *tls_clone(tls_t *master, int sock, int accept)
+{
+  tls_t *tls = tls_create(tls_slave);
+
+  if (tls) {
+    tls->ctx = master->ctx;
+    tls->bio_err = master->bio_err;
+
+    if (!(tls->read_buffer = malloc(tls_buffer_size)))
+      free(tls), tls = NULL;
+  }
+  if (!tls)
+    return tls;
+
+  assert(sock != -1);
+
+  tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE); 
+  tls->con = SSL_new(tls->ctx);
+
+  if (tls->con == NULL) {
+    BIO_printf(tls->bio_err, "tls_clone: SSL_new failed\n");
+    ERR_print_errors(tls->bio_err);
+    tls_free(tls);
+    errno = EIO;
+    return NULL;
+  }
+
+  SSL_set_bio(tls->con, tls->bio_con, tls->bio_con);
+  if (accept)
+    SSL_set_accept_state(tls->con);
+  else
+    SSL_set_connect_state(tls->con);
+  SSL_set_mode(tls->con, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+  tls_read(tls); /* XXX - works only with non-blocking sockets */
+
+  return tls;
+}
+
+tls_t *tls_init_slave(tls_t *master, int sock)
+{
+  int accept;
+  return tls_clone(master, sock, accept = 1);
+}
+
+tls_t *tls_init_client(tls_t *master, int sock)
+{
+  int accept;
+  return tls_clone(master, sock, accept = 0);
+}
+
+static char *tls_strdup(char const *s)
+{
+  if (s) {
+    size_t len = strlen(s) + 1;
+    char *d = malloc(len);
+    if (d)
+      memcpy(d, s, len);
+    return d;
+  }
+  return NULL;
+}
+
+static
+int tls_post_connection_check(tls_t *tls)
+{
+  X509 *cert;
+  int extcount;
+  int k, i, j, error;
+
+  if (!tls) return -1;
+
+  cert = SSL_get_peer_certificate(tls->con); 
+  if (!cert)
+    return X509_V_OK;
+  
+  extcount = X509_get_ext_count(cert);
+
+  for (k = 0; k < TLS_MAX_HOSTS && tls->hosts[k]; k++)
+    ;
+
+  /* Find matching subjectAltName.DNS */
+  for (i = 0; i < extcount; i++) {
+    X509_EXTENSION *ext;
+    char const *name;
+    X509V3_EXT_METHOD *vp;
+    STACK_OF(CONF_VALUE) *values;
+    CONF_VALUE *value;
+    void *d2i;
+
+    ext = X509_get_ext(cert, i);
+    name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+    
+    if (strcmp(name, "subjectAltName") != 0)
+      continue;
+      
+    vp = X509V3_EXT_get(ext); if (!vp) continue;
+    d2i = X509V3_EXT_d2i(ext);
+    values = vp->i2v(vp, d2i, NULL);
+    
+    for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
+      value = sk_CONF_VALUE_value(values, j);
+      if (strcmp(value->name, "DNS") == 0) {
+	if (k < TLS_MAX_HOSTS) {
+	  tls->hosts[k] = tls_strdup(value->value);
+	  k += tls->hosts[k] != NULL;
+	}
+      }
+      else if (strcmp(value->name, "URI") == 0) {
+	char const *uri = strchr(value->value, ':');
+	if (uri ++ && k < TLS_MAX_HOSTS) {
+	  tls->hosts[k] = tls_strdup(uri);
+	  k += tls->hosts[k] != NULL;
+	}
+      }
+    }
+  }
+   
+  if (k < TLS_MAX_HOSTS) {
+    X509_NAME *subject;
+    char name[256];
+
+    subject = X509_get_subject_name(cert);
+    if (subject) {
+      if (X509_NAME_get_text_by_NID(subject, NID_commonName, 
+				    name, sizeof name) > 0) {
+	name[(sizeof name) - 1] = '\0';
+
+	for (i = 0; tls->hosts[i]; i++) 
+	  if (strcasecmp(tls->hosts[i], name) == 0)
+	    break;
+
+	if (i == k)
+	  tls->hosts[k++] = tls_strdup(name);
+      }
+    }
+  }
+
+  X509_free(cert);
+
+  error = SSL_get_verify_result(tls->con);
+
+  if (error == X509_V_OK)
+    tls->verified = 1;
+  
+  return error;
+}
+
+int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS])
+{
+  int i, j;
+
+  if (tls == NULL) { errno = EINVAL; return -1; }
+  if (!tls->verified) { errno = EAGAIN; return -1; }
+
+  if (!hosts) 
+    return 0;
+
+  for (i = 0; hosts[i]; i++) {
+    for (j = 0; tls->hosts[j]; j++) {
+      if (strcasecmp(hosts[i], tls->hosts[j]) == 0)
+	break;
+    }
+    if (tls->hosts[j] == NULL) {
+      errno = EACCES;
+      return -1;
+    }
+  }
+  
+  return 0;
+}
+
+static
+int tls_error(tls_t *tls, int ret, char const *who, char const *operation,
+	      void *buf, int size)
+{
+  char errorbuf[128];
+  int events = 0;
+  int err = SSL_get_error(tls->con, ret);
+
+  switch (err) {
+  case SSL_ERROR_WANT_WRITE:
+    events = SU_WAIT_OUT;
+    break;
+
+  case SSL_ERROR_WANT_READ:
+    events = SU_WAIT_IN;
+    break;
+
+  case SSL_ERROR_ZERO_RETURN:
+    return 0;
+
+  case SSL_ERROR_SYSCALL:
+    return -1;
+
+  default:
+    BIO_printf(tls->bio_err, "%s: %s failed (%d): %s\n", 
+	       who, operation, err, ERR_error_string(err, errorbuf));
+    ERR_print_errors(tls->bio_err);
+    errno = EIO;
+    return -1;
+  }
+
+  if (buf) {
+    tls->write_events = events;
+    tls->write_buffer = buf, tls->write_buffer_len = size;
+  }
+  else {
+    tls->read_events = events;
+  }
+
+  errno = EAGAIN;
+  return -1;
+}
+
+ssize_t tls_read(tls_t *tls)
+{
+  ssize_t ret;
+
+  if (tls == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (0)
+    fprintf(stderr, "tls_read(%p) called on %s (events %u)\n", tls,
+	    tls->type == tls_slave ? "server" : "client",
+	    tls->read_events);
+
+  if (tls->read_buffer_len)
+    return (ssize_t)tls->read_buffer_len;
+
+  tls->read_events = SU_WAIT_IN;
+
+  ret = SSL_read(tls->con, tls->read_buffer, tls_buffer_size);
+  if (ret <= 0)
+    return tls_error(tls, ret, "tls_read", "SSL_read", NULL, 0);
+
+  if (!tls->verified) {
+    int err = tls_post_connection_check(tls);
+
+    if (err != X509_V_OK && 
+	err != SSL_ERROR_SYSCALL &&
+	err != SSL_ERROR_WANT_WRITE &&
+	err != SSL_ERROR_WANT_READ) {
+      BIO_printf(tls->bio_err, 
+		 "%s: server certificate doesn't verify\n", 
+		 "tls_read");
+    }
+  }
+
+  return (ssize_t)(tls->read_buffer_len = ret);
+}
+
+void *tls_read_buffer(tls_t *tls, size_t N)
+{
+  assert(N == tls->read_buffer_len);
+  tls->read_buffer_len = 0;
+  return tls->read_buffer;
+}
+
+int tls_pending(tls_t const *tls)
+{
+  return tls && tls->con && SSL_pending(tls->con);
+}
+
+int tls_want_read(tls_t *tls, int events)
+{
+  if (tls && (events & tls->read_events)) {
+    int ret = tls_read(tls);
+
+    if (ret >= 0)
+      return 1;
+    else if (errno == EAGAIN)
+      return 0;
+    else
+      return -1;
+  }
+
+  return 0;
+}
+
+ssize_t tls_write(tls_t *tls, void *buf, size_t size)
+{
+  ssize_t ret;
+
+  if (0) 
+    fprintf(stderr, "tls_write(%p, %p, "MOD_ZU") called on %s\n", 
+	    tls, buf, size,
+	    tls && tls->type == tls_slave ? "server" : "client");
+
+  if (tls == NULL || buf == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (tls->write_buffer) {
+    assert(buf == tls->write_buffer);
+    assert(size >= tls->write_buffer_len);
+    assert(tls->write_events == 0);
+
+    if (tls->write_events ||
+	buf != tls->write_buffer || 
+	size < tls->write_buffer_len) {
+      errno = EIO;		
+      return -1;
+    }
+
+    ret = tls->write_buffer_len;
+
+    tls->write_buffer = NULL;
+    tls->write_buffer_len = 0;
+
+    return ret;
+  }
+
+  if (size == 0)
+    return 0;
+
+  tls->write_events = 0;
+
+  if (!tls->verified) {
+    if (tls_post_connection_check(tls) != X509_V_OK) {
+      BIO_printf(tls->bio_err, 
+		 "tls_read: server certificate doesn't verify\n");
+    }
+  }
+
+  ret = SSL_write(tls->con, buf, size);
+  if (ret < 0)
+    return tls_error(tls, ret, "tls_write", "SSL_write", buf, size);
+
+  return ret;
+}
+
+int tls_want_write(tls_t *tls, int events)
+{
+  if (tls && (events & tls->write_events)) {
+    int ret;
+    void *buf = tls->write_buffer;
+    size_t size = tls->write_buffer_len;
+
+    tls->write_events = 0;
+
+    /* remove buf */
+    tls->write_buffer = NULL;
+    tls->write_buffer_len = 0;
+
+    ret = tls_write(tls, buf, size);
+
+    if (ret >= 0)
+      /* Restore buf */
+      return tls->write_buffer = buf, tls->write_buffer_len = ret;
+    else if (errno == EAGAIN)
+      return 0;
+    else
+      return -1;
+  }
+  return 0;
+}
+
+int tls_events(tls_t const *tls, int mask)
+{
+
+  if (!tls)
+    return mask;
+
+  if (tls->type == tls_master)
+    return mask;
+  
+  return
+    (mask & ~(SU_WAIT_IN|SU_WAIT_OUT)) |
+    ((mask & SU_WAIT_IN) ? tls->read_events : 0) | 
+    ((mask & SU_WAIT_OUT) ? tls->write_events : 0);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_TLS_H
+/** Defined when <tport_tls.h> has been included. */
+#define TPORT_TLS_H
+/**@IFILE tport_tls.h
+ * @brief TLS interface
+ * 
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>
+ *
+ * Copyright 2001, 2002 Nokia Research Center.  All rights reserved.
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define TLS_MAX_HOSTS (16)
+
+typedef struct tls_s tls_t;
+
+extern char const tls_version[];
+
+typedef struct tls_issues_s {
+  int  verify_depth;    /* if 0, then do nothing                      */
+  int   configured;	/* If non-zero, complain about certificate errors */
+  char *cert;		/* CERT file name. File format is PEM         */
+  char *key;		/* Private key file. PEM format               */
+  char *randFile;       /* Seed file for the PRNG (default: tls_seed.dat) */
+  char *CAfile;		/* PEM file of CA's                           */
+  char *CApath;		/* PEM file path of CA's		      */
+  char *cipher;         /* Should be one of the above defined ciphers *
+			 * or NULL (default: "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH
+                         */
+  int   version;	/* For tls1, version is 1. When ssl3/ssl2 is 
+			 * used, it is 0. */
+} tls_issues_t;
+
+tls_t *tls_init_master(tls_issues_t *tls_issues);
+tls_t *tls_init_slave(tls_t *tls_master, int sock);
+tls_t *tls_init_client(tls_t *tls_master, int sock);
+void tls_free(tls_t *tls);
+int tls_get_socket(tls_t *tls);
+ssize_t tls_read(tls_t *tls);
+void *tls_read_buffer(tls_t *tls, size_t N);
+int tls_want_read(tls_t *tls, int events);
+int tls_pending(tls_t const *tls);
+
+ssize_t tls_write(tls_t *tls, void *buf, size_t size);
+int tls_want_write(tls_t *tls, int events);
+
+int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS]);
+
+int tls_events(tls_t const *tls, int flags);
+
+SOFIA_END_DECLS
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo Starting TLS Test Server
+./tport_test_server &
+sleep 1
+./tport_test_client 

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_connect.c Transport using HTTP CONNECT.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* TCP using HTTP CONNECT */
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+
+static int tport_http_connect_init_primary(tport_primary_t *,
+					   tp_name_t tpn[1], 
+					   su_addrinfo_t *, 
+					   tagi_t const *,
+					   char const **return_culprit);
+
+static void tport_http_connect_deinit_primary(tport_primary_t *);
+
+static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai, 
+				   tp_name_t const *tpn);
+
+static void tport_http_deliver(tport_t *self, msg_t *msg, su_time_t now);
+
+typedef struct
+{
+  tport_primary_t thc_primary[1];
+  su_addrinfo_t  *thc_proxy;
+} tport_http_connect_t;
+
+typedef struct
+{
+  tport_t thci_tport[1];
+  msg_t *thci_response;
+  msg_t *thci_stackmsg;
+} tport_http_connect_instance_t;
+
+tport_vtable_t const tport_http_connect_vtable =
+{
+  "TCP", tport_type_connect,
+  sizeof (tport_http_connect_t),
+  tport_http_connect_init_primary,
+  tport_http_connect_deinit_primary,
+  NULL,
+  tport_http_connect,
+  sizeof (tport_http_connect_instance_t),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_stream,
+  tport_send_stream,
+  tport_http_deliver,
+};
+
+static int tport_http_connect_init_primary(tport_primary_t *pri,
+					   tp_name_t tpn[1], 
+					   su_addrinfo_t *ai, 
+					   tagi_t const *tags,
+					   char const **return_culprit)
+{
+  tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+  char const *http_connect = NULL;
+  url_t *http_proxy;
+  int error;
+  char const *host, *port;
+  su_addrinfo_t hints[1];
+
+  tl_gets(tags,
+	  TPTAG_HTTP_CONNECT_REF(http_connect),
+	  TAG_END());
+  if (!http_connect)
+    return *return_culprit = "missing proxy url", -1;
+
+  http_proxy = url_hdup(pri->pri_home, URL_STRING_MAKE(http_connect)->us_url);
+  if (!http_proxy || !http_proxy->url_host)
+    return *return_culprit = "invalid proxy url", -1;
+
+  host = http_proxy->url_host;
+  port = http_proxy->url_port;
+  if (!port || !port[0])
+    port = "8080";
+
+  memcpy(hints, ai, sizeof hints);
+  
+  hints->ai_flags = 0;
+  hints->ai_addr = NULL;
+  hints->ai_addrlen = 0;
+  hints->ai_next = NULL;
+  hints->ai_canonname = NULL;
+  
+  error = su_getaddrinfo(host, port, hints, &thc->thc_proxy);
+  if (error)
+    return *return_culprit = "su_getaddrinfo", -1;
+
+  return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static void tport_http_connect_deinit_primary(tport_primary_t *pri)
+{
+  tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+  
+  su_freeaddrinfo(thc->thc_proxy), thc->thc_proxy = NULL;
+}
+
+static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai, 
+				   tp_name_t const *tpn)
+{
+  tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+  tport_http_connect_instance_t *thci;
+  tport_master_t *mr = pri->pri_master;
+  
+  msg_t *msg, *response;
+
+  char hostport[TPORT_HOSTPORTSIZE];
+
+  tport_t *tport;
+  http_request_t *rq;
+  
+  msg = msg_create(http_default_mclass(), 0);
+
+  if (!msg)
+    return NULL;
+
+  tport_hostport(hostport, sizeof hostport, (void *)ai->ai_addr, 1);
+
+  rq = http_request_format(msg_home(msg), "CONNECT %s HTTP/1.1", hostport);
+
+  if (msg_header_insert(msg, NULL, (void *)rq) < 0
+      || msg_header_add_str(msg, NULL, 
+			    "User-Agent: Sofia-SIP/" VERSION "\n") < 0
+      || msg_header_add_str(msg, NULL, "Proxy-Connection: keepalive\n") < 0
+      || msg_header_add_make(msg, NULL, http_host_class, hostport) < 0
+      || msg_header_add_make(msg, NULL, http_separator_class, "\r\n") < 0 
+      || msg_serialize(msg, NULL) < 0
+      || msg_prepare(msg) < 0)
+    return (void)msg_destroy(msg), NULL;
+
+  /* 
+   * Create a response message that ignores the body 
+   * if there is no Content-Length 
+   */
+  response = msg_create(http_default_mclass(), mr->mr_log | MSG_FLG_MAILBOX);
+  
+  tport = tport_base_connect(pri, thc->thc_proxy, ai, tpn);
+  if (!tport) {
+    msg_destroy(msg); msg_destroy(response);
+    return tport;
+  }
+
+  thci = (tport_http_connect_instance_t*)tport;
+  
+  thci->thci_response = response;
+  tport->tp_msg = response;
+  msg_set_next(response, thci->thci_stackmsg = tport_msg_alloc(tport, 512));
+
+  if (tport_send_msg(tport, msg, tpn, NULL) < 0) {
+    SU_DEBUG_9(("tport_send_msg failed in tpot_http_connect\n"));
+    msg_destroy(msg); 
+    tport_zap_secondary(tport);
+    return NULL;
+  }  
+
+  return tport;
+}
+
+#include <sofia-sip/msg_buffer.h>
+
+static void tport_http_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+  tport_http_connect_instance_t *thci = (tport_http_connect_instance_t*)self;
+
+  if (msg && thci->thci_response == msg) {
+    tport_http_connect_t *thc = (tport_http_connect_t *)self->tp_pri;
+    http_t *http = http_object(msg);
+
+    if (http && http->http_status) {
+      SU_DEBUG_0(("tport_http_connect: %u %s\n", 
+		  http->http_status->st_status,
+		  http->http_status->st_phrase));
+      if (http->http_status->st_status < 300) {
+	msg_buf_move(thci->thci_stackmsg, msg);
+	thci->thci_response = NULL;
+	thci->thci_stackmsg = NULL;
+	return;
+      }
+    }
+
+    msg_destroy(msg);
+    thci->thci_response = NULL;
+    tport_error_report(self, EPROTO, (void *)thc->thc_proxy->ai_addr);
+    tport_close(self);
+    return;
+  }
+
+  tport_base_deliver(self, msg, now);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,262 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_sctp.c Transport using SCTP.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @RFC4168.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ * @date Original Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#if HAVE_SCTP
+
+#include "tport_internal.h"
+
+#if HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#undef HAVE_SCTP
+#define HAVE_SCTP 1
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* SCTP */
+
+#undef MAX_STREAMS
+#define MAX_STREAMS MAX_STREAMS
+
+enum { MAX_STREAMS = 1 };
+typedef struct tport_sctp_t
+{
+  tport_t sctp_base[1];
+  
+  msg_t *sctp_recv[MAX_STREAMS];
+  struct sctp_send {
+    msg_t *ss_msg;
+    msg_iovec_t *ss_unsent;	/**< Pointer to first unsent iovec */
+    unsigned     ss_unsentlen;  /**< Number of unsent iovecs */
+    msg_iovec_t *ss_iov;	/**< Iovecs allocated for sending */
+    unsigned     ss_iovlen;	/**< Number of allocated iovecs */
+  } sctp_send[MAX_STREAMS];
+} tport_sctp_t;
+
+#define TP_SCTP_MSG_MAX (65536)
+
+static int tport_sctp_init_primary(tport_primary_t *, 
+				   tp_name_t tpn[1], 
+				   su_addrinfo_t *, tagi_t const *,
+				   char const **return_culprit);
+static int tport_sctp_init_client(tport_primary_t *, 
+				  tp_name_t tpn[1], 
+				  su_addrinfo_t *, tagi_t const *,
+				  char const **return_culprit);
+static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
+				     char const **return_reason);
+static int tport_sctp_init_socket(tport_primary_t *pri, 
+				  int socket,
+				  char const **return_reason);
+static int tport_recv_sctp(tport_t *self);
+static int tport_send_sctp(tport_t const *self, msg_t *msg,
+			   msg_iovec_t iov[], int iovused);
+
+tport_vtable_t const tport_sctp_client_vtable =
+{
+  "sctp", tport_type_client,
+  sizeof (tport_primary_t),
+  tport_sctp_init_client,
+  NULL,
+  tport_accept,
+  NULL,
+  sizeof (tport_t),
+  tport_sctp_init_secondary,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_sctp,
+  tport_send_sctp,
+};
+
+#undef NEXT_VTABLE
+#define NEXT_VTABLE &tport_sctp_client_vtable
+
+tport_vtable_t const tport_sctp_vtable =
+{
+  "sctp", tport_type_local,
+  sizeof (tport_primary_t),
+  tport_sctp_init_primary,
+  NULL,
+  tport_accept,
+  NULL,
+  sizeof (tport_t),
+  tport_sctp_init_secondary,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_sctp,
+  tport_send_sctp,
+};
+
+#undef NEXT_VTABLE
+#define NEXT_VTABLE &tport_sctp_vtable
+
+static int tport_sctp_init_primary(tport_primary_t *pri, 
+				   tp_name_t tpn[1],
+				   su_addrinfo_t *ai,
+				   tagi_t const *tags,
+				   char const **return_culprit)
+{
+  int socket;
+
+  if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
+    pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
+
+  socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+
+  if (socket == INVALID_SOCKET)
+    return *return_culprit = "socket", -1;
+
+  if (tport_sctp_init_socket(pri, socket, return_culprit) < 0)
+    return -1;
+  
+  return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit);
+}
+
+static int tport_sctp_init_client(tport_primary_t *pri, 
+				  tp_name_t tpn[1],
+				  su_addrinfo_t *ai,
+				  tagi_t const *tags,
+				  char const **return_culprit)
+{
+  if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
+    pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
+
+  return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
+				     char const **return_reason)
+{
+  self->tp_has_connection = 1;
+
+  if (su_setblocking(socket, 0) < 0)
+    return *return_reason = "su_setblocking", -1;
+
+  if (accepted) {
+    /* Accepted socket inherit the init information from listen socket */
+    return 0;
+  }
+  else {
+    return tport_sctp_init_socket(self->tp_pri, socket, return_reason);
+  }
+}
+
+/** Initialize a SCTP socket */
+static int tport_sctp_init_socket(tport_primary_t *pri, 
+				  int socket,
+				  char const **return_reason)
+{
+  struct sctp_initmsg initmsg = { 0 };
+
+  initmsg.sinit_num_ostreams = MAX_STREAMS;
+  initmsg.sinit_max_instreams = MAX_STREAMS;
+
+  if (setsockopt(socket, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof initmsg) < 0)
+    return *return_reason = "SCTP_INITMSG", -1;
+
+  return 0;
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream  
+ * @retval 1  normal receive
+ * @retval 2  incomplete recv, recv again
+ */
+static 
+int tport_recv_sctp(tport_t *self)
+{
+  msg_t *msg;
+  ssize_t N, veclen;
+  msg_iovec_t iovec[2] = {{ 0 }};
+
+  char sctp_buf[TP_SCTP_MSG_MAX];
+
+  iovec[0].mv_base = sctp_buf;
+  iovec[0].mv_len = sizeof(sctp_buf);
+
+  N = su_vrecv(self->tp_socket, iovec, 1, 0, NULL, NULL);
+  if (N == SOCKET_ERROR) {
+    return su_is_blocking(su_errno()) ? 1 : -1;
+  }
+
+  if (N == 0) {
+    if (self->tp_msg)
+      msg_recv_commit(self->tp_msg, 0, 1);
+    return 0;    /* End of stream */
+  }
+
+  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+  if (veclen < 0)
+    return -1;
+
+  assert(veclen == 1); assert(iovec[0].mv_len == N);
+  msg = self->tp_msg;
+
+  msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+
+  memcpy(iovec[0].mv_base, sctp_buf, iovec[0].mv_len);
+
+  if (self->tp_master->mr_dump_file)
+    tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from");
+
+  msg_recv_commit(msg, N, 0);  /* Mark buffer as used */
+
+  return 2;
+}
+
+static int tport_send_sctp(tport_t const *self, msg_t *msg,
+			   msg_iovec_t iov[], int iovused)
+{
+  
+
+  return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+}
+
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_stun.c Transport using stun.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#define STUN_DISCOVERY_MAGIC_T  struct tport_primary
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* STUN */
+
+#include <sofia-sip/stun.h>
+
+static int tport_udp_init_stun(tport_primary_t *,
+			       tp_name_t tpn[1], 
+			       su_addrinfo_t *, 
+			       tagi_t const *,
+			       char const **return_culprit);
+
+static void tport_udp_deinit_stun(tport_primary_t *pri);
+
+static
+void tport_stun_bind_cb(tport_primary_t *pri,
+			stun_handle_t *sh,
+			stun_discovery_t *sd,
+			stun_action_t action,
+			stun_state_t event);
+static
+void tport_stun_bind_done(tport_primary_t *pri,
+			  stun_handle_t *sh,
+			  stun_discovery_t *sd);
+static
+int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+			 tagi_t const *taglist);
+
+static int tport_stun_response(tport_t const *self,
+			       void *dgram, size_t n,
+			       void *from, socklen_t fromlen);
+
+tport_vtable_t const tport_stun_vtable =
+{
+  "UDP", tport_type_stun,
+  sizeof (tport_primary_t),
+  tport_udp_init_stun,
+  tport_udp_deinit_stun,
+  NULL,
+  NULL,
+  sizeof (tport_t),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_dgram,
+  tport_send_dgram,
+  NULL,
+  NULL,
+  tport_stun_keepalive,
+  tport_stun_response
+};
+
+static int tport_udp_init_stun(tport_primary_t *pri,
+			       tp_name_t tpn[1], 
+			       su_addrinfo_t *ai, 
+			       tagi_t const *tags,
+			       char const **return_culprit)
+{
+  stun_handle_t *sh;
+
+#if 0
+  if (!stun_is_requested(TAG_NEXT(tags)))
+    return -1;
+#endif
+
+  sh = stun_handle_init(pri->pri_master->mr_root, TAG_NEXT(tags));
+  if (!sh)
+    return *return_culprit = "stun_handle_init", -1;
+
+  pri->pri_stun_handle = sh;
+  tpn->tpn_canon = NULL;
+
+  if (tport_udp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+    return -1;
+
+#if 0
+  if (stun_obtain_shared_secret(sh, tport_stun_tls_cb, pri, 
+				TAG_NEXT(tags)) < 0) {
+    return *return_culprit = "stun_request_shared_secret()", -1;
+  }
+#endif
+
+  if (stun_bind(sh, tport_stun_bind_cb, pri,
+		STUNTAG_SOCKET(pri->pri_primary->tp_socket),
+		STUNTAG_REGISTER_EVENTS(0),
+		TAG_NULL()) < 0) {
+    return *return_culprit = "stun_bind()", -1;
+  }
+
+  pri->pri_updating = 1;
+
+  return 0;
+}
+
+
+static void tport_udp_deinit_stun(tport_primary_t *pri)
+{
+  if (pri->pri_stun_handle) 
+    stun_handle_destroy(pri->pri_stun_handle); 
+  pri->pri_stun_handle = NULL;
+}
+
+
+static int tport_stun_response(tport_t const *self,
+			       void *dgram, size_t n,
+			       void *from, socklen_t fromlen)
+{
+  stun_process_message(self->tp_pri->pri_stun_handle, self->tp_socket,
+		       from, fromlen, (void *)dgram, n);
+
+  return 3;
+}
+
+
+/**Callback for STUN bind */
+static
+void tport_stun_bind_cb(tport_primary_t *pri,
+			stun_handle_t *sh,
+			stun_discovery_t *sd,
+			stun_action_t action,
+			stun_state_t event)
+{
+  tport_master_t *mr;
+  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+  mr = pri->pri_master;
+
+  if (event == stun_discovery_done) {
+    tport_stun_bind_done(pri, sh, sd);
+  }
+}
+
+
+static
+void tport_stun_bind_done(tport_primary_t *pri,
+			  stun_handle_t *sh,
+			  stun_discovery_t *sd)
+{
+  tport_t *self = pri->pri_primary;
+  su_socket_t socket;
+  su_sockaddr_t *su = self->tp_addr;
+  su_addrinfo_t *ai = self->tp_addrinfo;
+
+  socket = stun_discovery_get_socket(sd);
+  assert(pri->pri_primary->tp_socket == socket);
+
+  if (stun_discovery_get_address(sd, su, &ai->ai_addrlen) == 0) {
+    char ipname[SU_ADDRSIZE + 2] = { 0 };
+    ai->ai_addr = (void *)su;
+
+    SU_DEBUG_5(("%s: stun_bind() ok: local address NATed as %s:%u\n", 
+		__func__,
+		inet_ntop(su->su_family, SU_ADDR(su), ipname, sizeof(ipname)),
+		(unsigned) ntohs(su->su_port)));
+  }
+
+  /* Send message to calling application indicating 
+   * there's a new public address available 
+   */
+  tport_has_been_updated(self);
+  
+  return;
+}
+
+/** Initialize STUN keepalives.
+ *
+ *@retval 0
+ */
+static
+int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+			 tagi_t const *taglist)
+{
+  tport_primary_t *pri = tp->tp_pri;
+  int err;
+
+  err = stun_keepalive(pri->pri_stun_handle, 
+		       (su_sockaddr_t *)ai->ai_addr,
+		       STUNTAG_SOCKET(tp->tp_socket),
+		       STUNTAG_TIMEOUT(10000),
+		       TAG_NEXT(taglist));
+  
+  if (err < 0)
+    return -1;
+
+  tp->tp_has_keepalive = 1;
+
+  return 0;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_tcp.c TCP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+char const __func__[] = "tport_type_tcp";
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* TCP */
+
+tport_vtable_t const tport_tcp_vtable =
+{
+  "tcp", tport_type_local,
+  sizeof (tport_primary_t),
+  tport_tcp_init_primary,
+  NULL,
+  tport_accept,
+  NULL,
+  sizeof (tport_t),
+  tport_tcp_init_secondary,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_stream,
+  tport_send_stream,
+};
+
+tport_vtable_t const tport_tcp_client_vtable =
+{
+  "tcp", tport_type_client,
+  sizeof (tport_primary_t),
+  tport_tcp_init_client,
+  NULL,
+  tport_accept,
+  NULL,
+  sizeof (tport_t),
+  tport_tcp_init_secondary,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_stream,
+  tport_send_stream,
+};
+
+static int tport_tcp_setsndbuf(int socket, int atleast);
+
+int tport_tcp_init_primary(tport_primary_t *pri, 
+			   tp_name_t tpn[1],
+			   su_addrinfo_t *ai,
+			   tagi_t const *tags,
+			   char const **return_culprit)
+{
+  int socket;
+
+  socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+
+  if (socket == INVALID_SOCKET)
+    return *return_culprit = "socket", -1;
+
+  tport_tcp_setsndbuf(socket, 64 * 1024);
+
+  return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit);
+}
+
+int tport_stream_init_primary(tport_primary_t *pri, 
+			      su_socket_t socket,
+			      tp_name_t tpn[1],
+			      su_addrinfo_t *ai,
+			      tagi_t const *tags,
+			      char const **return_culprit)
+{
+  pri->pri_primary->tp_socket = socket;
+
+  /* Set IP TOS if set */
+  tport_set_tos(socket, ai, pri->pri_params->tpp_tos);
+
+#if defined(__linux__)
+  /* Linux does not allow reusing TCP port while this one is open,
+     so we can safely call su_setreuseaddr() before bind(). */
+  su_setreuseaddr(socket, 1);
+#endif
+
+  if (tport_bind_socket(socket, ai, return_culprit) == -1)
+    return -1;
+
+  if (listen(socket, pri->pri_params->tpp_qsize) == SOCKET_ERROR)
+    return *return_culprit = "listen", -1;
+
+#if !defined(__linux__)
+  /* Allow reusing TCP sockets
+   *
+   * On Solaris & BSD, call setreuseaddr() after bind in order to avoid
+   * binding to a port owned by an existing server.
+   */
+  su_setreuseaddr(socket, 1);
+#endif
+
+  pri->pri_primary->tp_events = SU_WAIT_ACCEPT;
+  pri->pri_primary->tp_conn_orient = 1;
+
+  return 0;
+}
+
+int tport_tcp_init_client(tport_primary_t *pri, 
+			  tp_name_t tpn[1],
+			  su_addrinfo_t *ai,
+			  tagi_t const *tags,
+			  char const **return_culprit)
+{
+  pri->pri_primary->tp_conn_orient = 1;
+
+  return 0;
+}
+
+int tport_tcp_init_secondary(tport_t *self, int socket, int accepted,
+			     char const **return_reason)
+{
+  int one = 1;
+
+  self->tp_has_connection = 1;
+
+  if (setsockopt(socket, SOL_TCP, TCP_NODELAY, (void *)&one, sizeof one) == -1)
+    return *return_reason = "TCP_NODELAY", -1;
+  if (su_setblocking(socket, 0) < 0)
+    return *return_reason = "su_setblocking", -1;
+
+  if (!accepted)
+    tport_tcp_setsndbuf(socket, 64 * 1024);
+
+  return 0;
+}
+
+static int tport_tcp_setsndbuf(int socket, int atleast)
+{
+#if SU_HAVE_WINSOCK2
+  /* Set send buffer size to something reasonable on windows */
+  int size = 0;
+  socklen_t sizelen = sizeof size;
+
+  if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (void *)&size, &sizelen) < 0)
+    return -1;
+
+  if (sizelen != sizeof size)
+    return su_seterrno(EINVAL);
+
+  if (size >= atleast)
+    return 0;			/* OK */
+
+  return setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
+		    (void *)&atleast, sizeof atleast);
+#else
+  return 0;
+#endif
+}
+
+/** Receive from stream.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream  
+ * @retval 1  normal receive
+ * @retval 2  incomplete recv, recv again
+ * 
+ */
+int tport_recv_stream(tport_t *self)
+{
+  msg_t *msg;
+  ssize_t n, N, veclen;
+  int err;
+  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+
+  N = su_getmsgsize(self->tp_socket);
+  if (N == 0) {
+    if (self->tp_msg)
+      msg_recv_commit(self->tp_msg, 0, 1);
+    return 0;    /* End of stream */
+  }
+  if (N == -1) {
+    err = su_errno();
+    SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, self,
+		su_strerror(err), err));
+    return -1;
+  }
+
+  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+  if (veclen == -1)
+    return -1;
+
+  msg = self->tp_msg;
+
+  msg_set_address(msg, self->tp_addr, (socklen_t)(self->tp_addrlen));
+
+  n = su_vrecv(self->tp_socket, iovec, veclen, 0, NULL, NULL);
+  if (n == SOCKET_ERROR)
+    return tport_recv_error_report(self);
+
+  assert(n <= N);
+
+  /* Write the received data to the message dump file */
+  if (self->tp_master->mr_dump_file)
+    tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+  /* Mark buffer as used */
+  msg_recv_commit(msg, n, 0);
+
+  return 1;
+}
+
+ssize_t tport_send_stream(tport_t const *self, msg_t *msg, 
+			  msg_iovec_t iov[], 
+			  size_t iovused)
+{
+#if __sun__			/* XXX - there must be a better way... */
+  if (iovused > 16)
+    iovused = 16;
+#endif
+  return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,490 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_tls.c TLS over TCP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Ismo Puustinen <Ismo.H.Puustinen at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Split here: Fri Mar 24 08:45:49 EET 2006 ppessi
+ * @date Originally Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* TLS */
+
+#include <tport_tls.h>
+
+static int tport_tls_init_primary(tport_primary_t *,
+				  tp_name_t tpn[1], 
+				  su_addrinfo_t *, tagi_t const *,
+				  char const **return_culprit);
+static int tport_tls_init_client(tport_primary_t *,
+				 tp_name_t tpn[1], 
+				 su_addrinfo_t *, tagi_t const *,
+				 char const **return_culprit);
+static int tport_tls_init_master(tport_primary_t *pri,
+				 tp_name_t tpn[1],
+				 su_addrinfo_t *ai,
+				 tagi_t const *tags,
+				 char const **return_culprit);
+static void tport_tls_deinit_primary(tport_primary_t *pri);
+static int tport_tls_init_secondary(tport_t *self, int socket, int accepted,
+				    char const **return_reason);
+static void tport_tls_deinit_secondary(tport_t *self);
+static void tport_tls_shutdown(tport_t *self, int how);
+static int tport_tls_set_events(tport_t const *self);
+static int tport_tls_events(tport_t *self, int events);
+static int tport_tls_recv(tport_t *self);
+static ssize_t tport_tls_send(tport_t const *self, msg_t *msg,
+			      msg_iovec_t iov[], size_t iovused);
+
+typedef struct
+{
+  tport_primary_t tlspri_pri[1];
+  tls_t *tlspri_master;
+} tport_tls_primary_t;
+
+typedef struct
+{
+  tport_t tlstp_tp[1];
+  tls_t  *tlstp_context;
+  char   *tlstp_buffer;    /**< 2k Buffer  */
+} tport_tls_t;
+
+tport_vtable_t const tport_tls_vtable =
+{
+  "tls", tport_type_local,
+  sizeof (tport_tls_primary_t),
+  tport_tls_init_primary,
+  tport_tls_deinit_primary,
+  tport_accept,
+  NULL,
+  sizeof (tport_tls_t),
+  tport_tls_init_secondary,
+  tport_tls_deinit_secondary,
+  tport_tls_shutdown,
+  tport_tls_set_events,
+  tport_tls_events,
+  tport_tls_recv,
+  tport_tls_send,
+};
+
+tport_vtable_t const tport_tls_client_vtable =
+{
+  "tls", tport_type_client,
+  sizeof (tport_tls_primary_t),
+  tport_tls_init_client,
+  tport_tls_deinit_primary,
+  tport_accept,
+  NULL,
+  sizeof (tport_tls_t),
+  tport_tls_init_secondary,
+  tport_tls_deinit_secondary,
+  tport_tls_shutdown,
+  tport_tls_set_events,
+  tport_tls_events,
+  tport_tls_recv,
+  tport_tls_send,
+};
+
+static int tport_tls_init_primary(tport_primary_t *pri,
+				  tp_name_t tpn[1],
+				  su_addrinfo_t *ai,
+				  tagi_t const *tags,
+				  char const **return_culprit)
+{
+  if (tport_tls_init_master(pri, tpn, ai, tags, return_culprit) < 0)
+    return -1;
+
+  return tport_tcp_init_primary(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_tls_init_client(tport_primary_t *pri,
+				 tp_name_t tpn[1],
+				 su_addrinfo_t *ai,
+				 tagi_t const *tags,
+				 char const **return_culprit)
+{
+  tport_tls_init_master(pri, tpn, ai, tags, return_culprit);
+
+  return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_tls_init_master(tport_primary_t *pri,
+				 tp_name_t tpn[1],
+				 su_addrinfo_t *ai,
+				 tagi_t const *tags,
+				 char const **return_culprit)
+{
+  tport_tls_primary_t *tlspri = (tport_tls_primary_t *)pri;
+  char *homedir;
+  char *tbf = NULL;
+  char const *path = NULL;
+  unsigned tls_version = 1;
+  su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
+  tls_issues_t ti = {0};
+
+  su_home_auto(autohome, sizeof autohome);
+
+  if (getenv("TPORT_SSL"))
+    tls_version = 0;
+
+  tl_gets(tags,
+	  TPTAG_CERTIFICATE_REF(path),
+	  TPTAG_TLS_VERSION_REF(tls_version),
+	  TAG_END());
+
+  if (!path) {
+    homedir = getenv("HOME");
+    if (!homedir)
+      homedir = "";
+    path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir);
+  }
+  
+  if (path) {
+    ti.verify_depth = 2;
+    ti.configured = path != tbf;
+    ti.randFile = su_sprintf(autohome, "%s/%s", path, "tls_seed.dat");
+    ti.key = su_sprintf(autohome, "%s/%s", path, "agent.pem");
+    ti.cert = ti.key;
+    ti.CAfile = su_sprintf(autohome, "%s/%s", path, "cafile.pem");
+    ti.version = tls_version;
+
+    SU_DEBUG_9(("%s(%p): tls key = %s\n", __func__, pri, ti.key));
+
+    if (ti.key && ti.CAfile && ti.randFile) {
+      tlspri->tlspri_master = tls_init_master(&ti);
+    }
+  }
+
+  su_home_zap(autohome);
+
+  if (!tlspri->tlspri_master) {
+    if (!path || ti.configured) {
+      SU_DEBUG_1(("tls_init_master: %s\n", strerror(errno)));
+    }
+    else {
+      SU_DEBUG_5(("tls_init_master: %s\n", strerror(errno)));
+    }
+    return *return_culprit = "tls_init_master", -1;
+  }
+
+  pri->pri_has_tls = 1;
+
+  return 0;
+}
+
+static void tport_tls_deinit_primary(tport_primary_t *pri)
+{
+  tport_tls_primary_t *tlspri = (tport_tls_primary_t *)pri;
+  tls_free(tlspri->tlspri_master), tlspri->tlspri_master = NULL;
+}
+
+static int tport_tls_init_secondary(tport_t *self, int socket, int accepted,
+				    char const **return_reason)
+{
+  tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+
+  tls_t *master = tlspri->tlspri_master;
+
+  if (tport_tcp_init_secondary(self, socket, accepted, return_reason) < 0)
+    return -1;
+
+  if (accepted) {
+    tlstp->tlstp_context = tls_init_slave(master, socket);
+    if (!tlstp->tlstp_context)
+      return *return_reason = "tls_init_slave", -1;
+  }
+
+  return 0;
+}
+
+static void tport_tls_deinit_secondary(tport_t *self)
+{
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+
+  /* XXX - PPe: does the tls_shutdown zap everything but socket? */
+  if (tlstp->tlstp_context != NULL) 
+    tls_free(tlstp->tlstp_context);
+  tlstp->tlstp_context = NULL;
+
+  su_free(self->tp_home, tlstp->tlstp_buffer);
+  tlstp->tlstp_buffer = NULL;
+}
+
+static void tport_tls_shutdown(tport_t *self, int how)
+{
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+
+  /* XXX - send alert */
+  (void)tlstp;
+
+  shutdown(self->tp_socket, how);
+
+  if (how >= 2)
+    tport_tls_deinit_secondary(self);
+}
+
+
+static
+int tport_tls_set_events(tport_t const *self)
+{
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+  int mask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+  SU_DEBUG_7(("%s(%p): logical events%s%s real%s%s\n",
+	      "tport_tls_set_events", self, 
+	      (self->tp_events & SU_WAIT_IN) ? " IN" : "",
+	      (self->tp_events & SU_WAIT_OUT) ? " OUT" : "",
+	      (mask & SU_WAIT_IN) ? " IN" : "",
+	      (mask & SU_WAIT_OUT) ? " OUT" : ""));
+
+  return
+    su_root_eventmask(self->tp_master->mr_root, 
+		      self->tp_index, 
+		      self->tp_socket, 
+		      mask);
+}
+
+/** Handle poll events for tls */
+int tport_tls_events(tport_t *self, int events)
+{
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+  int old_mask = tls_events(tlstp->tlstp_context, self->tp_events), mask;
+  int ret, error = 0;
+
+  if (events & SU_WAIT_ERR)
+    error = tport_error_event(self);
+
+  if ((self->tp_events & SU_WAIT_OUT) && !self->tp_closed) {
+    ret = tls_want_write(tlstp->tlstp_context, events);
+    if (ret > 0)
+      tport_send_event(self);
+    else if (ret < 0)
+      tport_error_report(self, errno, NULL);
+  }
+  
+  if ((self->tp_events & SU_WAIT_IN) && !self->tp_closed) {
+    ret = tls_want_read(tlstp->tlstp_context, events);
+    if (ret > 0)
+      tport_recv_event(self);
+    else if (ret < 0)
+      tport_error_report(self, errno, NULL);
+  }
+
+  if ((events & SU_WAIT_HUP) && !self->tp_closed)
+    tport_hup_event(self);
+
+  if (error && !self->tp_closed)
+    tport_error_report(self, error, NULL);
+
+  if (self->tp_closed)
+    return 0;
+
+  events = self->tp_events;
+  mask = tls_events(tlstp->tlstp_context, events);
+  if ((old_mask ^ mask) == 0)
+    return 0;
+
+  SU_DEBUG_7(("%s(%p): logical events%s%s real%s%s\n",
+	      "tport_tls_events", self, 
+	      (events & SU_WAIT_IN) ? " IN" : "",
+	      (events & SU_WAIT_OUT) ? " OUT" : "",
+	      (mask & SU_WAIT_IN) ? " IN" : "",
+	      (mask & SU_WAIT_OUT) ? " OUT" : ""));
+
+  su_root_eventmask(self->tp_master->mr_root, 
+		    self->tp_index, 
+		    self->tp_socket, 
+		    mask);
+
+  return 0;
+}
+
+/** Receive data from TLS.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream  
+ * @retval 1  normal receive
+ * @retval 2  incomplete recv, recv again
+ * 
+ */
+static 
+int tport_tls_recv(tport_t *self)
+{
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+  msg_t *msg;
+  ssize_t n, N, veclen, i, m;
+  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+  char *tls_buf;
+
+  N = tls_read(tlstp->tlstp_context);
+
+  SU_DEBUG_7(("%s(%p): tls_read() returned "MOD_ZD"\n", __func__, self, N));
+
+  if (N == 0) /* End-of-stream */
+    return 0;
+  else if (N == -1) {
+    if (su_is_blocking(su_errno())) {
+      tport_tls_set_events(self);
+      return 1;
+    }
+    return -1;
+  }
+
+  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+  if (veclen < 0)
+    return -1;
+
+  msg = self->tp_msg;
+
+  tls_buf = tls_read_buffer(tlstp->tlstp_context, N);
+
+  msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+
+  for (i = 0, n = 0; i < veclen; i++) {
+    m = iovec[i].mv_len; assert(N >= n + m);
+    memcpy(iovec[i].mv_base, tls_buf + n, m);
+    n += m;
+  }
+    
+  assert(N == n);
+
+  /* Write the received data to the message dump file */
+  if (self->tp_master->mr_dump_file)
+    tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+  /* Mark buffer as used */
+  msg_recv_commit(msg, N, 0);
+
+  return tls_pending(tlstp->tlstp_context) ? 2 : 1;
+}
+
+static
+ssize_t tport_tls_send(tport_t const *self,
+		       msg_t *msg,
+		       msg_iovec_t iov[],
+		       size_t iovlen)
+{
+  tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
+  tport_tls_t *tlstp = (tport_tls_t *)self;
+  enum { TLSBUFSIZE = 2048 };
+  size_t i, j, n, m, size = 0;
+  ssize_t nerror;
+  int oldmask, mask;
+
+  if (tlstp->tlstp_context == NULL) {
+    tls_t *master = tlspri->tlspri_master;
+    tlstp->tlstp_context = tls_init_client(master, self->tp_socket);
+    if (!tlstp->tlstp_context)
+      return -1;
+  }
+
+  oldmask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+#if 0
+  if (!tlstp->tlstp_buffer)
+    tlstp->tlstp_buffer = su_alloc(self->tp_home, TLSBUFSIZE);
+#endif
+
+  for (i = 0; i < iovlen; i = j) {
+#if 0
+    nerror = tls_write(tlstp->tlstp_context, 
+		  iov[i].siv_base,
+		  m = iov[i].siv_len);
+    j = i + 1;
+#else
+    char *buf = tlstp->tlstp_buffer;
+    unsigned tlsbufsize = TLSBUFSIZE;
+
+    if (i + 1 == iovlen)
+      buf = NULL;		/* Don't bother copying single chunk */
+
+    if (buf && 
+	(char *)iov[i].siv_base - buf < TLSBUFSIZE &&
+	(char *)iov[i].siv_base - buf >= 0) {
+      tlsbufsize = buf + TLSBUFSIZE - (char *)iov[i].siv_base;
+      assert(tlsbufsize <= TLSBUFSIZE);
+    }
+
+    for (j = i, m = 0; buf && j < iovlen; j++) {
+      if (m + iov[j].siv_len > tlsbufsize)
+	break;
+      if (buf + m != iov[j].siv_base)
+	memcpy(buf + m, iov[j].siv_base, iov[j].siv_len);
+      m += iov[j].siv_len; iov[j].siv_len = 0;
+    }
+
+    if (j == i)
+      buf = iov[i].siv_base, m = iov[i].siv_len, j++;
+    else
+      iov[j].siv_base = buf, iov[j].siv_len = m;
+
+    nerror = tls_write(tlstp->tlstp_context, buf, m);
+#endif
+
+    SU_DEBUG_9(("tport_tls_writevec: vec %p %p %lu ("MOD_ZD")\n",  
+		tlstp->tlstp_context, iov[i].siv_base, (LU)iov[i].siv_len, 
+		nerror));
+
+    if (nerror == -1) {
+      int err = su_errno();
+      if (su_is_blocking(err))
+	break;
+      SU_DEBUG_3(("tls_write: %s\n", strerror(err)));
+      return -1;
+    }
+
+    n = (size_t)nerror;
+    size += n;
+
+    /* Return if the write buffer is full for now */
+    if (n != m)
+      break;
+  }
+
+  mask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+  if (oldmask != mask)
+    tport_tls_set_events(self);
+
+  return size;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,435 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_udp.c UDP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <sys/uio.h>
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* UDP */
+
+static
+int tport_udp_init_client(tport_primary_t *pri,
+			  tp_name_t tpn[1],
+			  su_addrinfo_t *ai,
+			  tagi_t const *tags,
+			  char const **return_culprit);
+
+tport_vtable_t const tport_udp_client_vtable =
+{
+  "udp", tport_type_client,
+  sizeof (tport_primary_t),
+  tport_udp_init_client,
+  NULL,
+  NULL,
+  NULL,
+  sizeof (tport_t),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_dgram,
+  tport_send_dgram,
+};
+
+tport_vtable_t const tport_udp_vtable =
+{
+  "udp", tport_type_local,
+  sizeof (tport_primary_t),
+  tport_udp_init_primary,
+  NULL,
+  NULL,
+  NULL,
+  sizeof (tport_t),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  tport_recv_dgram,
+  tport_send_dgram,
+};
+
+static void tport_check_trunc(tport_t *tp, su_addrinfo_t *ai);
+
+int tport_udp_init_primary(tport_primary_t *pri,
+			   tp_name_t tpn[1],
+			   su_addrinfo_t *ai,
+			   tagi_t const *tags,
+			   char const **return_culprit)
+{
+  unsigned rmem = 0, wmem = 0;
+  int events = SU_WAIT_IN;
+  int s;
+
+  s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+  if (s == INVALID_SOCKET)
+    return *return_culprit = "socket", -1;
+
+  pri->pri_primary->tp_socket = s;
+
+  if (tport_bind_socket(s, ai, return_culprit) < 0)
+    return -1;
+
+  tport_set_tos(s, ai, pri->pri_params->tpp_tos);
+
+#if HAVE_IP_RECVERR
+  if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
+    int const one = 1;
+    if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) {
+      if (ai->ai_family == AF_INET)
+	SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno())));
+    }
+    events |= SU_WAIT_ERR;
+  }
+#endif
+#if HAVE_IPV6_RECVERR
+  if (ai->ai_family == AF_INET6) {
+    int const one = 1;
+    if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)
+      SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())));
+    events |= SU_WAIT_ERR;
+  }
+#endif
+
+  tl_gets(tags, 
+	  TPTAG_UDP_RMEM_REF(rmem),
+	  TPTAG_UDP_WMEM_REF(wmem),
+	  TAG_END());
+
+  if (rmem != 0 && 
+      setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rmem, sizeof rmem) < 0) {
+    SU_DEBUG_3(("setsockopt(SO_RCVBUF): %s\n", 
+		su_strerror(su_errno())));
+  }
+
+  if (wmem != 0 && 
+      setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&wmem, sizeof wmem) < 0) {
+    SU_DEBUG_3(("setsockopt(SO_SNDBUF): %s\n", 
+		su_strerror(su_errno())));
+  }
+
+  pri->pri_primary->tp_events = events;
+
+  tport_init_compressor(pri->pri_primary, tpn->tpn_comp, tags);
+
+  tport_check_trunc(pri->pri_primary, ai);
+
+  tport_stun_server_add_socket(pri->pri_primary);
+
+  return 0;
+}
+
+static
+int tport_udp_init_client(tport_primary_t *pri,
+			  tp_name_t tpn[1],
+			  su_addrinfo_t *ai,
+			  tagi_t const *tags,
+			  char const **return_culprit)
+{
+  pri->pri_primary->tp_conn_orient = 1;
+  return 0;
+}
+
+/** Runtime test making sure MSG_TRUNC work as expected */
+static void tport_check_trunc(tport_t *tp, su_addrinfo_t *ai)
+{
+#if HAVE_MSG_TRUNC
+  ssize_t n;
+  char buffer[2];
+  su_sockaddr_t su[1];
+  socklen_t sulen = sizeof su;
+
+  n = su_sendto(tp->tp_socket,
+		"TEST", 4, 0,
+		(void *)ai->ai_addr, ai->ai_addrlen);
+
+  for (;;) {
+    n = su_recvfrom(tp->tp_socket, buffer, sizeof buffer, MSG_TRUNC, 
+		    (void *)&su, &sulen);
+
+    if (n > (ssize_t)sizeof buffer) {
+      tp->tp_trunc = 1;
+      return;
+    }
+
+    /* XXX - check that su and tp->tp_addrinfo->ai_addr match */
+
+    return;
+  }
+#endif
+}
+
+/** Receive datagram.
+ *
+ * @retval -1 error
+ * @retval 0  end-of-stream  
+ * @retval 1  normal receive (should never happen)
+ * @retval 2  incomplete recv, call me again (should never happen)
+ * @retval 3  STUN keepalive, ignore
+ */
+int tport_recv_dgram(tport_t *self)
+{
+  msg_t *msg;
+  ssize_t n, veclen;
+  su_addrinfo_t *ai;
+  su_sockaddr_t *from;
+  socklen_t fromlen;
+  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+  uint8_t sample[1];
+
+  /* Simulate packet loss */
+  if (self->tp_params->tpp_drop && 
+      (unsigned)su_randint(0, 1000) < self->tp_params->tpp_drop) {
+    su_recv(self->tp_socket, sample, 1, 0);
+    SU_DEBUG_3(("tport(%p): simulated packet loss!\n", self));
+    return 0;
+  }
+
+  assert(self->tp_msg == NULL);
+
+  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, 65536, 1);
+  if (veclen < 0)
+    return -1;
+
+  msg = self->tp_msg;
+
+  ai = msg_addrinfo(msg);
+  from = (su_sockaddr_t *)ai->ai_addr, fromlen = (socklen_t)(ai->ai_addrlen);
+
+  n = su_vrecv(self->tp_socket, iovec, veclen, 0, from, &fromlen);
+  
+  ai->ai_addrlen = fromlen;
+  
+  if (n == SOCKET_ERROR) {
+    int error = su_errno();
+    msg_destroy(msg); self->tp_msg = NULL;
+    su_seterrno(error);
+
+    if (su_is_blocking(error))
+      return 0;
+    else
+      return -1;
+  }
+  else if (n <= 1) {
+    SU_DEBUG_1(("%s(%p): runt of "MOD_ZD" bytes\n", "tport_recv_dgram", self, n));
+    msg_destroy(msg), self->tp_msg = NULL;
+    return 0;
+  }
+
+  SU_CANONIZE_SOCKADDR(from);
+
+  if (self->tp_master->mr_dump_file)
+    tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+  *sample = *((uint8_t *)iovec[0].mv_base);
+
+  /* Commit received data into buffer. This may relocate iovec contents */
+  msg_recv_commit(msg, n, 1);
+
+  if ((sample[0] & 0xf8) == 0xf8)
+    /* SigComp */
+    return tport_recv_comp_dgram(self, self->tp_comp, &self->tp_msg, 
+				 from, fromlen);
+  else if (sample[0] == 0 || sample[0] == 1)
+    /* STUN request or response */
+    return tport_recv_stun_dgram(self, &self->tp_msg, from, fromlen);
+  else
+    return 0;
+}
+
+/** Send using su_vsend(). Map IPv4 addresses as IPv6 addresses, if needed. */
+ssize_t tport_send_dgram(tport_t const *self, msg_t *msg, 
+			 msg_iovec_t iov[], 
+			 size_t iovused)
+{
+  su_sockaddr_t su[1];
+  socklen_t sulen = sizeof su;
+
+  if (tport_is_connection_oriented(self))
+    return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+
+  msg_get_address(msg, su, &sulen);
+
+#if SU_HAVE_IN6 && defined(IN6_INADDR_TO_V4MAPPED)
+  if (su->su_family == AF_INET && self->tp_addrinfo->ai_family == AF_INET6) {
+    su_sockaddr_t su0[1];
+
+    memset(su0, 0, sizeof su0);
+
+    su0->su_family = self->tp_addrinfo->ai_family;
+    su0->su_port = su->su_port;
+
+    IN6_INADDR_TO_V4MAPPED(&su->su_sin.sin_addr, &su0->su_sin6.sin6_addr);
+
+    memcpy(su, su0, sulen = sizeof(su0->su_sin6));
+  }
+#endif
+
+  su_soerror(self->tp_socket); /* XXX - we *still* have a race condition */
+
+  return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, su, sulen);
+}
+
+
+#if !HAVE_IP_RECVERR && !HAVE_IPV6_RECVERR
+
+/** Process UDP error event. */
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1])
+{
+  if (tport_is_connection_oriented(self))
+    name[0] = self->tp_addr[0];
+  return su_soerror(self->tp_socket);
+}
+
+#else
+
+/** Process UDP error event. */
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1])
+{
+  struct cmsghdr *c;
+  struct sock_extended_err *ee;
+  su_sockaddr_t *from;
+  char control[512];
+  char errmsg[64 + 768];
+  struct iovec iov[1];
+  struct msghdr msg[1] = {{ 0 }};
+  int n;
+
+  msg->msg_name = name, msg->msg_namelen = sizeof(*name);
+  msg->msg_iov = iov, msg->msg_iovlen = 1;
+  iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
+  msg->msg_control = control, msg->msg_controllen = sizeof(control);
+
+  n = recvmsg(self->tp_socket, msg, MSG_ERRQUEUE);
+
+  if (n < 0) {
+    int err = su_errno();
+    if (!su_is_blocking(err))
+      SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(err)));
+    return 0;
+  }
+
+  if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {
+    SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));
+    return 0;
+  }
+
+  if (msg->msg_flags & MSG_CTRUNC) {
+    SU_DEBUG_1(("%s: extended error was truncated\n", __func__));
+    return 0;
+  }
+
+  if (msg->msg_flags & MSG_TRUNC) {
+    /* ICMP message may contain original message... */
+    SU_DEBUG_3(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));
+  }
+
+  /* Go through the ancillary data */
+  for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
+    if (0
+#if HAVE_IP_RECVERR
+	|| (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR)
+#endif
+#if HAVE_IPV6_RECVERR
+	|| (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR)
+#endif
+	) {
+      char info[128];
+      char const *origin;
+
+      ee = (struct sock_extended_err *)CMSG_DATA(c);
+      from = (su_sockaddr_t *)SO_EE_OFFENDER(ee);
+      info[0] = '\0';
+
+      switch (ee->ee_origin) {
+      case SO_EE_ORIGIN_LOCAL:
+	origin = "local";
+	break;
+      case SO_EE_ORIGIN_ICMP:
+	origin = "icmp";
+	snprintf(info, sizeof(info), " type=%u code=%u", 
+		 ee->ee_type, ee->ee_code);
+	break;
+      case SO_EE_ORIGIN_ICMP6:
+	origin = "icmp6";
+	snprintf(info, sizeof(info), " type=%u code=%u", 
+		ee->ee_type, ee->ee_code);
+	break;
+      case SO_EE_ORIGIN_NONE:
+	origin = "none";
+	break;
+      default:
+	origin = "unknown";
+	break;
+      }
+
+      if (ee->ee_info)
+	snprintf(info + strlen(info), sizeof(info) - strlen(info), 
+		 " info=%08x", ee->ee_info);
+
+      SU_DEBUG_3(("%s: %s (%d) [%s%s]\n",
+		  __func__, su_strerror(ee->ee_errno), ee->ee_errno, 
+		  origin, info));
+      if (from->su_family != AF_UNSPEC)
+	SU_DEBUG_3(("\treported by [%s]:%u\n",
+		    inet_ntop(from->su_family, SU_ADDR(from), 
+			      info, sizeof(info)),
+		    ntohs(from->su_port)));
+
+      if (msg->msg_namelen == 0)
+	name->su_family = AF_UNSPEC;
+
+      SU_CANONIZE_SOCKADDR(name);
+
+      return ee->ee_errno;
+    }
+  }
+
+  return 0;
+}
+#endif

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+2005-07-18  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Initial import of the module to Sofia-SIP tree.

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+PROJECT_NAME         = "url"
+OUTPUT_DIRECTORY     = ../docs/html/url
+
+INPUT 		     = url.docs sofia-sip . 
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES             += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE     = ../docs/url.doxytags
+
+PREDEFINED += "URL_DLL"

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+#
+# Makefile.am for url module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = 	-I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = 	liburl.la
+
+check_PROGRAMS = 	torture_url test_urlmap
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES =		url_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+			sofia-sip/url.h sofia-sip/url_tag.h \
+			sofia-sip/url_tag_class.h
+
+liburl_la_SOURCES = 	url.c url_tag.c url_tag_ref.c
+
+COVERAGE_INPUT = 	$(liburl_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = 		liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_urlmap_SOURCES = 	urlmap.c urlmap.h
+test_urlmap_CFLAGS =	$(CFLAGS) -DTEST_URLMAP=1
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST =		Doxyfile url.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = 		torture_url test_urlmap
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = 	DLLREF=1

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,726 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for url module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) torture_url.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = torture_url$(EXEEXT) test_urlmap$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/url
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+liburl_la_LIBADD =
+am_liburl_la_OBJECTS = url.lo url_tag.lo url_tag_ref.lo
+liburl_la_OBJECTS = $(am_liburl_la_OBJECTS)
+am_test_urlmap_OBJECTS = test_urlmap-urlmap.$(OBJEXT)
+test_urlmap_OBJECTS = $(am_test_urlmap_OBJECTS)
+test_urlmap_LDADD = $(LDADD)
+test_urlmap_DEPENDENCIES = liburl.la ../bnf/libbnf.la ../su/libsu.la
+torture_url_SOURCES = torture_url.c
+torture_url_OBJECTS = torture_url.$(OBJEXT)
+torture_url_LDADD = $(LDADD)
+torture_url_DEPENDENCIES = liburl.la ../bnf/libbnf.la ../su/libsu.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) torture_url.c
+DIST_SOURCES = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) \
+	torture_url.c
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+		-I$(srcdir)/../ipt -I../ipt \
+		-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = liburl.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = url_tag_ref.c
+nobase_include_sofia_HEADERS = \
+			sofia-sip/url.h sofia-sip/url_tag.h \
+			sofia-sip/url_tag_class.h
+
+liburl_la_SOURCES = url.c url_tag.c url_tag_ref.c
+COVERAGE_INPUT = $(liburl_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = liburl.la \
+			../bnf/libbnf.la \
+			../su/libsu.la
+
+test_urlmap_SOURCES = urlmap.c urlmap.h
+test_urlmap_CFLAGS = $(CFLAGS) -DTEST_URLMAP=1
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile url.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_url test_urlmap
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) 
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+# rules for building tag files
+TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+INTERNAL_INCLUDES = \
+	-I$(srcdir)/../features -I../features \
+	-I$(srcdir)/../ipt -I../ipt \
+	-I$(srcdir)/../iptsec -I../iptsec \
+	-I$(srcdir)/../bnf -I../bnf \
+	-I$(srcdir)/../http -I../http \
+	-I$(srcdir)/../msg -I../msg \
+	-I$(srcdir)/../nth -I../nth \
+	-I$(srcdir)/../nta -I../nta \
+	-I$(srcdir)/../nea -I../nea \
+	-I$(srcdir)/../nua -I../nua \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sdp -I../sdp \
+	-I$(srcdir)/../sip -I../sip \
+	-I$(srcdir)/../soa -I../soa \
+	-I$(srcdir)/../sresolv -I../sresolv \
+	-I$(srcdir)/../tport -I../tport \
+	-I$(srcdir)/../stun -I../stun \
+	-I$(srcdir)/../url -I../url \
+	-I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+TAG_DLL_FLAGS = DLLREF=1
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  libsofia-sip-ua/url/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libsofia-sip-ua/url/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+liburl.la: $(liburl_la_OBJECTS) $(liburl_la_DEPENDENCIES) 
+	$(LINK)  $(liburl_la_LDFLAGS) $(liburl_la_OBJECTS) $(liburl_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+test_urlmap$(EXEEXT): $(test_urlmap_OBJECTS) $(test_urlmap_DEPENDENCIES) 
+	@rm -f test_urlmap$(EXEEXT)
+	$(LINK) $(test_urlmap_LDFLAGS) $(test_urlmap_OBJECTS) $(test_urlmap_LDADD) $(LIBS)
+torture_url$(EXEEXT): $(torture_url_OBJECTS) $(torture_url_DEPENDENCIES) 
+	@rm -f torture_url$(EXEEXT)
+	$(LINK) $(torture_url_LDFLAGS) $(torture_url_OBJECTS) $(torture_url_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_urlmap-urlmap.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_url.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url_tag_ref.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+test_urlmap-urlmap.o: urlmap.c
+ at am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -MT test_urlmap-urlmap.o -MD -MP -MF "$(DEPDIR)/test_urlmap-urlmap.Tpo" -c -o test_urlmap-urlmap.o `test -f 'urlmap.c' || echo '$(srcdir)/'`urlmap.c; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/test_urlmap-urlmap.Tpo" "$(DEPDIR)/test_urlmap-urlmap.Po"; else rm -f "$(DEPDIR)/test_urlmap-urlmap.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='urlmap.c' object='test_urlmap-urlmap.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -c -o test_urlmap-urlmap.o `test -f 'urlmap.c' || echo '$(srcdir)/'`urlmap.c
+
+test_urlmap-urlmap.obj: urlmap.c
+ at am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -MT test_urlmap-urlmap.obj -MD -MP -MF "$(DEPDIR)/test_urlmap-urlmap.Tpo" -c -o test_urlmap-urlmap.obj `if test -f 'urlmap.c'; then $(CYGPATH_W) 'urlmap.c'; else $(CYGPATH_W) '$(srcdir)/urlmap.c'; fi`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/test_urlmap-urlmap.Tpo" "$(DEPDIR)/test_urlmap-urlmap.Po"; else rm -f "$(DEPDIR)/test_urlmap-urlmap.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='urlmap.c' object='test_urlmap-urlmap.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -c -o test_urlmap-urlmap.obj `if test -f 'urlmap.c'; then $(CYGPATH_W) 'urlmap.c'; else $(CYGPATH_W) '$(srcdir)/urlmap.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__vpath_adj) \
+	  echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  $(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+uninstall-nobase_include_sofiaHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@$(am__vpath_adj_setup) \
+	list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
+	  $(am__vpath_adj) \
+	  echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+		echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+		xfail=`expr $$xfail + 1`; \
+		echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      echo "SKIP: $$tst"; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    skipped="($$skip tests were not run)"; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_include_sofiaHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man \
+	install-nobase_include_sofiaHEADERS install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-nobase_include_sofiaHEADERS
+
+
+built-sources: $(BUILT_SOURCES)
+
+clean-built-sources:
+	-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+	$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at ENABLE_COVERAGE_TRUE@	@$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+
+../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
+ ../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
+ ../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
+ ../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
+ ../tport/libtport.la ../url/liburl.la:
+	$(MAKE) -C $(@D) $(@F)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,315 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/url.h
+ *
+ * URL struct and helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun  8 19:28:55 2000 ppessi
+ */
+
+#ifndef URL_H_TYPES
+#define URL_H_TYPES
+
+/** Recognized URL schemes (value of url_t.url_type). */
+enum url_type_e {
+  url_invalid = -2,		/**< Invalid url. */
+  url_unknown = -1,		/**< Unknown scheme. */
+  url_any = 0,			/**< @c "*" */
+  url_sip,			/**< @c "sip:" */
+  url_sips,			/**< @c "sips:" */
+  url_tel,			/**< @c "tel:" */
+  url_fax,			/**< @c "fax:" */
+  url_modem,			/**< @c "modem:" */
+  url_http,			/**< @c "http:" */
+  url_https,			/**< @c "https:" */
+  url_ftp,			/**< @c "ftp:" */
+  url_file,			/**< @c "file:" */
+  url_rtsp,			/**< @c "rtsp:" */
+  url_rtspu,			/**< @c "rtspu:" */
+  url_mailto,			/**< @c "mailto:" */
+  url_im,			/**< @c "im:" (simple instant messaging) */
+  url_pres,			/**< @c "pres:" (simple presence) */
+  url_cid,			/**< @c "cid:" (Content-ID) */
+  url_msrp,			/**< @c "msrp:" (message session relay)  */
+  url_msrps,			/**< @c "msrps:" (new in @VERSION_1_12_2) */
+  url_wv,			/**< @c "wv:" (Wireless village) */
+  _url_none
+};
+
+/** URL structure. 
+ * 
+ * This structure is used to present a parsed URL.
+ */
+typedef struct {
+  char                url_pad[sizeof(void *) - 2];   
+				    /**< Zero pad for URL_STRING_P(). */
+  signed char         url_type;	    /**< URL type (url_type_e). */
+  char                url_root;	    /**< Nonzero if root "//" */
+  char const         *url_scheme;   /**< URL type as string. */
+  char const         *url_user;	    /**< User part */
+  char const         *url_password; /**< Password */
+  char const         *url_host;     /**< Host part */
+  char const         *url_port;     /**< Port */
+  char const         *url_path;     /**< Path part, starts with "/" */
+  char const         *url_params;   /**< Parameters (separated by ;) */
+  char const         *url_headers;  /**< Headers (separated by ? and &) */
+  char const         *url_fragment; /**< Fragment (separated by #) */
+} url_t;
+
+enum { 
+  /** Maximum size of a URL. */
+  URL_MAXLEN = 65536
+};
+
+/** Type to present either a parsed URL or string.
+ * 
+ * The union type url_string_t is used to pass a parsed URL or string as a
+ * parameter. The URL_STRING_P() checks if a passed pointer points to a
+ * string or a parsed URL. Testing requires that the first character of the
+ * string is nonzero. Use URL_STRING_MAKE() to properly cast a string
+ * pointer as a pointer to url_string_t.
+ */
+typedef union {
+  char  us_str[URL_MAXLEN];	/**< URL as a string. */
+  url_t us_url[1];		/**< Parsed URL. */
+} url_string_t;
+
+#endif
+
+#ifndef URL_H
+/** Defined when <sofia-sip/url.h> has been included. */
+#define URL_H
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Convert a string to a url struct. */ 
+SOFIAPUBFUN url_t *url_make(su_home_t *h, char const *str);
+
+/** Convert a string formatting result to a url struct. */
+SOFIAPUBFUN url_t *url_format(su_home_t *h, char const *fmt, ...);
+
+/** Convert #url_t to a string allocated from @a home */
+SOFIAPUBFUN char *url_as_string(su_home_t *home, url_t const *url);
+
+/** Duplicate the url to memory allocated via home */ 
+SOFIAPUBFUN url_t *url_hdup(su_home_t *h, url_t const *src);
+
+/** Sanitize a URL. */
+SOFIAPUBFUN int url_sanitize(url_t *u);
+
+/** Get URL scheme by type. */
+SOFIAPUBFUN char const *url_scheme(enum url_type_e type);
+
+/* ---------------------------------------------------------------------- */
+/* URL comparison */
+
+/** Compare two URLs lazily. */
+SOFIAPUBFUN int url_cmp(url_t const *a, url_t const *b);
+
+/** Compare two URLs conservatively. */
+SOFIAPUBFUN int url_cmp_all(url_t const *a, url_t const *b);
+
+/* ---------------------------------------------------------------------- */
+/* Parameter handling */
+
+/** Search for a parameter. */
+SOFIAPUBFUN isize_t url_param(char const *params, char const *tag,
+			      char value[], isize_t vlen);
+
+/** Check for a parameter. */
+SOFIAPUBFUN int url_has_param(url_t const *url, char const *name);
+
+/** Check for a presence of a parameter in string. */
+SOFIAPUBFUN isize_t url_have_param(char const *params, char const *tag);
+
+/** Add a parameter. */
+SOFIAPUBFUN int url_param_add(su_home_t *h, url_t *url, char const *param);
+
+/** Strip transport-specific stuff away from URI. */
+SOFIAPUBFUN int url_strip_transport(url_t *u);
+
+/** Strip parameter away from URI. */
+SOFIAPUBFUN char *url_strip_param_string(char *params, char const *name);
+
+/** Test if url has any transport-specific stuff. */
+SOFIAPUBFUN int url_have_transport(url_t const *u);
+
+/* ---------------------------------------------------------------------- */
+/* Query handling */
+
+/** Convert a URL query to a header string. */
+SOFIAPUBFUN char *url_query_as_header_string(su_home_t *home, 
+					     char const *query);
+
+/* ---------------------------------------------------------------------- */
+/* Handling url-escque strings */
+
+/** Test if string contains url-reserved characters. */
+SOFIAPUBFUN int url_reserved_p(char const *s);
+
+/** Escape a string. */
+SOFIAPUBFUN char *url_escape(char *d, char const *s, char const reserved[]);
+
+/** Calculate length of string when escaped. */
+SOFIAPUBFUN isize_t url_esclen(char const *s, char const reserved[]);
+
+/** Unescape characters from string */
+SOFIAPUBFUN size_t url_unescape_to(char *d, char const *s, size_t n);
+
+/** Unescape a string */
+SOFIAPUBFUN char *url_unescape(char *d, char const *s);
+
+#define URL_RESERVED_CHARS ";/?:@&=+$,"
+
+/* ---------------------------------------------------------------------- */
+/* Initializing */
+
+/** Initializer for an #url_t structure. @HI 
+ * 
+ * The macro URL_INIT_AS() is used to initialize a #url_t structure with a
+ * known url type:
+ * @code
+ *   url_t urls[2] = { URL_INIT_AS(sip), URL_INIT_AS(http) };
+ * @endcode
+ */
+#define URL_INIT_AS(type)  \
+  { "\0\0", url_##type, 0, url_##type != url_any ? #type : "*" }
+
+/** Init a url structure as given type */
+SOFIAPUBFUN void url_init(url_t *url, enum url_type_e type);
+
+/* ---------------------------------------------------------------------- */
+/* Resolving helpers */
+
+/** Return default port number corresponding to the url type. */
+SOFIAPUBFUN char const *url_port_default(enum url_type_e url_type);
+
+/** Return default transport name corresponding to the url type */
+SOFIAPUBFUN char const *url_tport_default(enum url_type_e url_type);
+
+/** Return the URL port string, using default port if not present. */
+SOFIAPUBFUN char const *url_port(url_t const *u);
+
+/** Return the URL port string, using default port if none present. */
+#define URL_PORT(u) \
+  ((u) && (u)->url_port ? (u)->url_port : \
+  url_port_default((u) ? (u)->url_type : url_any))
+
+/* ---------------------------------------------------------------------- */
+/* url_string_t handling */
+
+/** Test if a pointer to #url_string_t is a string 
+ * (not a pointer to a #url_t structure). */
+#define URL_STRING_P(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+
+/** Test if a pointer to #url_string_t is a string 
+ * (not a pointer to a #url_t structure). */
+#define URL_IS_STRING(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+SOFIAPUBFUN int url_string_p(url_string_t const * url);
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+SOFIAPUBFUN int url_is_string(url_string_t const * url);
+
+/** Cast a string to a #url_string_t. @HI */
+#define URL_STRING_MAKE(s) \
+  ((url_string_t *)((s) && *((char *)(s)) ? (s) : NULL))
+
+/* ---------------------------------------------------------------------- */
+/* Printing URL */
+
+/** Format string used when printing url with printf(). @HI */
+#define URL_PRINT_FORMAT "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+#define URL_FORMAT_STRING URL_PRINT_FORMAT
+
+/** Argument list used when printing url with printf(). @HI */
+#define URL_PRINT_ARGS(u) \
+  (u)->url_scheme ? (u)->url_scheme : "",	\
+  (u)->url_type != url_any && (u)->url_scheme && (u)->url_scheme[0] \
+    ? ":" : "", \
+  (u)->url_root && ((u)->url_host || (u)->url_user) ? "//" : "", \
+  (u)->url_user ? (u)->url_user : "", \
+  (u)->url_user && (u)->url_password ? ":" : "", \
+  (u)->url_user && (u)->url_password ? (u)->url_password : "", \
+  (u)->url_user && (u)->url_host ? "@" : "", \
+  (u)->url_host ? (u)->url_host : "", \
+  (u)->url_host && (u)->url_port ? ":" : "", \
+  (u)->url_host && (u)->url_port ? (u)->url_port : "", \
+  (u)->url_root && (u)->url_path ? "/" : "", \
+  (u)->url_path ? (u)->url_path : "", \
+  (u)->url_params ? ";" : "", (u)->url_params ? (u)->url_params : "", \
+  (u)->url_headers ? "?" : "", (u)->url_headers ? (u)->url_headers : "", \
+  (u)->url_fragment ? "#" : "", (u)->url_fragment ? (u)->url_fragment : ""
+
+/* ---------------------------------------------------------------------- */
+/* URL digests */
+
+struct su_md5_t;
+
+/** Update MD5 sum with URL contents. */
+SOFIAPUBFUN void url_update(struct su_md5_t *md5, url_t const *url);
+
+/** Calculate a digest from URL contents. */
+SOFIAPUBFUN void url_digest(void *hash, int hsize,
+			    url_t const *, char const *key);
+
+/* ---------------------------------------------------------------------- */
+/* Parsing and manipulating URLs */
+
+/** Decode a URL. */
+SOFIAPUBFUN int url_d(url_t *url, char *s);
+
+/** Calculate the encoding length of URL. */
+SOFIAPUBFUN isize_t url_len(url_t const * url);
+
+/** Encode a URL. */
+SOFIAPUBFUN issize_t url_e(char buffer[], isize_t n, url_t const *url);
+
+/** Encode a URL: use @a buf up to @a end. @HI */
+#define URL_E(buf, end, url) \
+  (buf) += url_e((buf), (buf) < (end) ? (end) - (buf) : 0, (url))
+
+/** Calculate the size of srings attached to the url. */
+SOFIAPUBFUN isize_t url_xtra(url_t const * url);
+
+/** Duplicate the url in the provided memory area. */ 
+SOFIAPUBFUN issize_t url_dup(char *, isize_t , url_t *dst, url_t const *src);
+
+/** Duplicate the url: use @a buf up to @a end. @HI */ 
+#define URL_DUP(buf, end, dst, src) \
+  (buf) += url_dup((buf), (isize_t)((buf) < (end) ? (end) - (buf) : 0), (dst), (src))
+
+SOFIA_END_DECLS
+#endif
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URL_TAG_H
+/** Defined when <sofia-sip/url_tag.h> has been included. */
+#define URL_TAG_H
+/**@file  url_tag.h
+ * @brief Tags for URLs
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef URL_H
+#define URL_H
+#include <sofia-sip/url.h>		/* Include only types */
+#undef URL_H
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Filter tag matching any url tag. */
+#define URLTAG_ANY()         urltag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t urltag_any;
+
+SOFIAPUBVAR tag_typedef_t urltag_url;
+
+/** Tag list item for an URL. */
+#define URLTAG_URL(u)      urltag_url, urltag_url_v(u)
+
+SOFIAPUBVAR tag_typedef_t urltag_url_ref;
+
+#define URLTAG_URL_REF(u)  urltag_url_ref, urltag_url_vr(&(u))
+
+#if SU_HAVE_INLINE
+su_inline 
+tag_value_t urltag_url_v(void const *v) { return (tag_value_t)v; }
+su_inline 
+tag_value_t urltag_url_vr(url_string_t const **vp) { return(tag_value_t)vp; }
+#else
+#define urltag_url_v(v)   (tag_value_t)(v)
+#define urltag_url_vr(vr) (tag_value_t)(vr)
+#endif
+
+
+SOFIA_END_DECLS
+#endif
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URL_TAG_CLASS_H
+/**Defined when <sofia-sip/url_tag_class.h> has been included. */
+#define URL_TAG_CLASS_H 
+/**@file  url_tag_class.h
+ * @brief Tag classes for URLs
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBVAR tag_class_t url_tag_class[1];
+
+#define URLTAG_TYPEDEF(t) TAG_TYPEDEF(t, url)
+
+SOFIA_END_DECLS
+
+#endif
+
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1061 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE torture_url.c Test functions for url parser
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/url.h"
+#include "sofia-sip/url_tag.h"
+
+static int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "torture_url";
+
+void usage(void)
+{
+  fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+unsigned char hash1[16], hash2[16];
+
+/* test unquoting and canonizing */
+int test_quote(void)
+{
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t *u;
+  char s[] = "%73ip:q%74est%01:%01%02%00 at host%2enokia.com;%70aram=%01%02";
+  char c[] = "sip:qtest%01:%01%02%00 at host.nokia.com;param=%01%02";
+  char *d;
+
+#define RESERVED        ";/?:@&=+$,"
+#define DELIMS          "<>#%\""
+#define UNWISE		"{}|\\^[]`"
+#define EXCLUDED	RESERVED DELIMS UNWISE
+
+  char escaped[1 + 3 * 23 + 1];
+
+#define UNRESERVED    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                      "abcdefghijklmnopqrstuvwxyz" \
+                      "0123456789" \
+                      "-_.!~*'()"
+  
+  char unreserved[26 + 26 + 10 + 9 + 1];
+  
+  BEGIN();
+
+  d = url_as_string(home, (url_t *)"sip:joe at example.com");
+  TEST_S(d, "sip:joe at example.com");
+
+  TEST(strlen(EXCLUDED), 23);
+  TEST(strlen(UNRESERVED), 71);
+
+  TEST_1(!url_reserved_p("foo"));
+  TEST_1(!url_reserved_p(""));
+  TEST_1(url_reserved_p("foobar:bar"));
+
+  TEST_SIZE(url_esclen("a" EXCLUDED, ""), 
+	    1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
+  TEST_SIZE(url_esclen("a" EXCLUDED, DELIMS UNWISE), 
+	    1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
+  TEST_SIZE(url_esclen("a" EXCLUDED, EXCLUDED), 1 + 3 * strlen(EXCLUDED));
+  TEST_SIZE(url_esclen("a" EXCLUDED, NULL), 1 + 3 * strlen(EXCLUDED));
+
+  TEST_S(url_escape(escaped, "a" EXCLUDED, NULL),
+	 "a%3B%2F%3F%3A%40%26%3D%2B%24%2C"
+	 "%3C%3E%23%25%22"
+	 "%7B%7D%7C%5C%5E%5B%5D%60");
+  TEST_S(url_unescape(escaped, escaped), "a" EXCLUDED);
+
+  TEST_SIZE(url_esclen(UNRESERVED, NULL), strlen(UNRESERVED));
+  TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED);
+  TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED);
+
+  d = "%73ip:%55@%68";
+  u = url_hdup(home, (url_t *)d); TEST_1(u);
+  url_digest(hash1, sizeof(hash1), u, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  d = "sip:u at h";
+  u = url_hdup(home, (url_t *)d); TEST_1(u);
+  url_digest(hash1, sizeof(hash1), u, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  u = url_hdup(home, (url_t *)s); TEST_1(u);
+  d = url_as_string(home, u); TEST_1(d);
+  TEST_S(d, c);
+
+  d = "sip:&=+$,;?/:&=+$, at host:56001;param=+$,/:@&;another=@"
+    "?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c";
+  u = url_hdup(home, (url_t *)d); TEST_1(u);
+  TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C");
+  url_digest(hash1, sizeof(hash1), u, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  u = url_hdup(home, (url_t *)s); TEST_1(u);
+  d = url_as_string(home, u); TEST_1(d);
+  TEST_S(d, c);
+
+  d = "http://&=+$,;:&=+$,;@host:8080/foo;param=+$,/:@&;another=@?query=" RESERVED;
+  u = url_hdup(home, (url_t *)d); TEST_1(u);
+  url_digest(hash1, sizeof(hash1), u, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  u = url_hdup(home, (url_t *)s); TEST_1(u);
+  d = url_as_string(home, u); TEST_1(d);
+  TEST_S(d, c);
+
+  url_digest(hash1, sizeof(hash1), u, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t const *)s, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  url_digest(hash2, sizeof(hash2), (url_t const *)c, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  END();
+}
+
+
+int test_any(void)
+{
+  /* Test any (*) urls */
+  url_t any[1] = { URL_INIT_AS(any) };
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t *u, url[1];
+  char *tst;
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_any), "*");
+  TEST_S(url_scheme(url_mailto), "mailto");
+  TEST_S(url_scheme(url_im), "im");
+  TEST_S(url_scheme(url_cid), "cid");
+  TEST_S(url_scheme(url_msrp), "msrp");
+  TEST_S(url_scheme(url_msrps), "msrps");
+
+  TEST_1(tst = su_strdup(home, "*"));
+  TEST(url_d(url, tst), 0);
+  TEST(url_cmp(any, url), 0);
+  TEST(url->url_type, url_any);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_any);
+  TEST(url_cmp(any, u), 0);
+  
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)"*", NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  {
+    char buf[6];
+    
+    TEST_1(u = url_hdup(home, (void *)"error"));
+    TEST_SIZE(url_xtra(u), 6);
+    TEST_SIZE(url_dup(buf, 6, url, u), 6);
+    TEST_S(buf, "error");
+  }
+
+  {
+    TEST_1(u = url_hdup(home, (void *)"scheme:test"));
+    TEST(u->url_type, url_unknown);
+  }
+
+  {
+    TEST_1(u = url_hdup(home, (void *)"*;param=foo?query=bar"));
+    TEST(u->url_type, url_unknown);
+    TEST_S(u->url_host, "*");
+    TEST_S(u->url_params, "param=foo");
+    TEST_S(u->url_headers, "query=bar");
+  }
+
+  {
+    TEST_1(u = url_hdup(home, (void *)"#foo"));
+    TEST(u->url_type, url_unknown);
+    TEST_S(u->url_fragment, "foo");
+  }
+
+  su_home_deinit(home);
+  
+  END();
+}
+
+int test_sip(void)
+{
+  /* sip urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t sip[1] = { URL_INIT_AS(sip) };
+  url_t *u, url[1];
+  char *tst, *s;
+  char sipurl0[] = 
+    "sip:pekka%2Epessi at nokia%2Ecom;method=%4D%45%53%53%41%47%45"
+    "?body=CANNED%20MSG";
+  char sipurl[] = 
+    "sip:user:pass at host:32;param=1"
+    "?From=foo at bar&To=bar at baz#unf";
+  char sip2url[] = 
+    "sip:user/path;tel-param:pass at host:32;param=1"
+    "?From=foo at bar&To=bar at baz#unf";
+  char sip2[sizeof(sipurl) + 32];
+  char sipsurl[] = 
+    "sips:user:pass at host:32;param=1"
+    "?From=foo at bar&To=bar at baz#unf";
+  size_t i, j;
+  url_t *a, *b;
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_sip), "sip");
+  TEST_S(url_scheme(url_sips), "sips");
+
+  memset(url, 255, sizeof url);
+
+  TEST(url_d(url, sipurl0), 0);
+
+  TEST(url->url_type, url_sip);
+  TEST(url->url_root, 0);
+  TEST_S(url->url_scheme, "sip");
+  TEST_S(url->url_user, "pekka.pessi");
+  TEST_P(url->url_password, NULL);
+  TEST_S(url->url_host, "nokia.com");
+  TEST_P(url->url_port, NULL);
+  TEST_P(url->url_path, NULL);
+  TEST_S(url->url_params, "method=MESSAGE");
+  TEST_S(url->url_headers, "body=CANNED%20MSG");
+  TEST_P(url->url_fragment, NULL);
+
+  TEST_S(url_query_as_header_string(home, url->url_headers),
+	 "\n\nCANNED MSG");
+  
+  sip->url_user = "user";
+  sip->url_password = "pass";
+  sip->url_host = "host";
+  sip->url_port = "32";
+  sip->url_params = "param=1";
+  sip->url_headers = "From=foo at bar&To=bar at baz";
+  sip->url_fragment = "unf";
+
+  memset(url, 255, sizeof url);
+
+  TEST_1(tst = su_strdup(home, sipurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(sip, url) == 0);
+  TEST(url->url_type, url_sip);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_sip);
+  TEST_1(url_cmp(sip, u) == 0);
+  TEST(url_e(sip2, sizeof(sip2), u), strlen(sipurl));
+  TEST_1(strcmp(sip2, sipurl) == 0);
+  TEST_SIZE(snprintf(sip2, sizeof(sip2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(sip)), strlen(sipurl));
+  TEST_1(strcmp(sip2, sipurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t const *)sipurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  TEST_1(tst = su_strdup(home, sip2url));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_S(url->url_user, "user/path;tel-param");
+
+  TEST_S(url_query_as_header_string(home, url->url_headers),
+	 "From:foo at bar\nTo:bar at baz");
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)sip2url, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  sip->url_type = url_sips; sip->url_scheme = "sips";
+
+  TEST_1(tst = su_strdup(home, sipsurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(sip, url) == 0);
+  TEST(url->url_type, url_sips);
+
+  /* Test url_dup() */
+  for (i = 0; i <= sizeof(sipsurl); i++) {
+    char buf[sizeof(sipsurl) + 1];
+    url_t dst[1];
+
+    buf[i] = '\377';
+    TEST_SIZE(url_dup(buf, i, dst, url), sizeof(sipsurl) - 1 - strlen("sips"));
+    TEST(buf[i], '\377');
+  }
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)sipsurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  u = url_hdup(home, (url_t*)"SIP:test at 127.0.0.1:55"); TEST_1(u);
+  TEST(u->url_type, url_sip);
+
+  TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1::55"), NULL);
+  TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1:55:"), NULL);
+  TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1:sip"), NULL);
+
+  for (i = 32; i <= 256; i++) {
+    char pu[512];
+    char param[512];
+
+    for (j = 0; j < i; j++)
+      param[j] = 'x';
+    param[j] = '\0';
+    memcpy(param, "x=", 2);
+
+    snprintf(pu, sizeof(pu), "sip:test at host;%s", param);
+    u = url_hdup(home, (url_t*)pu); TEST_1(u);
+    s = url_as_string(home, u);
+    TEST_S(pu, s);
+  }
+
+  s = su_strdup(home, "ttl;transport=tcp;ttl=15;ttl=;method=INVITE;ttl");
+  TEST_1(s);
+  s = url_strip_param_string(s, "ttl");
+  TEST_S(s, "transport=tcp;method=INVITE");
+
+  u = url_hdup(home, (void*)"sip:u:p at host:5060;maddr=127.0.0.1;transport=tcp");
+  TEST_1(u);
+  TEST_1(url_have_transport(u));
+  TEST_1(url_strip_transport(u));
+  TEST_P(u->url_params, NULL);
+  TEST_1(!url_have_transport(u));
+
+  u = url_hdup(home, (void*)"sip:u:p at host:5060;user=phone;ttl=1;isfocus");
+  TEST_1(u);
+  TEST_1(url_have_transport(u));
+  TEST_1(url_strip_transport(u));
+  TEST_S(u->url_params, "user=phone;isfocus");
+  TEST_1(!url_have_transport(u));
+
+  u = url_hdup(home, (void*)"sip:u:p at host:5060;maddr=127.0.0.1;user=phone");
+  TEST_1(u);
+  TEST_1(url_have_transport(u));
+  TEST_1(url_strip_transport(u));
+  TEST_S(u->url_params, "user=phone");
+  TEST_1(!url_have_transport(u));
+
+  u = url_hdup(home, (void*)"sip:u:p at host:5060;user=phone;transport=tcp");
+  TEST_1(u);
+  TEST_1(url_have_transport(u));  
+  TEST_1(url_strip_transport(u));
+  TEST_S(u->url_params, "user=phone");
+  TEST_1(!url_have_transport(u));
+  
+  u = url_hdup(home, (void*)"sip:u:p at host;user=phone;;");
+  TEST_1(u);
+  /* We don't have transport params */
+  TEST_1(!url_have_transport(u));
+  /* ...but we still strip empty params */
+  TEST_1(url_strip_transport(u));
+  TEST_S(u->url_params, "user=phone");
+  TEST_1(!url_have_transport(u));
+
+  u = url_hdup(home, (void*)"sip:u:p at host:5060;ttl=1;isfocus;transport=udp;");
+  TEST_1(u);
+  TEST_1(url_have_transport(u));
+  TEST_1(url_strip_transport(u));
+  TEST_S(u->url_params, "isfocus");
+  TEST_1(!url_have_transport(u));
+
+  a = url_hdup(home, (void *)"sip:172.21.55.55:5060");
+  b = url_hdup(home, (void *)"sip:172.21.55.55");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) == 0);
+  TEST(url_cmp_all(a, b), 0);
+
+  a = url_hdup(home, (void *)"sips:172.21.55.55:5060");
+  b = url_hdup(home, (void *)"sips:172.21.55.55");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) != 0);
+  TEST_1(url_cmp_all(a, b) < 0);
+
+  a = url_hdup(home, (void *)"sips:172.21.55.55:5061");
+  b = url_hdup(home, (void *)"sips:172.21.55.55");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) == 0);
+  TEST(url_cmp_all(a, b), 0);
+
+  a = url_hdup(home, (void *)"sip:my.domain:5060");
+  b = url_hdup(home, (void *)"sip:my.domain");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) > 0);
+  TEST_1(url_cmp_all(a, b) > 0);
+
+  a = url_hdup(home, (void *)"sips:my.domain:5061");
+  b = url_hdup(home, (void *)"sips:my.domain");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) > 0);
+  TEST_1(url_cmp_all(a, b) > 0);
+
+  a = url_hdup(home, (void *)"sip:my.domain");
+  b = url_hdup(home, (void *)"SIP:MY.DOMAIN");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) == 0);
+  TEST_1(url_cmp_all(a, b) == 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_wv(void)
+{
+  /* wv urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t wv[1] = { URL_INIT_AS(wv) };
+  url_t *u, url[1];
+  char *tst;
+  char wvurl[] = "wv:+12345678 at imps.com";
+  char wv2[sizeof(wvurl) + 32];
+  
+  BEGIN();
+
+  TEST_S(url_scheme(url_wv), "wv");
+
+  wv->url_user = "+12345678";
+  wv->url_host = "imps.com";
+  
+  TEST_1(tst = su_strdup(home, wvurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(wv, url) == 0);
+  TEST_1(url_cmp(url_hdup(home, (void *)"wv:+12345678 at imps.com"), url) == 0);
+  TEST(url->url_type, url_wv);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_wv);
+  TEST_1(url_cmp(wv, u) == 0);
+  TEST_SIZE(url_e(wv2, sizeof(wv2), u), strlen(wvurl));
+  TEST_1(strcmp(wv2, wvurl) == 0);
+  TEST_SIZE(snprintf(wv2, sizeof(wv2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(wv)), strlen(wvurl));
+  TEST_1(strcmp(wv2, wvurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)wvurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  TEST_1(u = url_hdup(home, (void*)"wv:/managers at imps.com"));
+  TEST_S(u->url_user, "/managers");
+
+  su_home_deinit(home);
+
+  END();
+}
+
+
+int test_tel(void)
+{
+  /* tel urls: RFC 3906 */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t tel[1] = { URL_INIT_AS(tel) };
+  url_t *u, url[1];
+  char *tst;
+  char telurl[] = 
+    "tel:+12345678"
+    ";param=1;param=2"
+    "?From=foo at bar&To=bar at baz#unf";
+  char tel2[sizeof(telurl) + 32];
+  url_t *a, *b;
+  
+  BEGIN();
+
+  TEST_S(url_scheme(url_tel), "tel");
+
+  tel->url_user = "+12345678";
+  tel->url_params = "param=1;param=2";
+  tel->url_headers = "From=foo at bar&To=bar at baz";
+  tel->url_fragment = "unf";
+  
+  TEST_1(tst = su_strdup(home, telurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(tel, url) == 0);
+  TEST_1(url_cmp(url_hdup(home, (url_t const *)"tel:+12345678"
+			  ";param=1;param=2"
+			  "?From=foo at bar&To=bar at baz#unf"), url) == 0);
+  TEST(url->url_type, url_tel);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_tel);
+  TEST_1(url_cmp(tel, u) == 0);
+  TEST_SIZE(url_e(tel2, sizeof(tel2), u), strlen(telurl));
+  TEST_1(strcmp(tel2, telurl) == 0);
+  TEST_SIZE(snprintf(tel2, sizeof(tel2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(tel)), strlen(telurl));
+  TEST_1(strcmp(tel2, telurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)telurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  a = url_hdup(home, (void *)"tel:+1.245.62357");
+  b = url_hdup(home, (void *)"tel:+(1).245.62357");
+  TEST_1(a); TEST_1(b);
+  TEST_1(url_cmp(a, b) == 0);
+  TEST_1(url_cmp_all(a, b) == 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_fax(void)
+{
+  /* fax urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t fax[1] = { URL_INIT_AS(fax) };
+  url_t *u, url[1];
+  char *tst;
+  char faxurl[] = 
+    "fax:+12345678"
+    ";param=1;param=2"
+    "?From=foo at bar&To=bar at baz#unf";
+  char fax2[sizeof(faxurl) + 32];
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_fax), "fax");
+
+  fax->url_user = "+12345678";
+  fax->url_params = "param=1;param=2";
+  fax->url_headers = "From=foo at bar&To=bar at baz";
+  fax->url_fragment = "unf";
+
+  TEST_1(tst = su_strdup(home, faxurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(fax, url) == 0);
+  TEST(url->url_type, url_fax);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_fax);
+  TEST_1(url_cmp(fax, u) == 0);
+  TEST_SIZE(url_e(fax2, sizeof(fax2), u), strlen(faxurl));
+  TEST_1(strcmp(fax2, faxurl) == 0);
+  TEST_SIZE(snprintf(fax2, sizeof(fax2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(fax)), strlen(faxurl));
+  TEST_1(strcmp(fax2, faxurl) == 0);
+
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)faxurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_modem(void)
+{
+  /* modem urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t modem[1] = { URL_INIT_AS(modem) };
+  url_t *u, url[1];
+  char *tst;
+  char modemurl[] = 
+    "modem:+12345678"
+    ";param=1;param=2"
+    "?From=foo at bar&To=bar at baz#unf";
+  char modem2[sizeof(modemurl) + 32];
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_modem), "modem");
+
+  modem->url_user = "+12345678";
+  modem->url_params = "param=1;param=2";
+  modem->url_headers = "From=foo at bar&To=bar at baz";
+  modem->url_fragment = "unf";
+
+  TEST_1(tst = su_strdup(home, modemurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(modem, url) == 0);
+  TEST(url->url_type, url_modem);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_modem);
+  TEST_1(url_cmp(modem, u) == 0);
+  TEST_SIZE(url_e(modem2, sizeof(modem2), u), strlen(modemurl));
+  TEST_1(strcmp(modem2, modemurl) == 0);
+  TEST_SIZE(snprintf(modem2, sizeof(modem2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(modem)), strlen(modemurl));
+  TEST_1(strcmp(modem2, modemurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)modemurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_file(void)
+{
+  /* Test a url with path like file:/foo/bar  */
+  char fileurl[] = "file:/foo/bar";
+  url_t file[1] = { URL_INIT_AS(file) };
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  char *tst;
+  url_t *u, url[1];
+  char buf1[sizeof(fileurl) + 32];
+  char buf2[sizeof(fileurl) + 32];
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_file), "file");
+
+  TEST_1(tst = su_strdup(home, fileurl));
+  TEST(url_d(url, tst), 0);
+  file->url_root = '/';
+  file->url_path = "foo/bar";
+  TEST(url_cmp(file, url), 0);
+  TEST(url->url_type, url_file);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_file);
+  TEST(url_cmp(file, u), 0);
+  TEST_SIZE(url_e(buf1, sizeof(buf1), u), strlen(fileurl));
+  TEST_S(buf1, fileurl);
+  TEST_SIZE(snprintf(buf2, sizeof(buf2), URL_PRINT_FORMAT, URL_PRINT_ARGS(u)), 
+	    strlen(fileurl));
+  TEST_S(buf2, fileurl);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)fileurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_ldap(void)
+{
+  /* Test a LDAP url  */
+  char ldapurl[] = "ldap://cn=Manager,o=nokia:secret@localhost:389/ou=devices,o=nokia";
+  url_t ldap[1] = { URL_INIT_AS(file) };
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  char *tst;
+  url_t *u, url[1];
+  char buf1[sizeof(ldapurl) + 32];
+  char buf2[sizeof(ldapurl) + 32];
+
+  BEGIN();
+
+  ldap->url_type = url_unknown; 
+  ldap->url_scheme = "ldap"; 
+
+  /* TEST_S(url_scheme(url_ldap), "ldap"); */
+
+  TEST_1(tst = su_strdup(home, ldapurl));
+  TEST(url_d(url, tst), 0);
+
+  TEST_S(url->url_user, "cn=Manager,o=nokia:secret");
+  /* TEST_S(url->url_password, "secret"); */
+  TEST_S(url->url_host, "localhost");
+  TEST_S(url->url_port, "389");
+  TEST_S(url->url_path, "ou=devices,o=nokia");
+
+  ldap->url_user = "cn=Manager,o=nokia";
+  ldap->url_password = "secret";
+  ldap->url_user = "cn=Manager,o=nokia:secret", ldap->url_password = NULL;
+  ldap->url_host = "localhost";
+  ldap->url_port = "389";
+  ldap->url_path = "ou=devices,o=nokia";
+
+  TEST(url_cmp(ldap, url), 0);
+  TEST(url->url_type, url_unknown);
+  TEST_S(url->url_scheme, "ldap");
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_unknown);
+  TEST_S(u->url_scheme, "ldap");
+  TEST(url_cmp(ldap, u), 0);
+  TEST_SIZE(url_e(buf1, sizeof(buf1), u), strlen(ldapurl));
+  TEST_S(buf1, ldapurl);
+  TEST_SIZE(snprintf(buf2, sizeof(buf2), URL_PRINT_FORMAT, URL_PRINT_ARGS(u)), 
+	    strlen(ldapurl));
+  TEST_S(buf2, ldapurl);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)ldapurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_rtsp(void)
+{
+  /* RTSP urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t rtsp[1] = { URL_INIT_AS(rtsp) };
+  url_t *u, url[1];
+  char *tst;
+  char rtspurl[] = "rtsp://example.com:42/barfoo.rm";
+  char rtspuurl[] = "rtspu://example.com:42/barfoo.rm";
+  char rtsp2[sizeof(rtspurl) + 32];
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_rtsp), "rtsp");
+  TEST_S(url_scheme(url_rtspu), "rtspu");
+
+  rtsp->url_root = 1;
+  rtsp->url_host = "example.com";
+  rtsp->url_port = "42";
+  rtsp->url_path = "barfoo.rm";
+
+  TEST_1(tst = su_strdup(home, rtspurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(rtsp, url) == 0);
+  TEST(url->url_type, url_rtsp);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_rtsp);
+  TEST_1(url_cmp(rtsp, u) == 0);
+  TEST(url_e(rtsp2, sizeof(rtsp2), u), strlen(rtspurl));
+  TEST_1(strcmp(rtsp2, rtspurl) == 0);
+  TEST_SIZE(snprintf(rtsp2, sizeof(rtsp2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(rtsp)), strlen(rtspurl));
+  TEST_1(strcmp(rtsp2, rtspurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)rtspurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+  rtsp->url_type = url_rtspu, rtsp->url_scheme = "rtspu";
+
+  TEST_1(tst = su_strdup(home, rtspuurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(rtsp, url) == 0);
+  TEST(url->url_type, url_rtspu);
+
+  url_digest(hash1, sizeof(hash1), url, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)rtspuurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_http(void)
+{
+  /* http urls */
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+  url_t http[1] = { URL_INIT_AS(http) };
+  url_t *u, url[1];
+  char *tst;
+  char httpurl[] = 
+    "http://user:pass@host:32/foo;param=1/bar;param=3"
+    "?From=foo at bar&To=bar at baz#unf";
+  char http2[sizeof(httpurl) + 32];
+
+  char queryonly[] = 
+    "http://some.host?query";
+
+  BEGIN();
+
+  TEST_S(url_scheme(url_http), "http");
+  TEST_S(url_scheme(url_https), "https");
+
+  http->url_root = '/';
+  http->url_user = "user";
+  http->url_password = "pass";
+  http->url_host = "host";
+  http->url_port = "32";
+  http->url_path = "foo;param=1/bar;param=3";
+  http->url_headers = "From=foo at bar&To=bar at baz";
+  http->url_fragment = "unf";
+
+  TEST_1(tst = su_strdup(home, httpurl));
+  TEST_1(url_d(url, tst) == 0);
+  TEST_1(url_cmp(http, url) == 0);
+  TEST(url->url_type, url_http);
+  TEST_1(u = url_hdup(home, url));
+  TEST(u->url_type, url_http);
+  TEST_1(url_cmp(http, u) == 0);
+  TEST_SIZE(url_e(http2, sizeof(http2), u), strlen(httpurl));
+  TEST_1(strcmp(http2, httpurl) == 0);
+  TEST_SIZE(snprintf(http2, sizeof(http2), URL_PRINT_FORMAT, 
+		     URL_PRINT_ARGS(http)), strlen(httpurl));
+  TEST_1(strcmp(http2, httpurl) == 0);
+
+  url_digest(hash1, sizeof(hash1), http, NULL);
+  url_digest(hash2, sizeof(hash2), (url_t *)httpurl, NULL);
+  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+  memset(url, 0, sizeof url);
+  TEST_1(tst = su_strdup(home, queryonly));
+  TEST(url_d(url, tst), 0);
+  TEST_S(url->url_host, "some.host");
+  TEST_S(url->url_headers, "query");
+  TEST_S(url->url_params, NULL);
+    
+  su_home_deinit(home);
+
+  END();
+}
+
+int test_sanitizing(void)
+{
+  url_t url[1];
+  char www[] = "www.hut.fi";
+  char ftp[] = "ftp.hut.fi";
+  char www2[] = "iptel.hut.fi/humppa";
+  char sip[] = "test.host";
+  char buf[64];
+
+  BEGIN();
+
+  TEST_1(url_d(url, www) == 0);
+  TEST_1(url_sanitize(url) == 0);
+  TEST(url->url_type, url_http);
+  snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+  TEST_S(buf, "http://www.hut.fi");
+
+  TEST_1(url_d(url, ftp) == 0);
+  TEST_1(url_sanitize(url) == 0);
+  TEST(url->url_type, url_ftp);
+  snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+  TEST_S(buf, "ftp://ftp.hut.fi");
+
+  TEST_1(url_d(url, www2) == 0);
+  TEST_1(url_sanitize(url) == 0);
+  TEST(url->url_type, url_http);
+  snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+  TEST_S(buf, "http://iptel.hut.fi/humppa");
+
+  TEST_1(url_d(url, sip) == 0);
+  TEST_1(url_sanitize(url) == 0);
+  TEST(url->url_type, url_sip);
+  snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+  TEST_S(buf, "sip:test.host");
+
+  END();
+}
+
+
+int test_tags(void)
+{
+  url_t u0[1];
+  url_t *u1 = NULL;
+  url_t const *u2 = (void *)-1;
+  url_t const u3[1] = { URL_INIT_AS(sip) };
+  char c0[] = "http://www.nokia.com";
+  char const *c1 = "http://goodfeel.nokia.com";
+  char *c2 = "http://forum.nokia.com";
+  char const c3[] = "http://www.research.nokia.com";
+  url_string_t *us0 = NULL;
+
+  tagi_t *lst, *dup;
+  
+  tag_value_t value;
+  char *s;
+  su_home_t home[1] = { SU_HOME_INIT(home) };
+
+  BEGIN();
+
+  TEST(t_scan(urltag_url, home, c0, &value), 0);
+  TEST_S(s = url_as_string(home, (url_t *)value), c0);
+
+  TEST(t_scan(urltag_url, home, c3, &value), 0);
+  TEST_S(s = url_as_string(home, (url_t *)value), c3);
+
+  TEST_1(url_d(u0, c0) == 0);
+
+  lst = tl_list(URLTAG_URL(u0),
+		URLTAG_URL(u1),
+		URLTAG_URL(u2),
+		URLTAG_URL(u3),
+		URLTAG_URL(c0),
+		URLTAG_URL(c1),
+		URLTAG_URL(c2),
+		URLTAG_URL(c3),
+		URLTAG_URL(us0),
+		TAG_NULL());
+
+  TEST_1(lst);
+
+  dup = tl_adup(home, lst);
+
+  tl_vfree(lst);
+
+  su_free(home, dup);
+
+  su_home_deinit(home);
+
+  END();
+}
+
+#include <sofia-sip/su_tag_class.h>
+
+int test_tag_filter(void)
+{
+  BEGIN();
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "test"
+  tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+#define TAG_A(s)      tag_a, tag_str_v((s))
+  tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+#define TAG_B(s)      tag_b, tag_str_v((s))
+
+  tagi_t filter[2] = {{ URLTAG_ANY() }, { TAG_END() }};
+
+  tagi_t *lst, *result;
+
+  lst = tl_list(TAG_A("X"),
+		TAG_SKIP(2), 
+		URLTAG_URL((void *)"urn:foo"),
+		TAG_B("Y"),
+		URLTAG_URL((void *)"urn:bar"),
+		TAG_NULL());
+
+  TEST_1(lst);
+
+  result = tl_afilter(NULL, filter, lst);
+
+  TEST_1(result);
+  TEST_P(result[0].t_tag, urltag_url);
+  TEST_P(result[1].t_tag, urltag_url);
+
+  tl_vfree(lst);
+  free(result);
+
+  END();
+}
+
+#if 0 
+/* This is just a spike. How we can get 
+ *   register_printf_function('U', printf_url, printf_url_info)
+ * run while initializing?
+ */
+#include <printf.h>
+
+int printf_url(FILE *fp,
+	       const struct printf_info *info,
+	       const void * const *args)
+{
+  url_t const *url = *(url_t **)args[0];
+
+  return fprintf(fp, URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+}
+
+/* This is the appropriate argument information function for `printf_url'.  */
+int printf_url_info(const struct printf_info *info, 
+		    size_t n, int *argtypes)
+{
+  if (n > 0) {
+    argtypes[0] = PA_POINTER;
+    return 1;
+  }
+  return 0;
+}
+#endif
+
+int test_print(void)
+{
+#if 0 
+  url_t u0[1];
+  url_t *u1 = NULL;
+  url_t const *u2 = (void *)-1;
+  url_t const u3[1] = { URL_INIT_AS(sip) };
+  char c0[] = "http://www.nokia.com/";
+  char c1[] = "http://goodfeel.nokia.com/test";
+  char c2[] = "/test2/";
+  char c3[] = "///file/";
+
+  tagi_t *lst;
+
+  BEGIN();
+
+  TEST(register_printf_function('U', printf_url, printf_url_info), 0);
+
+  TEST(url_d(u0, c0), 0);
+  printf("URL is %U\n", u0);
+
+  TEST(url_d(u0, c1), 0);
+  printf("URL is %U\n", u0);
+
+  TEST(url_d(u0, c2), 0);
+  printf("URL is %U\n", u0);
+
+  TEST(url_d(u0, c3), 0);
+  printf("URL is %U\n", u0);
+#else
+  BEGIN();
+#endif
+
+  END();
+}
+
+
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_quote(); fflush(stdout);
+  retval |= test_any(); fflush(stdout);
+  retval |= test_sip(); fflush(stdout);
+  retval |= test_wv(); fflush(stdout);
+  retval |= test_tel(); fflush(stdout);
+  retval |= test_fax(); fflush(stdout);
+  retval |= test_modem(); fflush(stdout);
+  retval |= test_file(); fflush(stdout);
+  retval |= test_ldap(); fflush(stdout);
+  retval |= test_rtsp(); fflush(stdout);
+  retval |= test_http(); fflush(stdout);
+  retval |= test_sanitizing(); fflush(stdout);
+  retval |= test_tags(); fflush(stdout);
+  retval |= test_print(); fflush(stdout);
+  retval |= test_tag_filter(); fflush(stdout);
+
+  return retval;
+}
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2088 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE url.c
+ *
+ * Implementation of basic URL parsing and handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 22:44:37 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/bnf.h>
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/url.h>
+
+#include <sofia-sip/string0.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+
+/**@def URL_PRINT_FORMAT
+ * Format string used when printing url with printf().
+ *
+ * The macro URL_PRINT_FORMAT is used in format string of printf() or
+ * similar printing functions.  A URL can be printed like this:
+ * @code
+ *   printf("%s received URL " URL_PRINT_FORMAT "\n", 
+ *          my_name, URL_PRINT_ARGS(url));
+ * @endcode
+ */
+
+/** @def URL_PRINT_ARGS(u)
+ * Argument list used when printing url with printf().
+ *
+ * The macro URL_PRINT_ARGS() is used to create a stdarg list for printf()
+ * or similar printing functions.  Using it, a URL can be printed like this:
+ *
+ * @code
+ *   printf("%s received URL " URL_PRINT_FORMAT "\n", 
+ *          my_name, URL_PRINT_ARGS(url));
+ * @endcode
+ */
+
+#define RESERVED        ";/?:@&=+$,"
+#define DELIMS          "<>#%\""
+#define UNWISE		"{}|\\^[]`"
+
+#define EXCLUDED	RESERVED DELIMS UNWISE
+
+#define UNRESERVED    	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                      	"abcdefghijklmnopqrstuvwxyz" \
+                      	"0123456789" \
+                      	"-_.!~*'()"
+
+#define IS_EXCLUDED(u, m32, m64, m96)			\
+  (u <= ' '						\
+   || u >= '\177'					\
+   || (u < 64 ? (m32 & (1 << (63 - u)))			\
+       : (u < 96 ? (m64 & (1 << (95 - u)))		\
+	  : /*u < 128*/ (m96 & (1 << (127 - u))))) != 0)
+
+#define MASKS_WITH_RESERVED(reserved, m32, m64, m96)		\
+  if (reserved == NULL) {					\
+    m32 = 0xbe19003f, m64 = 0x8000001e, m96 = 0x8000001d;	\
+  } else do {							\
+    m32 = 0xb400000a, m64 = 0x0000001e, m96 = 0x8000001d;	\
+    								\
+    for (;reserved[0]; reserved++) {				\
+      unsigned r = reserved[0];					\
+      RESERVE(r, m32, m64, m96);				\
+    }								\
+  } while (0)
+
+#define RESERVE(reserved, m32, m64, m96)				\
+  if (r < 32)								\
+    ;									\
+  else if (r < 64)							\
+    m32 |= 1U << (63 - r);						\
+  else if (r < 96)							\
+    m64 |= 1U << (95 - r);						\
+  else if (r < 128)							\
+    m96 |= 1U << (127 - r)
+
+#define MASKS_WITH_ALLOWED(allowed, mask32, mask64, mask96)	\
+  do {								\
+    if (allowed) {						\
+      for (;allowed[0]; allowed++) {				\
+	unsigned a = allowed[0];				\
+	ALLOW(a, mask32, mask64, mask96);			\
+      }								\
+    }								\
+  } while (0)
+
+#define ALLOW(a, mask32, mask64, mask96)	\
+  if (a < 32)					\
+    ;						\
+  else if (a < 64)				\
+    mask32 &= ~(1U << (63 - a));		\
+  else if (a < 96)				\
+    mask64 &= ~(1U << (95 - a));		\
+  else if (a < 128)				\
+    mask96 &= ~(1U << (127 - a))
+
+
+#define RMASK1 0xbe19003f
+#define RMASK2 0x8000001e
+#define RMASK3 0x8000001d
+
+#define RESERVED_MASK 0xbe19003f, 0x8000001e, 0x8000001d
+#define URIC_MASK     0xb400000a, 0x0000001e, 0x8000001d
+
+#define IS_EXCLUDED_MASK(u, m) IS_EXCLUDED(u, m)
+
+/* Internal prototypes */
+static char *url_canonize(char *d, char const *s, size_t n,
+			  char const allowed[]);
+static char *url_canonize2(char *d, char const *s, size_t n, 
+			   unsigned m32, unsigned m64, unsigned m96);
+static int url_tel_cmp_numbers(char const *A, char const *B);
+
+/**Test if string contains excluded or url-reserved characters. 
+ *
+ * 
+ *
+ * @param s  string to be searched
+ *
+ * @retval 0 if no reserved characters were found.
+ * @retval l if a reserved character was found.
+ */
+int url_reserved_p(char const *s)
+{
+  if (s) 
+    while (*s) {
+      unsigned char u = *s++;
+
+      if (IS_EXCLUDED(u, RMASK1, RMASK2, RMASK3))
+	return 1;
+    }
+
+  return 0;
+}
+
+/** Calculate length of string when escaped with %-notation.
+ *
+ * Calculate the length of string @a s when the excluded or reserved
+ * characters in it have been escaped.
+ * 
+ * @param s         String with reserved URL characters. [IN
+ * @param reserved  Optional array of reserved characters [IN]
+ *
+ * @return 
+ * The number of characters in corresponding but escaped string.
+ *
+ * You can handle a part of URL with reserved characters like this:
+ * @code
+ * if (url_reserved_p(s))  {
+ *   n = malloc(url_esclen(s, NULL) + 1);
+ *   if (n) url_escape(n, s);
+ * } else {
+ *   n = malloc(strlen(s) + 1);
+ *   if (n) strcpy(n, s);
+ * }
+ * @endcode
+ */
+isize_t url_esclen(char const *s, char const reserved[])
+{
+  size_t n;
+  unsigned mask32, mask64, mask96;
+
+  MASKS_WITH_RESERVED(reserved, mask32, mask64, mask96);
+
+  for (n = 0; s && *s; n++) {
+    unsigned char u = *s++;
+
+    if (IS_EXCLUDED(u, mask32, mask64, mask96))
+      n += 2;
+  }
+
+  return (isize_t)n;
+}
+
+/** Escape a string.
+ *
+ * The function url_escape() copies the string pointed by @a s to the array
+ * pointed by @a d, @b excluding the terminating \\0 character.  All reserved
+ * characters in @a s are copied in hexadecimal format, for instance, @c
+ * "$%#" is copied as @c "%24%25%23".  The destination array @a d must be
+ * large enough to receive the escaped copy.
+ *
+ * @param d         Destination buffer [OUT]
+ * @param s         String to be copied [IN]
+ * @param reserved  Array of reserved characters [IN]
+ *
+ * @return Pointer to the destination array.
+ */
+char *url_escape(char *d, char const *s, char const reserved[])
+{
+  char *retval = d;
+  unsigned mask32, mask64, mask96;
+ 
+  MASKS_WITH_RESERVED(reserved, mask32, mask64, mask96);
+
+  while (s && *s) {
+    unsigned char u = *s++;
+
+    if (IS_EXCLUDED(u, mask32, mask64, mask96)) {
+#     define URL_HEXIFY(u) ((u) + '0' + ((u) >= 10 ? 'A' - '0' - 10 : 0))
+
+      *d++ = '%';
+      *d++ = URL_HEXIFY(u >> 4);
+      *d++ = URL_HEXIFY(u & 15);
+
+#     undef URL_HEXIFY
+    }
+    else {
+      *d++ = u;
+    }
+  }
+
+  *d = '\0';
+  
+  return retval;
+}
+
+
+/**Unescape url-escaped string fragment.
+ *
+ * Unescape @a n characters from string @a s to the buffer @a d, including
+ * the terminating \\0 character. All %-escaped triplets in @a s are
+ * unescaped, for instance, @c "%40%25%23" is copied as @c "@%#". The
+ * destination array @a d must be large enough to receive the escaped copy
+ * (@a n bytes is always enough).
+ *
+ * @param d  destination buffer
+ * @param s  string to be unescaped
+ * @param n  maximum number of characters to unescape
+ *
+ * @return Length of unescaped string
+ *
+ * @NEW_1_12_4.
+ */
+size_t url_unescape_to(char *d, char const *s, size_t n)
+{
+  size_t i = 0, j = 0;
+
+  if (s == NULL)
+    return 0;
+
+  i = j = strncspn(s, n, "%");
+
+  if (d && d != s)
+    memmove(d, s, i);
+
+  for (; i < n;) {
+    char c = s[i++];
+
+    if (c == '\0')
+      break;
+
+    if (c == '%' && i + 1 < n && IS_HEX(s[i]) && IS_HEX(s[i + 1])) {
+#define   UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+      c = (UNHEX(s[i]) << 4) | UNHEX(s[i + 1]);
+#undef    UNHEX
+      i += 2;
+    }
+
+    if (d)
+      d[j] = c;
+    j++;
+  }
+
+  return j;
+}
+
+/**Unescape url-escaped string.
+ *
+ * Unescape string @a s to the buffer @a d, including the terminating \\0
+ * character. All %-escaped triplets in @a s are unescaped, for instance, @c
+ * "%40%25%23" is copied as @c "@%#". The destination array @a d must be
+ * large enough to receive the escaped copy.
+ *
+ * @param d  destination buffer
+ * @param s  string to be copied
+ *
+ * @return Pointer to the destination buffer.
+ */
+char *url_unescape(char *d, char const *s)
+{
+  size_t n = url_unescape_to(d, s, SIZE_MAX);
+  if (d)
+    d[n] = '\0';
+  return d;
+}
+
+/** Canonize a URL component */
+static
+char *url_canonize(char *d, char const *s, size_t n, char const allowed[])
+{
+  unsigned mask32 = 0xbe19003f, mask64 = 0x8000001e, mask96 = 0x8000001d;
+
+  MASKS_WITH_ALLOWED(allowed, mask32, mask64, mask96);
+
+  return url_canonize2(d, s, n, mask32, mask64, mask96);
+}
+
+/** Canonize a URL component (with precomputed mask) */
+static
+char *url_canonize2(char *d, char const * const s, size_t n, 
+		    unsigned m32, unsigned m64, unsigned m96)
+{
+  size_t i = 0;
+
+  if (d == s)
+    for (;s[i] && i < n; d++, i++) 
+      if (s[i] == '%')
+	break;
+
+  for (;s[i] && i < n; d++, i++) {
+    unsigned char c = s[i], h1, h2;
+
+    if (c != '%') {
+      if (IS_EXCLUDED(c, m32, m64, m96))
+	return NULL;
+      *d = c;
+      continue;
+    }
+
+    h1 = s[i + 1], h2 = s[i + 2];
+    
+    if (!IS_HEX(h1) || !IS_HEX(h2)) {
+      *d = '\0';
+      return NULL;
+    }
+    
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+    c = (UNHEX(h1) << 4) | UNHEX(h2);
+
+    if (!IS_EXCLUDED(c, m32, m64, m96)) {
+      /* Convert hex to normal character */
+      *d = c, i += 2;
+      continue;
+    }
+
+    /* Convert hex to uppercase */
+    if (h1 >= 'a' /* && h1 <= 'f' */)
+      h1 = h1 - 'a' + 'A';
+    if (h2 >= 'a' /* && h2 <= 'f' */)
+      h2 = h2 - 'a' + 'A';
+
+    d[0] = '%', d[1] = h1, d[2] = h2;
+
+    d +=2, i += 2;
+#undef    UNHEX
+  }
+  
+  *d = '\0';
+
+  return d;
+}
+
+
+/** Canonize a URL component (with precomputed mask).
+ *
+ * This version does not flag error if *s contains character that should 
+ * be escaped.
+ */
+static
+char *url_canonize3(char *d, char const * const s, size_t n, 
+		    unsigned m32, unsigned m64, unsigned m96)
+{
+  size_t i = 0;
+
+  if (d == s)
+    for (;s[i] && i < n; d++, i++) 
+      if (s[i] == '%')
+	break;
+
+  for (;s[i] && i < n; d++, i++) {
+    unsigned char c = s[i], h1, h2;
+
+    if (c != '%') {
+      *d = c;
+      continue;
+    }
+
+    h1 = s[i + 1], h2 = s[i + 2];
+    
+    if (!IS_HEX(h1) || !IS_HEX(h2)) {
+      *d = '\0';
+      return NULL;
+    }
+    
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+    c = (UNHEX(h1) << 4) | UNHEX(h2);
+
+    if (!IS_EXCLUDED(c, m32, m64, m96)) {
+      *d = c, i += 2;
+      continue;
+    }
+
+    /* Convert hex to uppercase */
+    if (h1 >= 'a' /* && h1 <= 'f' */)
+      h1 = h1 - 'a' + 'A';
+    if (h2 >= 'a' /* && h2 <= 'f' */)
+      h2 = h2 - 'a' + 'A';
+
+    d[0] = '%', d[1] = h1, d[2] = h2;
+
+    d +=2, i += 2;
+#undef    UNHEX
+  }
+  
+  *d = '\0';
+
+  return d;
+}
+
+
+/** Get URL scheme. */
+char const* url_scheme(enum url_type_e url_type)
+{
+  switch (url_type) {
+  case url_any:    return "*";
+  case url_sip:    return "sip";
+  case url_sips:   return "sips";
+  case url_tel:    return "tel";
+  case url_fax:    return "fax";
+  case url_modem:  return "modem";
+  case url_http:   return "http";
+  case url_https:  return "https";
+  case url_ftp:    return "ftp";
+  case url_file:   return "file";
+  case url_rtsp:   return "rtsp";
+  case url_rtspu:  return "rtspu";
+  case url_mailto: return "mailto";
+  case url_im:     return "im";
+  case url_pres:   return "pres";
+  case url_cid:    return "cid";
+  case url_msrp:   return "msrp";
+  case url_msrps:  return "msrps";
+  case url_wv:     return "wv";
+  default:       
+    assert(url_type == url_unknown);
+    return NULL;
+  }
+}
+
+static inline
+int url_type_is_opaque(enum url_type_e url_type)
+{
+  return 
+    url_type == url_invalid ||
+    url_type == url_tel || 
+    url_type == url_modem || 
+    url_type == url_fax ||
+    url_type == url_cid;
+}
+
+/** Init an url as given type */
+void url_init(url_t *url, enum url_type_e type)
+{
+  memset(url, 0, sizeof(*url));
+  url->url_type = type;
+  if (type > url_unknown) {
+    char const *scheme = url_scheme(url->url_type);
+    if (scheme)
+      url->url_scheme = scheme;
+  }
+}
+
+/** Get url type */
+static inline
+enum url_type_e url_get_type(char const *scheme, size_t len)
+{
+#define test_scheme(s) \
+   if (len == strlen(#s) && !strncasecmp(scheme, #s, len)) return url_##s
+  
+  switch (scheme[0]) {
+  case '*': if (strcmp(scheme, "*") == 0) return url_any;
+  case 'c': case 'C': 
+    test_scheme(cid); break;
+  case 'f': case 'F': 
+    test_scheme(ftp); test_scheme(file); test_scheme(fax); break;
+  case 'h': case 'H': 
+    test_scheme(http); test_scheme(https); break;
+  case 'i': case 'I': 
+    test_scheme(im); break;
+  case 'm': case 'M': 
+    test_scheme(mailto); test_scheme(modem); 
+    test_scheme(msrp); test_scheme(msrps); break;
+  case 'p': case 'P': 
+    test_scheme(pres); break;
+  case 'r': case 'R': 
+    test_scheme(rtsp); test_scheme(rtspu); break;
+  case 's': case 'S': 
+    test_scheme(sip); test_scheme(sips); break;
+  case 't': case 'T': 
+    test_scheme(tel); break;
+  case 'w': case 'W': 
+    test_scheme(wv); break;
+
+
+  default: break;
+  }
+
+#undef test_scheme
+
+  if (len != span_unreserved(scheme))
+    return url_invalid;
+  else
+    return url_unknown;
+}
+
+/**
+ * Decode a URL.
+ *
+ * This function decodes a (SIP) URL string to a url_t structure.
+ *
+ * @param url structure to store the parsing result
+ * @param s   NUL-terminated string to be parsed
+ *
+ * @note The parsed string @a s will be modified when parsing it.
+ *
+ * @retval 0 if successful, 
+ * @retval -1 otherwise.
+ */
+static
+int _url_d(url_t *url, char *s)
+{
+  size_t n;
+  char *s0, rest_c, *host;
+  int net_path = 1;
+
+  memset(url, 0, sizeof(*url));
+  
+  if (strcmp(s, "*") == 0) {
+    url->url_type = url_any;
+    url->url_scheme = "*";
+    return 0;
+  }
+
+  s0 = s;
+
+  n = strcspn(s, ":/?#");
+
+  if (n && s[n] == ':') {
+    char *scheme;
+    url->url_scheme = scheme = s; s[n] = '\0'; s = s + n + 1;
+
+    if (!(scheme = url_canonize(scheme, scheme, SIZE_MAX, "+")))
+      return -1;
+
+    n = scheme - url->url_scheme;
+
+    url->url_type = url_get_type(url->url_scheme, n);
+
+    net_path = !url_type_is_opaque(url->url_type);
+  }
+  else {
+    url->url_type = url_unknown;
+  }
+
+  host = s;
+
+  if (url->url_type == url_sip || url->url_type == url_sips) {
+    /* SIP URL may have /; in user part */
+    n = strcspn(s, "@#");	/* Opaque part */
+    if (s[n] != '@')
+      n = 0;
+    n += strcspn(s + n, "/;?#");
+  }
+  else if (url->url_type == url_wv) {
+    /* WV URL may have / in user part */
+    n = strcspn(s, "@#?;");
+    if (s[n] == '@')
+      n += strcspn(s + n, ";?#");
+  }
+  else if (url->url_type == url_invalid) {
+    n = strcspn(s, "#");
+  }
+  else if (net_path && host[0] == '/') {
+    url->url_root = host[0];	/* Absolute path */
+
+    if (host[1] == '/') {	/* We have host-part */
+      host += 2; s += 2;
+    }
+    else 
+      host = NULL;
+    n = strcspn(s, "/;?#");	/* Find path, query and/or fragment */
+  }
+  else {
+    n = strcspn(s, "/;?#");	/* Find params, query and/or fragment */
+  }
+
+  rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+
+  if (host) {
+    char *atsign, *port;
+
+    if (!net_path) {
+      url->url_user = host;
+      host = NULL;
+    }
+    else if ((atsign = strchr(host, '@'))) {
+      char *user;
+
+      url->url_user = user = host;
+
+      if (atsign)
+	*atsign++ = '\0';
+      host = atsign;
+
+      if (url->url_type != url_unknown) {
+	char *colon = strchr(user, ':');
+	if (colon)
+	  *colon++ = '\0';
+	url->url_password = colon;
+      }
+    }
+
+    if ((url->url_host = host)) {
+      /* IPv6 (and in some cases, IPv4) addresses are quoted with [] */
+      if (host[0] == '[') {
+	port = strchr(host, ']');
+	if (!port)
+	  return -1;
+	port = strchr(port + 1, ':');
+      }
+      else 
+	port = strchr(host, ':');
+
+      if (port) {
+	*port++ = '\0';
+	url->url_port = port;
+	switch (url->url_type) {
+	case url_any:
+	case url_sip:
+	case url_sips:
+	case url_http:
+	case url_https:
+	case url_ftp:
+	case url_file:
+	case url_rtsp:
+	case url_rtspu:
+	  
+	  if (!url_canonize2(port, port, SIZE_MAX, RESERVED_MASK))
+	    return -1;
+
+	  /* Check that port is really numeric or wildcard */
+	  /* Port can be *digit, empty string or "*" */
+	  while (*port >= '0' && *port <= '9')
+	    port++;
+	  if (port != url->url_port 
+	      ? port[0] != '\0' 
+	      : port[0] != '\0'
+	      && (port[0] != '*' || port[1] != '\0'))
+	    return -1;
+	}
+      }
+    }
+  }
+
+  if (rest_c == '/') {
+    url->url_path = s; n = strcspn(s, "?#");
+    rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+  }
+  if (rest_c == ';') {
+    url->url_params = s; n = strcspn(s, "?#");
+    rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+  }
+  if (rest_c == '?') {
+    url->url_headers = s; n = strcspn(s, "#");
+    rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+  }
+  if (rest_c == '#') {
+    url->url_fragment = s;
+    rest_c = '\0';
+  }
+  if (rest_c)
+    return -1;
+
+  return 0;
+}
+
+/* Unreserved things */
+
+/**
+ * Decode a URL.
+ *
+ * This function decodes a URL string to a url_t structure.
+ *
+ * @param url structure to store the parsing result
+ * @param s   NUL-terminated string to be parsed
+ *
+ * @note The parsed string @a s will be modified when parsing it.
+ *
+ * @retval 0 if successful, 
+ * @retval -1 otherwise.
+ */
+int url_d(url_t *url, char *s)
+{
+  if (url == NULL || _url_d(url, s) < 0)
+    return -1;
+
+  /* Canonize  URL */
+  /* scheme is canonized by _url_d() */
+  if (url->url_type == url_sip || url->url_type == url_sips) {
+
+#   define SIP_USER_UNRESERVED "&=+$,;?/"
+    s = (char *)url->url_user;
+    if (s && !url_canonize(s, s, SIZE_MAX, SIP_USER_UNRESERVED))
+      return -1;
+
+#   define SIP_PASS_UNRESERVED "&=+$,"
+    s = (char *)url->url_password;
+    if (s && !url_canonize(s, s, SIZE_MAX, SIP_PASS_UNRESERVED))
+      return -1;
+
+  } else {
+
+#   define USER_UNRESERVED "&=+$,;"
+    s = (char *)url->url_user;
+    if (s && !url_canonize(s, s, SIZE_MAX, USER_UNRESERVED))
+      return -1;
+
+#   define PASS_UNRESERVED "&=+$,;:"
+    s = (char *)url->url_password;
+    if (s && !url_canonize(s, s, SIZE_MAX, PASS_UNRESERVED))
+      return -1;
+  }
+
+  s = (char *)url->url_host;
+  if (s && !url_canonize2(s, s, SIZE_MAX, RESERVED_MASK))
+    return -1;
+
+  /* port is canonized by _url_d() */
+
+  /* Allow all URI characters but ? and ; */
+# define PATH_UNRESERVED "/:@&=+$,"
+  s = (char *)url->url_path;
+  if (s && !url_canonize(s, s, SIZE_MAX, PATH_UNRESERVED))
+    return -1;
+
+  /* Allow all URI characters but ? */
+# define PARAMS_UNRESERVED ";" PATH_UNRESERVED
+  s = (char *)url->url_params;
+  if (s && !url_canonize(s, s, SIZE_MAX, PARAMS_UNRESERVED))
+    return -1;
+  
+  /* Unhex alphanumeric and unreserved URI characters */
+  s = (char *)url->url_headers;
+  if (s && !url_canonize3(s, s, SIZE_MAX, RESERVED_MASK))
+    return -1;
+
+  /* Allow all URI characters (including reserved ones) */
+  s = (char *)url->url_fragment;
+  if (s && !url_canonize2(s, s, SIZE_MAX, URIC_MASK))
+    return -1;
+
+  return 0;
+}
+
+/** Encode an URL. 
+ * 
+ * The function url_e() combines a URL from substrings in url_t structure
+ * according the @ref url_syntax "URL syntax" presented above.  The encoded
+ * @a url is stored in a @a buffer of @a n bytes.
+ *
+ * @param buffer memory area to store the encoded @a url.
+ * @param n      size of @a buffer.
+ * @param url    URL to be encoded.
+ *
+ * @return 
+ * Return the number of bytes in the encoding.  
+ *
+ * @note The function follows the convention set by C99 snprintf().  Even if
+ * the result does not fit into the @a buffer and it is truncated, the
+ * function returns the number of bytes in an untruncated encoding.
+ */
+issize_t url_e(char buffer[], isize_t n, url_t const *url)
+{
+  size_t i;
+  char *b = buffer;
+  size_t m = n;
+  int do_copy = n > 0;
+
+  if (url == NULL)
+    return -1;
+
+  if (URL_STRING_P(url)) {
+    char const *u = (char *)url;
+    i = strlen(u);
+    if (!buffer)
+      return i;
+
+    if (i >= n) {
+      memcpy(buffer, u, n - 2);
+      buffer[n - 1] = '\0';
+    } else {
+      memcpy(buffer, u, i + 1);
+    }
+
+    return i;
+  }
+
+
+  if (url->url_type == url_any) {
+    if (b && m > 0) {
+      if (m > 1) strcpy(b, "*"); else b[0] = '\0';
+    }
+    return 1;
+  }
+
+  if (url->url_scheme && url->url_scheme[0]) {
+    i = strlen(url->url_scheme) + 1;
+    if (do_copy && (do_copy = i <= n)) {
+      memcpy(b, url->url_scheme, i - 1);
+      b[i - 1] = ':';
+    }
+    b += i; n -= i;
+  }
+
+  if (url->url_root && (url->url_host || url->url_user)) {
+    if (do_copy && (do_copy = 2 <= n))
+      memcpy(b, "//", 2);
+    b += 2; n -= 2;
+  }
+
+  if (url->url_user) {
+    i = strlen(url->url_user);
+    if (do_copy && (do_copy = i <= n))
+      memcpy(b, url->url_user, i);
+    b += i; n -= i;
+
+    if (url->url_password) {
+      if (do_copy && (do_copy = 1 <= n))
+	*b = ':'; 
+      b++; n--;
+      i = strlen(url->url_password);
+      if (do_copy && (do_copy = i <= n))
+	memcpy(b, url->url_password, i);
+      b += i; n -= i;
+    }
+
+    if (url->url_host) {
+      if (do_copy && (do_copy = 1 <= n))
+	*b = '@'; 
+      b++; n--;
+    }
+  }
+
+  if (url->url_host) {
+    i = strlen(url->url_host);
+    if (do_copy && (do_copy = i <= n))
+      memcpy(b, url->url_host, i);
+    b += i; n -= i;
+
+    if (url->url_port) {
+      i = strlen(url->url_port) + 1;
+      if (do_copy && (do_copy = i <= n)) {
+	b[0] = ':';
+	memcpy(b + 1, url->url_port, i - 1);
+      } 
+      b += i; n -= i;
+    }
+  }
+
+  if (url->url_path) {
+    if (url->url_root) {
+      if (do_copy && (do_copy = 1 <= n))
+	b[0] = '/';
+      b++, n--;
+    }
+    i = strlen(url->url_path);
+    if (do_copy && (do_copy = i < n))
+      memcpy(b, url->url_path, i);
+    b += i; n -= i;
+  }
+  
+  {
+    static char const sep[] = ";?#";
+    char const *pp[3];
+    size_t j;
+
+    pp[0] = url->url_params;
+    pp[1] = url->url_headers;
+    pp[2] = url->url_fragment;
+
+    for (j = 0; j < 3; j++) {
+      char const *p = pp[j];
+      if (!p) continue;
+      i = strlen(p) + 1;
+      if (do_copy && (do_copy = i <= n)) {
+	*b = sep[j];
+	memcpy(b + 1, p, i - 1);
+      }
+      b += i; n -= i;
+    }
+  }
+
+  if (do_copy && (do_copy = 1 <= n))
+    *b = '\0';
+  else if (buffer && m > 0)
+    buffer[m - 1] = '\0';
+
+  assert((size_t)(b - buffer) == (size_t)(m - n));
+  
+  /* This follows the snprintf(C99) return value, 
+   * Number of characters written (excluding NUL)
+   */
+  return b - buffer;
+}
+
+
+/** Calculate the lengh of URL when encoded. 
+ *
+ */
+isize_t url_len(url_t const * url)
+{
+  size_t rv = 0;
+
+  if (url->url_scheme) rv += strlen(url->url_scheme) + 1; /* plus ':' */
+  if (url->url_user) {
+    rv += strlen(url->url_user);
+    if (url->url_password) 
+      rv += strlen(url->url_password) + 1;   /* plus ':' */
+    rv += url->url_host != NULL;  /* plus '@' */
+  }
+  if (url->url_host) rv += strlen(url->url_host);
+  if (url->url_port) rv += strlen(url->url_port) + 1;	        /* plus ':' */
+  if (url->url_path) rv += strlen(url->url_path) + 1;     /* plus initial / */
+  if (url->url_params) rv += strlen(url->url_params) + 1; /* plus initial ; */
+  if (url->url_headers) rv += strlen(url->url_headers) + 1;	/* plus '?' */
+  if (url->url_fragment) rv += strlen(url->url_fragment) + 1;   /* plus '#' */
+
+  return rv;
+}
+
+/**@def URL_E(buf, end, url)
+ * Encode an URL: use @a buf up to @a end. 
+ * @hideinitializer
+ */
+
+/** 
+ * Calculate the size of strings associated with a #url_t sructure.
+ *
+ * @param url pointer to a #url_t structure or string
+ * @return Number of bytes for URL
+ */
+isize_t url_xtra(url_t const *url)
+{
+  size_t xtra;
+
+  if (URL_STRING_P(url)) {
+    xtra = strlen((char const *)url) + 1;
+  }
+  else {
+    size_t len_scheme, len_user, len_password,
+      len_host, len_port, len_path, len_params, 
+      len_headers, len_fragment;
+
+    len_scheme = (url->url_type <= url_unknown && url->url_scheme) ?
+      strlen(url->url_scheme) + 1 : 0;
+    len_user = url->url_user ? strlen(url->url_user) + 1 : 0;
+    len_password = url->url_password ? strlen(url->url_password) + 1 : 0;
+    len_host = url->url_host ? strlen(url->url_host) + 1 : 0;
+    len_port = url->url_port ? strlen(url->url_port) + 1 : 0;
+    len_path = url->url_path ? strlen(url->url_path) + 1 : 0;
+    len_params = url->url_params ? strlen(url->url_params) + 1 : 0;
+    len_headers = url->url_headers ? strlen(url->url_headers) + 1 : 0;
+    len_fragment = url->url_fragment ? strlen(url->url_fragment) + 1 : 0;
+
+    xtra =
+      len_scheme + len_user + len_password + len_host + len_port +
+      len_path + len_params + len_headers + len_fragment;
+  }
+
+  return xtra;
+}
+
+static inline
+char *copy(char *buf, char *end, char const *src)
+{
+#if HAVE_MEMCCPY
+  char *b = memccpy(buf, src, '\0', end - buf);
+  if (b)
+    return b;
+  else
+    return end + strlen(src + (end - buf)) + 1;
+#else
+  for (; buf < end && (*buf = *src); buf++, src++)
+    ;
+
+  if (buf >= end) 
+    while (*src++)
+      buf++;
+
+  return buf + 1;
+#endif
+}
+
+/** 
+ * Duplicate the url.
+ * 
+ * The function url_dup() copies the url structure @a src and the strings
+ * attached to it to @a url.  The non-constant strings in @a src are copied
+ * to @a buf.  If the size of duplicated strings exceed @a bufsize, the 
+ * corresponding string fields in @a url are set to NULL.
+ *
+ * The calling function can calculate the size of buffer required by calling
+ * url_dup() with zero as @a bufsize and NULL as @a dst.
+
+ * @param buf     Buffer for non-constant strings copied from @a src.
+ * @param bufsize Size of @a buf.
+ * @param dst     Destination URL structure.
+ * @param src     Source URL structure.
+ *
+ * @return Number of characters required for
+ * duplicating the strings in @a str, or -1 if an error
+ * occurred.
+ */
+issize_t url_dup(char *buf, isize_t bufsize, url_t *dst, url_t const *src)
+{
+  if (!src && !dst)
+    return -1;
+  else if (URL_STRING_P(src)) {
+    size_t n = strlen((char *)src) + 1;
+    if (n > bufsize || dst == NULL)
+      return n;
+
+    strcpy(buf, (char *)src);
+    memset(dst, 0, sizeof(*dst));
+    if (url_d(dst, buf) < 0)
+      return -1;
+
+    return n;
+  }
+  else {
+    char *b = buf;
+    char *end = b + bufsize;
+    char const **dstp; 
+    char const * const *srcp;
+    url_t dst0[1];
+
+    if (dst == NULL)
+      dst = dst0;
+
+    memset(dst, 0, sizeof(*dst));
+
+    if (!src)
+      return 0;
+
+    memset(dst->url_pad, 0, sizeof dst->url_pad);
+    dst->url_type = src->url_type;
+    dst->url_root = src->url_root;
+
+    dstp = &dst->url_scheme;
+    srcp = &src->url_scheme;
+
+    if (dst->url_type > url_unknown)
+      *dstp = url_scheme(dst->url_type);
+
+    if (*dstp != NULL)
+      dstp++, srcp++;	/* Skip scheme if it is constant */
+
+    if (dst != dst0 && buf != NULL && bufsize != 0)
+      for (; srcp <= &src->url_fragment; srcp++, dstp++)
+	if (*srcp) {
+	  char *next = copy(b, end, *srcp);
+
+	  if (next > end)
+	    break;
+
+	  *dstp = b, b = next;
+	}
+
+    for (; srcp <= &src->url_fragment; srcp++)
+      if (*srcp) {
+	b += strlen(*srcp) + 1;
+      }
+
+    return b - buf;
+  }
+}
+
+/**@def URL_DUP(buf, end, dst, src)
+ *  Duplicate the url: use @a buf up to @a end. @HI 
+ *
+ * The macro URL_DUP() duplicates the url.  The non-constant strings in @a
+ * src are copied to @a buf.  However, no strings are copied past @a end.
+ * In other words, the size of buffer is @a end - @a buf.
+ *
+ * The macro updates the buffer pointer @a buf, so that it points to the
+ * first unused byte in the buffer.  The buffer pointer @a buf is updated,
+ * even if the buffer is too small for the duplicated strings.
+ *
+ * @param buf     Buffer for non-constant strings copied from @a src.
+ * @param end     End of @a buf.
+ * @param dst     Destination URL structure.
+ * @param src     Source URL structure.
+ *
+ * @return 
+ * The macro URL_DUP() returns pointer to first unused byte in the 
+ * buffer @a buf.
+ */
+
+/** Duplicate the url to memory allocated via home.
+ *
+ * The function url_hdup() duplicates (deep copies) an #url_t structure. 
+ * Alternatively, it can be passed a string; string is then copied and
+ * parsed to the #url_t structure.
+ *
+ * The function url_hdup() allocates the destination structure from @a home
+ * as a single memory block. It is possible to free the copied url structure
+ * and all the associated strings using a single call to su_free().
+ *
+ * @param home memory home used to allocate new url object
+ * @param src  pointer to URL (or string)
+ *
+ * @return
+ * The function url_hdup() returns a pointer to the newly allocated #url_t
+ * structure, or NULL upon an error.
+ */ 
+url_t *url_hdup(su_home_t *home, url_t const *src)
+{
+  if (src) {
+    size_t len = sizeof(*src) + url_xtra(src);
+    url_t *dst = su_alloc(home, len);
+    if (dst) {
+      ssize_t actual;
+      actual = url_dup((char *)(dst + 1), len - sizeof(*src), dst, src);
+      if (actual < 0)
+	su_free(home, dst), dst = NULL;
+      else
+	assert(len == sizeof(*src) + actual);
+    }
+    return dst;
+  }
+  else
+    return NULL;
+}
+
+
+/** Convert an string to an url */ 
+url_t *url_make(su_home_t *h, char const *str)
+{
+  return url_hdup(h, URL_STRING_MAKE(str)->us_url);
+}
+
+/** Print an URL */ 
+url_t *url_format(su_home_t *h, char const *fmt, ...)
+{
+  url_t *url;
+  char *us;
+  va_list ap;
+
+  va_start(ap, fmt);
+
+  us = su_vsprintf(h, fmt, ap);
+
+  va_end(ap);
+
+  if (us == NULL)
+    return NULL;
+
+  url = url_hdup(h, URL_STRING_MAKE(us)->us_url);
+
+  su_free(h, us);
+
+  return url;
+}
+
+
+/** Convert @a url to a string allocated from @a home.
+ *
+ * @param home memory home to allocate the new string
+ * @param url  url to convert to string
+ *
+ * The @a url can be a string, too.
+ *
+ * @return Newly allocated conversion result, or NULL upon an error.
+ */
+char *url_as_string(su_home_t *home, url_t const *url)
+{
+  if (url) {
+    int len = url_e(NULL, 0, url);
+    char *b = su_alloc(home, len + 1);
+    url_e(b, len + 1, url);
+    return b;
+  } else {
+    return NULL;
+  }
+}
+
+
+/** Test if param @a tag matches to parameter string @a p. 
+ */
+#define URL_PARAM_MATCH(p, tag) \
+ (strncasecmp(p, tag, strlen(tag)) == 0 && \
+  (p[strlen(tag)] == '\0' || p[strlen(tag)] == ';' || p[strlen(tag)] == '='))
+
+/**
+ * Search for a parameter.
+ *
+ * This function searches for a parameter from a parameter list.
+ *
+ * If you want to test if there is parameter @b user=phone, 
+ * call this function like 
+ * @code if (url_param(url->url_param, "user=phone", NULL, 0))
+ * @endcode
+ *
+ * @param params URL parameter string (excluding first semicolon)
+ * @param tag    parameter name
+ * @param value  string to which the parameter value is copied
+ * @param vlen   length of string reserved for value
+ *
+ * @retval positive length of parameter value (including final NUL) if found
+ * @retval zero     if not found.
+ */
+isize_t url_param(char const *params, 
+		  char const *tag, 
+		  char value[], isize_t vlen)
+{
+  size_t n, tlen, flen;
+  char *p;
+
+  if (!params)
+    return 0;
+
+  tlen = strlen(tag);
+  if (tlen && tag[tlen - 1] == '=')
+    tlen--;
+
+  for (p = (char *)params; *p; p += n + 1) {
+    n = strcspn(p, ";");
+    if (n < tlen) {
+      if (p[n]) continue; else break;
+    }
+    if (strncasecmp(p, tag, tlen) == 0) {
+      if (n == tlen) {
+	if (vlen > 0)
+	  value[0] = '\0';	
+	return 1;
+      }
+      if (p[tlen] != '=')
+	continue;
+      flen = n - tlen - 1;
+      if (flen >= (size_t)vlen)
+	return flen + 1;
+      memcpy(value, p + tlen + 1, flen);
+      value[flen] = '\0';
+      return flen + 1;
+    }
+    if (!p[n])
+      break;
+  }
+
+  return 0;
+}
+
+/** Check for a parameter. 
+ *
+ * @deprecated 
+ * Bad grammar. Use url_has_param().
+ */
+isize_t url_have_param(char const *params, char const *tag)
+{
+  return url_param(params, tag, NULL, 0);
+}
+
+/** Check for a parameter. */
+int url_has_param(url_t const *url, char const *tag)
+{
+  return url && url->url_params && url_param(url->url_params, tag, NULL, 0);
+}
+
+/** Add an parameter. */
+int url_param_add(su_home_t *h, url_t *url, char const *param)
+{
+  /* XXX - should remove existing parameters with same name? */
+  size_t n = url->url_params ? strlen(url->url_params) + 1: 0;
+  size_t nn = strlen(param) + 1;
+  char *s = su_alloc(h, n + nn);
+
+  if (!s)
+    return -1;
+  
+  if (url->url_params)
+    strcpy(s, url->url_params)[n - 1] = ';';
+  strcpy(s + n, param);
+  url->url_params = s;
+
+  return 0;
+}
+
+/** Remove a named parameter from url_param string.
+ *
+ * Remove a named parameter and its possible value from the URL parameter
+ * string (url_s##url_param).
+ *
+ * @return Pointer to modified string, or NULL if nothing is left in there.
+ */
+char *url_strip_param_string(char *params, char const *name)
+{
+  if (params && name) {
+    size_t i, n = strlen(name), remove, rest;
+    
+    for (i = 0; params[i];) {
+      if (strncasecmp(params + i, name, n) ||
+	  (params[i + n] != '=' && params[i + n] != ';' && params[i + n])) {
+	i = i + strcspn(params + i, ";");
+	if (!params[i++])
+	  break;
+	continue;
+      }
+      remove = n + strcspn(params + i + n, ";");
+      if (params[i + remove] == ';')
+	remove++;
+
+      if (i == 0) {
+	params += remove;
+	continue;
+      }
+
+      rest = strlen(params + i + remove);
+      if (!rest) {
+	if (i == 0)
+	  return NULL;		/* removed everything */
+	params[i - 1] = '\0';
+	break;
+      }
+      memmove(params + i, params + i + remove, rest + 1);
+    }
+
+    if (!params[0])
+      return NULL;
+  }
+
+  return params;
+}
+
+int url_string_p(url_string_t const *url)
+{
+  return URL_STRING_P(url);
+}
+
+int url_is_string(url_string_t const *url)
+{
+  return URL_IS_STRING(url);
+}
+
+/** Strip transport-specific stuff. */
+static
+int url_strip_transport2(url_t *url, int modify)
+{
+  char *p, *d;
+  size_t n;
+  int semi;
+
+  if (url->url_type != url_sip && url->url_type != url_sips)
+    return 0;
+  
+  if (url->url_port != NULL) {
+    if (!modify)
+      return 1;
+    url->url_port = NULL;
+  }
+
+  if (!url->url_params)
+    return 0;
+
+  for (d = p = (char *)url->url_params; *p; p += n + semi) {
+    n = strcspn(p, ";");
+    semi = (p[n] != '\0');
+
+    if (modify && n == 0)
+      continue;
+    if (URL_PARAM_MATCH(p, "method"))
+      continue;
+    if (URL_PARAM_MATCH(p, "maddr"))
+      continue;
+    if (URL_PARAM_MATCH(p, "ttl"))
+      continue;
+    if (URL_PARAM_MATCH(p, "transport"))
+      continue;
+
+    if (p != d) {
+      if (d != url->url_params)
+	d++;
+      if (p != d) {
+	if (!modify)
+	  return 1;
+	memmove(d, p, n + 1);
+      }
+    }
+    d += n;
+  }
+
+  if (d == p)
+    return 0;
+  else if (d + 1 == p)		/* empty param */
+    return 0;
+  else if (!modify)
+    return 1;
+
+  if (d != url->url_params)
+    *d = '\0';
+  else 
+    url->url_params = NULL;
+
+  return 1;
+}
+
+/** Strip transport-specific stuff. 
+ *
+ * The function url_strip_transport() removes transport-specific parameters
+ * from a SIP or SIPS URI.  These parameters include:
+ * - the port number
+ * - "maddr=" parameter
+ * - "transport=" parameter
+ * - "ttl=" parameter
+ * - "method=" parameter
+ *
+ * @note
+ * The @a url must be a pointer to a URL structure. It is stripped in-place.
+ *
+ * @note
+ * If the parameter string contains empty parameters, they are stripped, too.
+ *
+ * @return 
+ * The function url_strip_transport() returns @e true, if the URL was
+ * modified, @e false otherwise.
+ */
+int url_strip_transport(url_t *url)
+{
+  return url_strip_transport2(url, 1);
+}
+
+/** Check for transport-specific stuff. 
+ *
+ * The function url_have_transport() tests if there are transport-specific
+ * parameters in a SIP or SIPS URI. These parameters include:
+ * - the port number
+ * - "maddr=" parameters
+ * - "transport=" parameters
+ * 
+ * @note
+ * The @a url must be a pointer to a URL structure.
+ *
+ * @return The function url_have_transport() returns @e true, if the URL
+ * contains transport parameters, @e false otherwise.
+ */
+int url_have_transport(url_t const *url)
+{
+  return url_strip_transport2((url_t *)url, 0);
+}
+
+/**Lazily compare two URLs.
+ *
+ * Compare essential parts of URLs: schema, host, port, and username.
+ *
+ * any_url compares 0 with any other URL.
+ *
+ * pres: and im: URIs compares 0 with SIP URIs.
+ *
+ * @note
+ * The @a a and @a b must be pointers to URL structures.
+ *
+ * @note Currently, the url parameters are not compared. This is because the
+ * url_cmp() is used to sort URLs: taking parameters into account makes that
+ * impossible. 
+ */
+int url_cmp(url_t const *a, url_t const *b)
+{
+  int rv;
+  int url_type;
+
+  if ((a && a->url_type == url_any) || (b && b->url_type == url_any))
+    return 0;
+
+  if (!a || !b)
+    return (a != NULL) - (b != NULL);
+
+  if ((rv = a->url_type - b->url_type)) {
+#if 0
+    /* presence and instant messaging URLs match magically with SIP */
+    enum url_type_e a_type = a->url_type;
+    enum url_type_e b_type = b->url_type;
+    
+    if (a_type == url_im || a_type == url_pres)
+      a_type = url_sip;
+
+    if (b_type == url_im || b_type == url_pres)
+      b_type = url_sip;
+
+    if (a_type != b_type)
+#endif
+      return rv;
+  }
+
+  url_type = a->url_type;	/* Or b->url_type, they are equal! */
+
+  if (url_type <= url_unknown && 
+      ((rv = !a->url_scheme - !b->url_scheme) ||
+       (a->url_scheme && b->url_scheme &&
+	(rv = strcasecmp(a->url_scheme, b->url_scheme)))))
+    return rv;
+
+  if ((rv = host_cmp(a->url_host, b->url_host)))
+    return rv;
+
+  if (a->url_port != b->url_port) {
+    char const *a_port;
+    char const *b_port;
+
+    if (url_type != url_sip && url_type != url_sips)
+      a_port = b_port = url_port_default(url_type);
+    else if (host_is_ip_address(a->url_host))
+      a_port = b_port = url_port_default(url_type);
+    else
+      a_port = b_port = "";
+    
+    if (a->url_port) a_port = a->url_port;
+    if (b->url_port) b_port = b->url_port;
+
+    if ((rv = strcmp(a_port, b_port)))
+      return rv;
+  }
+
+  if (a->url_user != b->url_user) {
+    if (a->url_user == NULL) return -1;
+    if (b->url_user == NULL) return +1;
+    switch (url_type) {
+    case url_tel: case url_modem: case url_fax:
+      rv = url_tel_cmp_numbers(a->url_user, b->url_user);
+      break;
+    default:
+      rv = strcmp(a->url_user, b->url_user);
+      break;
+    }
+    if (rv)
+      return rv;
+  }
+
+#if 0
+  if (a->url_path != b->url_path) {
+    if (a->url_path == NULL) return -1;
+    if (b->url_path == NULL) return +1;
+    if ((rv = strcmp(a->url_path, b->url_path)))
+      return rv;
+  }
+#endif
+
+  return 0;
+}
+
+static
+int url_tel_cmp_numbers(char const *A, char const *B)
+{
+  char a, b;
+  int rv;
+
+  while (*A && *B) {
+    #define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+    /* Skip visual-separators */
+    do {
+      a = *A++;
+      if (a == '%' && IS_HEX(A[0]) && IS_HEX(A[1])) 
+	a = (UNHEX(A[0]) << 4) | UNHEX(A[1]), A +=2;
+    } while (a == ' ' || a == '-' || a == '.' || a == '(' || a == ')');
+
+    if (isupper(a))
+      a = tolower(a);
+
+    do {
+      b = *B++;
+      if (b == '%' && IS_HEX(B[0]) && IS_HEX(B[1])) 
+	b = (UNHEX(B[0]) << 4) | UNHEX(B[1]), B +=2;
+    } while (b == ' ' || b == '-' || b == '.' || b == '(' || b == ')');
+
+    if (isupper(b))
+      b = tolower(b);
+
+    if ((rv = a - b))
+      return rv;
+  }
+
+  return (int)*A - (int)*B;
+}
+
+/**Conservative comparison of urls.
+ *
+ * Compare all parts of URLs.
+ *
+ * @note
+ * The @a a and @a b must be pointers to URL structures.
+ *
+ */
+int url_cmp_all(url_t const *a, url_t const *b)
+{
+  int rv, url_type;
+
+  if (!a || !b)
+    return (a != NULL) - (b != NULL);
+
+  if ((rv = a->url_type - b->url_type))
+    return rv;
+
+  url_type = a->url_type;	/* Or b->url_type, they are equal! */
+
+  if (url_type <= url_unknown && 
+      ((rv = !a->url_scheme - !b->url_scheme) ||
+       (a->url_scheme && b->url_scheme &&
+	(rv = strcasecmp(a->url_scheme, b->url_scheme)))))
+    return rv;
+
+  if ((rv = a->url_root - b->url_root))
+    return rv;
+
+  if ((rv = host_cmp(a->url_host, b->url_host)))
+    return rv;
+
+  if (a->url_port != b->url_port) {
+    char const *a_port;
+    char const *b_port;
+
+    if (url_type != url_sip && url_type != url_sips)
+      a_port = b_port = url_port_default(url_type);
+    else if (host_is_ip_address(a->url_host))
+      a_port = b_port = url_port_default(url_type);
+    else
+      a_port = b_port = "";
+    
+    if (a->url_port) a_port = a->url_port;
+    if (b->url_port) b_port = b->url_port;
+
+    if ((rv = strcmp(a_port, b_port)))
+      return rv;
+  }
+
+  if (a->url_user != b->url_user) {
+    if (a->url_user == NULL) return -1;
+    if (b->url_user == NULL) return +1;
+
+    switch (url_type) {
+    case url_tel: case url_modem: case url_fax:
+      rv = url_tel_cmp_numbers(a->url_user, b->url_user);
+      break;
+    default:
+      rv = strcmp(a->url_user, b->url_user);
+      break;
+    }
+    if (rv)
+      return rv;
+  }
+
+  if (a->url_path != b->url_path) {
+    if (a->url_path == NULL) return -1;
+    if (b->url_path == NULL) return +1;
+    if ((rv = strcmp(a->url_path, b->url_path)))
+      return rv;
+  }
+
+  if (a->url_params != b->url_params) {
+    if (a->url_params == NULL) return -1;
+    if (b->url_params == NULL) return +1;
+    if ((rv = strcmp(a->url_params, b->url_params)))
+      return rv;
+  }
+
+  if (a->url_headers != b->url_headers) {
+    if (a->url_headers == NULL) return -1;
+    if (b->url_headers == NULL) return +1;
+    if ((rv = strcmp(a->url_headers, b->url_headers)))
+      return rv;
+  }
+
+  if (a->url_headers != b->url_headers) {
+    if (a->url_headers == NULL) return -1;
+    if (b->url_headers == NULL) return +1;
+    if ((rv = strcmp(a->url_headers, b->url_headers)))
+      return rv;
+  }
+
+  if (a->url_fragment != b->url_fragment) {
+    if (a->url_fragment == NULL) return -1;
+    if (b->url_fragment == NULL) return +1;
+    if ((rv = strcmp(a->url_fragment, b->url_fragment)))
+      return rv;
+  }
+
+  return 0;
+}
+
+/** Return default port number corresponding to the url type */
+char const *url_port_default(enum url_type_e url_type)
+{
+  switch (url_type) {
+  case url_sip:			/* "sip:" */
+    return "5060";
+  case url_sips:		/* "sips:" */
+    return "5061";
+  case url_http:		/* "http:" */
+    return "80";
+  case url_https:		/* "https:" */
+    return "443";
+  case url_ftp:			/* "ftp:" */
+  case url_file:		/* "file:" */
+    return "21";
+  case url_rtsp:		/* "rtsp:" */
+  case url_rtspu:		/* "rtspu:" */
+    return "554";
+  case url_mailto:		/* "mailto:" */
+    return "25";
+
+  case url_any:			/* "*" */
+    return "*";
+
+  case url_msrp:
+  case url_msrps:
+    return "9999";		/* XXXX */
+
+  case url_tel:	
+  case url_fax:	
+  case url_modem:
+  case url_im:	
+  case url_pres:
+  case url_cid:
+  case url_wv:
+
+  default:			/* Unknown scheme */
+    return "";
+  }
+}
+
+/** Return default transport name corresponding to the url type */
+char const *url_tport_default(enum url_type_e url_type)
+{
+  switch (url_type) {
+  case url_sip:
+    return "*";
+  case url_sips:
+    return "tls";
+  case url_http:
+    return "tcp";
+  case url_https:
+    return "tls";
+  case url_ftp:
+  case url_file:
+    return "tcp";
+  case url_rtsp:
+    return "tcp";
+  case url_rtspu:
+    return "udp";
+  case url_mailto:
+    return "tcp";
+  case url_msrp:
+    return "tcp";
+  case url_msrps:
+    return "tls";
+
+  case url_any:			/* "*" */
+  case url_tel:
+  case url_fax:
+  case url_modem:
+  case url_im:
+  case url_pres:
+  case url_cid:
+  case url_wv:
+
+  default:			/* Unknown scheme */
+    return "*";
+  }
+}
+
+
+/** Return the URL port string */
+char const *url_port(url_t const *u)
+{
+  if (!u)
+    return "";
+  else if (u->url_port && u->url_port[0])
+    return u->url_port;
+
+  if (u->url_type == url_sips || u->url_type == url_sip)
+    if (!host_is_ip_address(u->url_host))
+      return "";
+
+  return url_port_default(u->url_type);
+}
+
+/** Sanitize URL.
+ *
+ * The function url_sanitize() adds a scheme to an incomplete URL.  It
+ * modifies its parameter structure @a url.  Currently, the function follows
+ * simple heuristics:
+ *
+ * - URL with host name starting with @c ftp. is an FTP URL
+ * - URL with host name starting with @c www. is an HTTP URL
+ * - URL with host and path, e.g., @c host/foo;bar, is an HTTP URL
+ * - URL with host name, no path is a SIP URL.
+ *
+ * @param url pointer to URL struct to be sanitized (IN/OUT)
+ *
+ * @return
+ * The function url_sanitize() returns 0 if it considers URL to be
+ * sane, and -1 otherwise.
+ */
+int url_sanitize(url_t *url)
+{
+  if (!url)
+    return -1;
+  else if (url->url_scheme != NULL)
+    /* xyzzy */;
+  else if (url->url_host == NULL)
+    return -1;
+  else if (strncasecmp(url->url_host, "ftp.", strlen("ftp.")) == 0)
+    url->url_type = url_ftp, url->url_scheme = "ftp", url->url_root = '/';
+  else if (strncasecmp(url->url_host, "www.", strlen("www.")) == 0
+	   || url->url_path)
+    url->url_type = url_http, url->url_scheme = "http", url->url_root = '/';
+  else
+    url->url_type = url_sip, url->url_scheme = "sip";
+
+  return 0;
+}
+
+#include <sofia-sip/su_md5.h>
+
+static
+void canon_update(su_md5_t *md5, char const *s, size_t n, char const *allow)
+{
+  size_t i, j;
+
+  for (i = 0, j = 0; i < n && s[i]; i++) {
+    char c;
+
+    if (s[i] == '%' && i + 2 < n && IS_HEX(s[i+1]) && IS_HEX(s[i+2])) {
+#define   UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+      c = (UNHEX(s[i+1]) << 4) | UNHEX(s[i+2]);
+#undef    UNHEX
+      if (c != '%' && c > ' ' && c < '\177' && 
+	  (!strchr(EXCLUDED, c) || strchr(allow, c))) {
+	if (i != j)
+	  su_md5_iupdate(md5, s + j, i - j);
+	su_md5_iupdate(md5, &c, 1);
+	j = i + 3;
+      }
+      i += 2;
+    }
+  }
+
+  if (i != j)
+    su_md5_iupdate(md5, s + j, i - j);
+}
+
+/** Update MD5 sum with url-string contents */
+static
+void url_string_update(su_md5_t *md5, char const *s)
+{
+  size_t n;
+  int hostpart = 1;
+  enum url_type_e type = url_any;
+  char const *at, *colon;
+  char schema[48];
+
+  if (s == NULL || strlen(s) == 0 || strcmp(s, "*") == 0) {
+    su_md5_update(md5, "*\0\0*", 4);
+    return;
+  }
+
+  n = strcspn(s, ":/?#");
+  if (n >= sizeof schema) {
+    su_md5_update(md5, ":", 1);
+  }
+  else if (n && s[n] == ':' ) {
+    at = url_canonize(schema, s, n, "+");
+
+    type = url_get_type(schema, at - schema);
+    su_md5_iupdate(md5, schema, at - schema);
+
+    hostpart = !url_type_is_opaque(type);
+    s += n + 1;
+  }
+  else {
+    su_md5_update(md5, "", 1);
+  }
+  
+  if (type == url_sip || type == url_sips) {
+    n = strcspn(s, "@#");	/* Opaque part */
+    if (s[n] != '@')
+      n = 0;
+    n += strcspn(s + n, "/;?#");
+  }
+  else if (type == url_wv) {    /* WV URL may have / in user part */
+    n = strcspn(s, "@#?;");
+    if (s[n] == '@')
+      n += strcspn(s + n, ";?#");
+  }
+  else if (!hostpart || s[0] != '/') {
+    n = strcspn(s, "/;?#");	/* Opaque part */
+  }
+  else if (s[1] == '/') {
+    s += 2;
+    n = strcspn(s, "/;?#");	/* Until host, path, query or fragment */
+  }
+  else {
+    /* foo:/bar */
+    su_md5_update(md5, "\0\0", 2); /* user, host */
+    su_md5_striupdate(md5, url_port_default(type));
+    return;
+  }
+  
+  if (!hostpart) {
+    char const *colon = memchr(s, ':', n);
+    
+    if (colon) n = colon - s;
+    canon_update(md5, s, n, ""); /* user */
+    su_md5_update(md5, "\0", 1); /* host, no port */
+    su_md5_striupdate(md5, url_port_default(type));
+    return;
+  }
+
+  at = memchr(s, '@', n);
+
+  if (at) {
+    char const *allow = 
+      (type == url_sip || type == url_sips) 
+      ? SIP_USER_UNRESERVED
+      : USER_UNRESERVED;
+
+    colon = type == url_unknown ? NULL : memchr(s, ':', at - s);
+
+    /* Updated only user part */
+    if (colon)
+      canon_update(md5, s, colon - s, allow);
+    else
+      canon_update(md5, s, at - s, allow);
+    n = n - (at + 1 - s);
+    s = at + 1;
+  }
+  else
+    su_md5_iupdate(md5, "", 1);	/* user */
+
+  colon = memchr(s, ':', n);	/* XXX - IPv6! */
+  if (colon) {
+    canon_update(md5, s, colon - s, ""); /* host */
+    canon_update(md5, colon + 1, (s + n) - (colon + 1), "");
+  }
+  else {
+    canon_update(md5, s, n, ""); /* host */
+    su_md5_strupdate(md5, url_port_default(type));	/* port */
+  }
+
+  /* ignore parameters/path/headers.... */
+}
+
+
+/** Update md5 digest with contents of URL.
+ *
+ */
+void url_update(su_md5_t *md5, url_t const *url)
+{
+  if (url_string_p((url_string_t *)url)) {
+    url_string_update(md5, (char const *)url);
+  }
+  else {
+    SU_MD5_STRI0UPDATE(md5, url->url_scheme);
+    SU_MD5_STRI0UPDATE(md5, url->url_user);
+    SU_MD5_STRI0UPDATE(md5, url->url_host);
+    su_md5_striupdate(md5, URL_PORT(url));
+    /* XXX - parameters/path.... */
+    /* SU_MD5_STRI0UPDATE(md5, url->url_path); */
+  }
+}
+
+/** Calculate a digest from URL contents. */
+void url_digest(void *hash, int hsize, url_t const *url, char const *key)
+{
+  su_md5_t md5[1];
+  uint8_t digest[SU_MD5_DIGEST_SIZE];
+
+  su_md5_init(md5);
+  if (key) su_md5_strupdate(md5, key);
+  url_update(md5, url);
+  su_md5_digest(md5, digest);
+
+  if (hsize > SU_MD5_DIGEST_SIZE) {
+    memset((char *)hash + SU_MD5_DIGEST_SIZE, 0, hsize - SU_MD5_DIGEST_SIZE);
+    hsize = SU_MD5_DIGEST_SIZE;
+  }
+
+  memcpy(hash, digest, hsize);
+}
+
+/** Convert a URL query to a header string.
+ *
+ * URL query is converted by replacing each "=" in header name "=" value
+ * pair with semicolon (":"), and the "&" separating header-name-value pairs
+ * with line feed ("\n"). The "body" pseudoheader is moved last in the
+ * string. The %-escaping is removed. Note that if the @a query contains %00,
+ * the resulting string will be truncated.
+ *
+ * @param home memory home used to alloate string (if NULL, malloc() it)
+ * @param query query part from SIP URL 
+ * 
+ * The result string is allocated from @a home, and it can be used as
+ * argument to msg_header_parse_str(), msg_header_add_str() or
+ * SIPTAG_HEADER_STR().
+ *
+ * @sa msg_header_add_str(), SIPTAG_HEADER_STR(),
+ * sip_headers_as_url_query(), sip_url_query_as_taglist(), 
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers,
+ * url_unescape(), url_unescape_to()
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+char *url_query_as_header_string(su_home_t *home, 
+				 char const *query)
+{
+  size_t i, j, n, b_start = 0, b_len = 0;
+  char *s = su_strdup(home, query);
+
+  if (!s) 
+    return NULL;
+
+  for (i = 0, j = 0; s[i];) {
+    n = strcspn(s + i, "=");
+    if (!s[i + n])
+      break;
+    if (n == 4 && strncasecmp(s + i, "body", 4) == 0) {
+      if (b_start)
+	break;
+      b_start = i + n + 1, b_len = strcspn(s + b_start, "&");
+      i = b_start + b_len + 1;
+      continue;
+    }
+    if (i != j)
+      memmove(s + j, s + i, n);
+    s[j + n] = ':';
+    i += n + 1, j += n + 1;
+    n = strcspn(s + i, "&");
+    j += url_unescape_to(s + j, s + i, n);
+    i += n;
+    if (s[i]) {
+      s[j++] = '\n', i++;
+    }
+  }
+
+  if (s[i])
+    return (void)su_free(home, s), NULL;
+
+  if (b_start) {
+    s[j++] = '\n', s[j++] = '\n';
+    j += url_unescape_to(s + j, query + b_start, b_len);
+  }
+  s[j] = '\0'; assert(j <= i);
+
+  return s;
+}

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,189 @@
+/**@MODULEPAGE "url" - URL Module
+
+ at section url_meta Module Meta Information
+
+The Sofia @b url module contains macros and functions for using URL
+datatype #url_t, parsing and printing URLs. 
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section url_syntax Using URL Library
+
+The URL library provides URL datatype and helper functions related to it. 
+There is URL parser, which separates the URL components to the #url_t
+structure.
+
+ at note 
+Please note that we use terms URL and URI interchangeable.
+
+The formal URI syntax is defined in the 
+<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC2396</a>.
+
+The URLs consist of a subset of printable ASCII (ECMA-5) characters. The
+subset excludes space and characters commonly used as @e delimiters in
+text-based protocols, such as <b> < > # \% </b>and<b> " </b> (double
+quote), and so called @e unwise characters whose positions are reserved for
+national extensions in ECMA-5. In US-ASCII, those characters are:
+<code><b>
+{ } | \ ^ [ ] `
+</b></code>
+
+There are also nine characters that can have special syntactic meaning in
+some parts of the URI. These @e reserved characters are used to separate
+syntactical parts of the URLs from each other. The reserved characters are
+as follows: <b> : @ / ; ? & = + </b>and<b> $</b>.
+
+The URL library understands two alternative URL syntaxes. First, the
+basic syntax used by, e.g., @b ftp:, @b http: and @b rtsp: URLs:
+
+<i>scheme</i> ":" ["//" [ <i>user</i> [":" <i>password</i> ] "@"] 
+<i>host</i> [":" <i>port</i> ] ] 
+      ["/" <i>path</i> ] ["?" <i>query</i> ] ["#" <i>fragment</i> ]
+
+Alternatively, the syntax used by @b mailto:, @b sip:, @b im:, @b tel,
+and @b pres: URLs:
+
+<i>scheme</i> ":" [ [ <i>user</i> [":" <i>password</i> ] "@"] 
+<i>host</i> [":" <i>port</i> ] ] [";" <i>params</i> ] ["?" <i>query</i> ]
+["#" <i>fragment</i> ]
+
+Note that also "*" is considered to be a valid URL (with type #url_any).
+
+For example: \n
+ at code
+http://example.org:7100/cgi-bin/query?key=90786
+ftp://user:pass\@ftp.example.com/pub/
+sip:user:pass\@example.com;user=ip
+tel:+358718008000
+ at endcode
+
+ at subsection url_parsing Converting a String to #url_t
+
+The function url_make() converts a string to a freshly allocated #url_t
+structure. The URL components are split into parts as shown above.
+The hex encoding using \% is removed if the encoded character can
+syntactically be part of the field. For instance, "%41" is decoded as
+"A" in the user part, but "%40" (@) is left as is. (This is called
+canonization of the URL fields.)
+
+The function url_format() is provided for generating the URL with
+printf()-like formatting.
+
+For example, when we make the url from the string below
+ at code
+sip:joe%2Euser at example%2Ecom;method=%4D%45%53%53%41%47%45?body=CANNED%20MSG
+ at endcode
+the components are NUL-terminated, canonized and assigned to the structure
+as follows:
+ at code
+ url_type = url_sip
+ url_root = 0 
+ url_scheme = "sip"
+ url_user = "joe.user"
+ url_password = NULL
+ url_host = "example.com"
+ url_port = NULL
+ url_path = NULL
+ url_params = "method=MESSAGE"
+ url_headers = "body=CANNED%20MSG"
+ url_fragment = NULL
+ at endcode
+
+You can use the function url_param() and url_have_param() to access
+particular parameters from @ref url_t::url_params "url->url_params" string.
+
+ at subsection url_parsing Converting a #url_t structure to string
+
+The function url_as_string() converts contents of #url_t structure to a
+newly allocated string.
+
+ at subsection url_reference Functions and Macros in URL Module
+
+The include file <url.h> contains the types, function and macros of URL
+module. The functions and macros are listed here for the reference, too.
+The most important functions and macros for manipulating URLs are here:
+ at code
+url_t *url_make(su_home_t *h, char const *str);
+url_t *url_format(su_home_t *h, char const *fmt, ...);
+char *url_as_string(su_home_t *home, url_t const *url);
+url_t *url_hdup(su_home_t *h, url_t const *src);
+int url_sanitize(url_t *u);
+char const *url_scheme(enum url_type_e type);
+
+#define URL_INIT_AS(type) 
+void url_init(url_t *url, enum url_type_e type);
+
+int url_cmp(url_t const *a, url_t const *b);
+int url_cmp_all(url_t const *a, url_t const *b);
+
+isize_t url_param(char const *params, char const *tag,
+		  char value[], isize_t vlen);
+int url_has_param(url_t const *url, char const *name);
+isize_t url_have_param(char const *params, char const *tag);
+int url_param_add(su_home_t *h, url_t *url, char const *param);
+ at endcode
+
+There are functions for handling %-encoding used in URLs:
+ at code
+int url_reserved_p(char const *s);
+char *url_escape(char *d, char const *s, char const reserved[]);
+int url_esclen(char const *s, char const reserved[]);
+char *url_unescape(char *d, char const *s);
+ at endcode
+
+There are a few function and macros helping resolving URLs:
+ at code
+char const *url_port_default(enum url_type_e url_type);
+char const *url_tport_default(enum url_type_e url_type);
+char const *url_port(url_t const *u);
+#define URL_PORT(u) 
+ at endcode
+
+In addition to the basic URL structure, #url_t, the library interface
+provides an union type #url_string_t for passing unparsed strings instead
+of parsed URLs as function arguments:
+ at code
+#define URL_STRING_P(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+#define URL_IS_STRING(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+int url_string_p(url_string_t const * url);
+int url_is_string(url_string_t const * url);
+#define URL_STRING_MAKE(s) 
+ at endcode
+
+There are a macros for printf()-like formatting of URLs:
+ at code
+#define URL_PRINT_FORMAT
+#define URL_PRINT_ARGS(u) 
+ at endcode
+
+These functions calculate MD5 digest of URL or contribute contents of the
+URL to MD5 sum:
+ at code
+void url_update(struct su_md5_t *md5, url_t const *url);
+void url_digest(void *hash, int hsize, url_t const *, char const *key);
+ at endcode
+
+SIP or SIPS URIs have some parameters that control transport of the request. 
+In some cases, they should be detected and removed:
+ at code
+int url_have_transport(url_t const *u);
+int url_strip_transport(url_t *u);
+ at endcode
+
+Finally, there are functions used as building blocks for protocol parsers
+using URLs:
+ at code
+int url_d(url_t *url, char *s);
+isize_t url_len(url_t const * url);
+issize_t url_e(char buffer[], isize_t n, url_t const *url);
+#define URL_E(buf, end, url)
+isize_t url_xtra(url_t const * url);
+issize_t url_dup(char *, isize_t , url_t *dst, url_t const *src);
+#define URL_DUP(buf, end, dst, src) 
+ at endcode
+
+*/

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE url_tag.c  URL Tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 10:15:20 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "url"
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/url_tag.h>
+#include <sofia-sip/url_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+
+#include <sofia-sip/url.h>
+
+#include <string.h>
+
+tag_typedef_t urltag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t urltag_url = URLTAG_TYPEDEF(url);
+
+int urltag_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  url_string_t const *us = (url_string_t const *)t->t_value;
+
+  if (us == NULL)
+    return snprintf(b, size, "<null>");
+  if (URL_STRING_P(us))
+    return snprintf(b, size, "<%s>", us->us_str);
+  else
+    return snprintf(b, size, "<" URL_PRINT_FORMAT ">", 
+		    URL_PRINT_ARGS(us->us_url));
+}
+
+size_t urltag_xtra(tagi_t const *t, size_t offset)
+{
+  url_t const *url = (url_t const *)t->t_value;
+
+  if (url == NULL || url == (url_t *)-1)
+    return 0;
+  else if (URL_STRING_P(url))
+    return t_str_xtra(t, offset);
+  else
+    return SU_ALIGN(offset) + sizeof(*url) + url_xtra(url);
+}
+
+tagi_t *urltag_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  url_t const *url = (url_t const *)src->t_value;
+
+  if (url == NULL || url == (url_t *)-1) {
+    dst->t_tag = src->t_tag;
+    dst->t_value = src->t_value;
+  }
+  else if (URL_STRING_P(url)) {
+    return t_str_dup(dst, src, bb);
+  } else {
+    size_t xtra = url_xtra(url);
+    char *b = *bb;
+    url_t *d;
+
+    b += SU_ALIGN(b);
+    d = (url_t *)b;
+    url_dup(b + sizeof(*d), xtra, d, url);
+
+    dst->t_tag = src->t_tag;
+    dst->t_value = (tag_value_t)d;
+    *bb = b + sizeof(*d) + xtra;
+  }
+  
+  return dst + 1;
+}
+
+#define IS_EXCLUDED(u)						\
+  (u <= ' '							\
+   || u >= '\177'						\
+   || (u < 64 ? (0xb400000aU  & (1 << (63 - u)))			\
+       : (u < 96 ? (0x0000001eU & (1 << (95 - u)))		\
+	  : /*u < 128*/ (0x8000001dU & (1 << (127 - u))))) != 0)
+
+/** Tag function used to convert a string to a URL tag value.
+ *
+ * @param tt tag type
+ * @param home memory home used to allocate new #url_t structure
+ * @param str string to convert 
+ * @param return_value return-value parameter for converted url
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+int urltag_scan(tag_type_t tt, su_home_t *home,
+		char const *str,
+		tag_value_t *return_value)
+{
+  size_t len;
+  url_t *url;
+  char *s;
+
+  for (len = 0; !IS_EXCLUDED(str[len]); len++)
+    ;
+  
+  url = su_alloc(home, (sizeof *url) + len + 1);
+  if (!url)
+    return -1;
+  s = memcpy((char *)(url + 1), str, len);
+  s[len] = 0;
+
+  if (url_d(url, s) < 0)
+    return (void)su_free(home, url), -1;
+
+  *return_value = (tag_value_t)url;
+
+  return 0;
+}
+
+tag_class_t url_tag_class[1] = 
+  {{
+    sizeof(url_tag_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     urltag_xtra,
+    /* tc_dup */      urltag_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ urltag_snprintf,
+    /* tc_filter */   NULL,
+    /* tc_ref_set */  t_ptr_ref_set,
+    /* tc_scan */     urltag_scan,
+  }};
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file urlmap.c
+ * @brief Mapping with hierarchical URLs.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "urlmap.h"
+
+/** Create map entry. */
+UrlMap *url_map_new(su_home_t *home,
+		    url_string_t const *url,
+		    unsigned size)
+{
+  UrlMap *um;
+  int xtra;
+  url_t *u;
+
+  xtra = url_xtra(url->us_url);
+  um = su_zalloc(home, size + xtra);
+  if (!um || url_dup((char *)um + size, xtra, um->um_url, url->us_url) < 0) {
+    su_free(home, um);
+    return NULL;
+  }
+
+  u = um->um_url;
+  if (!u->url_path)
+    u->url_path = "";
+
+  return um;
+}
+
+static
+void left_rotate(UrlMap **top, UrlMap *x)
+{
+  /*               x                c
+   *              / \              / \
+   * Convert     a   c    into    x   d
+   *                / \          / \
+   *               b   d        a   b
+   */
+  UrlMap *c = x->um_right, *dad = x->um_dad; assert(c);
+
+  if ((x->um_right = c->um_left))
+    x->um_right->um_dad = x;
+
+  if (!(c->um_dad = dad))
+    *top = c;
+  else if (dad->um_left == x)
+    dad->um_left = c;
+  else
+    assert(dad->um_right == x), dad->um_right = c;
+
+  c->um_left = x;
+  x->um_dad = c;
+}
+
+static
+void right_rotate(UrlMap **top, UrlMap *x)
+{
+  /*               x                c
+   *              / \              / \
+   * Convert     c   f    into    a   x
+   *            / \                  / \
+   *           a   d                d   f
+   */
+  UrlMap *c = x->um_left, *dad = x->um_dad; assert(c);
+
+  if ((x->um_left = c->um_right))
+    x->um_left->um_dad = x;
+
+  if (!(c->um_dad = dad))
+    *top = c;
+  else if (dad->um_right == x)
+    dad->um_right = c;
+  else
+    assert(dad->um_left == x), dad->um_left = c;
+
+  c->um_right = x;
+  x->um_dad = c;
+}
+
+/** Balance Red-Black binary tree after inserting node @a um.
+ *
+ * The function red_black_balance_insert() balances a red-black tree after
+ * insertion.
+ */
+static
+void red_black_balance_insert(UrlMap **top, UrlMap *um)
+{
+  UrlMap *dad, *uncle, *granddad;
+
+  um->um_black = 0;
+
+  for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {
+    /* Repeat until we are parent or we have a black dad */
+    granddad = dad->um_dad; assert(granddad);
+    if (dad == granddad->um_left) {
+      uncle = granddad->um_right;
+      if (uncle && !uncle->um_black) {
+	dad->um_black = 1;
+	uncle->um_black = 1;
+	granddad->um_black = 0;
+	um = granddad;
+      } else {
+	if (um == dad->um_right) {
+	  left_rotate(top, um = dad);
+	  dad = um->um_dad; assert(dad);
+	  granddad = dad->um_dad; assert(granddad);
+	}
+	dad->um_black = 1;
+	granddad->um_black = 0;
+	right_rotate(top, granddad);
+      }
+    } else { assert(dad == granddad->um_right);
+      uncle = granddad->um_left;
+      if (uncle && !uncle->um_black) {
+	dad->um_black = 1;
+	uncle->um_black = 1;
+	granddad->um_black = 0;
+	um = granddad;
+      } else {
+	if (um == dad->um_left) {
+	  right_rotate(top, um = dad);
+	  dad = um->um_dad; assert(dad);
+	  granddad = dad->um_dad; assert(granddad);
+	}
+	dad->um_black = 1;
+	granddad->um_black = 0;
+	left_rotate(top, granddad);
+      }
+    }
+  }
+
+  assert(*top);
+
+  (*top)->um_black = 1;
+}
+
+static 
+void red_black_balance_delete(UrlMap **top, UrlMap *um)
+{
+  UrlMap *dad, *brother;
+
+  for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {
+    if (um == dad->um_left) {
+      brother = dad->um_right;
+
+      if (!brother) {
+	um = dad;
+	continue;
+      }
+
+      assert(brother->um_black);
+      if ((!brother->um_left || brother->um_left->um_black) &&
+	  (!brother->um_right || brother->um_right->um_black)) {
+	brother->um_black = 0;
+	um = dad;
+	continue;
+      } 
+
+      if (!brother->um_right || brother->um_right->um_black) {
+	brother->um_left->um_black = 1;
+	brother->um_black = 0;
+	right_rotate(top, brother);
+	brother = dad->um_right;
+      }
+
+      brother->um_black = dad->um_black;
+      dad->um_black = 1;
+      if (brother->um_right)
+	brother->um_right->um_black = 1;
+      left_rotate(top, dad);
+      um = *top;
+      break;
+    } else { 
+      assert(um == dad->um_right);
+      brother = dad->um_left;
+
+      if (!brother) {
+	um = dad;
+	continue;
+      }
+
+      assert(brother->um_black);
+
+      if ((!brother->um_left || brother->um_left->um_black) &&
+	  (!brother->um_right || brother->um_right->um_black)) {
+	brother->um_black = 0;
+	um = dad;
+	continue;
+      } 
+
+      if (!brother->um_left || brother->um_left->um_black) {
+	brother->um_right->um_black = 1;
+	brother->um_black = 0;
+	left_rotate(top, brother);
+	brother = dad->um_left;
+      }
+
+      brother->um_black = um->um_dad->um_black;
+      um->um_dad->um_black = 1;
+      if (brother->um_left)
+	brother->um_left->um_black = 1;
+      right_rotate(top, dad);
+      um = *top;
+      break;
+    }
+  }
+
+  um->um_black = 1;
+}
+
+/** Compare paths. */
+static inline
+int urlmap_pathcmp(url_t const *a, url_t const *b, int *return_hostmatch)
+{
+  int retval;
+
+  retval = url_cmp(a, b);
+
+  *return_hostmatch = !retval;
+
+  if (retval)
+    return retval;
+  else
+    return strcmp(a->url_path, b->url_path);
+}
+
+/** Insert URL into map. */
+int url_map_insert(UrlMap ** const tree,
+		   UrlMap * const um,
+		   UrlMap **return_old)
+{
+  UrlMap *old, *dad, **tslot;
+  url_t *u;
+  int cmp, hostmatch;
+
+  if (tree == NULL || um == NULL || um->um_inserted)
+    return (errno = EINVAL), -1;
+
+  u = um->um_url;
+
+  /* Insert into red-black binary tree */
+
+  tslot = tree;
+
+  for (old = *tree, dad = NULL; old; old = *tslot) {
+    cmp = urlmap_pathcmp(u, old->um_url, &hostmatch);
+    if (cmp < 0)
+      dad = old, tslot = &old->um_left;
+    else if (cmp > 0)
+      dad = old, tslot = &old->um_right;
+    else
+      break;
+  }
+
+  assert(old != um);
+
+  if (old) {
+    if ((um->um_left = old->um_left))
+      um->um_left->um_dad = um;
+    if ((um->um_right = old->um_right))
+      um->um_right->um_dad = um;
+
+    if (!(um->um_dad = old->um_dad))
+      *tree = um;
+    else if (um->um_dad->um_left == old)
+      um->um_dad->um_left = um;
+    else assert(um->um_dad->um_right == old),
+      um->um_dad->um_right = um;
+
+    um->um_black = old->um_black;
+
+    old->um_left = NULL;
+    old->um_right = NULL;
+    old->um_dad = NULL;
+    old->um_inserted = 0;
+  } else {
+    *tslot = um;
+    um->um_dad = dad;
+    if (tree != tslot) {
+      red_black_balance_insert(tree, um);
+    } else {
+      um->um_black = 1;
+    }
+  }
+
+  um->um_inserted = 1;
+
+  if (return_old)
+    *return_old = old;
+
+  return 0;
+}
+
+/** Find a URL */
+UrlMap *
+url_map_find(UrlMap *root,
+	     url_string_t const *url,
+	     int relative)
+{
+  UrlMap *um, *maybe = NULL;
+  url_t u[1];
+  void *tbf = NULL;
+  char *end;
+  int cmp, hostmatch;
+
+  if (root == NULL || url == NULL)
+    return NULL;
+
+  url = tbf = url_hdup(NULL, (url_t *)url);
+  if (!url)
+    return NULL;
+
+  *u = *url->us_url;
+  if (!u->url_path)
+    u->url_path = "";
+
+  for (um = root; um; um = cmp < 0 ? um->um_left : um->um_right) {
+    cmp = urlmap_pathcmp(u, um->um_url, &hostmatch);
+    if (cmp == 0)
+      break;
+    if (hostmatch && !maybe)
+      maybe = um;
+  }
+
+  while (!um && relative && u->url_path[0]) {
+    end = strrchr(u->url_path, '/');
+    end = end ? end + 1 : (char *)u->url_path;
+    if (*end)
+      *end = '\0';
+    for (um = maybe; um; um = cmp < 0 ? um->um_left : um->um_right) {
+      if ((cmp = urlmap_pathcmp(u, um->um_url, &hostmatch)) == 0)
+	break;
+    }
+  }
+
+  su_free(NULL, tbf);
+
+  return um;
+}
+
+/** Remove URL. */
+void url_map_remove(UrlMap **top, UrlMap *um)
+{
+  UrlMap *kid, *dad;
+  int need_to_balance;
+
+  if (top == NULL || um == NULL || !um->um_inserted)
+    return;
+
+  /* Make sure that node is in tree */
+  for (dad = um; dad; dad = dad->um_dad)
+    if (dad == *top)
+      break;
+
+  assert(dad);
+  if (!dad)
+    return;
+
+  /* Find a successor node with a free branch */
+  if (!um->um_left || !um->um_right)
+    dad = um;
+  else for (dad = um->um_right; dad->um_left; dad = dad->um_left)
+    ;
+  /* Dad has a free branch => kid is dad's only child */
+  kid = dad->um_left ? dad->um_left : dad->um_right;
+
+  /* Remove dad from tree */
+  if (!(dad->um_dad))
+    *top = kid;
+  else if (dad->um_dad->um_left == dad)
+    dad->um_dad->um_left = kid;
+  else assert(dad->um_dad->um_right == dad),
+    dad->um_dad->um_right = kid;
+  if (kid)
+    kid->um_dad = dad->um_dad;
+
+  need_to_balance = kid && dad->um_black;
+
+  /* Put dad in place of um */
+  if (um != dad) {
+    if (!(dad->um_dad = um->um_dad))
+      *top = dad;
+    else if (dad->um_dad->um_left == um)
+      dad->um_dad->um_left = dad;
+    else assert(dad->um_dad->um_right == um),
+      dad->um_dad->um_right = dad;
+
+    dad->um_black = um->um_black;
+    
+    if ((dad->um_left = um->um_left))
+      dad->um_left->um_dad = dad;      
+
+    if ((dad->um_right = um->um_right))
+      dad->um_right->um_dad = dad;      
+  }
+
+  um->um_left = NULL;
+  um->um_right = NULL;
+  um->um_dad = NULL;
+  um->um_black = 0;
+  um->um_inserted = 0;
+
+  if (need_to_balance) 
+    red_black_balance_delete(top, kid);
+}
+
+#if TEST_URLMAP
+/* Functions currently used only by test cases */
+
+/** Return inorder successor of node @a um. */
+UrlMap *url_map_succ(UrlMap *um)
+{
+  UrlMap *dad;
+
+  if (um->um_right) {
+    for (um = um->um_right; um->um_left; um = um->um_left)
+      ;
+    return um;
+  }
+
+  for (dad = um->um_dad; dad && um == dad->um_right; dad = um->um_dad)
+    um = dad;
+
+  return dad;
+}
+
+/** Return inorder precedessor of node @a um. */
+UrlMap *url_map_prec(UrlMap *um)
+{
+  UrlMap *dad;
+
+  if (um->um_left) {
+    for (um = um->um_left; um->um_right; um = um->um_right)
+      ;
+    return um;
+  }
+
+  for (dad = um->um_dad; dad && um == dad->um_left; dad = um->um_dad)
+    um = dad;
+
+  return dad;
+}
+
+/** Return first node in tree @a um. */
+UrlMap *url_map_first(UrlMap *um)
+{
+  while (um && um->um_left)
+    um = um->um_left;
+
+  return um;
+}
+
+/** Return last node in tree @a um. */
+UrlMap *url_map_last(UrlMap *um)
+{
+  while (um && um->um_right)
+    um = um->um_right;
+
+  return um;
+}
+
+/** Return height of the tree */
+int url_map_height(UrlMap const *tree)
+{
+  int left, right;
+
+  if (!tree)
+    return 0;
+
+  left = tree->um_left ? url_map_height(tree->um_left) : 0;
+  right = tree->um_right ? url_map_height(tree->um_right) : 0;
+
+  if (left > right)
+    return left + 1;
+  else
+    return right + 1;
+}
+
+/** Check consistency */
+static
+int redblack_check(UrlMap const *n)
+{
+  UrlMap const *l, *r;
+
+  if (!n)
+    return 1;
+
+  l = n->um_left, r = n->um_right;
+
+  if (n->um_black || ((!l || l->um_black) && (!r || r->um_black)))
+    return (!l || redblack_check(l)) && (!r || redblack_check(r));
+  else
+    return 0;
+}
+
+/* Testing functions */
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <sofia-sip/tstdef.h>
+
+char const *name = "test_urlmap";
+
+int test_path(void)
+{
+  su_home_t *home;
+  UrlMap *tree = NULL, *o;
+  UrlMap *um, *um1, *um2, *um3;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  um1 = url_map_new(home, (void*)"http://host/aa/", sizeof *um1);
+  TEST_1(um1);
+
+  um2 = url_map_new(home, (void*)"http://host/aa/bb/", sizeof *um1);
+  TEST_1(um2);
+
+  um3 = url_map_new(home, (void*)"http://host/aa/bb/cc/",
+				sizeof *um);
+  TEST_1(um3);
+
+  TEST_1(um1 != um2 && um1 != um3 && um2 != um3);
+
+  o = (void *)-1;
+  TEST(url_map_insert(&tree, um3, &o), 0);
+  TEST_P(o, NULL); o = (void *)-1;
+  TEST(url_map_insert(&tree, um2, &o), 0);
+  TEST_P(o, NULL); o = (void *)-1;
+  TEST(url_map_insert(&tree, um1, &o), 0);
+  TEST_P(o, NULL);
+
+  um = url_map_find(tree, (void*)"http://host/aa/bb/cc", 1); TEST_P(um, um2);
+  um = url_map_find(tree, (void*)"http://host/aa/bb/cc/oo", 1);
+                                                          TEST_P(um, um3);
+  um = url_map_find(tree, (void*)"http://host/aa/bb", 1); TEST_P(um, um1);
+  um = url_map_find(tree, (void*)"http://host/aa/bb", 0); TEST_P(um, NULL);
+  um = url_map_find(tree, (void*)"http://host/aa/bb/", 1); TEST_P(um, um2);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_insert(void)
+{
+  su_home_t *home;
+  UrlMap *tree = NULL, *o, *old;
+  UrlMap *one, *three, *five, *six, *seven;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+  one = url_map_new(home, (void*)"/1", sizeof (UrlMap));
+  three = url_map_new(home, (void*)"/3", sizeof (UrlMap));
+  five = url_map_new(home, (void*)"/5", sizeof (UrlMap));
+  six = url_map_new(home, (void*)"/6", sizeof (UrlMap));
+  seven = url_map_new(home, (void*)"/7", sizeof (UrlMap));
+
+  TEST_1(one); 
+  TEST_1(three);
+  TEST_1(five);
+  TEST_1(six);
+  TEST_1(seven);
+
+  /* Check single node */
+  TEST(url_map_insert(&tree, five, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree, five);
+  TEST_P(five->um_left, NULL); TEST_P(five->um_right, NULL);
+  TEST_P(five->um_dad, NULL); TEST(five->um_black, 1);
+
+  /* Check after another node: 
+   *
+   *         5b
+   *        / 
+   *       3r
+   */
+  TEST(url_map_insert(&tree, three, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->um_left, three); TEST(tree->um_black, 1);
+  TEST_P(three->um_left, NULL); TEST_P(three->um_right, NULL);
+  TEST_P(three->um_dad, tree); TEST(three->um_black, 0); 
+
+  /* Check third node
+   *         5b
+   *        / \
+   *       3r  7r
+   */
+  TEST(url_map_insert(&tree, seven, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->um_right, seven); TEST(tree->um_black, 1);
+  TEST_P(seven->um_left, NULL); TEST_P(seven->um_right, NULL);
+  TEST_P(seven->um_dad, tree); TEST(seven->um_black, 0); 
+
+  /* Check after fourth node:
+   *         5b
+   *        / \
+   *       3b  7b
+   *      /
+   *     1r  
+   */
+  TEST(url_map_insert(&tree, one, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree->um_left->um_left, one); 
+  TEST(tree->um_black, 1); 
+  TEST(tree->um_left->um_black, 1); TEST(tree->um_right->um_black, 1);
+  TEST_P(one->um_left, NULL); TEST_P(one->um_right, NULL);
+  TEST_P(one->um_dad, tree->um_left); TEST(one->um_black, 0); 
+
+  /* Checks that we got after fifth node:
+   *         5b
+   *        / \
+   *       3b  7b
+   *      /   /
+   *     1r  6r
+   */
+  TEST(url_map_insert(&tree, six, &o), 0); TEST_P(o, NULL);
+  TEST_P(tree, five); TEST(five->um_black, 1);
+  TEST_P(tree->um_left, three); TEST(three->um_black, 1);
+  TEST_P(tree->um_left->um_left, one); TEST(one->um_black, 0);
+  TEST_P(tree->um_right, seven); TEST(seven->um_black, 1);
+  TEST_P(tree->um_right->um_left, six); TEST(six->um_black, 0);
+
+  /* Insert five second time */
+  old = five;
+  five = url_map_new(home, (void*)"/5", sizeof (UrlMap));
+  TEST(url_map_insert(&tree, five, &o), 0); TEST_P(o, old);
+  TEST_P(tree, five); TEST(five->um_black, 1);
+  TEST_P(tree->um_left, three); TEST(three->um_black, 1);
+  TEST_P(three->um_dad, five);
+  TEST_P(tree->um_left->um_left, one); TEST(one->um_black, 0);
+  TEST_P(tree->um_right, seven); TEST(seven->um_black, 1);
+  TEST_P(seven->um_dad, five);
+  TEST_P(tree->um_right->um_left, six); TEST(six->um_black, 0);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_rotate(void)
+{
+  su_home_t *home;
+  UrlMap *tree = NULL;
+  UrlMap *x, *y, *o;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  x = url_map_new(home, (void*)"/x", sizeof *x);
+  y = url_map_new(home, (void*)"/y", sizeof *y);
+
+  TEST_1(x);
+  TEST_1(y); 
+
+  /*
+   *              x                   y               x
+   * Checks that   \  transforms to  /   and back to   \
+   *                y               x                   y
+   */
+  TEST(url_map_insert(&tree, x, &o), 0); TEST_P(o, NULL);
+  TEST(url_map_insert(&tree, y, &o), 0); TEST_P(o, NULL);
+
+  TEST_P(tree, x); TEST_P(x->um_right, y);
+  left_rotate(&tree, x);
+  TEST_P(tree, y); TEST_P(y->um_left, x);
+  right_rotate(&tree, y);
+  TEST_P(tree, x); TEST_P(x->um_right, y);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+/** ceil of log2 */
+static
+unsigned log2ceil(unsigned k)
+{
+  unsigned result = 0;
+
+#if 0
+  if (k > (1 << 32))
+    result += 32, k = (k >> 32) + ((k & ((1 << 32) - 1)) != 0);
+#endif
+  if (k > (1 << 16)) 
+    result += 16, k = (k >> 16) + ((k & ((1 << 16) - 1)) != 0);
+  if (k > (1 << 8)) 
+    result += 8, k = (k >> 8) + ((k & ((1 << 8) - 1)) != 0);
+  if (k > (1 << 4))
+    result += 4, k = (k >> 4) + ((k & 15) != 0);
+  if (k > (1 << 2))
+    result += 2, k = (k >> 2) + ((k & 3) != 0);
+  if (k > (1 << 1))
+    result += 1, k = (k >> 1) + (k & 1);
+  if (k > 1)
+    result += 1;
+  
+  return result;
+}
+
+typedef struct {
+  UrlMap te_urlmap[1];
+  int      te_value;
+  int      te_inserted;
+} TEntry;
+
+int test_balance(void)
+{
+  su_home_t *home;
+  UrlMap *tree = NULL, *o = NULL;
+  url_t *u;
+  TEntry *te, **nodes;
+  char path[16];
+  int i, j;
+  int const N = 1000;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+  nodes = su_zalloc(home, (N + 2) * (sizeof *nodes)); TEST_1(nodes);
+  nodes++;
+
+  u = url_hdup(home, (url_t *)"http://host");
+  u->url_path = path;
+
+  for (i = 0; i < N; i++) {
+    snprintf(path, (sizeof path), "p%07u", i);
+    te = (TEntry *)url_map_new(home, (void *)u, sizeof *te);
+    te->te_value = i;
+    nodes[i] = te;
+    TEST(url_map_insert(&tree, te->te_urlmap, &o), 0);
+    TEST_P(o, NULL);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    snprintf(path, (sizeof path), "p%07u", i);
+    te = (TEntry *)url_map_find(tree, (void*)u, 1);
+    TEST_1(te); TEST(te->te_value, i);
+  }
+
+  snprintf(path, (sizeof path), "p%07u", 0);
+
+  te = (TEntry *)url_map_find(tree, (void*)u, 1);
+
+  for (i = 0; i < N; i++) {
+    TEST_1(te); TEST(te->te_value, i);
+    te = (TEntry *)url_map_succ(te->te_urlmap);
+  }
+  TEST_1(te == NULL);
+
+  for (i = 0; i < N; i++) {
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    snprintf(path, (sizeof path), "p%07u", i);
+    te = (TEntry *)url_map_find(tree, (void*)u, 1);
+    TEST_1(te); TEST(te->te_value, i);
+    url_map_remove(&tree, te->te_urlmap);
+    TEST_1(te->te_urlmap->um_dad == NULL && 
+	   te->te_urlmap->um_left == NULL && 
+	   te->te_urlmap->um_right == NULL); 
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = N - 1; i >= 0; i--) {
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    url_map_remove(&tree, nodes[i]->te_urlmap);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 57) % N;
+    o = (void *)-1;
+    TEST(nodes[sn]->te_inserted, 0);
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    nodes[sn]->te_inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 23) % N;	/* 23 is relative prime to N */
+    TEST(nodes[sn]->te_inserted, 1);
+    url_map_remove(&tree, nodes[sn]->te_urlmap);
+    nodes[sn]->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 517) % N;	/* relative prime to N */
+    o = (void *)-1;
+    TEST(nodes[sn]->te_inserted, 0);
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    nodes[sn]->te_inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 497) % N;	/* relative prime to N */
+    TEST(nodes[sn]->te_inserted, 1);
+    url_map_remove(&tree, nodes[sn]->te_urlmap);
+    nodes[sn]->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 1957) % N;	/* relative prime to N */
+    o = (void *)-1;
+    TEST(nodes[sn]->te_inserted, 0);
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    nodes[sn]->te_inserted = 1;
+    TEST_P(o, NULL);
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    int sn = (i * 1519) % N;	/* relative prime to N */
+    TEST(nodes[sn]->te_inserted, 1);
+    url_map_remove(&tree, nodes[sn]->te_urlmap);
+    nodes[sn]->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N - i - 1;
+    TEST(nodes[i]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->te_inserted = 1;
+
+    TEST(nodes[sn]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->te_inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  for (i = 0; i < N; i++) {
+    te = (TEntry *)((i & 1) ? url_map_succ(tree) : url_map_prec(tree));
+    if (te == NULL)
+      te = (TEntry *)tree;
+    TEST(te->te_inserted, 1);
+    url_map_remove(&tree, te->te_urlmap);
+    te->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N - i - 1;
+    TEST(nodes[i]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->te_inserted = 1;
+
+    TEST(nodes[sn]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->te_inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  /* Remove last, first, last, first, ... */
+  for (i = 0; i < N; i++) {
+    te = (TEntry *)((i & 1) ? url_map_first(tree) : url_map_last(tree));
+    TEST_1(te);
+    TEST(te->te_inserted, 1);
+    url_map_remove(&tree, te->te_urlmap);
+    te->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert small, big, small, big ... */
+
+  for (i = 0; i < N / 2; i++) {
+    int sn = N / 2 + i;
+    TEST(nodes[i]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[i]->te_inserted = 1;
+
+    TEST(nodes[sn]->te_inserted, 0);
+    o = (void *)-1;
+    TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0); 
+    TEST_P(o, NULL);
+    nodes[sn]->te_inserted = 1;
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  /* Remove last, first, last, first, ... */
+  for (i = 0; i < N; i++) {
+    te = (TEntry *)((i & 1) ? url_map_first(tree) : url_map_last(tree));
+    TEST_1(te);
+    TEST(te->te_inserted, 1);
+    url_map_remove(&tree, te->te_urlmap);
+    te->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  /* Insert in perfect order ... */
+  
+  for (j = N / 2; j > 0; j /= 2) {
+    for (i = N - j; i >= 0; i -= j) {
+      if (nodes[i]->te_inserted)
+	continue;
+      o = (void *)-1;
+      TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0); 
+      TEST_P(o, NULL);
+      nodes[i]->te_inserted = 1;
+    }
+  }
+
+  for (i = 0; i < N; i++) {
+    TEST(nodes[i]->te_inserted, 1);
+    TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+    TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+  }
+
+  /* Remove such nodes that insert red uncles into tree */
+  for (i = 0; i < N; i++) {
+    te = (TEntry *)url_map_last(tree);
+    for (o = te->te_urlmap; o; o = url_map_prec(o)) {
+      UrlMap *dad, *granddad, *uncle, *to_be_removed;
+      /* We must have a node with black dad, no brother, red granddad and uncle */
+      if (!(dad = o->um_dad) || !dad->um_black)
+	continue;
+      if (dad->um_left && dad->um_right)
+	continue;
+      if (!(granddad = dad->um_dad) || granddad->um_black)
+	continue;
+      if (granddad->um_left == dad)
+	uncle = granddad->um_right;
+      else
+	uncle = granddad->um_left;
+      if (!uncle || uncle->um_black)
+	continue;
+      to_be_removed = url_map_prec(o->um_dad);
+      if (to_be_removed == granddad || to_be_removed == uncle)
+	continue;
+      if (!to_be_removed->um_left || !to_be_removed->um_right)
+	continue;
+      te = (TEntry *)to_be_removed;
+      break;
+    }
+    TEST(te->te_inserted, 1);
+    url_map_remove(&tree, te->te_urlmap);
+    te->te_inserted = 0;
+    TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+    TEST_1(redblack_check(tree));
+  }
+
+  TEST_P(tree, NULL);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+int test_speed(void)
+{
+  su_home_t *home;
+  UrlMap *tree = NULL, *o = NULL;
+  url_t *u;
+  TEntry *te;
+  unsigned i;
+  char path[16];
+  int const N = 1000000;
+
+  BEGIN();
+
+  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+  u = url_hdup(home, (url_t *)"http://host");
+  u->url_path = path;
+
+  for (i = 0; i < N; i++) {
+    snprintf(path, (sizeof path), "p%07u", i);
+    te = (TEntry *)url_map_new(home, (void *)u, sizeof *te);
+    te->te_value = i;
+    TEST(url_map_insert(&tree, te->te_urlmap, &o), 0);
+    TEST_P(o, NULL);
+  }
+
+  TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1));
+
+  for (i = 0; i < N; i++) {
+    snprintf(path, (sizeof path), "p%07u", i);
+    te = (TEntry *)url_map_find(tree, (void*)u, 1);
+    TEST_1(te); TEST(te->te_value, i);
+  }
+
+  snprintf(path, (sizeof path), "p%07u", 0);
+
+  te = (TEntry *)url_map_find(tree, (void*)u, 1);
+
+  for (i = 0; i < N; i++) {
+    TEST_1(te); TEST(te->te_value, i);
+    te = (TEntry *)url_map_succ(te->te_urlmap);
+  }
+  TEST_1(te == NULL);
+
+  su_home_check(home);
+  su_home_zap(home);
+
+  END();
+}
+
+
+
+void usage(void)
+{
+  fprintf(stderr,
+	  "usage: %s [-v]\n",
+	  name);
+}
+
+int main(int argc, char *argv[])
+{
+  int retval = 0;
+  int i;
+
+  for (i = 1; argv[i]; i++) {
+    if (strcmp(argv[i], "-v") == 0)
+      tstflags |= tst_verbatim;
+    else
+      usage();
+  }
+
+  retval |= test_insert(); fflush(stdout);
+  retval |= test_rotate(); fflush(stdout);
+  retval |= test_path(); fflush(stdout);
+  retval |= test_balance(); fflush(stdout);
+
+  return retval;
+}
+
+#endif
+

Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URLMAP_H
+/** Defined when <urlmap.h> has been included. */
+#define URLMAP_H
+
+/**
+ * @file urlmap.h
+ * @brief 
+ * 
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *  
+ * @date Created: Wed Mar 10 17:06:20 2004 ppessi
+ */
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Mapping of URLs */
+typedef struct _UrlMap UrlMap;
+
+struct _UrlMap {
+  UrlMap        *um_left, *um_right, *um_dad;
+  unsigned       um_black:1;
+  unsigned       um_inserted:1;
+  unsigned       :0;
+  url_t          um_url[1];
+};
+
+UrlMap *url_map_new(su_home_t *home, url_string_t const *url, unsigned size);
+
+int url_map_insert(UrlMap **tree, UrlMap * um, UrlMap **return_old);
+void url_map_remove(UrlMap **tree, UrlMap *ume);
+
+UrlMap *url_map_find(UrlMap *tree, url_string_t const *u, int relative);
+
+
+SOFIA_END_DECLS
+#endif /* !defined URLMAP_H */
+

Added: freeswitch/trunk/libs/sofia-sip/ltmain.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ltmain.sh	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6425 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# RH: define SED for historic ltconfig's generated by Libtool 1.3
+[ -z "$SED" ] && SED=sed
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.6
+TIMESTAMP=" (1.1220.2.95 2004/04/11 05:50:42)"
+
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell, and then maybe $echo will work.
+  exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo A|tr A '\301'` in
+ A) # EBCDIC based system
+  SP2NL="tr '\100' '\n'"
+  NL2SP="tr '\r\n' '\100\100'"
+  ;;
+ *) # Assume ASCII based system
+  SP2NL="tr '\040' '\012'"
+  NL2SP="tr '\015\012' '\040\040'"
+  ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+  save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+  save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+# Make sure IFS has a sensible default
+: ${IFS=" 	
+"}
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+  $echo "$modename: not configured to build any kind of library" 1>&2
+  $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid () {
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+      $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+      win32_nmres=`eval $NM -f posix -A $1 | \
+	sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
+      if test "X$win32_nmres" = "Ximport" ; then
+        win32_libid_type="x86 archive import"
+      else
+        win32_libid_type="x86 archive static"
+      fi
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag () {
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	case $arg in
+	  *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	CC_quoted="$CC_quoted $arg"
+      done
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	    # Double-quote args containing other shell metacharacters.
+	    case $arg in
+	      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	      arg="\"$arg\""
+	      ;;
+	    esac
+	    CC_quoted="$CC_quoted $arg"
+	  done
+	    case "$@ " in
+	      " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  $echo "$modename: unable to infer tagged configuration"
+	  $echo "$modename: specify a tag with \`--tag'" 1>&2
+	  exit $EXIT_FAILURE
+#        else
+#          $echo "$modename: using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+  arg="$1"
+  shift
+
+  case $arg in
+  -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    case $prev in
+    execute_dlfiles)
+      execute_dlfiles="$execute_dlfiles $arg"
+      ;;
+    tag)
+      tagname="$arg"
+      preserve_args="${preserve_args}=$arg"
+
+      # Check whether tagname contains only valid characters
+      case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+	$echo "$progname: invalid tag name: $tagname" 1>&2
+	exit $EXIT_FAILURE
+	;;
+      esac
+
+      case $tagname in
+      CC)
+	# Don't test for the "default" C tag, as we know, it's there, but
+	# not specially marked.
+	;;
+      *)
+	if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+	  taglist="$taglist $tagname"
+	  # Evaluate the configuration.
+	  eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+	else
+	  $echo "$progname: ignoring unknown tag $tagname" 1>&2
+	fi
+	;;
+      esac
+      ;;
+    *)
+      eval "$prev=\$arg"
+      ;;
+    esac
+
+    prev=
+    prevopt=
+    continue
+  fi
+
+  # Have we seen a non-optional argument yet?
+  case $arg in
+  --help)
+    show_help=yes
+    ;;
+
+  --version)
+    $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+    $echo
+    $echo "Copyright (C) 2003  Free Software Foundation, Inc."
+    $echo "This is free software; see the source for copying conditions.  There is NO"
+    $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+    exit $EXIT_SUCCESS
+    ;;
+
+  --config)
+    ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+    done
+    exit $EXIT_SUCCESS
+    ;;
+
+  --debug)
+    $echo "$progname: enabling shell trace mode"
+    set -x
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --dry-run | -n)
+    run=:
+    ;;
+
+  --features)
+    $echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      $echo "enable shared libraries"
+    else
+      $echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      $echo "enable static libraries"
+    else
+      $echo "disable static libraries"
+    fi
+    exit $EXIT_SUCCESS
+    ;;
+
+  --finish) mode="finish" ;;
+
+  --mode) prevopt="--mode" prev=mode ;;
+  --mode=*) mode="$optarg" ;;
+
+  --preserve-dup-deps) duplicate_deps="yes" ;;
+
+  --quiet | --silent)
+    show=:
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --tag) prevopt="--tag" prev=tag ;;
+  --tag=*)
+    set tag "$optarg" ${1+"$@"}
+    shift
+    prev=tag
+    preserve_args="$preserve_args --tag"
+    ;;
+
+  -dlopen)
+    prevopt="-dlopen"
+    prev=execute_dlfiles
+    ;;
+
+  -*)
+    $echo "$modename: unrecognized option \`$arg'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+
+  *)
+    nonopt="$arg"
+    break
+    ;;
+  esac
+done
+
+if test -n "$prevopt"; then
+  $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+  # Infer the operation mode.
+  if test -z "$mode"; then
+    $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+    $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2
+    case $nonopt in
+    *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+      mode=link
+      for arg
+      do
+	case $arg in
+	-c)
+	   mode=compile
+	   break
+	   ;;
+	esac
+      done
+      ;;
+    *db | *dbx | *strace | *truss)
+      mode=execute
+      ;;
+    *install*|cp|mv)
+      mode=install
+      ;;
+    *rm)
+      mode=uninstall
+      ;;
+    *)
+      # If we have no mode, but dlfiles were specified, then do execute mode.
+      test -n "$execute_dlfiles" && mode=execute
+
+      # Just use the default operation mode.
+      if test -z "$mode"; then
+	if test -n "$nonopt"; then
+	  $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+	else
+	  $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+	fi
+      fi
+      ;;
+    esac
+  fi
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$modename --help --mode=$mode' for more information."
+
+  # These modes are in order of execution frequency so that they run quickly.
+  case $mode in
+  # libtool compile mode
+  compile)
+    modename="$modename: compile"
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+
+    for arg
+    do
+      case "$arg_mode" in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  if test -n "$libobj" ; then
+	    $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-static | -prefer-pic | -prefer-non-pic)
+	  later="$later $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+ 	  for arg in $args; do
+	    IFS="$save_ifs"
+
+	    # Double-quote args containing other shell metacharacters.
+	    # Many Bourne shells cannot handle close brackets correctly
+	    # in scan sets, so we specify it separately.
+	    case $arg in
+	      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	      arg="\"$arg\""
+	      ;;
+	    esac
+	    lastarg="$lastarg $arg"
+	  done
+	  IFS="$save_ifs"
+	  lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+	  # Add the arguments to base_compile.
+	  base_compile="$base_compile $lastarg"
+	  continue
+	  ;;
+
+	* )
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+      case $lastarg in
+      # Double-quote args containing other shell metacharacters.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	lastarg="\"$lastarg\""
+	;;
+      esac
+
+      base_compile="$base_compile $lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      $echo "$modename: you must specify an argument for -Xcompile"
+      exit $EXIT_FAILURE
+      ;;
+    target)
+      $echo "$modename: you must specify a target with \`-o'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *)
+      # Get the name of the library object.
+      [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    xform='[cCFSifmso]'
+    case $libobj in
+    *.ada) xform=ada ;;
+    *.adb) xform=adb ;;
+    *.ads) xform=ads ;;
+    *.asm) xform=asm ;;
+    *.c++) xform=c++ ;;
+    *.cc) xform=cc ;;
+    *.ii) xform=ii ;;
+    *.class) xform=class ;;
+    *.cpp) xform=cpp ;;
+    *.cxx) xform=cxx ;;
+    *.f90) xform=f90 ;;
+    *.for) xform=for ;;
+    *.java) xform=java ;;
+    esac
+
+    libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+    case $libobj in
+    *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+    *)
+      $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -static)
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+    xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$xdir" = "X$obj"; then
+      xdir=
+    else
+      xdir=$xdir/
+    fi
+    lobj=${xdir}$objdir/$objname
+
+    if test -z "$base_compile"; then
+      $echo "$modename: you must specify a compilation command" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    $run $rm $removelist
+    trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+      removelist="$removelist $output_obj $lockfile"
+      trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+	$show "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+      $echo $srcfile > "$lockfile"
+    fi
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+
+    $run $rm "$libobj" "${libobj}T"
+
+    # Create a libtool object file (analogous to a ".la" file),
+    # but don't create it if we're doing a dry run.
+    test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $srcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $srcfile"
+      fi
+
+      if test ! -d "${xdir}$objdir"; then
+	$show "$mkdir ${xdir}$objdir"
+	$run $mkdir ${xdir}$objdir
+	status=$?
+	if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then
+	  exit $status
+	fi
+      fi
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	command="$command -o $lobj"
+      fi
+
+      $run $rm "$lobj" "$output_obj"
+
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+	test -n "$output_obj" && $run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	$show "$mv $output_obj $lobj"
+	if $run $mv $output_obj $lobj; then :
+	else
+	  error=$?
+	  $run $rm $removelist
+	  exit $error
+	fi
+      fi
+
+      # Append the name of the PIC object to the libtool object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+        suppress_output=' >/dev/null 2>&1'
+      fi
+    else
+      # No PIC object so indicate it doesn't exist in the libtool
+      # object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $srcfile"
+      else
+	command="$base_compile $srcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	command="$command -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      $run $rm "$obj" "$output_obj"
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	$show "$mv $output_obj $obj"
+	if $run $mv $output_obj $obj; then :
+	else
+	  error=$?
+	  $run $rm $removelist
+	  exit $error
+	fi
+      fi
+
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+    else
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+    fi
+
+    $run $mv "${libobj}T" "${libobj}"
+
+    # Unlock the critical section if it was locked
+    if test "$need_locks" != no; then
+      $run $rm "$lockfile"
+    fi
+
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool link mode
+  link | relink)
+    modename="$modename: link"
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args="$nonopt"
+    base_compile="$nonopt $@"
+    compile_command="$nonopt"
+    finalize_command="$nonopt"
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+
+    avoid_version=no
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -all-static | -static)
+	if test "X$arg" = "X-all-static"; then
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	else
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	fi
+	build_libtool_libs=no
+	build_old_libs=yes
+	prefer_static_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+	;;
+      *) qarg=$arg ;;
+      esac
+      libtool_args="$libtool_args $qarg"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  compile_command="$compile_command @OUTPUT@"
+	  finalize_command="$finalize_command @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    compile_command="$compile_command @SYMFILE@"
+	    finalize_command="$finalize_command @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      dlfiles="$dlfiles $arg"
+	    else
+	      dlprefiles="$dlprefiles $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  if test ! -f "$arg"; then
+	    $echo "$modename: symbol file \`$arg' does not exist"
+	    exit $EXIT_FAILURE
+	  fi
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat $save_arg`
+	    do
+#	      moreargs="$moreargs $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		# If there is no directory component, then add one.
+		case $arg in
+		*/* | *\\*) . $arg ;;
+		*) . ./$arg ;;
+		esac
+
+		if test -z "$pic_object" || \
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none && \
+		   test "$non_pic_object" = none; then
+		  $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+		  exit $EXIT_FAILURE
+		fi
+
+		# Extract subdirectory from the argument.
+		xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+		if test "X$xdir" = "X$arg"; then
+		  xdir=
+		else
+		  xdir="$xdir/"
+		fi
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      dlfiles="$dlfiles $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    dlprefiles="$dlprefiles $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  libobjs="$libobjs $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  non_pic_objects="$non_pic_objects $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if test -z "$run"; then
+		  $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+		  exit $EXIT_FAILURE
+		else
+		  # Dry-run case.
+
+		  # Extract subdirectory from the argument.
+		  xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+		  if test "X$xdir" = "X$arg"; then
+		    xdir=
+		  else
+		    xdir="$xdir/"
+		  fi
+
+		  pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+		  non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+		  libobjs="$libobjs $pic_object"
+		  non_pic_objects="$non_pic_objects $non_pic_object"
+		fi
+	      fi
+	    done
+	  else
+	    $echo "$modename: link input file \`$save_arg' does not exist"
+	    exit $EXIT_FAILURE
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    $echo "$modename: only absolute run-paths are allowed" 1>&2
+	    exit $EXIT_FAILURE
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) rpath="$rpath $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) xrpath="$xrpath $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	xcompiler)
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  compile_command="$compile_command $qarg"
+	  finalize_command="$finalize_command $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $wl$qarg"
+	  prev=
+	  compile_command="$compile_command $wl$qarg"
+	  finalize_command="$finalize_command $wl$qarg"
+	  continue
+	  ;;
+	xcclinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  compile_command="$compile_command $qarg"
+	  finalize_command="$finalize_command $qarg"
+	  continue
+	  ;;
+	shrext)
+  	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  compile_command="$compile_command $link_static_flag"
+	  finalize_command="$finalize_command $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	$echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+	continue
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  $echo "$modename: more than one -exported-symbols argument is not allowed"
+	  exit $EXIT_FAILURE
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  compile_command="$compile_command $arg"
+	  finalize_command="$finalize_command $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  if test -z "$absdir"; then
+	    $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "*) ;;
+	*)
+	  deplibs="$deplibs -L$dir"
+	  lib_search_path="$lib_search_path $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$dir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-pw32* | *-*-beos*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-mingw* | *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    deplibs="$deplibs -framework System"
+	    continue
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	deplibs="$deplibs $arg"
+	continue
+	;;
+
+     -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+	deplibs="$deplibs $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # gcc -m* arguments should be passed to the linker via $compiler_flags
+      # in order to pass architecture information to the linker
+      # (e.g. 32 vs 64-bit).  This may also be accomplished via -Wl,-mfoo
+      # but this is not reliable with gcc because gcc may use -mfoo to
+      # select a different linker, different libraries, etc, while
+      # -Wl,-mfoo simply passes -mfoo to the linker.
+      -m*)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+        compile_command="$compile_command $arg"
+        finalize_command="$finalize_command $arg"
+        if test "$with_gcc" = "yes" ; then
+          compiler_flags="$compiler_flags $arg"
+        fi
+        continue
+        ;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # in order for the loader to find any dlls it needs.
+	  $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+	  $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  $echo "$modename: only absolute run-paths are allowed" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) xrpath="$xrpath $dir" ;;
+	esac
+	continue
+	;;
+
+      -static)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -Wc,*)
+	args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+	  case $flag in
+	    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	    flag="\"$flag\""
+	    ;;
+	  esac
+	  arg="$arg $wl$flag"
+	  compiler_flags="$compiler_flags $flag"
+	done
+	IFS="$save_ifs"
+	arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+	;;
+
+      -Wl,*)
+	args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+	  case $flag in
+	    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	    flag="\"$flag\""
+	    ;;
+	  esac
+	  arg="$arg $wl$flag"
+	  compiler_flags="$compiler_flags $wl$flag"
+	  linker_flags="$linker_flags $flag"
+	done
+	IFS="$save_ifs"
+	arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # Some other compiler flag.
+      -* | +*)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	;;
+
+      *.$objext)
+	# A standard object.
+	objs="$objs $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  # If there is no directory component, then add one.
+	  case $arg in
+	  */* | *\\*) . $arg ;;
+	  *) . ./$arg ;;
+	  esac
+
+	  if test -z "$pic_object" || \
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none && \
+	     test "$non_pic_object" = none; then
+	    $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+	  if test "X$xdir" = "X$arg"; then
+	    xdir=
+ 	  else
+	    xdir="$xdir/"
+	  fi
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		dlfiles="$dlfiles $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      dlprefiles="$dlprefiles $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    libobjs="$libobjs $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    non_pic_objects="$non_pic_objects $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if test -z "$run"; then
+	    $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+	    exit $EXIT_FAILURE
+	  else
+	    # Dry-run case.
+
+	    # Extract subdirectory from the argument.
+	    xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+	    if test "X$xdir" = "X$arg"; then
+	      xdir=
+	    else
+	      xdir="$xdir/"
+	    fi
+
+	    pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+	    non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+	    libobjs="$libobjs $pic_object"
+	    non_pic_objects="$non_pic_objects $non_pic_object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	deplibs="$deplibs $arg"
+	old_deplibs="$old_deplibs $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  dlfiles="$dlfiles $arg"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  dlprefiles="$dlprefiles $arg"
+	  prev=
+	else
+	  deplibs="$deplibs $arg"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	compile_command="$compile_command $arg"
+	finalize_command="$finalize_command $arg"
+      fi
+    done # argument parsing loop
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      compile_command="$compile_command $arg"
+      finalize_command="$finalize_command $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$output_objdir" = "X$output"; then
+      output_objdir="$objdir"
+    else
+      output_objdir="$output_objdir/$objdir"
+    fi
+    # Create the object directory.
+    if test ! -d "$output_objdir"; then
+      $show "$mkdir $output_objdir"
+      $run $mkdir $output_objdir
+      status=$?
+      if test "$status" -ne 0 && test ! -d "$output_objdir"; then
+	exit $status
+      fi
+    fi
+
+    # Determine the type of output
+    case $output in
+    "")
+      $echo "$modename: you must specify an output file" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    case $host in
+    *cygwin* | *mingw* | *pw32*)
+      # don't eliminate duplications in $postdeps and $predeps
+      duplicate_compiler_generated_deps=yes
+      ;;
+    *)
+      duplicate_compiler_generated_deps=$duplicate_deps
+      ;;
+    esac
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if test "X$duplicate_deps" = "Xyes" ; then
+	case "$libs " in
+	*" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	esac
+      fi
+      libs="$libs $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+	  esac
+	  pre_post_deps="$pre_post_deps $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+    case $linkmode in
+    lib)
+	passes="conv link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+	    exit $EXIT_FAILURE
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+    for pass in $passes; do
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+	    continue
+	  fi
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+	  for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if (${SED} -e '2q' $lib |
+                    grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+		  library_names=
+		  old_library=
+		  case $lib in
+		  */* | *\\*) . $lib ;;
+		  *) . ./$lib ;;
+		  esac
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+		    test "X$ladir" = "X$lib" && ladir="."
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+	        ;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+	    ;;
+	  *)
+	    $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) xrpath="$xrpath $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la) lib="$deplib" ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    if test "$deplibs_check_method" != pass_all; then
+	      $echo
+	      $echo "*** Warning: Trying to link with static lib archive $deplib."
+	      $echo "*** I have the capability to make that library automatically link in when"
+	      $echo "*** you link to this library.  But I can only do this if you have a"
+	      $echo "*** shared version of the library, which you do not appear to have"
+	      $echo "*** because the file extensions .$libext of this argument makes me believe"
+	      $echo "*** that it is just a static archive that I should not used here."
+	    else
+	      $echo
+	      $echo "*** Warning: Linking the shared library $output against the"
+	      $echo "*** static library $deplib is not portable!"
+	      deplibs="$deplib $deplibs"
+	    fi
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      newdlprefiles="$newdlprefiles $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      newdlfiles="$newdlfiles $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  $echo "$modename: cannot find the library \`$lib'" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$ladir" = "X$lib" && ladir="."
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+
+	# Read the .la file
+	case $lib in
+	*/* | *\\*) . $lib ;;
+	*) . ./$lib ;;
+	esac
+
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+	  test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+	      exit $EXIT_FAILURE
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    convenience="$convenience $ladir/$objdir/$old_library"
+	    old_convenience="$old_convenience $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+              if test "X$duplicate_deps" = "Xyes" ; then
+	        case "$tmp_libs " in
+	        *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	        esac
+              fi
+	      tmp_libs="$tmp_libs $deplib"
+	    done
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    $echo "$modename: \`$lib' is not a convenience library" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	for l in $old_library $library_names; do
+	  linklib="$l"
+	done
+	if test -z "$linklib"; then
+	  $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    dlprefiles="$dlprefiles $lib $dependency_libs"
+	  else
+	    newdlfiles="$newdlfiles $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+	    $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    $echo "$modename: warning: library \`$lib' was moved." 1>&2
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$libdir"
+	    absdir="$libdir"
+	  fi
+	else
+	  dir="$ladir/$objdir"
+	  absdir="$abs_ladir/$objdir"
+	  # Remove this search path later
+	  notinst_path="$notinst_path $abs_ladir"
+	fi # $installed = yes
+	name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir"; then
+	    $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  # Prefer using a static library (so that no silly _DYNAMIC symbols
+	  # are required to link).
+	  if test -n "$old_library"; then
+	    newdlprefiles="$newdlprefiles $dir/$old_library"
+	  # Otherwise, use the dlname, so that lt_dlopen finds it.
+	  elif test -n "$dlname"; then
+	    newdlprefiles="$newdlprefiles $dir/$dlname"
+	  else
+	    newdlprefiles="$newdlprefiles $dir/$linklib"
+	  fi
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  newlib_search_path="$newlib_search_path $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if test "X$duplicate_deps" = "Xyes" ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var"; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath " in
+	      *" $dir "*) ;;
+	      *" $absdir "*) ;;
+	      *) temp_rpath="$temp_rpath $dir" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	if test -n "$library_names" &&
+	   { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+	  if test "$installed" = no; then
+	    notinst_deplibs="$notinst_deplibs $lib"
+	    need_relink=yes
+	  fi
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on
+	  # some systems (darwin)
+	  if test "$shouldnotlink" = yes && test "$pass" = link ; then
+	    $echo
+	    if test "$linkmode" = prog; then
+	      $echo "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $echo "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $echo "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    realname="$2"
+	    shift; shift
+	    libname=`eval \\$echo \"$libname_spec\"`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw*)
+		major=`expr $current - $age`
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+	    newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      $show "extracting exported symbol list from \`$soname'"
+	      save_ifs="$IFS"; IFS='~'
+	      cmds=$extract_expsyms_cmds
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd" || exit $?
+	      done
+	      IFS="$save_ifs"
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      $show "generating import library for \`$soname'"
+	      save_ifs="$IFS"; IFS='~'
+	      cmds=$old_archive_from_expsyms_cmds
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd" || exit $?
+	      done
+	      IFS="$save_ifs"
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a module then we can not link against
+		    # it, someone is ignoring the new warnings I added
+		    if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then
+		      $echo "** Warning, lib $linklib is a module, not a shared library"
+		      if test -z "$old_library" ; then
+		        $echo
+		        $echo "** And there doesn't seem to be a static archive available"
+		        $echo "** The link will probably fail, sorry"
+		      else
+		        add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$dir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case "$libdir" in
+		    [\\/]*)
+		      add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      $echo "$modename: configuration error: unsupported hardcode properties"
+	      exit $EXIT_FAILURE
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes && \
+		 test "$hardcode_minus_L" != yes && \
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+	        add="$inst_prefix_dir$libdir/$linklib"
+	      else
+	        add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case "$libdir" in
+		  [\\/]*)
+		    add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    $echo
+	    $echo "*** Warning: This system can not link to static lib archive $lib."
+	    $echo "*** I have the capability to make that library automatically link in when"
+	    $echo "*** you link to this library.  But I can only do this if you have a"
+	    $echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      $echo "*** But as you try to build a module library, libtool will still create "
+	      $echo "*** a static module, that should work as long as the dlopening application"
+	      $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		$echo
+		$echo "*** However, this would only work if libtool was able to extract symbol"
+		$echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		$echo "*** not find such a program.  So, this module is probably useless."
+		$echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    convenience="$convenience $dir/$old_library"
+	    old_convenience="$old_convenience $dir/$old_library"
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) xrpath="$xrpath $temp_xrpath";;
+		   esac;;
+	      *) temp_deplibs="$temp_deplibs $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  newlib_search_path="$newlib_search_path $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    if test "X$duplicate_deps" = "Xyes" ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+		dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+		test "X$dir" = "X$deplib" && dir="."
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if grep "^installed=no" $deplib > /dev/null; then
+		  path="$absdir/$objdir"
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  if test -z "$libdir"; then
+		    $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+		    exit $EXIT_FAILURE
+		  fi
+		  if test "$absdir" != "$libdir"; then
+		    $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+		  fi
+		  path="$absdir"
+		fi
+		depdepl=
+		case $host in
+		*-*-darwin*)
+		  # we do not want to link against static libs,
+		  # but need to link against shared
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$path/$depdepl" ; then
+		      depdepl="$path/$depdepl"
+		    fi
+		    # do not add paths which are already there
+		    case " $newlib_search_path " in
+		    *" $path "*) ;;
+		    *) newlib_search_path="$newlib_search_path $path";;
+		    esac
+		  fi
+		  path=""
+		  ;;
+		*)
+		  path="-L$path"
+		  ;;
+		esac
+		;;
+	      -l*)
+		case $host in
+		*-*-darwin*)
+		  # Again, we only want to link against shared libraries
+		  eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+		  for tmp in $newlib_search_path ; do
+		    if test -f "$tmp/lib$tmp_libs.dylib" ; then
+		      eval depdepl="$tmp/lib$tmp_libs.dylib"
+		      break
+		    fi
+		  done
+		  path=""
+		  ;;
+		*) continue ;;
+		esac
+		;;
+	      *) continue ;;
+	      esac
+	      case " $deplibs " in
+	      *" $depdepl "*) ;;
+	      *) deplibs="$depdepl $deplibs" ;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$deplibs $path" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) lib_search_path="$lib_search_path $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) tmp_libs="$tmp_libs $deplib" ;;
+	      esac
+	      ;;
+	    *) tmp_libs="$tmp_libs $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  tmp_libs="$tmp_libs $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$deplibs"; then
+	$echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+	$echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+	$echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	$echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+      fi
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      objs="$objs$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	if test "$module" = no; then
+	  $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+	  exit $EXIT_FAILURE
+	else
+	  $echo
+	  $echo "*** Warning: Linking the shared library $output against the non-libtool"
+	  $echo "*** objects $objs is not portable!"
+	  libobjs="$libobjs $objs"
+	fi
+      fi
+
+      if test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+      fi
+
+      set dummy $rpath
+      if test "$#" -gt 2; then
+	$echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+      fi
+      install_libdir="$2"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	if test -n "$vinfo"; then
+	  $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+	fi
+
+	if test -n "$release"; then
+	  $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+	fi
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	IFS="$save_ifs"
+
+	if test -n "$8"; then
+	  $echo "$modename: too many parameters to \`-version-info'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$2"
+	  number_minor="$3"
+	  number_revision="$4"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  darwin|linux|osf|windows)
+	    current=`expr $number_major + $number_minor`
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    current=`expr $number_major + $number_minor - 1`
+	    age="$number_minor"
+	    revision="$number_minor"
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$2"
+	  revision="$3"
+	  age="$4"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	[0-9]*) ;;
+	*)
+	  $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	case $revision in
+	[0-9]*) ;;
+	*)
+	  $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	case $age in
+	[0-9]*) ;;
+	*)
+	  $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  major=.`expr $current - $age`
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  minor_current=`expr $current + 1`
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current";
+	  ;;
+
+	irix | nonstopux)
+	  major=`expr $current - $age + 1`
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    iface=`expr $revision - $loop`
+	    loop=`expr $loop - 1`
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux)
+	  major=.`expr $current - $age`
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  major=.`expr $current - $age`
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    iface=`expr $current - $loop`
+	    loop=`expr $loop - 1`
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  verstring="$verstring:${current}.0"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  major=`expr $current - $age`
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  $echo "$modename: unknown library version type \`$version_type'" 1>&2
+	  $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+      fi
+
+      if test "$mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$echo "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+	         if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+	         then
+		   continue
+		 fi
+	       fi
+	       removelist="$removelist $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	if test -n "$removelist"; then
+	  $show "${rm}r $removelist"
+	  $run ${rm}r $removelist
+	fi
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      for path in $notinst_path; do
+	lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
+	deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
+	dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+      done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  temp_xrpath="$temp_xrpath -R$libdir"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) dlfiles="$dlfiles $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) dlprefiles="$dlprefiles $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    deplibs="$deplibs -framework System"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+ 	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      deplibs="$deplibs -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $rm conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $rm conftest
+	  $LTCC -o conftest conftest.c $deplibs
+	  if test "$?" -eq 0 ; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      name="`expr $i : '-l\(.*\)'`"
+	      # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" -ne "0"; then
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    newdeplibs="$newdeplibs $i"
+		    i=""
+		    ;;
+		  esac
+	        fi
+		if test -n "$i" ; then
+		  libname=`eval \\$echo \"$libname_spec\"`
+		  deplib_matches=`eval \\$echo \"$library_names_spec\"`
+		  set dummy $deplib_matches
+		  deplib_match=$2
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    newdeplibs="$newdeplibs $i"
+		  else
+		    droppeddeps=yes
+		    $echo
+		    $echo "*** Warning: dynamic linker does not accept needed library $i."
+		    $echo "*** I have the capability to make that library automatically link in when"
+		    $echo "*** you link to this library.  But I can only do this if you have a"
+		    $echo "*** shared version of the library, which I believe you do not have"
+		    $echo "*** because a test_compile did reveal that the linker did not use it for"
+		    $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+	      else
+		newdeplibs="$newdeplibs $i"
+	      fi
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      name="`expr $i : '-l\(.*\)'`"
+	      # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" != "0"; then
+		$rm conftest
+		$LTCC -o conftest conftest.c $i
+		# Did it work?
+		if test "$?" -eq 0 ; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      newdeplibs="$newdeplibs $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval \\$echo \"$libname_spec\"`
+		    deplib_matches=`eval \\$echo \"$library_names_spec\"`
+		    set dummy $deplib_matches
+		    deplib_match=$2
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      newdeplibs="$newdeplibs $i"
+		    else
+		      droppeddeps=yes
+		      $echo
+		      $echo "*** Warning: dynamic linker does not accept needed library $i."
+		      $echo "*** I have the capability to make that library automatically link in when"
+		      $echo "*** you link to this library.  But I can only do this if you have a"
+		      $echo "*** shared version of the library, which you do not appear to have"
+		      $echo "*** because a test_compile did reveal that the linker did not use this one"
+		      $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  $echo
+		  $echo "*** Warning!  Library $i is needed by this library but I was not able to"
+		  $echo "***  make it link in!  You will probably need to install it or some"
+		  $echo "*** library that it depends on before this library will be fully"
+		  $echo "*** functional.  Installing it before continuing would be even better."
+		fi
+	      else
+		newdeplibs="$newdeplibs $i"
+	      fi
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method
+	  file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    name="`expr $a_deplib : '-l\(.*\)'`"
+	    # If $name is empty we are operating on a -L argument.
+            if test "$name" != "" && test  "$name" != "0"; then
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval \\$echo \"$libname_spec\"`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null \
+			 | grep " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+			 | ${SED} 10q \
+			 | $EGREP "$file_magic_regex" > /dev/null; then
+			newdeplibs="$newdeplibs $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$echo
+		$echo "*** Warning: linker path does not have real file for library $a_deplib."
+		$echo "*** I have the capability to make that library automatically link in when"
+		$echo "*** you link to this library.  But I can only do this if you have a"
+		$echo "*** shared version of the library, which you do not appear to have"
+		$echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $echo "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $echo "*** with $libname and none of the candidates passed a file format test"
+		  $echo "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	    else
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	    fi
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    name="`expr $a_deplib : '-l\(.*\)'`"
+	    # If $name is empty we are operating on a -L argument.
+	    if test -n "$name" && test "$name" != "0"; then
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval \\$echo \"$libname_spec\"`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval $echo \"$potent_lib\" 2>/dev/null \
+		        | ${SED} 10q \
+		        | $EGREP "$match_pattern_regex" > /dev/null; then
+		      newdeplibs="$newdeplibs $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$echo
+		$echo "*** Warning: linker path does not have real file for library $a_deplib."
+		$echo "*** I have the capability to make that library automatically link in when"
+		$echo "*** you link to this library.  But I can only do this if you have a"
+		$echo "*** shared version of the library, which you do not appear to have"
+		$echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $echo "*** with $libname and none of the candidates passed a file format test"
+		  $echo "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	    else
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	    fi
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+	    -e 's/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+	    done
+	  fi
+	  if $echo "X $tmp_deplibs" | $Xsed -e 's/[ 	]//g' \
+	    | grep . >/dev/null; then
+	    $echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      $echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      $echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    $echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	  fi
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library is the System framework
+	  newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    $echo
+	    $echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $echo "*** dependencies of module $libname.  Therefore, libtool will create"
+	    $echo "*** a static module, that should work as long as the dlopening"
+	    $echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      $echo
+	      $echo "*** However, this would only work if libtool was able to extract symbol"
+	      $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      $echo "*** not find such a program.  So, this module is probably useless."
+	      $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    $echo "*** The inter-library dependencies that have been dropped here will be"
+	    $echo "*** automatically added whenever a program is linked with this library"
+	    $echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      $echo
+	      $echo "*** Since this library must not contain undefined symbols,"
+	      $echo "*** because either the platform does not support them or"
+	      $echo "*** it was explicitly requested with -no-undefined,"
+	      $echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		dep_rpath="$dep_rpath $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) perm_rpath="$perm_rpath $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    if test -n "$hardcode_libdir_flag_spec_ld"; then
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+	    else
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+	    fi
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      rpath="$rpath$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	realname="$2"
+	shift; shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	for link
+	do
+	  linknames="$linknames $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    $show "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $run $rm $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $cmds; do
+	      IFS="$save_ifs"
+	      eval cmd=\"$cmd\"
+	      if len=`expr "X$cmd" : ".*"` &&
+	       test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	        $show "$cmd"
+	        $run eval "$cmd" || exit $?
+	        skipped_export=false
+	      else
+	        # The command line is too long to execute in one step.
+	        $show "using reloadable object file for export list..."
+	        skipped_export=:
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex"; then
+	      $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+	      $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+	      $run eval '$mv "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+		case " $convenience " in
+		*" $test_deplib "*) ;;
+		*)
+			tmp_deplibs="$tmp_deplibs $test_deplib"
+			;;
+		esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    $show "${rm}r $gentop"
+	    $run ${rm}r "$gentop"
+	    $show "$mkdir $gentop"
+	    $run $mkdir "$gentop"
+	    status=$?
+	    if test "$status" -ne 0 && test ! -d "$gentop"; then
+	      exit $status
+	    fi
+	    generated="$generated $gentop"
+
+	    for xlib in $convenience; do
+	      # Extract the objects.
+	      case $xlib in
+	      [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+	      *) xabs=`pwd`"/$xlib" ;;
+	      esac
+	      xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+	      xdir="$gentop/$xlib"
+
+	      $show "${rm}r $xdir"
+	      $run ${rm}r "$xdir"
+	      $show "$mkdir $xdir"
+	      $run $mkdir "$xdir"
+	      status=$?
+	      if test "$status" -ne 0 && test ! -d "$xdir"; then
+		exit $status
+	      fi
+	      # We will extract separately just the conflicting names and we will no
+	      # longer touch any unique names. It is faster to leave these extract
+	      # automatically by $AR in one run.
+	      $show "(cd $xdir && $AR x $xabs)"
+	      $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+	      if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+		:
+	      else
+		$echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+		$echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+		$AR t "$xabs" | sort | uniq -cd | while read -r count name
+		do
+		  i=1
+		  while test "$i" -le "$count"
+		  do
+		   # Put our $i before any first dot (extension)
+		   # Never overwrite any file
+		   name_to="$name"
+		   while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+		   do
+		     name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+		   done
+		   $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+		   $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+		   i=`expr $i + 1`
+		  done
+		done
+	      fi
+
+	      libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+	    done
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  linker_flags="$linker_flags $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$mode" = relink; then
+	  $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	  eval test_cmds=\"$archive_expsym_cmds\"
+	  cmds=$archive_expsym_cmds
+	else
+	  eval test_cmds=\"$archive_cmds\"
+	  cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+	   test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise.
+	  $echo "creating reloadable object files..."
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  delfiles=
+	  last_robj=
+	  k=1
+	  output=$output_objdir/$save_output-${k}.$objext
+	  # Loop over the list of objects to be linked.
+	  for obj in $save_libobjs
+	  do
+	    eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+	    if test "X$objlist" = X ||
+	       { len=`expr "X$test_cmds" : ".*"` &&
+		 test "$len" -le "$max_cmd_len"; }; then
+	      objlist="$objlist $obj"
+	    else
+	      # The command $test_cmds is almost too long, add a
+	      # command to the queue.
+	      if test "$k" -eq 1 ; then
+		# The first file doesn't have a previous command to add.
+		eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+	      else
+		# All subsequent reloadable object files will link in
+		# the last one created.
+		eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+	      fi
+	      last_robj=$output_objdir/$save_output-${k}.$objext
+	      k=`expr $k + 1`
+	      output=$output_objdir/$save_output-${k}.$objext
+	      objlist=$obj
+	      len=1
+	    fi
+	  done
+	  # Handle the remaining objects by creating one last
+	  # reloadable object file.  All subsequent reloadable object
+	  # files will link in the last one created.
+	  test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	  eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+	  if ${skipped_export-false}; then
+	    $show "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $run $rm $export_symbols
+	    libobjs=$output
+	    # Append the command to create the export file.
+	    eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+          fi
+
+	  # Set up a command to remove the reloadale object files
+	  # after they are used.
+	  i=0
+	  while test "$i" -lt "$k"
+	  do
+	    i=`expr $i + 1`
+	    delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+	  done
+
+	  $echo "creating a temporary reloadable object file: $output"
+
+	  # Loop through the commands generated above and execute them.
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $concat_cmds; do
+	    IFS="$save_ifs"
+	    $show "$cmd"
+	    $run eval "$cmd" || exit $?
+	  done
+	  IFS="$save_ifs"
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    cmds=$archive_expsym_cmds
+	  else
+	    cmds=$archive_cmds
+	    fi
+	  fi
+
+	  # Append the command to remove the reloadable object files
+	  # to the just-reset $cmds.
+	  eval cmds=\"\$cmds~\$rm $delfiles\"
+	fi
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $show "$cmd"
+	  $run eval "$cmd" || exit $?
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$mode" = relink; then
+	  $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+	    $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$deplibs"; then
+	$echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+	$echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+	$echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+      fi
+
+      case $output in
+      *.lo)
+	if test -n "$objs$old_deplibs"; then
+	  $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+	libobj="$output"
+	obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $run $rm $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+	else
+	  gentop="$output_objdir/${obj}x"
+	  $show "${rm}r $gentop"
+	  $run ${rm}r "$gentop"
+	  $show "$mkdir $gentop"
+	  $run $mkdir "$gentop"
+	  status=$?
+	  if test "$status" -ne 0 && test ! -d "$gentop"; then
+	    exit $status
+	  fi
+	  generated="$generated $gentop"
+
+	  for xlib in $convenience; do
+	    # Extract the objects.
+	    case $xlib in
+	    [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+	    *) xabs=`pwd`"/$xlib" ;;
+	    esac
+	    xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+	    xdir="$gentop/$xlib"
+
+	    $show "${rm}r $xdir"
+	    $run ${rm}r "$xdir"
+	    $show "$mkdir $xdir"
+	    $run $mkdir "$xdir"
+	    status=$?
+	    if test "$status" -ne 0 && test ! -d "$xdir"; then
+	      exit $status
+	    fi
+	    # We will extract separately just the conflicting names and we will no
+	    # longer touch any unique names. It is faster to leave these extract
+	    # automatically by $AR in one run.
+	    $show "(cd $xdir && $AR x $xabs)"
+	    $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+	    if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+	      :
+	    else
+	      $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+	      $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+	      $AR t "$xabs" | sort | uniq -cd | while read -r count name
+	      do
+		i=1
+		while test "$i" -le "$count"
+		do
+		 # Put our $i before any first dot (extension)
+		 # Never overwrite any file
+		 name_to="$name"
+		 while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+		 do
+		   name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+		 done
+		 $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+		 $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+		 i=`expr $i + 1`
+		done
+	      done
+	    fi
+
+	    reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+	  done
+	fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      cmds=$reload_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+	IFS="$save_ifs"
+	eval cmd=\"$cmd\"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  $show "${rm}r $gentop"
+	  $run ${rm}r $gentop
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  $show "${rm}r $gentop"
+	  $run ${rm}r $gentop
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $run eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	cmds=$reload_cmds
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $show "$cmd"
+	  $run eval "$cmd" || exit $?
+	done
+	IFS="$save_ifs"
+      fi
+
+      if test -n "$gentop"; then
+	$show "${rm}r $gentop"
+	$run ${rm}r $gentop
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+      esac
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+      fi
+
+      if test "$preload" = yes; then
+	if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+	   test "$dlopen_self_static" = unknown; then
+	  $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+	fi
+      fi
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	;;
+      esac
+
+      case $host in
+      *darwin*)
+        # Don't allow lazy linking, it breaks C++ global constructors
+        if test "$tagname" = CXX ; then
+        compile_command="$compile_command ${wl}-bind_at_load"
+        finalize_command="$finalize_command ${wl}-bind_at_load"
+        fi
+        ;;
+      esac
+
+      compile_command="$compile_command $compile_deplibs"
+      finalize_command="$finalize_command $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) perm_rpath="$perm_rpath $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$libdir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+      fi
+
+      dlsyms=
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	  dlsyms="${outputname}S.c"
+	else
+	  $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+	fi
+      fi
+
+      if test -n "$dlsyms"; then
+	case $dlsyms in
+	"") ;;
+	*.c)
+	  # Discover the nlist of each of the dlfiles.
+	  nlist="$output_objdir/${outputname}.nm"
+
+	  $show "$rm $nlist ${nlist}S ${nlist}T"
+	  $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+	  # Parse the name list into a source file.
+	  $show "creating $output_objdir/$dlsyms"
+
+	  test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+	  if test "$dlself" = yes; then
+	    $show "generating symbol list for \`$output'"
+
+	    test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+	    # Add our own program objects to the symbol list.
+	    progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	    for arg in $progfiles; do
+	      $show "extracting global C symbols from \`$arg'"
+	      $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+	    done
+
+	    if test -n "$exclude_expsyms"; then
+	      $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      $run eval '$mv "$nlist"T "$nlist"'
+	    fi
+
+	    if test -n "$export_symbols_regex"; then
+	      $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      $run eval '$mv "$nlist"T "$nlist"'
+	    fi
+
+	    # Prepare the list of exported symbols
+	    if test -z "$export_symbols"; then
+	      export_symbols="$output_objdir/$output.exp"
+	      $run $rm $export_symbols
+	      $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	    else
+	      $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+	      $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+	      $run eval 'mv "$nlist"T "$nlist"'
+	    fi
+	  fi
+
+	  for arg in $dlprefiles; do
+	    $show "extracting global C symbols from \`$arg'"
+	    name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+	    $run eval '$echo ": $name " >> "$nlist"'
+	    $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -z "$run"; then
+	    # Make sure we have at least an empty file.
+	    test -f "$nlist" || : > "$nlist"
+
+	    if test -n "$exclude_expsyms"; then
+	      $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	      $mv "$nlist"T "$nlist"
+	    fi
+
+	    # Try sorting and uniquifying the output.
+	    if grep -v "^: " < "$nlist" |
+		if sort -k 3 </dev/null >/dev/null 2>&1; then
+		  sort -k 3
+		else
+		  sort +2
+		fi |
+		uniq > "$nlist"S; then
+	      :
+	    else
+	      grep -v "^: " < "$nlist" > "$nlist"S
+	    fi
+
+	    if test -f "$nlist"S; then
+	      eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+	    else
+	      $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+	    fi
+
+	    $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+	    $echo >> "$output_objdir/$dlsyms" "\
+  {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	  fi
+
+	  pic_flag_for_symtable=
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    case "$compile_command " in
+	    *" -static "*) ;;
+	    *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+	    esac;;
+	  *-*-hpux*)
+	    case "$compile_command " in
+	    *" -static "*) ;;
+	    *) pic_flag_for_symtable=" $pic_flag";;
+	    esac
+	  esac
+
+	  # Now compile the dynamic symbol file.
+	  $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+	  $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+	  # Clean up the generated files.
+	  $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+	  $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+	  # Transform the symbol file into the correct name.
+	  compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+	  finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+	  ;;
+	*)
+	  $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+      else
+	# We keep going just in case the user didn't refer to
+	# lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+	# really was required.
+
+	# Nullify the symbol file.
+	compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+	finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+	# Replace the output file specification.
+	compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	$show "$link_command"
+	$run eval "$link_command"
+	status=$?
+
+	# Delete the generated files.
+	if test -n "$dlsyms"; then
+	  $show "$rm $output_objdir/${outputname}S.${objext}"
+	  $run $rm "$output_objdir/${outputname}S.${objext}"
+	fi
+
+	exit $status
+      fi
+
+      if test -n "$shlibpath_var"; then
+	# We should set the shlibpath_var
+	rpath=
+	for dir in $temp_rpath; do
+	  case $dir in
+	  [\\/]* | [A-Za-z]:[\\/]*)
+	    # Absolute path.
+	    rpath="$rpath$dir:"
+	    ;;
+	  *)
+	    # Relative path: add a thisdir entry.
+	    rpath="$rpath\$thisdir/$dir:"
+	    ;;
+	  esac
+	done
+	temp_rpath="$rpath"
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$run $rm $output
+	# Link the executable and exit
+	$show "$link_command"
+	$run eval "$link_command" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	$echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+	$echo "$modename: \`$output' will be relinked during installation" 1>&2
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      $show "$link_command"
+      $run eval "$link_command" || exit $?
+
+      # Now create the wrapper script.
+      $show "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+	    relink_command="$var=\"$var_value\"; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Quote $echo for shipping.
+      if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+	case $progpath in
+	[\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+	*) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+	esac
+	qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+      else
+	qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if our run command is non-null.
+      if test -z "$run"; then
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    cwrappersource=`$echo ${objdir}/lt-${output}.c`
+	    cwrapper=`$echo ${output}.exe`
+	    $rm $cwrappersource $cwrapper
+	    trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "/bin/sh $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+	    cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+#define HAVE_DOS_BASED_FILE_SYSTEM
+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+        (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+char * basename (const char *name);
+char * fnqualify(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int i;
+
+  program_name = (char *) xstrdup ((char *) basename (argv[0]));
+  newargz = XMALLOC(char *, argc+2);
+EOF
+
+	    cat >> $cwrappersource <<EOF
+  newargz[0] = "$SHELL";
+EOF
+
+	    cat >> $cwrappersource <<"EOF"
+  newargz[1] = fnqualify(argv[0]);
+  /* we know the script has the same name, without the .exe */
+  /* so make sure newargz[1] doesn't end in .exe */
+  strendzap(newargz[1],".exe");
+  for (i = 1; i < argc; i++)
+    newargz[i+1] = xstrdup(argv[i]);
+  newargz[argc+1] = NULL;
+EOF
+
+	    cat >> $cwrappersource <<EOF
+  execv("$SHELL",newargz);
+EOF
+
+	    cat >> $cwrappersource <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void * p = (void *) malloc (num);
+  if (!p)
+    lt_fatal ("Memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+char *
+basename (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha (name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return (char *) base;
+}
+
+char *
+fnqualify(const char *path)
+{
+  size_t size;
+  char *p;
+  char tmp[LT_PATHMAX + 1];
+
+  assert(path != NULL);
+
+  /* Is it qualified already? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha (path[0]) && path[1] == ':')
+    return xstrdup (path);
+#endif
+  if (IS_DIR_SEPARATOR (path[0]))
+    return xstrdup (path);
+
+  /* prepend the current directory */
+  /* doesn't handle '~' */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal ("getcwd failed");
+  size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
+  p = XMALLOC(char, size);
+  sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
+  return p;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert(str != NULL);
+  assert(pat != NULL);
+
+  len = strlen(str);
+  patlen = strlen(pat);
+
+  if (patlen <= len)
+  {
+    str += len - patlen;
+    if (strcmp(str, pat) == 0)
+      *str = '\0';
+  }
+  return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+          const char * message, va_list ap)
+{
+  fprintf (stderr, "%s: %s: ", program_name, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  va_end (ap);
+}
+EOF
+	  # we should really use a build-platform specific compiler
+	  # here, but OTOH, the wrappers (shell script and this C one)
+	  # are only useful if you want to execute the "real" binary.
+	  # Since the "real" binary is built for $host, then this
+	  # wrapper might as well be built for $host, too.
+	  $run $LTCC -s -o $cwrapper $cwrappersource
+	  ;;
+	esac
+	$rm $output
+	trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+	$echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variable:
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$echo are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    echo=\"$qecho\"
+    file=\"\$0\"
+    # Make sure echo works.
+    if test \"X\$1\" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+      # Yippee, \$echo works!
+      :
+    else
+      # Restart under the correct shell, and then maybe \$echo will work.
+      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+    fi
+  fi\
+"
+	$echo >> $output "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $echo >> $output "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" || \\
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $mkdir \"\$progdir\"
+    else
+      $rm \"\$progdir/\$file\"
+    fi"
+
+	  $echo >> $output "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$echo \"\$relink_command_output\" >&2
+	$rm \"\$progdir/\$file\"
+	exit $EXIT_FAILURE
+      fi
+    fi
+
+    $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $rm \"\$progdir/\$program\";
+      $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $rm \"\$progdir/\$file\"
+  fi"
+	else
+	  $echo >> $output "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$echo >> $output "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $echo >> $output "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	# fixup the dll searchpath if we need to.
+	if test -n "$dllsearchpath"; then
+	  $echo >> $output "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	$echo >> $output "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+"
+	case $host in
+	# Backslashes separate directories on plain windows
+	*-*-mingw | *-*-os2*)
+	  $echo >> $output "\
+      exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+	  ;;
+
+	*)
+	  $echo >> $output "\
+      exec \$progdir/\$program \${1+\"\$@\"}
+"
+	  ;;
+	esac
+	$echo >> $output "\
+      \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+      exit $EXIT_FAILURE
+    fi
+  else
+    # The program doesn't exist.
+    \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+    \$echo \"This script is just a wrapper for \$program.\" 1>&2
+    $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi\
+"
+	chmod +x $output
+      fi
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	$show "${rm}r $gentop"
+	$run ${rm}r "$gentop"
+	$show "$mkdir $gentop"
+	$run $mkdir "$gentop"
+	status=$?
+	if test "$status" -ne 0 && test ! -d "$gentop"; then
+	  exit $status
+	fi
+	generated="$generated $gentop"
+
+	# Add in members from convenience archives.
+	for xlib in $addlibs; do
+	  # Extract the objects.
+	  case $xlib in
+	  [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+	  *) xabs=`pwd`"/$xlib" ;;
+	  esac
+	  xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+	  xdir="$gentop/$xlib"
+
+	  $show "${rm}r $xdir"
+	  $run ${rm}r "$xdir"
+	  $show "$mkdir $xdir"
+	  $run $mkdir "$xdir"
+	  status=$?
+	  if test "$status" -ne 0 && test ! -d "$xdir"; then
+	    exit $status
+	  fi
+	  # We will extract separately just the conflicting names and we will no
+	  # longer touch any unique names. It is faster to leave these extract
+	  # automatically by $AR in one run.
+	  $show "(cd $xdir && $AR x $xabs)"
+	  $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+	  if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+	    :
+	  else
+	    $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+	    $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+	    $AR t "$xabs" | sort | uniq -cd | while read -r count name
+	    do
+	      i=1
+	      while test "$i" -le "$count"
+	      do
+	       # Put our $i before any first dot (extension)
+	       # Never overwrite any file
+	       name_to="$name"
+	       while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+	       do
+		 name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+	       done
+	       $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+	       $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+	       i=`expr $i + 1`
+	      done
+	    done
+	  fi
+
+	  oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+	done
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       cmds=$old_archive_from_new_cmds
+      else
+	eval cmds=\"$old_archive_cmds\"
+
+	if len=`expr "X$cmds" : ".*"` &&
+	     test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  $echo "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  # GNU ar 2.10+ was changed to match POSIX; thus no paths are
+	  # encoded into archives.  This makes 'ar r' malfunction in
+	  # this piecewise linking case whenever conflicting object
+	  # names appear in distinct ar calls; check, warn and compensate.
+	    if (for obj in $save_oldobjs
+	    do
+	      $echo "X$obj" | $Xsed -e 's%^.*/%%'
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	    :
+	  else
+	    $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2
+	    $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2
+	    AR_FLAGS=cq
+	  fi
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  for obj in $save_oldobjs
+	  do
+	    oldobjs="$objlist $obj"
+	    objlist="$objlist $obj"
+	    eval test_cmds=\"$old_archive_cmds\"
+	    if len=`expr "X$test_cmds" : ".*"` &&
+	       test "$len" -le "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+	        RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+        eval cmd=\"$cmd\"
+	IFS="$save_ifs"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$generated"; then
+      $show "${rm}r$generated"
+      $run ${rm}r$generated
+    fi
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      $show "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+	  relink_command="$var=\"$var_value\"; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+
+      # Only create the output if not a dry run.
+      if test -z "$run"; then
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		if test -z "$libdir"; then
+		  $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+		  exit $EXIT_FAILURE
+		fi
+		newdependency_libs="$newdependency_libs $libdir/$name"
+		;;
+	      *) newdependency_libs="$newdependency_libs $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+	      eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+	      if test -z "$libdir"; then
+		$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+		exit $EXIT_FAILURE
+	      fi
+	      newdlfiles="$newdlfiles $libdir/$name"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+	      eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+	      if test -z "$libdir"; then
+		$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+		exit $EXIT_FAILURE
+	      fi
+	      newdlprefiles="$newdlprefiles $libdir/$name"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlfiles="$newdlfiles $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlprefiles="$newdlprefiles $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $rm $output
+	  # place dlname in correct position for cygwin
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+	  esac
+	  $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $echo >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      fi
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+      $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool install mode
+  install)
+    modename="$modename: install"
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+      # Aesthetically quote it.
+      arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*)
+	arg="\"$arg\""
+	;;
+      esac
+      install_prog="$arg "
+      arg="$1"
+      shift
+    else
+      install_prog=
+      arg="$nonopt"
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+    case $arg in
+    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*)
+      arg="\"$arg\""
+      ;;
+    esac
+    install_prog="$install_prog$arg"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+	files="$files $dest"
+	dest="$arg"
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f) prev="-f" ;;
+      -g) prev="-g" ;;
+      -m) prev="-m" ;;
+      -o) prev="-o" ;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*) ;;
+
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  prev=
+	else
+	  dest="$arg"
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*)
+	arg="\"$arg\""
+	;;
+      esac
+      install_prog="$install_prog $arg"
+    done
+
+    if test -z "$install_prog"; then
+      $echo "$modename: you must specify an install program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prev' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	$echo "$modename: no file or destination specified" 1>&2
+      else
+	$echo "$modename: you must specify a destination" 1>&2
+      fi
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Strip any trailing slash from the destination.
+    dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$destdir" = "X$dest" && destdir=.
+      destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files
+      if test "$#" -gt 2; then
+	$echo "$modename: \`$dest' is not a directory" 1>&2
+	$echo "$help" 1>&2
+	exit $EXIT_FAILURE
+      fi
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	staticlibs="$staticlibs $file"
+	;;
+
+      *.la)
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	library_names=
+	old_library=
+	relink_command=
+	# If there is no directory component, then add one.
+	case $file in
+	*/* | *\\*) . $file ;;
+	*) . ./$file ;;
+	esac
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) current_libdirs="$current_libdirs $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) future_libdirs="$future_libdirs $libdir" ;;
+	  esac
+	fi
+
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+	test "X$dir" = "X$file/" && dir=
+	dir="$dir$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  if test "$inst_prefix_dir" = "$destdir"; then
+	    $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  $echo "$modename: warning: relinking \`$file'" 1>&2
+	  $show "$relink_command"
+	  if $run eval "$relink_command"; then :
+	  else
+	    $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names
+	if test -n "$2"; then
+	  realname="$2"
+	  shift
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  $show "$install_prog $dir/$srcname $destdir/$realname"
+	  $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+	  if test -n "$stripme" && test -n "$striplib"; then
+	    $show "$striplib $destdir/$realname"
+	    $run eval "$striplib $destdir/$realname" || exit $?
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    for linkname
+	    do
+	      if test "$linkname" != "$realname"; then
+		$show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+		$run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+	      fi
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  cmds=$postinstall_cmds
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $cmds; do
+	    IFS="$save_ifs"
+	    eval cmd=\"$cmd\"
+	    $show "$cmd"
+	    $run eval "$cmd" || exit $?
+	  done
+	  IFS="$save_ifs"
+	fi
+
+	# Install the pseudo-library for information purposes.
+	name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	instname="$dir/$name"i
+	$show "$install_prog $instname $destdir/$name"
+	$run eval "$install_prog $instname $destdir/$name" || exit $?
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	if test -n "$destfile"; then
+	  $show "$install_prog $file $destfile"
+	  $run eval "$install_prog $file $destfile" || exit $?
+	fi
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+	  $show "$install_prog $staticobj $staticdest"
+	  $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      file=`$echo $file|${SED} 's,.exe$,,'`
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin*|*mingw*)
+	    wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  # To insure that "foo" is sourced, and not "foo.exe",
+	  # finese the cygwin/MSYS system by explicitly sourcing "foo."
+	  # which disallows the automatic-append-.exe behavior.
+	  case $build in
+	  *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+	  *) wrapperdot=${wrapper} ;;
+	  esac
+	  # If there is no directory component, then add one.
+	  case $file in
+	  */* | *\\*) . ${wrapperdot} ;;
+	  *) . ./${wrapperdot} ;;
+	  esac
+
+	  # Check the variables that should have been set.
+	  if test -z "$notinst_deplibs"; then
+	    $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      # If there is no directory component, then add one.
+	      case $lib in
+	      */* | *\\*) . $lib ;;
+	      *) . ./$lib ;;
+	      esac
+	    fi
+	    libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  # To insure that "foo" is sourced, and not "foo.exe",
+	  # finese the cygwin/MSYS system by explicitly sourcing "foo."
+	  # which disallows the automatic-append-.exe behavior.
+	  case $build in
+	  *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+	  *) wrapperdot=${wrapper} ;;
+	  esac
+	  # If there is no directory component, then add one.
+	  case $file in
+	  */* | *\\*) . ${wrapperdot} ;;
+	  *) . ./${wrapperdot} ;;
+	  esac
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    if test "$finalize" = yes && test -z "$run"; then
+	      tmpdir="/tmp"
+	      test -n "$TMPDIR" && tmpdir="$TMPDIR"
+	      tmpdir="$tmpdir/libtool-$$"
+	      save_umask=`umask`
+	      umask 0077
+	      if $mkdir "$tmpdir"; then
+	        umask $save_umask
+	      else
+	        umask $save_umask
+		$echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+		continue
+	      fi
+	      file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+	      outputname="$tmpdir/$file"
+	      # Replace the output file specification.
+	      relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+	      $show "$relink_command"
+	      if $run eval "$relink_command"; then :
+	      else
+		$echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+		${rm}r "$tmpdir"
+		continue
+	      fi
+	      file="$outputname"
+	    else
+	      $echo "$modename: warning: cannot relink \`$file'" 1>&2
+	    fi
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyways
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+	    ;;
+	  esac
+	  ;;
+	esac
+	$show "$install_prog$stripme $file $destfile"
+	$run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+	test -n "$outputname" && ${rm}r "$tmpdir"
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      $show "$install_prog $file $oldlib"
+      $run eval "$install_prog \$file \$oldlib" || exit $?
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	$show "$old_striplib $oldlib"
+	$run eval "$old_striplib $oldlib" || exit $?
+      fi
+
+      # Do each command in the postinstall commands.
+      cmds=$old_postinstall_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+	IFS="$save_ifs"
+	eval cmd=\"$cmd\"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$future_libdirs"; then
+      $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+    fi
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      test -n "$run" && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool finish mode
+  finish)
+    modename="$modename: finish"
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+	libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  cmds=$finish_cmds
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $cmds; do
+	    IFS="$save_ifs"
+	    eval cmd=\"$cmd\"
+	    $show "$cmd"
+	    $run eval "$cmd" || admincmds="$admincmds
+       $cmd"
+	  done
+	  IFS="$save_ifs"
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $run eval "$cmds" || admincmds="$admincmds
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    test "$show" = : && exit $EXIT_SUCCESS
+
+    $echo "----------------------------------------------------------------------"
+    $echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      $echo "   $libdir"
+    done
+    $echo
+    $echo "If you ever happen to want to link against installed libraries"
+    $echo "in a given directory, LIBDIR, you must either use libtool, and"
+    $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    $echo "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      $echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      $echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      $echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      $echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      $echo "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      $echo "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      $echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    $echo
+    $echo "See any operating system documentation about shared libraries for"
+    $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+    $echo "----------------------------------------------------------------------"
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool execute mode
+  execute)
+    modename="$modename: execute"
+
+    # The first argument is the command name.
+    cmd="$nonopt"
+    if test -z "$cmd"; then
+      $echo "$modename: you must specify a COMMAND" 1>&2
+      $echo "$help"
+      exit $EXIT_FAILURE
+    fi
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      if test ! -f "$file"; then
+	$echo "$modename: \`$file' is not a file" 1>&2
+	$echo "$help" 1>&2
+	exit $EXIT_FAILURE
+      fi
+
+      dir=
+      case $file in
+      *.la)
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+
+	# If there is no directory component, then add one.
+	case $file in
+	*/* | *\\*) . $file ;;
+	*) . ./$file ;;
+	esac
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$dir" = "X$file" && dir=.
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  dir="$dir/$objdir"
+	else
+	  $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$dir" = "X$file" && dir=.
+	;;
+
+      *)
+	$echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -*) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  # If there is no directory component, then add one.
+	  case $file in
+	  */* | *\\*) . $file ;;
+	  *) . ./$file ;;
+	  esac
+
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+      args="$args \"$file\""
+    done
+
+    if test -z "$run"; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      if test "${save_LC_ALL+set}" = set; then
+	LC_ALL="$save_LC_ALL"; export LC_ALL
+      fi
+      if test "${save_LANG+set}" = set; then
+	LANG="$save_LANG"; export LANG
+      fi
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+	$echo "export $shlibpath_var"
+      fi
+      $echo "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool clean and uninstall mode
+  clean | uninstall)
+    modename="$modename: $mode"
+    rm="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) rm="$rm $arg"; rmforce=yes ;;
+      -*) rm="$rm $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    if test -z "$rm"; then
+      $echo "$modename: you must specify an RM program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    rmdirs=
+
+    origobjdir="$objdir"
+    for file in $files; do
+      dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+      if test "X$dir" = "X$file"; then
+	dir=.
+	objdir="$origobjdir"
+      else
+	objdir="$dir/$origobjdir"
+      fi
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+      test "$mode" = uninstall && objdir="$dir"
+
+      # Remember objdir for removal later, being careful to avoid duplicates
+      if test "$mode" = clean; then
+	case " $rmdirs " in
+	  *" $objdir "*) ;;
+	  *) rmdirs="$rmdirs $objdir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if (test -L "$file") >/dev/null 2>&1 \
+	|| (test -h "$file") >/dev/null 2>&1 \
+	|| test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  . $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    rmfiles="$rmfiles $objdir/$n"
+	  done
+	  test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+	  test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+	  if test "$mode" = uninstall; then
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      cmds=$postuninstall_cmds
+	      save_ifs="$IFS"; IFS='~'
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd"
+		if test "$?" -ne 0 && test "$rmforce" != yes; then
+		  exit_status=1
+		fi
+	      done
+	      IFS="$save_ifs"
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      cmds=$old_postuninstall_cmds
+	      save_ifs="$IFS"; IFS='~'
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd"
+		if test "$?" -ne 0 && test "$rmforce" != yes; then
+		  exit_status=1
+		fi
+	      done
+	      IFS="$save_ifs"
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+	  # Read the .lo file
+	  . $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" \
+	     && test "$pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" \
+	     && test "$non_pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    file=`$echo $file|${SED} 's,.exe$,,'`
+	    noexename=`$echo $name|${SED} 's,.exe$,,'`
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    rmfiles="$rmfiles $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	    relink_command=
+	    . $dir/$noexename
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      rmfiles="$rmfiles $objdir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      $show "$rm $rmfiles"
+      $run $rm $rmfiles || exit_status=1
+    done
+    objdir="$origobjdir"
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	$show "rmdir $dir"
+	$run rmdir $dir >/dev/null 2>&1
+      fi
+    done
+
+    exit $exit_status
+    ;;
+
+  "")
+    $echo "$modename: you must specify a MODE" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+  esac
+
+  if test -z "$exec_cmd"; then
+    $echo "$modename: invalid operation mode \`$mode'" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+  eval exec $exec_cmd
+  exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+    --config          show all configuration variables
+    --debug           enable verbose shell tracing
+-n, --dry-run         display commands without modifying any files
+    --features        display basic configuration information and exit
+    --finish          same as \`--mode=finish'
+    --help            display this help message and exit
+    --mode=MODE       use operation mode MODE [default=inferred from MODE-ARGS]
+    --quiet           same as \`--silent'
+    --silent          don't print informational messages
+    --tag=TAG         use configuration variables from tag TAG
+    --version         print version information
+
+MODE must be one of the following:
+
+      clean           remove files from the build directory
+      compile         compile a source file into a libtool object
+      execute         automatically set library path, then run a program
+      finish          complete the installation of libtool libraries
+      install         install libraries or executables
+      link            create a library or an executable
+      uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool at gnu.org>."
+  exit $EXIT_SUCCESS
+  ;;
+
+clean)
+  $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+compile)
+  $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -prefer-pic       try to building PIC objects only
+  -prefer-non-pic   try to building non-PIC objects only
+  -static           always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+  ;;
+
+execute)
+  $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+  ;;
+
+finish)
+  $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+  ;;
+
+install)
+  $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+  ;;
+
+link)
+  $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+		    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+		    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -static           do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+		    specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+  ;;
+
+uninstall)
+  $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+*)
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+  ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $EXIT_SUCCESS
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:

Added: freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,418 @@
+dnl =====================================================================
+dnl This file contains autoconf macros shared by Sofia modules.
+dnl 
+dnl Author: Pekka Pessi <Pekka.Pessi at nokia.com>
+dnl 
+dnl License:
+dnl
+dnl Copyright (c) 2001,2004 Nokia and others. All Rights Reserved.
+dnl
+dnl Please note that every macro contained in this file is copyrighted by
+dnl its respective author, unless the macro source explicitely says
+dnl otherwise. Permission has been granted, though, to use and distribute
+dnl all macros under the following license, which is a modified version of
+dnl the GNU General Public License version 2:
+dnl 
+dnl Each Autoconf macro in this file is free software; you can redistribute it
+dnl and/or modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2, or (at your
+dnl option) any later version.
+dnl 
+dnl They are distributed in the hope that they will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+dnl FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+dnl details. (You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA.)
+dnl 
+dnl As a special exception, the Free Software Foundation gives unlimited
+dnl permission to copy, distribute and modify the configure scripts that are
+dnl the output of Autoconf. You need not follow the terms of the GNU General
+dnl Public License when using or distributing such scripts, even though
+dnl portions of the text of Autoconf appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that constitutes
+dnl the Autoconf program.
+dnl 
+dnl Certain portions of the Autoconf source text are designed to be copied
+dnl (in certain cases, depending on the input) into the output of Autoconf. 
+dnl We call these the "data" portions. The rest of the Autoconf source text
+dnl consists of comments plus executable code that decides which of the data
+dnl portions to output in any given case. We call these comments and
+dnl executable code the "non-data" portions. Autoconf never copies any of
+dnl the non-data portions into its output.
+dnl 
+dnl This special exception to the GPL applies to versions of Autoconf
+dnl released by the Free Software Foundation. When you make and distribute a
+dnl modified version of Autoconf, you may extend this special exception to
+dnl the GPL to apply to your modified version as well, *unless* your
+dnl modified version has the potential to copy into its output some of the
+dnl text that was the non-data portion of the version that you started with. 
+dnl (In other words, unless your change moves or copies text from the
+dnl non-data portions to the data portions.) If your modification has such
+dnl potential, you must delete any notice of this special exception to the
+dnl GPL from your modified version.
+dnl
+dnl =====================================================================
+
+dnl ===================================================================
+dnl Get host, target and build variables filled with appropriate info,
+dnl and check the validity of the cache 
+dnl ===================================================================
+
+AC_DEFUN([SAC_CANONICAL_SYSTEM_CACHE_CHECK], [
+
+dnl Get host, target and build variables filled with appropriate info.
+
+AC_CANONICAL_TARGET([])
+
+dnl Check to assure the cached information is valid.
+
+AC_MSG_CHECKING(cached information)
+hostcheck="$host"
+AC_CACHE_VAL(ac_cv_hostcheck, [ ac_cv_hostcheck="$hostcheck" ])
+if test "$ac_cv_hostcheck" != "$hostcheck"; then
+  AC_MSG_RESULT(changed)
+  AC_MSG_WARN(config.cache exists!)
+  AC_MSG_ERROR([you must do 'make distclean' first to compile 
+ for different host or different parameters.])
+else
+  AC_MSG_RESULT(ok)
+fi
+
+dnl SOSXXX: AC_PATH_ADJUST
+
+])
+
+dnl ======================================================================
+dnl Find C compiler
+dnl ======================================================================
+
+AC_DEFUN([SAC_TOOL_CC], [
+AC_REQUIRE([SAC_CANONICAL_SYSTEM_CACHE_CHECK])
+AC_BEFORE([$0], [AC_PROG_CPP])dnl
+
+AC_CHECK_TOOL(CC, gcc, gcc)
+if test -z "$CC"; then
+  AC_CHECK_TOOL(CC, cc, cc, , , /usr/ucb/cc)
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32* ) AC_CHECK_PROG(CC, cl, cl) ;;
+    esac
+  fi
+  test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
+fi
+
+AC_PROG_CC
+
+#
+# Wall
+#
+AC_CACHE_CHECK([for maximum warnings compiler flag],
+  ac_cv_cwflag,
+[case "${CC-cc}" in
+  *gcc*) ac_cv_cwflag=-Wall;;
+  *)	case "$host" in
+    *irix*)	ac_cv_cwflag=-fullwarn ;;
+    *solaris*)  ac_cv_cwflag="-erroff=%none,E_END_OF_LOOP_CODE_NOT_REACHED -xCC"
+	        ;;
+    *)		ac_cv_cwflag=;;
+		esac 
+  ;;
+esac])
+AC_SUBST([CWFLAG], [$ac_cv_cwflag])
+
+AC_ARG_VAR([SOFIA_CFLAGS], [CFLAGS not used during configure])
+
+#
+# GCoverage
+#
+AC_ARG_ENABLE(coverage,
+[  --enable-coverage       compile test-coverage (disabled)],
+ , enable_coverage=no)
+
+if test X$enable_coverage != Xno ; then
+case "${CC-cc}" in
+  *gcc*) 
+	SOFIA_CFLAGS="$SOFIA_CFLAGS -fprofile-arcs -ftest-coverage" 
+	;;
+  *) AC_MSG_ERROR([--enable-coverage requires gcc])
+esac
+fi
+
+AM_CONDITIONAL([ENABLE_COVERAGE], test X$enable_coverage != Xno)
+
+AC_SUBST([MOSTLYCLEANFILES], "*.bb *.bbg *.da *.gcov *.gcda *.gcno")
+])
+
+dnl ======================================================================
+dnl Check for sockaddr_in6
+dnl ======================================================================
+AC_DEFUN([AC_STRUCT_SIN6], [
+AC_CACHE_CHECK([for sockaddr_in6],
+  ac_cv_sin6,
+[AC_EGREP_HEADER(struct sockaddr_in6, netinet/in.h, 
+  ac_cv_sin6=yes, ac_cv_sin6=no)])
+if test $ac_cv_sin6 = yes ;then
+	AC_DEFINE([HAVE_SIN6], 1, 
+		[Define to 1 if you have IPv6 structures and constants])
+fi
+])
+
+dnl ======================================================================
+dnl Check for sa_len in struct sockaddr
+dnl ======================================================================
+AC_DEFUN([AC_SYS_SA_LEN], [
+AC_CACHE_CHECK([for sa_len],
+  ac_cv_sa_len,
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <sys/socket.h>]], [[
+ struct sockaddr t;t.sa_len = 0;]])],[ac_cv_sa_len=yes],[ac_cv_sa_len=no])])
+if test "$ac_cv_sa_len" = yes ;then
+	AC_DEFINE([HAVE_SA_LEN], 1, 
+		[Define to 1 if you have sa_len in struct sockaddr])
+fi
+])
+
+dnl ======================================================================
+dnl Check for MSG_NOSIGNAL flag
+dnl ======================================================================
+AC_DEFUN([AC_FLAG_MSG_NOSIGNAL], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for MSG_NOSIGNAL], 
+  ac_cv_flag_msg_nosignal, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>]], [[
+  int flags = MSG_NOSIGNAL;
+]])],[ac_cv_flag_msg_nosignal=yes],[ac_cv_flag_msg_nosignal=no])])
+if test "$ac_cv_flag_msg_nosignal" = yes ; then
+	AC_DEFINE([HAVE_MSG_NOSIGNAL], 1,
+		[Define to 1 if you have MSG_NOSIGNAL flag for send()]) 
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for MSG_ERRQUEUE flag
+dnl ======================================================================
+AC_DEFUN([AC_SYS_MSG_ERRQUEUE], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for MSG_ERRQUEUE], 
+  ac_cv_flag_msg_errqueue, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>]], [[
+  int flags = MSG_ERRQUEUE;
+]])],[ac_cv_flag_msg_errqueue=yes],[ac_cv_flag_msg_errqueue=no])])
+if test "$ac_cv_flag_msg_errqueue" = yes; then
+	AC_DEFINE([HAVE_MSG_ERRQUEUE], 1,
+		[Define to 1 if you have MSG_ERRQUEUE flag for send()]) 
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for IP_RECVERR option
+dnl ======================================================================
+AC_DEFUN([AC_SYS_IP_RECVERR], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for IP_RECVERR], 
+  ac_cv_sys_ip_recverr, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+]], [[
+  int one = 1;
+  int s = 0;
+  setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one));
+]])],[ac_cv_sys_ip_recverr=yes],[ac_cv_sys_ip_recverr=no])])
+if test "$ac_cv_sys_ip_recverr" = yes ; then
+	AC_DEFINE([HAVE_IP_RECVERR], 1, 
+		[Define to 1 if you have IP_RECVERR in <netinet/in.h>])
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for IPV6_RECVERR option
+dnl ======================================================================
+AC_DEFUN([AC_SYS_IPV6_RECVERR], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for IPV6_RECVERR], 
+  ac_cv_sys_ipv6_recverr, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+]], [[
+  int one = 1;
+  int s = 0;
+  setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+]])],[ac_cv_sys_ipv6_recverr=yes],[ac_cv_sys_ipv6_recverr=no])])
+if test "$ac_cv_sys_ipv6_recverr" = yes ; then
+	AC_DEFINE([HAVE_IPV6_RECVERR], 1,
+		[Define to 1 if you have IPV6_RECVERR in <netinet/in6.h>])
+fi
+])dnl
+
+dnl ======================================================================
+dnl @synopsis AC_C_VAR_FUNC
+dnl
+dnl This macro tests if the C compiler supports the C99 standard
+dnl __func__ indentifier.
+dnl
+dnl The new C99 standard for the C language stipulates that the
+dnl identifier __func__ shall be implictly declared by the compiler
+dnl as if, immediately following the opening brace of each function
+dnl definition, the declaration
+dnl
+dnl     static const char __func__[] = "function-name";
+dnl
+dnl appeared, where function-name is the name of the function where
+dnl the __func__ identifier is used.
+dnl
+dnl @author Christopher Currie <christopher at currie.com>
+dnl @author Pekka Pessi <Pekka.Pessi at nokia.com>
+dnl ======================================================================
+
+AC_DEFUN([AC_C_VAR_FUNC],
+[AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes __func__, ac_cv_c_var_func,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[char *s = __func__;
+]])],[ac_cv_c_var_func=yes],[ac_cv_c_var_func=no]))
+if test $ac_cv_c_var_func = "yes"; then
+AC_DEFINE([HAVE_FUNC], 1, [Define to 1 if the C compiler supports __func__]) 
+fi
+])dnl
+
+AC_DEFUN([AC_C_MACRO_FUNCTION],
+[AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes __FUNCTION__, ac_cv_c_macro_function,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+char *s = __FUNCTION__;
+]])],[ac_cv_c_macro_function=yes],[ac_cv_c_macro_function=no]))
+if test $ac_cv_c_macro_function = "yes"; then
+AC_DEFINE([HAVE_FUNCTION], 1, [Define to 1 if the C compiler supports __FUNCTION__]) 
+fi
+])dnl
+
+dnl ======================================================================
+dnl AC_C_INLINE_DEFINE
+dnl ======================================================================
+AC_DEFUN([AC_C_INLINE_DEFINE], [
+AC_C_INLINE
+case "$ac_cv_c_inline" in *inline* | yes) 
+	AC_DEFINE([HAVE_INLINE], 1, [Define to 1 if you have inlining compiler]) ;; 
+esac
+])
+
+dnl ======================================================================
+dnl AC_C_KEYWORD_STRUCT
+dnl ======================================================================
+AC_DEFUN([AC_C_KEYWORD_STRUCT], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes field names in struct initialization, ac_cv_c_keyword_struct,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+  struct { int foo; char *bar; } test = { foo: 1, bar: "bar" };
+  return 0;
+]])],[ac_cv_c_keyword_struct=yes],[ac_cv_c_keyword_struct=no]))
+if test $ac_cv_c_keyword_struct = "yes"; then
+AC_DEFINE([HAVE_STRUCT_KEYWORDS], 1, [
+Define to 1 if your CC supports C99 struct initialization]) 
+fi
+])
+
+dnl ======================================================================
+dnl autoconf-version
+dnl should be removed after automake conversion is finished
+dnl ======================================================================
+
+AC_DEFUN([AC_AUTOCONF_PARAM], 
+[
+if autoconf --version | fgrep '2.13' > /dev/null ; then
+    AUTOCONF_PARAM="-l"
+else
+    AUTOCONF_PARAM="-I"
+fi
+AC_SUBST(AUTOCONF_PARAM)
+])
+
+dnl ======================================================================
+dnl SAC_ENABLE_NDEBUG
+dnl ======================================================================
+AC_DEFUN([SAC_ENABLE_NDEBUG],[
+AC_REQUIRE([SAC_TOOL_CC])
+AC_ARG_ENABLE(ndebug,
+[  --enable-ndebug             compile with NDEBUG (disabled)],
+ , enable_ndebug=no)
+AM_CONDITIONAL(NDEBUG, test x$enable_ndebug = yes)
+SOFIA_CFLAGS="$SOFIA_CFLAGS -DNDEBUG"
+])
+
+dnl ======================================================================
+dnl SAC_ENABLE_EXPENSIVE_CHECKS
+dnl ======================================================================
+AC_DEFUN([SAC_ENABLE_EXPENSIVE_CHECKS],[
+AC_ARG_ENABLE(expensive-checks,
+[  --enable-expensive-checks   run also expensive checks (disabled)],
+ , enable_expensive_checks=no)
+if test $enable_expensive_checks != no; then
+AC_SUBST([TESTS_ENVIRONMENT], [EXPENSIVE_CHECKS=1])
+fi
+AM_CONDITIONAL(EXPENSIVE_CHECKS, test x$enable_expensive_checks != no)
+])
+
+
+dnl ======================================================================
+dnl Check if we are using Windows with MinGW compiler
+dnl ======================================================================
+
+AC_DEFUN([AC_CHECK_COMPILATION_ENVIRONMENT], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for compilation environment], 
+  ac_cc_environment, [
+machine=`$CC -dumpmachine`
+if test "$machine" = mingw32 ; then
+  ac_cc_environment=$machine
+fi
+])
+
+if test "$ac_cc_environment" = mingw32 ; then
+CFLAGS="$CFLAGS -I\$(top_srcdir)/win32/pthread -DWINVER=0x0501 \
+	-D_WIN32_WINNT=0x0501 -DIN_LIBSOFIA_SIP_UA -DIN_LIBSOFIA_SRES \
+	-mms-bitfields \
+	-pipe -mno-cygwin -mwindows -mconsole -Wall -g -O0"
+LDFLAGS="$LDFLAGS -Wl,--enable-auto-image-base"
+LIBS="-L\$(top_srcdir)/win32/pthread -lpthreadVC2 -lws2_32 \
+	-lwsock32"
+MINGW_ENVIRONMENT=1
+AC_SUBST(MINGW_ENVIRONMENT)
+AC_DEFINE([HAVE_MINGW], [1], [Define to 1 if you are compiling in MinGW environment])
+AC_DEFINE([HAVE_WIN32], [1], [Define to 1 if you have WIN32])
+fi
+AM_CONDITIONAL([HAVE_MINGW32], [test "x$ac_cc_environment" != x])
+])dnl
+
+
+dnl ======================================================================
+dnl Find long long (at least 64 bits)
+dnl ======================================================================
+
+AC_DEFUN([AC_TYPE_LONGLONG],[dnl
+AC_CHECK_TYPE([long long],[dnl
+AC_DEFINE([longlong], [long long], [Define to a at least 64-bit int type])dnl
+ifelse([$1], ,:, [$1])],[ifelse([$2], ,:, [$2])])])
+
+dnl ======================================================================
+dnl Check for /dev/urandom
+dnl ======================================================================
+
+AC_DEFUN([AC_DEV_URANDOM],[
+AC_CACHE_CHECK([/dev/urandom], [ac_cv_dev_urandom],
+  [ac_cv_dev_urandom=no
+   if test -r /dev/urandom; then ac_cv_dev_urandom=yes; fi])
+if test $ac_cv_dev_urandom = yes; then
+  AC_DEFINE([HAVE_DEV_URANDOM], 1, 
+    [Define to 1 if you have /dev/urandom.])
+  AC_DEFINE([DEV_URANDOM], 1,
+    [Define to the random number source name.])
+fi
+])

Added: freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,36 @@
+dnl ======================================================================
+dnl SAC_OPENSSL
+dnl ======================================================================
+AC_DEFUN([SAC_OPENSSL], [
+
+AC_ARG_WITH(openssl,
+[  --with-openssl          use OpenSSL (enabled)],, with_openssl=yes)
+
+dnl SOSXXX:SAC_ASSERT_DEF([openssl libraries])
+
+if test "$with_openssl" != no  ;then
+  AC_CHECK_HEADERS(openssl/tls1.h, [
+
+    HAVE_OPENSSL=1 HAVE_TLS=1
+
+    AC_CHECK_LIB(crypto, BIO_new,, 
+    	HAVE_OPENSSL=0
+    	AC_MSG_WARN(OpenSSL crypto library was not found))
+
+    AC_CHECK_LIB(ssl, TLSv1_method,, 
+    	HAVE_TLS=0
+    	AC_MSG_WARN(OpenSSL protocol library was not found))
+
+    if test x$HAVE_OPENSSL = x1; then
+      AC_DEFINE([HAVE_OPENSSL], 1, [Define to 1 if you have OpenSSL])
+    fi
+
+    if test x$HAVE_TLS = x1; then
+      AC_DEFINE([HAVE_TLS], 1, [Define to 1 if you have TLS])
+    fi
+  ],
+  AC_MSG_WARN(OpenSSL include files were not found))
+fi
+
+AM_CONDITIONAL(HAVE_TLS, test x$HAVE_TLS = x1)
+])

Added: freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,36 @@
+dnl ======================================================================
+dnl su module
+dnl ======================================================================
+
+dnl The macro SAC_SOFIA_SU is in a separate file, sofia-su2.m4, because
+dnl SAC_SOFIA_SU creates a separate configuration file <su/su_configure.h>. 
+dnl If SAC_SOFIA_SU is included to a aclocal.m4 of another package,
+dnl autoheader returns a spurious error and automake complains about missing
+dnl su/su_configure.h.
+
+dnl ======================================================================
+dnl SAC_WITH_RT - check for POSIX realtime library
+dnl ======================================================================
+AC_DEFUN([SAC_WITH_RT],[
+AC_ARG_WITH(rt,  
+[  --with-rt               use POSIX realtime library (used by default)])
+])
+
+dnl ======================================================================
+dnl SAC_CHECK_SU_LIBS - check for libraries used by su
+dnl ======================================================================
+AC_DEFUN([SAC_CHECK_SU_LIBS], [
+AC_REQUIRE([SAC_WITH_RT])
+AC_CHECK_LIB(pthread, pthread_create)
+AC_CHECK_LIB(socket, socketpair,,,-lnsl)
+if test "${with_rt}" != no; then
+	AC_SEARCH_LIBS(clock_gettime, rt)
+fi
+])dnl
+
+dnl ======================================================================
+dnl SAC_SU - main macro for checking su dependencies
+dnl ======================================================================
+AC_DEFUN([SAC_SU], [
+AC_REQUIRE([SAC_CHECK_SU_LIBS])
+])

Added: freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,550 @@
+dnl ======================================================================
+dnl su module
+dnl ======================================================================
+
+AC_DEFUN([SAC_SOFIA_SU], [
+# Beginning of SAC_SOFIA_SU
+
+AC_REQUIRE([SAC_WITH_RT])
+
+# ======================================================================
+# Check for features used by su
+
+dnl Define compilation options for su_configure.h
+
+case "$target" in 
+*-*-solaris?.* )
+  SAC_SU_DEFINE(__EXTENSIONS__, 1, [Define to 1 in Solaris in order to get POSIX extensions.])
+;;
+esac
+
+# Check includes used by su includes
+AC_CHECK_HEADER(sys/types.h, 
+	SAC_SU_DEFINE([SU_HAVE_SYS_TYPES], 1, 
+		     [Define to 1 if Sofia uses sys/types.h]))
+
+ax_inttypes=false
+AC_CHECK_HEADER(stdint.h, [
+	ax_inttypes=true
+	SAC_SU_DEFINE([SU_HAVE_STDINT], 1, 
+		     [Define to 1 if Sofia uses stdint.h])])
+AC_CHECK_HEADER(inttypes.h,[
+	ax_inttypes=true
+	SAC_SU_DEFINE([SU_HAVE_INTTYPES], 1, 
+		     [Define to 1 if Sofia uses inttypes.h])])
+
+if $ax_inttypes; then : ; else 
+	AC_MSG_ERROR("No <stdint.h> or <inttypes.h> found.")
+fi
+
+if test "x$MINGW_ENVIRONMENT" != x1 ; then
+  AC_CHECK_HEADER(pthread.h, 
+        HAVE_PTHREADS=1;
+	SAC_SU_DEFINE([SU_HAVE_PTHREADS], 1, [Sofia SU uses pthreads]))
+else
+  HAVE_PTHREADS=1;
+  SAC_SU_DEFINE([SU_HAVE_PTHREADS], 1, [Sofia SU uses pthreads])
+fi
+
+dnl ===========================================================================
+dnl Checks for typedefs, headers, structures, and compiler characteristics.
+dnl ===========================================================================
+
+AC_REQUIRE([AC_C_CONST])
+AC_REQUIRE([AC_HEADER_TIME])
+AC_REQUIRE([AC_TYPE_SIZE_T])
+AC_REQUIRE([AC_C_VAR_FUNC])
+AC_REQUIRE([AC_C_MACRO_FUNCTION])
+
+AC_REQUIRE([AC_C_INLINE])
+
+case "$ac_cv_c_inline" in
+  yes) SAC_SU_DEFINE(su_inline, static inline, [
+		Define to declarator for static inline functions.
+	])dnl
+       SAC_SU_DEFINE(SU_INLINE, inline, [
+		Define to declarator for inline functions.
+	])dnl
+       SAC_SU_DEFINE(SU_HAVE_INLINE, 1, [
+		Define to 1 if you have inline functions.
+	])dnl
+  ;;
+  no)  SAC_SU_DEFINE(su_inline, static)dnl
+       SAC_SU_DEFINE(SU_INLINE)dnl
+       SAC_SU_DEFINE(SU_HAVE_INLINE)dnl
+  ;;
+  *)   SAC_SU_DEFINE_UNQUOTED(su_inline, static $ac_cv_c_inline)dnl
+       SAC_SU_DEFINE_UNQUOTED(SU_INLINE, $ac_cv_c_inline)dnl
+       SAC_SU_DEFINE(SU_HAVE_INLINE, 1)dnl
+  ;;
+esac
+
+AC_ARG_ENABLE(size-compat,
+[  --disable-size-compat            use compatibility size_t types (enabled)],
+ , enable_size_compat=yes)
+
+if test X$enable_size_compat != Xyes; then
+       SAC_SU_DEFINE(SOFIA_ISIZE_T, size_t)dnl
+       SAC_SU_DEFINE(ISIZE_MAX, SIZE_MAX)dnl
+       SAC_SU_DEFINE(SOFIA_ISSIZE_T, ssize_t)dnl
+       SAC_SU_DEFINE(ISSIZE_MAX, SSIZE_MAX)dnl
+       SAC_SU_DEFINE(SOFIA_USIZE_T, size_t)dnl
+       SAC_SU_DEFINE(USIZE_MAX, SIZE_MAX)dnl
+else
+       SAC_SU_DEFINE(SOFIA_ISIZE_T, int)dnl
+       SAC_SU_DEFINE(ISIZE_MAX, INT_MAX)dnl
+       SAC_SU_DEFINE(SOFIA_ISSIZE_T, int)dnl
+       SAC_SU_DEFINE(ISSIZE_MAX, INT_MAX)dnl
+       SAC_SU_DEFINE(SOFIA_USIZE_T, unsigned)dnl
+       SAC_SU_DEFINE(USIZE_MAX, UINT_MAX)dnl
+fi
+
+
+dnl ======================================================================
+dnl SAC_ENABLE_COREFOUNDATION
+dnl ======================================================================
+AC_ARG_ENABLE(corefoundation,
+[  --enable-corefoundation     compile with OSX COREFOUNDATION (disabled)],
+ , enable_corefoundation=no)
+AM_CONDITIONAL(COREFOUNDATION, test $enable_corefoundation = yes)
+
+if test $enable_corefoundation = yes ; then
+   SAC_SU_DEFINE([SU_HAVE_OSX_CF_API], 1, [
+Define as 1 if you have OSX CoreFoundation interface])
+   LIBS="-framework CoreFoundation -framework SystemConfiguration $LIBS"
+fi
+
+
+### ======================================================================
+### Test if we have stack suitable for handling tags directly
+###
+
+test -z "$ac_cv_tagstack" && 
+case "$target" in 
+i?86-*-* ) ac_cv_tagstack=yes ;;
+esac
+
+AC_CACHE_CHECK([for stack suitable for tags],[ac_cv_tagstack],[
+ac_cv_tagstack=no
+
+AC_RUN_IFELSE([
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+  va_list ap;
+  tv i, *p = &l;
+
+  va_start(ap, h);
+
+  if (*p++ != l || *p++ != h) return 1;
+
+  for (i = l; i <= h; i++) {
+    if (*p++ != i)
+      return 1;
+  }
+
+  for (i = l; i <= h; i++) {
+    if (va_arg(ap, tv) != i)
+      return 1;
+  }
+
+  va_end(ap);
+
+  return 0;
+}
+
+int main(int avc, char **av)
+{
+  return test1((tv)1, (tv)10,
+	       (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+	       (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+],[ac_cv_tagstack=yes],[ac_cv_tagstack=no],[ac_cv_tagstack=no])])
+
+if test $ac_cv_tagstack = yes ; then
+SAC_SU_DEFINE([SU_HAVE_TAGSTACK], 1, [
+Define this as 1 if your compiler puts the variable argument list nicely in memory])
+fi
+
+dnl ======================================================================
+dnl Socket features
+
+AC_REQUIRE([AC_SYS_SA_LEN])
+if test "$ac_cv_sa_len" = yes ;then
+  SAC_SU_DEFINE([SU_HAVE_SOCKADDR_SA_LEN], 1, 
+	        [Define to 1 if you have sa_len in struct sockaddr])
+fi
+
+AC_REQUIRE([AC_STRUCT_SIN6])
+case $ac_cv_sin6 in 
+yes) SAC_SU_DEFINE(SU_HAVE_IN6, 1, [
+	Define to 1 if you have struct sockaddr_in6]) ;;
+ no) ;;
+  *) AC_MSG_ERROR([Inconsistent struct sockaddr_sin6 test]) ;;
+esac
+
+AC_CHECK_HEADERS([unistd.h sys/time.h])
+
+AC_CHECK_HEADERS([fcntl.h dirent.h])
+
+AC_CHECK_HEADERS([winsock2.h], [
+  AC_DEFINE([HAVE_WIN32], 1, [Define to 1 you have WIN32])
+  SAC_SU_DEFINE([SU_HAVE_WINSOCK], 1, [Define to 1 you have WinSock])
+  SAC_SU_DEFINE([SU_HAVE_WINSOCK2], 1, [Define to 1 you have WinSock2])
+  SAC_SU_DEFINE([SU_HAVE_SOCKADDR_STORAGE], 1, 
+      [Define to 1 if you have struct sockaddr_storage])
+  AC_DEFINE([HAVE_ADDRINFO], 1,
+      [Define to 1 if you have addrinfo structure.])
+  AC_DEFINE([HAVE_GETADDRINFO], 1,
+      [Define to 1 if you have addrinfo structure.])
+  AC_DEFINE([HAVE_FREEADDRINFO], 1,
+      [Define to 1 if you have addrinfo structure.])
+  SAC_SU_DEFINE([SU_HAVE_ADDRINFO], 1,
+      [Define to 1 if you have addrinfo structure.])
+  AC_CHECK_HEADERS([windef.h ws2tcpip.h])
+  AC_CHECK_HEADERS([iphlpapi.h], [
+    AC_DEFINE([HAVE_INTERFACE_INFO_EX], 1, [
+       Define to 1 if you have WIN32 INTERFACE_INFO_EX type.])
+    AC_DEFINE([HAVE_SIO_ADDRESS_LIST_QUERY], 1, [
+       Define to 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY.])
+  ], [], [#if HAVE_WINDEF_H
+#include <windef.h>
+#include <winbase.h>
+#endif
+  ])
+  AC_DEFINE([HAVE_FILETIME], 1, [
+     Define to 1 if you have WIN32 FILETIME type and 
+     GetSystemTimeAsFileTime().])
+],[
+dnl no winsock2
+SAC_SU_DEFINE([SU_HAVE_BSDSOCK], 1, [Define to 1 if you have BSD socket interface])
+AC_CHECK_HEADERS([sys/socket.h sys/ioctl.h sys/filio.h sys/sockio.h \
+		  sys/select.h])
+AC_CHECK_HEADERS([netinet/in.h arpa/inet.h netdb.h \
+                  net/if.h net/if_types.h ifaddr.h netpacket/packet.h],,,
+		[
+#include <sys/types.h>
+#include <sys/socket.h>])
+
+AC_CHECK_DECL([MSG_TRUNC],
+AC_DEFINE([HAVE_MSG_TRUNC],1,[Define to 1 if you have MSG_TRUNC flag]),,[
+#include <sys/types.h>
+#include <sys/socket.h>])
+
+AC_CACHE_CHECK([for struct addrinfo],
+[ac_cv_struct_addrinfo],[
+ac_cv_struct_addrinfo=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+  AC_EGREP_HEADER([struct.+addrinfo], [netdb.h], [
+  ac_cv_struct_addrinfo=yes])
+else
+  ac_cv_struct_addrinfo='sys/socket.h missing'
+fi])
+
+if test "$ac_cv_struct_addrinfo" = yes; then
+  SAC_SU_DEFINE([SU_HAVE_ADDRINFO], 1, 
+    [Define to 1 if you have struct addrinfo.])
+fi
+
+AC_CACHE_CHECK([for struct sockaddr_storage],
+[ac_cv_struct_sockaddr_storage],[
+ac_cv_struct_sockaddr_storage=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+  AC_EGREP_HEADER([struct.+sockaddr_storage], [sys/socket.h], [
+  ac_cv_struct_sockaddr_storage=yes])
+else
+  ac_cv_struct_sockaddr_storage='sys/socket.h missing'
+fi])
+if test "$ac_cv_struct_sockaddr_storage" = yes; then
+  SAC_SU_DEFINE(SU_HAVE_SOCKADDR_STORAGE, 1, 
+    [Define to 1 if you have struct sockaddr_storage])
+fi
+
+AC_CACHE_CHECK([for field ifr_index in struct ifreq],
+[ac_cv_struct_ifreq_ifr_index],[
+ac_cv_struct_ifreq_ifr_index=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>]], [[
+struct ifreq ifreq; int index; index = ifreq.ifr_index;
+]])],[ac_cv_struct_ifreq_ifr_index=yes],[])
+else
+  ac_cv_struct_ifreq_ifr_index='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+])
+if test "$ac_cv_struct_ifreq_ifr_index" = yes ; then
+  :
+  AC_DEFINE(HAVE_IFR_INDEX, 1, [Define to 1 if you have ifr_index in <net/if.h>])
+else
+AC_CACHE_CHECK([for field ifr_ifindex in struct ifreq],
+[ac_cv_struct_ifreq_ifr_ifindex],[
+ac_cv_struct_ifreq_ifr_ifindex=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>]], [[
+struct ifreq ifreq; int index; index = ifreq.ifr_ifindex;
+]])],[ac_cv_struct_ifreq_ifr_ifindex=yes],[])
+else
+  ac_cv_struct_ifreq_ifr_ifindex='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+])
+if test "$ac_cv_struct_ifreq_ifr_ifindex" = yes; then
+  :
+  AC_DEFINE(HAVE_IFR_IFINDEX, 1, [Define to 1 if you have ifr_ifindex in <net/if.h>])
+fi
+
+fi # ifr_index in struct ifreq
+
+dnl SIOGCIFCONF & struct ifconf
+AC_CACHE_CHECK([for struct ifconf],
+[ac_cv_struct_ifconf],[
+ac_cv_struct_ifconf=no
+if test "$ac_cv_header_net_if_h" = yes; then
+  AC_EGREP_HEADER(struct.+ifconf, net/if.h, ac_cv_struct_ifconf=yes)
+else
+  ac_cv_struct_ifconf='net/if.h missing'
+fi])
+if test "$ac_cv_struct_ifconf" = yes; then
+  AC_DEFINE(HAVE_IFCONF, 1, [Define to 1 if you have SIOCGIFCONF])
+fi
+
+AC_CACHE_CHECK([for ioctl SIOCGIFNUM],
+[ac_cv_ioctl_siocgifnum],[
+ac_cv_ioctl_siocgifnum=no
+if test "$ac_cv_header_sys_sockio_h" = yes; then
+AC_EGREP_CPP(yes, [
+#include <sys/sockio.h>
+#ifdef SIOCGIFNUM
+  yes
+#endif
+], [ac_cv_ioctl_siocgifnum=yes])
+else
+  ac_cv_ioctl_siocgifnum='sys/sockio.h missing'
+fi])
+if test "$ac_cv_ioctl_siocgifnum" = yes; then
+  HAVE_IFNUM=1
+  AC_DEFINE(HAVE_IFNUM, 1, [Define to 1 if you have SIOCGIFNUM ioctl])
+else
+  HAVE_IFNUM=0
+fi
+
+]) dnl AC_CHECK_HEADERS([winsock2.h ... ])
+
+
+# ===========================================================================
+# Checks for libraries
+# ===========================================================================
+
+SAC_CHECK_SU_LIBS
+
+# No GLib path explicitly defined, use pkg-config
+AC_ARG_WITH(glib,
+[  --with-glib=version     use GLib (default=2.0)], [
+case "$with_glib" in 
+yes | "" ) with_glib=2.0 ;;
+esac
+], [with_glib=2.0])
+
+AC_ARG_WITH(glib-dir,
+[  --with-glib-dir=PREFIX  explicitly define GLib path],, 
+ with_glib_dir="pkg-config")
+
+if test "$with_glib" = no || test "$with_glib_dir" = "no" ; then
+
+  : # No glib
+
+elif test "$with_glib_dir" = "pkg-config" ; then 
+
+  PKG_CHECK_MODULES(GLIB, glib-$with_glib, [HAVE_GLIB=yes], [HAVE_GLIB=no])
+
+else # GLib path is explicitly defined 
+
+  gprefix=$with_glib_dir
+  GLIB_VERSION="$with_glib"
+  GLIBXXX=glib-$with_glib
+
+  if test "$gprefix" = "yes" ; then 
+    for gprefix in /usr /usr/local /opt/$GLIBXXX
+    do
+  	test -d $gprefix/include/$GLIBXXX && break
+    done
+  fi
+
+  if ! test -d $gprefix/include/$GLIBXXX ; then
+    AC_MSG_ERROR("No $GLIBXXX in --with-glib=$with_glib_dir")
+  else
+    exec_gprefix=${gprefix}
+    glibdir=${exec_gprefix}/lib
+    gincludedir=${gprefix}/include
+
+    # glib_genmarshal=glib-genmarshal
+    # glib_mkenums=glib-mkenums
+
+    HAVE_GLIB=yes
+    
+    if test "x$MINGW_ENVIRONMENT" = x1 ; then
+      GLIB_LIBS="${glibdir}/lib$GLIBXXX.dll.a ${glibdir}/libintl.a ${glibdir}/libiconv.a"
+    else
+      GLIB_LIBS="-L${glibdir} -l$GLIBXXX -lintl -liconv"
+    fi
+    GLIB_CFLAGS="-I${gincludedir}/$GLIBXXX -I${glibdir}/$GLIBXXX/include"
+  fi
+
+fi # GLib path is explicitly defined 
+
+if test "x$HAVE_GLIB" = xyes ; then
+  SAC_COMMA_APPEND([SOFIA_GLIB_PKG_REQUIRES],[glib-2.0])
+fi
+
+AM_CONDITIONAL([HAVE_GLIB], [test "x$HAVE_GLIB" = xyes])
+AC_SUBST([GLIB_LIBS])
+AC_SUBST([GLIB_CFLAGS])
+AC_SUBST([GLIB_VERSION])
+AC_SUBST([SOFIA_GLIB_PKG_REQUIRES])
+
+# ===========================================================================
+# Checks for library functions.
+# ===========================================================================
+
+AC_SEARCH_LIBS(socket, xnet socket)
+AC_SEARCH_LIBS(inet_ntop, socket nsl)
+dnl AC_SEARCH_LIBS(inet_pton, socket nsl)
+AC_SEARCH_LIBS(getipnodebyname, xnet socket nsl)
+AC_SEARCH_LIBS(gethostbyname, xnet nsl)
+AC_SEARCH_LIBS(getaddrinfo, xnet socket nsl)
+
+AC_CHECK_FUNCS([gettimeofday strerror random initstate tcsetattr flock alarm \
+                socketpair gethostname gethostbyname getipnodebyname \
+                poll epoll_create select if_nameindex \
+	        getaddrinfo getnameinfo freeaddrinfo gai_strerror getifaddrs \
+                getline getdelim getpass])
+# getline getdelim getpass are _GNU_SOURCE stuff
+
+if test $ac_cv_func_poll = yes ; then
+  SAC_SU_DEFINE([SU_HAVE_POLL], 1, [Define to 1 if you have poll().])
+fi
+
+if test $ac_cv_func_epoll_create = yes ; then
+  AC_DEFINE([HAVE_EPOLL], 1, [Define to 1 if you have epoll interface.])
+fi
+
+if test $ac_cv_func_if_nameindex = yes ; then
+  SAC_SU_DEFINE([SU_HAVE_IF_NAMEINDEX], 1, 
+    [Define to 1 if you have if_nameindex().])
+fi
+
+AC_REQUIRE([SAC_WITH_RT])
+if test "${with_rt}" != no; then
+    AC_CHECK_FUNCS([clock_gettime clock_getcpuclockid])
+fi
+
+SAC_REPLACE_FUNCS([memmem memccpy memspn memcspn strcasestr strtoull \
+		   inet_ntop inet_pton])
+
+
+# ===========================================================================
+# Check pthread_rwlock_unlock()
+# ===========================================================================
+
+AC_DEFUN([AC_DEFINE_HAVE_PTHREAD_RWLOCK],[dnl
+AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1,[
+Define to 1 if you have working pthread_rwlock_t implementation.
+
+   A  thread  may hold multiple concurrent read locks on rwlock - that is,
+   successfully call the pthread_rwlock_rdlock() function  n  times.  If
+   so,  the  application  shall  ensure that the thread performs matching
+   unlocks - that is, it  calls  the  pthread_rwlock_unlock()  function  n
+   times.
+])])
+
+if test x$HAVE_PTHREADS = x1 ; then
+
+AC_RUN_IFELSE([
+#define _XOPEN_SOURCE (500)
+
+#include <pthread.h>
+
+pthread_rwlock_t rw;
+
+int main()
+{
+  pthread_rwlock_init(&rw, NULL);
+  pthread_rwlock_rdlock(&rw);
+  pthread_rwlock_rdlock(&rw);
+  pthread_rwlock_unlock(&rw);
+  /* pthread_rwlock_trywrlock() should fail (not return 0) */
+  return pthread_rwlock_trywrlock(&rw) != 0 ? 0  : 1;
+}
+],[AC_DEFINE_HAVE_PTHREAD_RWLOCK],[
+AC_MSG_WARN([Recursive pthread_rwlock_rdlock() does not work!!! ])
+],[AC_DEFINE_HAVE_PTHREAD_RWLOCK])
+
+fi
+
+# ===========================================================================
+# Check IPv6 addresss configuration
+# ===========================================================================
+case "$target" in
+ *-*-linux*) AC_DEFINE([HAVE_PROC_NET_IF_INET6], 1, 
+	[Define to 1 if you have /proc/net/if_inet6 control file]) ;;
+esac
+
+AC_CONFIG_HEADERS([libsofia-sip-ua/su/sofia-sip/su_configure.h])
+
+# End of SAC_SOFIA_SU
+])
+
+dnl
+dnl Append a value $2 to a variable, separating values with comma
+dnl
+AC_DEFUN([SAC_COMMA_APPEND],[$1="`test -n "$$1" && echo "$$1, "`$2"])
+
+# SAC_SU_DEFINE(VARIABLE, [VALUE], [DESCRIPTION])
+# -------------------------------------------
+# Set VARIABLE to VALUE, verbatim, or 1.  Remember the value
+# and if VARIABLE is affected the same VALUE, do nothing, else
+# die.  The third argument is used by autoheader.
+
+m4_define([SAC_SU_DEFINE],[
+cat >>confdefs.h <<\_AXEOF
+[@%:@define] $1 m4_if($#, 2, [$2], $#, 3, [$2], 1)
+_AXEOF
+])
+
+# SAC_SU_DEFINE_UNQUOTED(VARIABLE, [VALUE], [DESCRIPTION])
+# ----------------------------------------------------
+# Similar, but perform shell substitutions $ ` \ once on VALUE.
+m4_define([SAC_SU_DEFINE_UNQUOTED],[
+cat >>confdefs.h <<_ACEOF
+[@%:@define] $1 m4_if($#, 2, [$2], $#, 3, [$2], 1)
+_ACEOF
+])
+
+AC_DEFUN([SAC_REPLACE_FUNCS],[dnl
+AC_CHECK_FUNCS([$1],ifelse([$2], , :,[$2]),[dnl
+case "$REPLACE_LIBADD" in
+    "$ac_func.lo"   | \
+  *" $ac_func.lo"   | \
+    "$ac_func.lo "* | \
+  *" $ac_func.lo "* ) ;;
+  *) REPLACE_LIBADD="$REPLACE_LIBADD $ac_func.lo" ;;
+esac])
+AC_SUBST([REPLACE_LIBADD])
+ifelse([$3], , :, [$3])
+])

Added: freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+dnl ======================================================================
+dnl SAC_TPORT - perform checks for tport
+dnl ======================================================================
+AC_DEFUN([SAC_TPORT], [
+
+AC_ARG_WITH(sigcomp,
+[  --with-sigcomp=dir      use Sofia SigComp package (not used by default)],,
+	with_sigcomp=no)
+
+if test -n "${with_sigcomp}" && test "${with_sigcomp}" != no ; then
+	if test "${with_sigcomp}" != yes ; then
+		CPPFLAGS="-I${with_sigcomp}/include $CPPFLAGS"
+		LIBS="-L${with_sigcomp}/lib -lsigcomp $LIBS"
+	else
+		LIBS="-lsigcomp $LIBS"
+	fi
+
+	AC_CHECK_HEADERS(sigcomp.h,,AC_MSG_ERROR([cannot find Sofia SigComp includes]))
+
+	AC_CHECK_FUNC(sigcomp_library_2_5,
+            [AC_DEFINE([HAVE_SIGCOMP], 1, [Define to 1 if you have Sofia sigcomp >= 2.5])
+             AC_DEFINE([HAVE_SOFIA_SIGCOMP], 1, [Define to 1 if you have Sofia sigcomp >= 2.5])], 
+             AC_MSG_ERROR(Sofia SigComp API >= 2.5 was not found))
+fi
+
+# Check for features used by tport.
+AC_SYS_IP_RECVERR
+AC_SYS_IPV6_RECVERR
+
+AC_CHECK_HEADERS(netinet/tcp.h netinet/sctp.h)
+
+AC_ARG_WITH(sctp,
+[  --enable-sctp          use LK-SCTP (not used by default)],,
+ enable_sigcomp=no)
+
+if test x$enable_sctp = xyes; then
+AC_DEFINE(HAVE_SCTP, 1, [Define to 1 if you have SCTP])
+fi
+])

Added: freeswitch/trunk/libs/sofia-sip/missing
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/missing	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,353 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2004-09-07.08
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004
+#   Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
+
+# 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, 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake at gnu.org>."
+    exit 0
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit 0
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case "$1" in
+  lex|yacc)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  tar)
+    if test -n "$run"; then
+       echo 1>&2 "ERROR: \`tar' requires --run"
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       exit 1
+    fi
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  autom4te)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo "#! /bin/sh"
+	echo "# Created by GNU Automake missing as a replacement of"
+	echo "#  $ $@"
+	echo "exit 0"
+	chmod +x $file
+	exit 1
+    fi
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f y.tab.h ]; then
+	echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+	 you modified a dependency of a manual page.  You may need the
+	 \`Help2man' package in order for those modifications to take
+	 effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+	file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+    fi
+    if [ -f "$file" ]; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo ".ab help2man is required to generate this page"
+	exit 1
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  tar)
+    shift
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+	case "$firstarg" in
+	*o*)
+	    firstarg=`echo "$firstarg" | sed s/o//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+	case "$firstarg" in
+	*h*)
+	    firstarg=`echo "$firstarg" | sed s/h//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:

Added: freeswitch/trunk/libs/sofia-sip/packages/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,26 @@
+2005-11-15  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* sofia-sip.spec.in: Removed the --includedir parameter. 
+	The public headers are now installed under 
+	includedir/sofia-sip-MAJOR.MINOR/
+
+2005-10-06  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added debian example directory from M Mela.
+
+    A ./packages/debian/
+    A ./packages/debian/README.Debian
+    A ./packages/debian/changelog
+    A ./packages/debian/compat
+    A ./packages/debian/control
+    A ./packages/debian/copyright
+    A ./packages/debian/docs
+    A ./packages/debian/files
+    A ./packages/debian/postinst.ex
+    A ./packages/debian/postrm.ex
+    A ./packages/debian/preinst.ex
+    A ./packages/debian/prerm.ex
+    A ./packages/debian/rules
+    A ./packages/debian/sofia-sip-default.ex
+    A ./packages/debian/sofia-sip.postinst.debhelper
+    A ./packages/debian/sofia-sip.postrm.debhelper

Added: freeswitch/trunk/libs/sofia-sip/packages/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+#
+# Makefile.am for sofia-sip/packages
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# Install pkg-config file here
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sofia-sip-ua.pc
+
+if HAVE_GLIB
+# We should probably have something here telling 
+# if we have gobject support or not
+pkgconfig_DATA += sofia-sip-ua-glib.pc
+endif
+
+EXTRA_DIST = sofia-sip-${PACKAGE_VERSION}.spec sofia-sip.spec.in
+EXTRA_DIST += sofia-sip-ua.pc.in sofia-sip-ua-glib.pc.in
+
+DISTCLEANFILES = sofia-sip-*.spec sofia-sip.spec

Added: freeswitch/trunk/libs/sofia-sip/packages/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,424 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/packages
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+
+# We should probably have something here telling 
+# if we have gobject support or not
+ at HAVE_GLIB_TRUE@am__append_1 = sofia-sip-ua-glib.pc
+subdir = packages
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/sofia-sip-ua-glib.pc.in $(srcdir)/sofia-sip-ua.pc.in \
+	$(srcdir)/sofia-sip.spec.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES = sofia-sip-ua.pc sofia-sip-ua-glib.pc \
+	sofia-sip-${PACKAGE_VERSION}.spec
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
+pkgconfigDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(pkgconfig_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+
+# Install pkg-config file here
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sofia-sip-ua.pc $(am__append_1)
+EXTRA_DIST = sofia-sip-${PACKAGE_VERSION}.spec sofia-sip.spec.in \
+	sofia-sip-ua.pc.in sofia-sip-ua-glib.pc.in
+DISTCLEANFILES = sofia-sip-*.spec sofia-sip.spec
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  packages/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  packages/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+sofia-sip-ua.pc: $(top_builddir)/config.status $(srcdir)/sofia-sip-ua.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-sip-ua-glib.pc: $(top_builddir)/config.status $(srcdir)/sofia-sip-ua-glib.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-sip-${PACKAGE_VERSION}.spec: $(top_builddir)/config.status $(srcdir)/sofia-sip.spec.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)"
+	@list='$(pkgconfig_DATA)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+	  $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+	done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+	for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-pkgconfigDATA
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	distclean distclean-generic distclean-libtool distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man install-pkgconfigDATA \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	uninstall uninstall-am uninstall-info-am \
+	uninstall-pkgconfigDATA
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+libexecdir=@libexecdir@
+includedir=@includedir@
+include_sofiadir=@include_sofiadir@
+gobject=@HAVE_GOBJECT@
+
+Name: sofia-sip-ua-glib
+Description: Sofia-SIP library bindings for glib
+Version: @PACKAGE_VERSION@
+Requires: sofia-sip-ua, @SOFIA_GLIB_PKG_REQUIRES@
+Libs: -L${libdir} -lsofia-sip-ua-glib
+Cflags: -I at include_sofiadir@

Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+libexecdir=@libexecdir@
+includedir=@includedir@
+include_sofiadir=@include_sofiadir@
+sofiaawkdir=@datadir@/@PACKAGE@
+
+Name: sofia-sip-ua
+Description: Sofia-SIP - a RFC3261 compliant SIP User-Agent library
+Version: @VERSION@
+Libs: -L${libdir} -lsofia-sip-ua
+Libs.private: @LIBS@
+Cflags: -I at include_sofiadir@
+

Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,247 @@
+# Sofia SIP UA Library
+
+Summary: Sofia SIP User-Agent library 
+Name: sofia-sip
+Version: @VERSION@
+Release: 1%{?dist}
+License: LGPL
+Group: System Environment/Libraries
+URL: http://sf.net/projects/sofia-sip
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+BuildRequires: pkgconfig
+
+%{!?bcond_with:%define bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}}}
+%{!?bcond_without:%define bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}}
+
+# Options: 
+%bcond_with doxygen	- Generate documents using doxygen and dot
+%bcond_with check	- Run tests
+%bcond_with openssl	- Always use OpenSSL (TLS)
+%bcond_with glib	- Always use glib-2.0 (>= 2.2)
+%bcond_with sctp	- Include SCTP transport
+
+%define have_doxygen %{?_with_doxygen:1}%{!?_with_doxygen:0}
+%define have_openssl %(%{?!_with_openssl:pkg-config 'openssl >= 0.9.7'&&}echo 1||echo 0)
+%define have_glib %(%{?!_with_glib:pkg-config 'glib-2.0 >= 2.2'&&}echo 1||echo 0)
+
+%if %{have_doxygen}
+BuildRequires: doxygen >= 1.3, graphviz
+%endif
+%if %{have_openssl}
+BuildRequires: openssl-devel >= 0.9.7
+%endif
+%if %{have_glib}
+BuildRequires: glib2-devel >= 2.2
+%endif
+
+%description
+Sofia SIP is a RFC-3261-compliant library for SIP user agents and other
+network elements.
+
+%prep
+%setup -q
+
+%build
+options="--disable-dependency-tracking"
+options="$options --with-pic --enable-shared --disable-static"
+%if !%{have_glib}
+options="$options --without-glib"
+%endif
+%if %{with sctp}
+options="$options --enable-sctp"
+%endif
+
+%configure $options
+
+make %{_smp_mflags}
+%if %{have_doxygen}
+make doxygen
+%endif
+
+# XXX comment next line to build with non-check aware rpmbuild.
+%check
+%if %{with check}
+make check
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+# Remove extra files
+find $RPM_BUILD_ROOT -type f -name *.la -print0 | xargs -0 rm
+
+%if %{have_doxygen}
+# Manually install development docs into manual
+cp -p -r libsofia-sip-ua/docs/html manual
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/libsofia-sip-ua.so.*
+%doc AUTHORS COPYING COPYRIGHTS README
+
+%if %{have_glib}
+# note: soname in pkgname allows install of multiple library versions
+# The glib interface is still a bit unstable
+%package	glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+Summary:	GLIB bindings for Sofia-SIP 
+Group:		System Environment/Libraries
+Requires:	sofia-sip
+Obsoletes:	sofia-sip-glib < %{version}-%{release}
+Provides:	sofia-sip-glib = %{version}-%{release}
+
+%description	glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+GLib interface to Sofia SIP User Agent library.
+
+%files 		glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+%defattr(-,root,root,-)
+%{_libdir}/libsofia-sip-ua-glib.so.*
+%doc AUTHORS COPYING COPYRIGHTS README libsofia-sip-ua-glib/ChangeLog
+
+%post glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ -p /sbin/ldconfig
+%postun glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ -p /sbin/ldconfig
+
+%endif
+
+%package	devel
+Summary:	Sofia-SIP Development Package
+Group:		Development/Libraries
+Requires:	sofia-sip = %{version}-%{release}
+Obsoletes:	sofia-devel < %{version}-%{release}
+Provides:	sofia-devel = %{version}-%{release}
+
+Requires:	pkgconfig
+
+%description	devel
+Development package for Sofia SIP UA library. This package includes 
+static libraries and include files.
+
+%if %{without doxygen}
+The reference documentation for Sofia SIP UA library is available at 
+<http://sofia-sip.sourceforge.net/development.html>
+%endif
+
+%files 		devel
+%defattr(-,root,root,-)
+%dir %{_includedir}/sofia-sip*
+%dir %{_includedir}/sofia-sip*/sofia-sip
+%{_includedir}/sofia-sip*/sofia-sip/*.h
+%{_includedir}/sofia-sip*/sofia-sip/*.h.in
+%dir %{_includedir}/sofia-sip*/sofia-resolv
+%{_includedir}/sofia-sip*/sofia-resolv/*.h
+%dir %{_datadir}/sofia-sip
+%{_datadir}/sofia-sip/tag_dll.awk
+%{_datadir}/sofia-sip/msg_parser.awk
+%{_libdir}/libsofia-sip-ua.so
+%{_libdir}/pkgconfig/sofia-sip-ua.pc
+%doc TODO README.developers
+
+%if %{have_glib}
+# note: no soname here as no multiple glib-devel packages can co-exist in peace
+%package	glib-devel
+Summary:	GLIB bindings for Sofia SIP development files
+Group:			Development/Libraries
+Requires:	sofia-sip-glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ = %{version}-%{release}
+Requires:	sofia-sip-devel >= 1.12
+BuildRequires:	glib2-devel >= 2.2
+
+%description	glib-devel
+Development package for Sofia SIP UA Glib library. This package includes
+static libraries and include files for developing glib programs using Sofia
+SIP.
+
+%files 		glib-devel
+%defattr(-,root,root,-)
+%{_includedir}/sofia-sip*/sofia-sip/su_source.h
+%{_libdir}/libsofia-sip-ua-glib.so
+%{_libdir}/pkgconfig/sofia-sip-ua-glib.pc
+%endif
+
+%package	docs
+Summary:	Sofia-SIP Development Manual Package
+Group:		Documentation
+%description	docs
+HTML reference documentation for Sofia SIP UA library.
+
+%if %{have_doxygen}
+%files docs
+%defattr(-,root,root,-)
+%doc manual
+%endif
+
+%package	utils
+Summary:	Sofia-SIP Command Line Utilities
+Group:		Applications/Internet
+Requires:	sofia-sip = %{version}-%{release}
+Obsoletes:	sofia-utils < %{version}-%{release}
+Provides:	sofia-utils = %{version}-%{release}
+%description	utils
+Command line utilities for Sofia SIP UA library.
+
+%files utils
+%defattr(-,root,root,-)
+%{_bindir}/localinfo
+%{_bindir}/addrinfo
+%{_bindir}/sip-options
+%{_bindir}/sip-date
+%{_bindir}/sip-dig
+%{_bindir}/stunc
+%{_mandir}/man?/*
+
+%changelog
+* Thu Dec  7 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4-1
+- Silenced all rpmlint warnings on FC6.
+
+* Wed Dec  6 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4-0
+- Fixing optional values on Fedora. rpmlinted. No doxygen docs.
+
+* Tue Dec  5 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4
+- Bumped version. rpmlinted.
+
+* Tue Dec  5 2006 Kai Vehmanen <first.lastname at nokia.com>
+- The 'nua-glib' module, and the related dependency to gobject, has been 
+  removed from the sofia-sip package
+
+* Fri Oct  6 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.3
+- Autodetecting openssl, glib and gobject support with pkg-config
+  (use --with openssl --with glib and --with gobject to force them)
+
+* Mon Sep 18 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Removed *.m4 files from the distribution package.
+
+* Fri Aug 11 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Modified the install location of the awk scripts.
+
+* Thu Jun 15 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Added library soname to sofia-sip-glib package name.
+- Modified dependencies - the glib subpackages do not depend
+  on a specific version of sofia-sip anymore.
+
+* Wed Mar 08 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Added libsofia-sip-ua-glib to the package.
+
+* Tue Nov 15 2005 Kai Vehmanen <first.lastname at nokia.com>
+- Removed the --includedir parameter. The public headers are
+  now installed under includedir/sofia-sip-MAJOR.MINOR/
+
+* Thu Oct 20 2005 Pekka Pessi <first.lastname at nokia.com>
+- Using %%{_lib} instead of lib
+
+* Thu Oct  6 2005 Pekka Pessi <first.lastname at nokia.com>
+- Added sub-package utils
+
+* Thu Oct  6 2005 Pekka Pessi <first.lastname at nokia.com> - 1.11.0
+- Added %%{?dist} to release
+
+* Sat Jul 23 2005 Pekka Pessi <first.lastname at nokia.com> - 1.10.1
+- Initial build.

Added: freeswitch/trunk/libs/sofia-sip/scripts/coverage
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/coverage	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# Calculate coverage of source files
+#
+
+gcovflags=-n
+
+usage ()
+{
+    cat <<EOF
+usage: coverage [OPTIONS] [output-files]
+    where OPTIONS are:
+    --output      generate .gcov files
+    --help -h -?  print this message
+EOF
+    exit $1
+}
+
+while true; do
+case "$1" in
+--output ) gcovflags= ; shift ;;
+'-?' | -h | --help ) usage ;;
+- ) shift ; break ;;
+-* ) usage 1 ;;
+* ) break ;;
+esac
+done
+
+{
+for f in *.bb
+do 
+    test "$f" = "*.bb" && { echo "run 'make check' first"; exit 1; }
+    gcov $gcovflags "$f" 2>/dev/null
+done 
+for f in $@
+do 
+    gcov $gcovflags "$f" 2>/dev/null
+done 
+} |
+awk '
+BEGIN {
+'"$(for f in "$@"; do echo 'include["'$f'"] = 1;'; done)"'
+}
+
+/^File/ {
+    if (sub(/^File `\/home\/ppessi\/sofia-proxy\/(proxy\/..\/)?/, "")) {
+	sub(/.$/, "");
+	file=$0;
+	if (file ~ /torture/) file = "";
+    }
+    else
+	file = "";
+}
+file ~ /\.[hc]$/ && /Lines executed/ { 
+	sub(/Lines executed:/, ""); 
+	covered = int($3*$1/100 + 0.5);
+	
+#	printf "%-5u %-5u %-5u %-7s %s\n", $3, covered, $3 - covered, $1, file;
+	if ($3 == 0) {
+		/* skip */
+        }
+	else if (!lines[file]) {
+          	names[i++] = file; lines[file] = $3; coverage[file] = covered;
+		coverage[file] = $3*$1/100;
+        }
+	else if (coverage[file] < covered) {
+		lines[file] = $3; coverage[file] = covered;
+		coverage[file] = $3*$1/100;
+        }
+}
+
+/torture/ { next; } 
+/test/ { next; }
+/\/usr\/include/ { next; }
+
+/(source )?lines executed in file (.*\/)?[-A-Za-z_0-9]+\.[ch]/ { 
+        file = $0;
+	sub(/.* in file /, "", file);
+	sub(/.*\//, "", file);
+	covered = int($3*$1/100 + 0.5);
+	#printf "%-5u %-5u %-5u %-7s %s\n", $3, covered, $3 - covered, $1, file;
+
+	if ($3 == 0) {
+		/* skip */
+        }
+	else if (!file in lines) {
+		lines[file] = $3; coverage[file] = $3*$1/100;
+        }
+	else if (coverage[file] <= $3*$1/100) {
+		lines[file] = $3; coverage[file] = $3*$1/100;
+        }
+}
+
+END {
+    for (file in lines) {
+        if (!(file in include))
+	    continue;
+	l = lines[file]; c = coverage[file];
+	covered = int(c + 0.5);
+        total += l; total_coverage += c;
+	printf "%-5u %-5u %-5u %6.2f%%  %s\n", 
+		l, covered, l - covered, 100.0 * c / l, file;
+    }
+    if (total) {
+      module = ENVIRON["PWD"];
+      gsub(/\/+$/, "", module);
+      gsub(/.*\//, "", module);
+      printf "%-5u %-5u %-5u %6.2f%%  %s in %s\n",
+	total, total_coverage, total - total_coverage,
+	100.0 * total_coverage / total, "TOTAL", module;
+  }
+}
+' |
+sort -n

Added: freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,209 @@
+#! /bin/sed -f
+# 
+# Run this script like
+#
+# fix-include-sofia-sip -i.bak source.h source.c
+#
+# or
+#
+# find . -name '*.[hc]' -print0 | xargs -0 fix-include-sofia-sip -i.bak 
+#
+/^ *# *include/ {
+# Not using features.h...
+s!include  *<sofia-sip/features.h>!include <sofia-sip/sofia_features.h>!
+s!include  *"sofia-sip/features.h"!include "sofia-sip/sofia_features.h"!
+s!include  *<bnf.h>!include <sofia-sip/bnf.h>!
+s!include  *<sofia_sip_features.h>!include <sofia-sip/sofia_features.h>!
+s!include  *<http.h>!include <sofia-sip/http.h>!
+s!include  *<http_hclasses.h>!include <sofia-sip/http_hclasses.h>!
+s!include  *<http_header.h>!include <sofia-sip/http_header.h>!
+s!include  *<http_parser.h>!include <sofia-sip/http_parser.h>!
+s!include  *<http_protos.h>!include <sofia-sip/http_protos.h>!
+s!include  *<http_status.h>!include <sofia-sip/http_status.h>!
+s!include  *<http_tag.h>!include <sofia-sip/http_tag.h>!
+s!include  *<http_tag_class.h>!include <sofia-sip/http_tag_class.h>!
+s!include  *<base64.h>!include <sofia-sip/base64.h>!
+s!include  *<rc4.h>!include <sofia-sip/rc4.h>!
+s!include  *<sha1.h>!include <sofia-sip/sha1.h>!
+s!include  *<string0.h>!include <sofia-sip/string0.h>!
+s!include  *<token64.h>!include <sofia-sip/token64.h>!
+s!include  *<uniqueid.h>!include <sofia-sip/uniqueid.h>!
+s!include  *<utf8.h>!include <sofia-sip/utf8.h>!
+s!include  *<auth_client.h>!include <sofia-sip/auth_client.h>!
+s!include  *<auth_digest.h>!include <sofia-sip/auth_digest.h>!
+s!include  *<auth_module.h>!include <sofia-sip/auth_module.h>!
+s!include  *<auth_plugin.h>!include <sofia-sip/auth_plugin.h>!
+s!include  *<msg.h>!include <sofia-sip/msg.h>!
+s!include  *<msg_addr.h>!include <sofia-sip/msg_addr.h>!
+s!include  *<msg_buffer.h>!include <sofia-sip/msg_buffer.h>!
+s!include  *<msg_date.h>!include <sofia-sip/msg_date.h>!
+s!include  *<msg_header.h>!include <sofia-sip/msg_header.h>!
+s!include  *<msg_mclass.h>!include <sofia-sip/msg_mclass.h>!
+s!include  *<msg_mclass_hash.h>!include <sofia-sip/msg_mclass_hash.h>!
+s!include  *<msg_mime.h>!include <sofia-sip/msg_mime.h>!
+s!include  *<msg_mime_protos.h>!include <sofia-sip/msg_mime_protos.h>!
+s!include  *<msg_parser.h>!include <sofia-sip/msg_parser.h>!
+s!include  *<msg_protos.h>!include <sofia-sip/msg_protos.h>!
+s!include  *<msg_tag_class.h>!include <sofia-sip/msg_tag_class.h>!
+s!include  *<msg_types.h>!include <sofia-sip/msg_types.h>!
+s!include  *<nea.h>!include <sofia-sip/nea.h>!
+s!include  *<nea_tag.h>!include <sofia-sip/nea_tag.h>!
+s!include  *<nta.h>!include <sofia-sip/nta.h>!
+s!include  *<nta_stateless.h>!include <sofia-sip/nta_stateless.h>!
+s!include  *<nta_tag.h>!include <sofia-sip/nta_tag.h>!
+s!include  *<nta_tport.h>!include <sofia-sip/nta_tport.h>!
+s!include  *<sl_utils.h>!include <sofia-sip/sl_utils.h>!
+s!include  *<nth.h>!include <sofia-sip/nth.h>!
+s!include  *<nth_tag.h>!include <sofia-sip/nth_tag.h>!
+s!include  *<nua.h>!include <sofia-sip/nua.h>!
+s!include  *<nua_tag.h>!include <sofia-sip/nua_tag.h>!
+s!include  *<sdp.h>!include <sofia-sip/sdp.h>!
+s!include  *<sdp_tag.h>!include <sofia-sip/sdp_tag.h>!
+s!include  *<sip.h>!include <sofia-sip/sip.h>!
+s!include  *<sip_hclasses.h>!include <sofia-sip/sip_hclasses.h>!
+s!include  *<sip_header.h>!include <sofia-sip/sip_header.h>!
+s!include  *<sip_parser.h>!include <sofia-sip/sip_parser.h>!
+s!include  *<sip_protos.h>!include <sofia-sip/sip_protos.h>!
+s!include  *<sip_status.h>!include <sofia-sip/sip_status.h>!
+s!include  *<sip_tag.h>!include <sofia-sip/sip_tag.h>!
+s!include  *<sip_tag_class.h>!include <sofia-sip/sip_tag_class.h>!
+s!include  *<sip_util.h>!include <sofia-sip/sip_util.h>!
+s!include  *<soa.h>!include <sofia-sip/soa.h>!
+s!include  *<soa_add.h>!include <sofia-sip/soa_add.h>!
+s!include  *<soa_session.h>!include <sofia-sip/soa_session.h>!
+s!include  *<soa_tag.h>!include <sofia-sip/soa_tag.h>!
+s!include  *<sresolv.h>!include <sofia-sip/sresolv.h>!
+s!include  *<stun.h>!include <sofia-sip/stun.h>!
+s!include  *<stun_common.h>!include <sofia-sip/stun_common.h>!
+s!include  *<stun_tag.h>!include <sofia-sip/stun_tag.h>!
+s!include  *<htable.h>!include <sofia-sip/htable.h>!
+s!include  *<htable2.h>!include <sofia-sip/htable2.h>!
+s!include  *<rbtree.h>!include <sofia-sip/rbtree.h>!
+s!include  *<su.h>!include <sofia-sip/su.h>!
+s!include  *<su_addrinfo.h>!include <sofia-sip/su_addrinfo.h>!
+s!include  *<su_alloc.h>!include <sofia-sip/su_alloc.h>!
+s!include  *<su_alloc_stat.h>!include <sofia-sip/su_alloc_stat.h>!
+s!include  *<su_memmem.h>!include <sofia-sip/su_bm.h>!
+s!include  *<su_config.h>!include <sofia-sip/su_config.h>!
+s!include  *<su_configure.h>!include <sofia-sip/su_configure.h>!
+s!include  *<su_debug.h>!include <sofia-sip/su_debug.h>!
+s!include  *<su_errno.h>!include <sofia-sip/su_errno.h>!
+s!include  *<su_localinfo.h>!include <sofia-sip/su_localinfo.h>!
+s!include  *<su_log.h>!include <sofia-sip/su_log.h>!
+s!include  *<su_md5.h>!include <sofia-sip/su_md5.h>!
+s!include  *<su_source.h>!include <sofia-sip/su_source.h>!
+s!include  *<su_strlst.h>!include <sofia-sip/su_strlst.h>!
+s!include  *<su_tag.h>!include <sofia-sip/su_tag.h>!
+s!include  *<su_tag_class.h>!include <sofia-sip/su_tag_class.h>!
+s!include  *<su_tag_inline.h>!include <sofia-sip/su_tag_inline.h>!
+s!include  *<su_tag_io.h>!include <sofia-sip/su_tag_io.h>!
+s!include  *<su_tagarg.h>!include <sofia-sip/su_tagarg.h>!
+s!include  *<su_time.h>!include <sofia-sip/su_time.h>!
+s!include  *<su_types.h>!include <sofia-sip/su_types.h>!
+s!include  *<su_uniqueid.h>!include <sofia-sip/su_uniqueid.h>!
+s!include  *<su_vector.h>!include <sofia-sip/su_vector.h>!
+s!include  *<su_wait.h>!include <sofia-sip/su_wait.h>!
+s!include  *<tstdef.h>!include <sofia-sip/tstdef.h>!
+s!include  *<tport.h>!include <sofia-sip/tport.h>!
+s!include  *<tport_tag.h>!include <sofia-sip/tport_tag.h>!
+s!include  *<url.h>!include <sofia-sip/url.h>!
+s!include  *<url_tag.h>!include <sofia-sip/url_tag.h>!
+s!include  *<url_tag_class.h>!include <sofia-sip/url_tag_class.h>!
+s!include  *"bnf.h"!include "sofia-sip/bnf.h"!
+s!include  *"sofia_sip_features.h"!include "sofia-sip/sofia_features.h"!
+s!include  *"http.h"!include "sofia-sip/http.h"!
+s!include  *"http_hclasses.h"!include "sofia-sip/http_hclasses.h"!
+s!include  *"http_header.h"!include "sofia-sip/http_header.h"!
+s!include  *"http_parser.h"!include "sofia-sip/http_parser.h"!
+s!include  *"http_protos.h"!include "sofia-sip/http_protos.h"!
+s!include  *"http_status.h"!include "sofia-sip/http_status.h"!
+s!include  *"http_tag.h"!include "sofia-sip/http_tag.h"!
+s!include  *"http_tag_class.h"!include "sofia-sip/http_tag_class.h"!
+s!include  *"base64.h"!include "sofia-sip/base64.h"!
+s!include  *"rc4.h"!include "sofia-sip/rc4.h"!
+s!include  *"sha1.h"!include "sofia-sip/sha1.h"!
+s!include  *"string0.h"!include "sofia-sip/string0.h"!
+s!include  *"token64.h"!include "sofia-sip/token64.h"!
+s!include  *"uniqueid.h"!include "sofia-sip/uniqueid.h"!
+s!include  *"utf8.h"!include "sofia-sip/utf8.h"!
+s!include  *"auth_client.h"!include "sofia-sip/auth_client.h"!
+s!include  *"auth_digest.h"!include "sofia-sip/auth_digest.h"!
+s!include  *"auth_module.h"!include "sofia-sip/auth_module.h"!
+s!include  *"auth_plugin.h"!include "sofia-sip/auth_plugin.h"!
+s!include  *"msg.h"!include "sofia-sip/msg.h"!
+s!include  *"msg_addr.h"!include "sofia-sip/msg_addr.h"!
+s!include  *"msg_buffer.h"!include "sofia-sip/msg_buffer.h"!
+s!include  *"msg_date.h"!include "sofia-sip/msg_date.h"!
+s!include  *"msg_header.h"!include "sofia-sip/msg_header.h"!
+s!include  *"msg_mclass.h"!include "sofia-sip/msg_mclass.h"!
+s!include  *"msg_mclass_hash.h"!include "sofia-sip/msg_mclass_hash.h"!
+s!include  *"msg_mime.h"!include "sofia-sip/msg_mime.h"!
+s!include  *"msg_mime_protos.h"!include "sofia-sip/msg_mime_protos.h"!
+s!include  *"msg_parser.h"!include "sofia-sip/msg_parser.h"!
+s!include  *"msg_protos.h"!include "sofia-sip/msg_protos.h"!
+s!include  *"msg_tag_class.h"!include "sofia-sip/msg_tag_class.h"!
+s!include  *"msg_types.h"!include "sofia-sip/msg_types.h"!
+s!include  *"nea.h"!include "sofia-sip/nea.h"!
+s!include  *"nea_tag.h"!include "sofia-sip/nea_tag.h"!
+s!include  *"nta.h"!include "sofia-sip/nta.h"!
+s!include  *"nta_stateless.h"!include "sofia-sip/nta_stateless.h"!
+s!include  *"nta_tag.h"!include "sofia-sip/nta_tag.h"!
+s!include  *"nta_tport.h"!include "sofia-sip/nta_tport.h"!
+s!include  *"sl_utils.h"!include "sofia-sip/sl_utils.h"!
+s!include  *"nth.h"!include "sofia-sip/nth.h"!
+s!include  *"nth_tag.h"!include "sofia-sip/nth_tag.h"!
+s!include  *"nua.h"!include "sofia-sip/nua.h"!
+s!include  *"nua_tag.h"!include "sofia-sip/nua_tag.h"!
+s!include  *"sdp.h"!include "sofia-sip/sdp.h"!
+s!include  *"sdp_tag.h"!include "sofia-sip/sdp_tag.h"!
+s!include  *"sip.h"!include "sofia-sip/sip.h"!
+s!include  *"sip_hclasses.h"!include "sofia-sip/sip_hclasses.h"!
+s!include  *"sip_header.h"!include "sofia-sip/sip_header.h"!
+s!include  *"sip_parser.h"!include "sofia-sip/sip_parser.h"!
+s!include  *"sip_protos.h"!include "sofia-sip/sip_protos.h"!
+s!include  *"sip_status.h"!include "sofia-sip/sip_status.h"!
+s!include  *"sip_tag.h"!include "sofia-sip/sip_tag.h"!
+s!include  *"sip_tag_class.h"!include "sofia-sip/sip_tag_class.h"!
+s!include  *"sip_util.h"!include "sofia-sip/sip_util.h"!
+s!include  *"soa.h"!include "sofia-sip/soa.h"!
+s!include  *"soa_add.h"!include "sofia-sip/soa_add.h"!
+s!include  *"soa_session.h"!include "sofia-sip/soa_session.h"!
+s!include  *"soa_tag.h"!include "sofia-sip/soa_tag.h"!
+s!include  *"sresolv.h"!include "sofia-sip/sresolv.h"!
+s!include  *"stun.h"!include "sofia-sip/stun.h"!
+s!include  *"stun_common.h"!include "sofia-sip/stun_common.h"!
+s!include  *"stun_tag.h"!include "sofia-sip/stun_tag.h"!
+s!include  *"htable.h"!include "sofia-sip/htable.h"!
+s!include  *"htable2.h"!include "sofia-sip/htable2.h"!
+s!include  *"rbtree.h"!include "sofia-sip/rbtree.h"!
+s!include  *"su.h"!include "sofia-sip/su.h"!
+s!include  *"su_addrinfo.h"!include "sofia-sip/su_addrinfo.h"!
+s!include  *"su_alloc.h"!include "sofia-sip/su_alloc.h"!
+s!include  *"su_alloc_stat.h"!include "sofia-sip/su_alloc_stat.h"!
+s!include  *"su_memmem.h"!include "sofia-sip/su_bm.h"!
+s!include  *"su_config.h"!include "sofia-sip/su_config.h"!
+s!include  *"su_configure.h"!include "sofia-sip/su_configure.h"!
+s!include  *"su_debug.h"!include "sofia-sip/su_debug.h"!
+s!include  *"su_errno.h"!include "sofia-sip/su_errno.h"!
+s!include  *"su_localinfo.h"!include "sofia-sip/su_localinfo.h"!
+s!include  *"su_log.h"!include "sofia-sip/su_log.h"!
+s!include  *"su_md5.h"!include "sofia-sip/su_md5.h"!
+s!include  *"su_source.h"!include "sofia-sip/su_source.h"!
+s!include  *"su_strlst.h"!include "sofia-sip/su_strlst.h"!
+s!include  *"su_tag.h"!include "sofia-sip/su_tag.h"!
+s!include  *"su_tag_class.h"!include "sofia-sip/su_tag_class.h"!
+s!include  *"su_tag_inline.h"!include "sofia-sip/su_tag_inline.h"!
+s!include  *"su_tag_io.h"!include "sofia-sip/su_tag_io.h"!
+s!include  *"su_tagarg.h"!include "sofia-sip/su_tagarg.h"!
+s!include  *"su_time.h"!include "sofia-sip/su_time.h"!
+s!include  *"su_types.h"!include "sofia-sip/su_types.h"!
+s!include  *"su_uniqueid.h"!include "sofia-sip/su_uniqueid.h"!
+s!include  *"su_vector.h"!include "sofia-sip/su_vector.h"!
+s!include  *"su_wait.h"!include "sofia-sip/su_wait.h"!
+s!include  *"tstdef.h"!include "sofia-sip/tstdef.h"!
+s!include  *"tport.h"!include "sofia-sip/tport.h"!
+s!include  *"tport_tag.h"!include "sofia-sip/tport_tag.h"!
+s!include  *"url.h"!include "sofia-sip/url.h"!
+s!include  *"url_tag.h"!include "sofia-sip/url_tag.h"!
+s!include  *"url_tag_class.h"!include "sofia-sip/url_tag_class.h"!
+}
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+#!/usr/bin/env bash
+#
+# This script builds a snapshot RPM package of already existing Sofia-SIP
+# build tree
+#
+# Copyright (C) 2006 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# Created: Fri May 23 17:16:54 EEST 2003 ppessi
+#
+
+function usage
+{
+  echo "usage: snapshot.sh [-bc|-bb] [-c|--configure] [rpmbuild options]" 
+  exit $@
+}
+
+bb=-bb
+configure=0
+
+case "$1" in -b? ) bb=$1 ; shift ;; esac
+
+while true ; do 
+  case "$1" in 
+  -c | --configure | --co ) configure=1; shift; ;;
+  '-?' | --help | -h ) usage 0 ;; 
+  *) break ;;
+  esac
+done
+
+test -z "$srcdir" && srcdir=.
+RPMROOT=${RPMROOT:-`rpmbuild --eval='%_topdir' --quiet 2> /dev/null`}
+
+c=$srcdir/configure.ac
+
+PACKAGE_NAME=$(sed -n '/^AC_INIT/ { s/[^[]*\[//; s/\].*//; p;}' $c)
+NAME=$(echo $PACKAGE_NAME | tr 'A-Z ' 'a-z-')
+VERSION=$(sed -n '/^AC_INIT/ { s/.*\], \[//; s/\].*//; p;}' $c)
+GLIB_SOVER=$(sed -n '/^AC_SUBST[(]LIBVER_SOFIA_SIP_UA_GLIB_SOVER/ { s/.*, \[//; s/\].*//; p;}' $c)
+
+# Find spec in
+if test -r $NAME.spec.in ; then
+    specin=$NAME.spec.in
+elif test -r packages/$NAME.spec.in ; then
+    specin=packages/$NAME.spec.in
+else
+    echo $NAME.spec.in: not found
+    exit 2
+fi
+
+specversion=$(sed -n -e '/^Version:/ { s/Version: //; p }' ${specin%.in})
+
+if [ "$VERSION" != "$specversion" ]; then
+  configure=1
+fi
+
+RELEASE=${RELEASE:-SNAP.$(date +"%Y%m%d.%H%M")}
+
+test -r config.status &&
+prefix=$(sed -n '/^s, at prefix@,/ { s/^s,[^,]*,//; s/,.*//; p;}' config.status)
+
+test -z "$prefix" && prefix=/usr
+
+wd=${TEMPDIR:=/tmp}/sofia-snapshot-$$
+spec=$wd/$NAME-${VERSION}-${RELEASE}.spec
+dummy=${NAME}-${VERSION}-${RELEASE}.tar.gz
+
+test -x ./configure || sh ./autogen.sh
+
+install -d ${RPMROOT}/{SOURCES/SNAP,SPECS,BUILD,RPMS,SRPMS} $wd &&
+echo Creating $spec &&
+awk '
+/@VERSION@/ { sub(/@VERSION@/, version); }
+/@PACKAGE@/ { sub(/@PACKAGE@/, package); }
+/@PACKAGE_NAME@/ { sub(/@PACKAGE_NAME@/, package_name); }
+/@LIBVER_SOFIA_SIP_UA_GLIB_SOVER@/ { 
+  sub(/@LIBVER_SOFIA_SIP_UA_GLIB_SOVER@/, glib_sover);
+}
+/^Release:/ { 
+  print "Release: " release "%{?dist}\n";
+  print "Prefix: " prefix "\n";
+  next;
+}
+/^Source0:/ { print "Source0:" dummy "\n"; next; }
+/disable-dependency-tracking/ { 
+  sub(/--disable-dependency-tracking/, "");
+}
+/^%configure/ { 
+ print "cd " "\"" pwd "\"";
+ if (!configure) { $1="echo skipping configure"; }
+ $1=$1 "-C --enable-maintainer-mode";
+ print $0; 
+ next; 
+}
+# Do not make documentation
+/^make doc/ { print "echo skipping " $0; next; }
+# Ignore CFLAGS set by RPM
+/^make/ { print "CFLAGS= " $0; next; }
+{ print; }' \
+pwd=$PWD \
+configure=$configure dummy=$dummy \
+package=$NAME package_name="$PACKAGE_NAME" \
+version=$VERSION release=$RELEASE glib_sover=$GLIB_SOVER prefix=$prefix \
+$specin > $spec &&
+ln -s `pwd` $wd/${NAME}-${VERSION} &&
+tar cfz ${RPMROOT}/SOURCES/SNAP/$dummy -C $wd ${NAME}-${VERSION} &&
+rpmbuild $bb $spec --define '__os_install_post /usr/lib/rpm/brp-compress' --without docs -D"_sourcedir ${RPMROOT}/SOURCES/SNAP" "$@"
+rc=$?
+
+rm -rf $wd
+rm ${RPMROOT}/SOURCES/SNAP/$dummy
+
+exit $rc

Added: freeswitch/trunk/libs/sofia-sip/utils/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+2006-02-08  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Makefile.am, nua_cli.c: nua_cli example add removed from the 
+	distribution package.
+
+2005-09-29  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Printing all events.
+
+    M ./utils/nua_cli.c -4 +15
+
+  * Not using MSS-related tags.
+
+    M ./utils/nua_cli.c +2
+
+2005-09-28  Pekka Pessi  <Pekka.Pessi at nokia.com>
+	
+	* Not using soa directly anymore. 
+
+	    M ./utils/nua_cli.c -5 +3
+
+2005-09-07  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* nua_cli.c: Cleaned up unused ifdefs.
+
+2005-09-07  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* ChangeLog: File created.

Added: freeswitch/trunk/libs/sofia-sip/utils/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Doxyfile	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,44 @@
+PROJECT_NAME         = "sofia-sip"
+
+FILE_PATTERNS        = *.h *.c 
+
+EXCLUDE_PATTERNS     = acconfig.h config.h confdefs.h \
+			test*.h test*.c torture*.c *test.c *torture.c \
+			*_tag_dll.c *_tag_ref.c
+
+TAGFILES            = 
+
+OUTPUT_LANGUAGE      = English
+
+DETAILS_AT_TOP       = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES      = NO
+
+QUIET                = YES
+WARNINGS             = YES
+DISABLE_INDEX        = NO
+
+HAVE_DOT	     = YES
+INCLUDE_GRAPH	     = NO
+INCLUDED_BY_GRAPH    = NO
+
+EXTRACT_ALL          = NO
+EXTRACT_PRIVATE      = NO
+HIDE_UNDOC_MEMBERS   = YES
+HIDE_UNDOC_CLASSES   = YES
+HIDE_SCOPE_NAMES     = YES
+BRIEF_MEMBER_DESC    = YES
+REPEAT_BRIEF         = YES
+JAVADOC_AUTOBRIEF    = YES
+MAX_INITIALIZER_LINES = 0
+ENUM_VALUES_PER_LINE = 1
+
+ENABLE_PREPROCESSING = NO
+
+GENERATE_MAN         = YES
+MAN_OUTPUT           = .
+MAN_EXTENSION        = .1
+MAN_LINKS            = NO
+
+GENERATE_HTML        = NO
+GENERATE_LATEX       = NO

Added: freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+#
+# Template for Doxyfile.build
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+PROJECT_NUMBER		= @VERSION@
+
+INPUT 		      = @srcdir@
+INPUT                += @top_srcdir@/libsofia-sip-ua/su/localinfo.c
+INPUT                += @top_srcdir@/libsofia-sip-ua/su/addrinfo.c
+INPUT                += @top_srcdir@/libsofia-sip-ua/stun/stunc.c
+
+OUTPUT_DIRECTORY     = ../man
+
+ at INCLUDE_PATH = . @srcdir@
+
+ at INCLUDE = ../libsofia-sip-ua/docs/Doxyfile.aliases
+ at INCLUDE = ../libsofia-sip-ua/docs/Doxyfile.rfc
+ at INCLUDE = Doxyfile

Added: freeswitch/trunk/libs/sofia-sip/utils/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+#
+# Makefile.am for sofia-sip/utils
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+# Header paths
+
+sofiasrc=$(top_srcdir)/libsofia-sip-ua
+sofiabld=$(top_builddir)/libsofia-sip-ua
+
+INCLUDES = 	-I$(sofiasrc)/features -I$(sofiabld)/features \
+		-I$(sofiasrc)/ipt -I$(sofiabld)/ipt \
+		-I$(sofiasrc)/iptsec -I$(sofiabld)/iptsec \
+		-I$(sofiasrc)/bnf -I$(sofiabld)/bnf \
+		-I$(sofiasrc)/http -I$(sofiabld)/http \
+		-I$(sofiasrc)/msg -I$(sofiabld)/msg \
+		-I$(sofiasrc)/nth -I$(sofiabld)/nth \
+		-I$(sofiasrc)/nta -I$(sofiabld)/nta \
+		-I$(sofiasrc)/nea -I$(sofiabld)/nea \
+		-I$(sofiasrc)/nua -I$(sofiabld)/nua \
+		-I$(sofiasrc)/soa -I$(sofiabld)/soa \
+		-I$(sofiasrc)/sdp -I$(sofiabld)/sdp \
+		-I$(sofiasrc)/sip -I$(sofiabld)/sip \
+		-I$(sofiasrc)/soa -I$(sofiabld)/soa \
+		-I$(sofiasrc)/sresolv -I$(sofiabld)/sresolv \
+		-I$(sofiasrc)/tport -I$(sofiabld)/tport \
+		-I$(sofiasrc)/stun -I$(sofiabld)/stun \
+		-I$(sofiasrc)/url -I$(sofiabld)/url \
+		-I$(sofiasrc)/su -I$(sofiabld)/su
+
+
+AM_CFLAGS =		$(SOFIA_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_HEADERS = 	apps_utils.h
+
+bin_PROGRAMS =		sip-options sip-date sip-dig
+
+LDADD =			../libsofia-sip-ua/libsofia-sip-ua.la $(GLIB_LIBS)
+
+EXTRA_DIST =		Doxyfile

Added: freeswitch/trunk/libs/sofia-sip/utils/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,566 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/utils
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+# Header paths
+
+
+SOURCES = sip-date.c sip-dig.c sip-options.c
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = sip-options$(EXEEXT) sip-date$(EXEEXT) sip-dig$(EXEEXT)
+subdir = utils
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Doxyfile.build.in \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES = Doxyfile.build
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+sip_date_SOURCES = sip-date.c
+sip_date_OBJECTS = sip-date.$(OBJEXT)
+sip_date_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+sip_date_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+	$(am__DEPENDENCIES_1)
+sip_dig_SOURCES = sip-dig.c
+sip_dig_OBJECTS = sip-dig.$(OBJEXT)
+sip_dig_LDADD = $(LDADD)
+sip_dig_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+	$(am__DEPENDENCIES_1)
+sip_options_SOURCES = sip-options.c
+sip_options_OBJECTS = sip-options.$(OBJEXT)
+sip_options_LDADD = $(LDADD)
+sip_options_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+	$(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = sip-date.c sip-dig.c sip-options.c
+DIST_SOURCES = sip-date.c sip-dig.c sip-options.c
+HEADERS = $(noinst_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+sofiasrc = $(top_srcdir)/libsofia-sip-ua
+sofiabld = $(top_builddir)/libsofia-sip-ua
+INCLUDES = -I$(sofiasrc)/features -I$(sofiabld)/features \
+		-I$(sofiasrc)/ipt -I$(sofiabld)/ipt \
+		-I$(sofiasrc)/iptsec -I$(sofiabld)/iptsec \
+		-I$(sofiasrc)/bnf -I$(sofiabld)/bnf \
+		-I$(sofiasrc)/http -I$(sofiabld)/http \
+		-I$(sofiasrc)/msg -I$(sofiabld)/msg \
+		-I$(sofiasrc)/nth -I$(sofiabld)/nth \
+		-I$(sofiasrc)/nta -I$(sofiabld)/nta \
+		-I$(sofiasrc)/nea -I$(sofiabld)/nea \
+		-I$(sofiasrc)/nua -I$(sofiabld)/nua \
+		-I$(sofiasrc)/soa -I$(sofiabld)/soa \
+		-I$(sofiasrc)/sdp -I$(sofiabld)/sdp \
+		-I$(sofiasrc)/sip -I$(sofiabld)/sip \
+		-I$(sofiasrc)/soa -I$(sofiabld)/soa \
+		-I$(sofiasrc)/sresolv -I$(sofiabld)/sresolv \
+		-I$(sofiasrc)/tport -I$(sofiabld)/tport \
+		-I$(sofiasrc)/stun -I$(sofiabld)/stun \
+		-I$(sofiasrc)/url -I$(sofiabld)/url \
+		-I$(sofiasrc)/su -I$(sofiabld)/su
+
+AM_CFLAGS = $(SOFIA_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_HEADERS = apps_utils.h
+LDADD = ../libsofia-sip-ua/libsofia-sip-ua.la $(GLIB_LIBS)
+EXTRA_DIST = Doxyfile
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  utils/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  utils/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+Doxyfile.build: $(top_builddir)/config.status $(srcdir)/Doxyfile.build.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	     || test -f $$p1 \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+sip-date$(EXEEXT): $(sip_date_OBJECTS) $(sip_date_DEPENDENCIES) 
+	@rm -f sip-date$(EXEEXT)
+	$(LINK) $(sip_date_LDFLAGS) $(sip_date_OBJECTS) $(sip_date_LDADD) $(LIBS)
+sip-dig$(EXEEXT): $(sip_dig_OBJECTS) $(sip_dig_DEPENDENCIES) 
+	@rm -f sip-dig$(EXEEXT)
+	$(LINK) $(sip_dig_LDFLAGS) $(sip_dig_OBJECTS) $(sip_dig_LDADD) $(LIBS)
+sip-options$(EXEEXT): $(sip_options_OBJECTS) $(sip_options_DEPENDENCIES) 
+	@rm -f sip-options$(EXEEXT)
+	$(LINK) $(sip_options_LDFLAGS) $(sip_options_OBJECTS) $(sip_options_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-date.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-dig.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-options.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-generic clean-libtool ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binPROGRAMS install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am \
+	uninstall-binPROGRAMS uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+#ifndef APPS_UTILS_H /** Defined when apps_utils.h has been included. */
+#define APPS_UTILS_H
+
+/**
+ * @nofile apps_utils.h
+ * @brief 
+ * 
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @STARTLGPL@
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ * @ENDLGPL@
+ * 
+ * @date Created: Thu Apr  8 15:55:15 2004 ppessi
+ *
+ */
+
+SOFIA_BEGIN_DECLS
+
+static inline
+int proxy_authenticate(context_t *c,
+		       nta_outgoing_t *oreq,
+		       sip_t const *sip,
+		       nta_response_f response_function)
+{
+  if (sip && sip->sip_status->st_status == 407 && 
+      sip->sip_proxy_authenticate &&
+      c->c_proxy_auth_retries++ < 3 && 
+      c->c_proxy && c->c_proxy->url_user && c->c_proxy->url_password) {
+    url_t *u = c->c_proxy;
+    msg_t *rmsg = nta_outgoing_getrequest(oreq);
+    sip_t *rsip = sip_object(rmsg);
+
+    if (auc_challenge(&c->c_proxy_auth, c->c_home, sip->sip_proxy_authenticate,
+		      sip_proxy_authorization_class) >= 0 
+	&&
+	auc_all_credentials(&c->c_proxy_auth, NULL, NULL, 
+			    u->url_user, u->url_password) > 0
+	&& 
+	auc_authorization(&c->c_proxy_auth, rmsg, (msg_pub_t *)rsip,
+			  rsip->sip_request->rq_method_name,
+			  rsip->sip_request->rq_url,
+			  rsip->sip_payload) > 0) {
+      nta_outgoing_destroy(c->c_orq);
+      sip_header_remove(rmsg, rsip, (sip_header_t *)rsip->sip_via);
+      nta_msg_request_complete(rmsg, c->c_leg, 0, NULL, NULL);
+      c->c_orq = nta_outgoing_tmcreate(c->c_agent, response_function, c, NULL, 
+				       rmsg, TAG_END());
+      return 1;
+    }
+  }
+
+  return 0;
+}				   
+
+static inline
+int server_authenticate(context_t *c,
+			nta_outgoing_t *oreq,
+			sip_t const *sip,
+			nta_response_f response_function)
+{
+  if (sip && sip->sip_status->st_status == 401 && 
+      sip->sip_www_authenticate &&
+      c->c_auth_retries++ < 3 && 
+      c->c_password && c->c_username) {
+    msg_t *rmsg = nta_outgoing_getrequest(oreq);
+    sip_t *rsip = sip_object(rmsg);
+
+    if (auc_challenge(&c->c_auth, c->c_home, sip->sip_www_authenticate,
+		      sip_authorization_class) >= 0 
+	&&
+	auc_all_credentials(&c->c_auth, NULL, NULL, c->c_username, c->c_password) > 0
+	&& 
+	auc_authorization(&c->c_auth, rmsg, (msg_pub_t *)rsip,
+			  rsip->sip_request->rq_method_name,
+			  rsip->sip_request->rq_url,
+			  rsip->sip_payload) > 0) {
+      nta_outgoing_destroy(c->c_orq);
+      sip_header_remove(rmsg, rsip, (sip_header_t *)rsip->sip_via);
+      nta_msg_request_complete(rmsg, c->c_leg, 0, NULL, NULL);
+      c->c_orq = nta_outgoing_tmcreate(c->c_agent, response_function, c, NULL, 
+				       rmsg, TAG_END());
+      return 1;
+    }
+  }
+
+  return 0;
+}				   
+
+static inline
+int tag_from_header(nta_agent_t *nta,
+		    su_home_t *home,
+		    sip_from_t *f)
+{
+  char *env = getenv("SIPTAG");
+  char *t = (void *)nta_agent_newtag(home, NULL, nta);
+  int retval;
+
+  if (env) {
+    char *t1 = su_sprintf(home, "tag=%s-%s", env, t);
+    su_free(home, t);
+    t = t1;
+  }
+
+  retval = sip_from_tag(home, f, t);
+
+  su_free(home, t);
+
+  return retval;
+}
+
+SOFIA_END_DECLS
+
+#endif /* !defined APPS_UTILS_H */

Added: freeswitch/trunk/libs/sofia-sip/utils/sip-date.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-date.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page sip-date Print or parse SIP date
+ * 
+ * @section synopsis Synopsis
+ *
+ * <tt>sip-date [-n] [SIP-date | [YYYYy] [DDd] [HHh] [MMm] [SS[s]]]</tt>
+ *
+ * @section description Description
+ * 
+ * @em sip-date is an utility for printing a SIP date (in the format
+ * specified by RFC 1123, but the timezone must always be GMT) or parsing a
+ * given SIP date. The date can be given as a SIP date or by giving year,
+ * day, hour, minutes and seconds separately.
+ * 
+ * @section options Options
+ *
+ * The @em sip-date utility takes options as follows:
+ * <dl>
+ * <dt>-n</dt>
+ * <dd>The @em sip-date utility prints the date as seconds elapsed since
+ * epoch (01 Jan 1900 00:00:00).
+ * </dd>
+ * </dl>
+ *
+ * @section examples Examples
+ *
+ * You want to convert current time to SIP date:
+ * @code
+ * $ sip-date
+ * @endcode
+ * You want to find out how many seconds there was in 1900's:
+ * @code
+ * $ siptime -n 2000y
+ * 3155673600
+ * @endcode
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Pekka Pessi <Pekka -dot- Pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/msg_date.h>
+
+void usage(void)
+{
+  fprintf(stderr, 
+	  "usage: sip-date [-n] "
+          "[SIP-date | [YYYYy] [DDd] [HHh] [MMm] [SS[s]]]\n");
+  exit(1);
+}
+
+/* Epoch year. */
+#define EPOCH 1900		
+/* Day number of New Year Day of given year */
+#define YEAR_DAYS(y) \
+  (((y)-1) * 365 + ((y)-1) / 4 - ((y)-1) / 100 + ((y)-1) / 400)
+
+int main(int ac, char *av[])
+{
+  int numeric = 0;
+  sip_time_t t, t2;
+  char const *s;
+  char buf[1024];
+
+  if (av[1] && strcmp(av[1], "-n") == 0)
+    av++, numeric = 1;
+
+  if (av[1] && (strcmp(av[1], "-?") == 0 || strcmp(av[1], "-h") == 0))
+    usage();
+
+  if ((s = av[1])) {
+    size_t n, m;
+    /* Concatenate all arguments with a space in between them */
+    for (n = 0; (s = av[1]); av++) {
+      m = strlen(s);
+      if (n + m + 2 > sizeof(buf))
+	exit(1);
+      memcpy(buf + n, s, m);
+      buf[n + m] = ' ';
+      n += m + 1;
+    }
+    buf[n] = '\0';
+
+    s = buf;
+      
+    if (s[0] < '0' || s[0] > '9') {
+      if (msg_date_d(&s, &t) < 0) {
+	fprintf(stderr, "sip-date: %s is not valid time\n", s);
+	exit(1);
+      }
+    }
+    else {
+      for (; *s; ) {
+	t2 = 0;
+
+	if (msg_delta_d(&s, &t2) < 0)
+	  usage();
+      
+	switch (*s) {
+	case 'y': t2 = YEAR_DAYS(t2) - YEAR_DAYS(EPOCH); 
+	  /*FALLTHROUGH*/
+	case 'd': t += t2 * 24 * 60 * 60; s++; break;
+	case 'h': t += t2 * 60 * 60; s++; break;
+	case 'm': t += t2 * 60; s++; break;
+	case 's': 
+	  s++;
+	default:
+	  t += t2; 
+	  break;
+	}
+
+	while (*s && *s == ' ')
+	  s++;
+      }
+    }
+  }
+  else {
+    t = sip_now();
+  }
+
+  if (numeric) {
+    msg_delta_e(buf, sizeof(buf), t);
+  }
+  else {
+    msg_date_e(buf, sizeof(buf), t);
+  }
+
+  puts(buf);
+
+  return 0;
+}

Added: freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,827 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * This is an example program for @b sresolv library in synchronous mode.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Original Created: Tue Jul 16 18:50:14 2002 ppessi
+ */
+
+/**@page sip-dig Resolve SIP URIs.
+ * 
+ * @section sip_dig_synopsis Synopsis
+ * <tt>sip-dig [OPTIONS] uri...</tt>
+ *
+ * @section sip_dig_description Description
+ * The @em sip-dig utility resolves SIP URIs as described in @RFC3263. It
+ * queries NAPTR, SRV and A/AAAA records and prints out the resulting
+ * transport addresses.
+ *
+ * The default transports are: UDP, TCP, SCTP, TLS and TLS-SCTP. The SIPS
+ * URIs are resolved using only TLS transports, TLS and TLS-SCTP. If not
+ * otherwise indicated by NAPTR or SRV records, the sip-dig uses UDP and TCP
+ * as transports for SIP and TLS for SIPS URIs.
+ *
+ * The results are printed intended, with a preference followed by weight, 
+ * then protocol name, port number and IP address in numeric format.
+ *
+ * @section sip_dig_options Command Line Options
+ * The @e sip-dig utility accepts following command line options:
+ * <dl>
+ * <dt>-p <em>protoname</em></dt>
+
+ * <dd>Use named transport protocol. The <em>protoname</em> can be either
+ * well-known, e.g., "udp", or it can specify NAPTR service and SRV
+ * identifier, e.g., "tls-udp/SIPS+D2U/_sips._udp.".
+ * </dd>
+ * <dt>--udp</dt>
+ * <dd>Use UDP transport protocol.
+ * </dd>
+ * <dt>--tcp</dt>
+ * <dd>Use TCP transport protocol.
+ * </dd>
+ * <dt>--tls</dt>
+ * <dd>Use TLS over TCP transport protocol.
+ * </dd>
+ * <dt>--sctp</dt>
+ * <dd>Use SCTP transport protocol.
+ * </dd>
+ * <dt>--tls-sctp</dt>
+ * <dd>Use TLS over SCTP transport protocol.
+ * </dd>
+ * <dt>--no-sctp</dt>
+ * <dd>Ignore SCTP or TLS-SCTP records in the list of default transports. 
+ * This option has no effect if transport protocols has been explicitly
+ * listed.
+ * </dd>
+ * <dt>-4</dt>
+ * <dd>Query IP4 addresses (A records)
+ * </dd>
+ * <dt>-6</dt>
+ * <dd>Query IP6 addresses (AAAA records).
+ * </dd>
+ * <dt>-v</dt>
+ * <dd>Be verbatim.
+ * </dd>
+ * <dt></dt>
+ * <dd>
+ * </dd>
+ * </dl>
+ *
+ * @section sip_dig_return Return Codes
+ * <table>
+ * <tr><td>0<td>when successful (a 2XX-series response is received)
+ * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
+ * <tr><td>2<td>initialization failure
+ * </table>
+ *
+ * @section sip_dig_examples Examples
+ *
+ * Resolve sip:openlaboratory.net, prefer TLS over TCP, TCP over UDP:
+ * @code
+ * $ sip-dig --tls --tcp --udp sip:openlaboratory.net
+ *	1 0.333 tls 5061 212.213.221.127
+ *	2 0.333 tcp 5060 212.213.221.127
+ *	3 0.333 udp 5060 212.213.221.127
+ * @endcode
+ *
+ * Resolve sips:example.net with TLS over SCTP (TLS-SCTP) and TLS:
+ * @code
+ * $ sip-dig -p tls-sctp --tls sips:example.net
+ *	1 0.500 tls-udp 5061 172.21.55.26
+ *	2 0.500 tls 5061 172.21.55.26
+ * @endcode
+ *
+ * @section sip_dig_environment Environment
+ * #SRESOLV_DEBUG, SRESOLV_CONF
+ * 
+ * @section sip_dig_bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section sip_dig_author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section sip_dig_copyright Copyright
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_WIN32)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "sofia-sip/su.h"
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_record.h"
+
+#include "sofia-sip/url.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/hostdomain.h"
+
+char const name[] = "sip-dig";
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+enum { N_TPORT = 16 };
+
+struct transport { char const *name, *service, *srv; };
+
+struct dig {
+  sres_resolver_t *sres;
+
+  unsigned preference, ip4, ip6, sips, print;
+
+  struct transport tports[N_TPORT];
+};
+
+int dig_naptr(struct dig *dig, char const *host, double weight);
+
+int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
+		 double weight);
+
+int dig_srv(struct dig *dig, char const *tport, char const *host,
+	    double weight);
+
+int dig_srv_at(struct dig *dig,
+	       char const *tport, sres_record_t **answers, 
+	       double weight, int pweight,
+	       int priority);
+
+int dig_addr(struct dig *dig, 
+	     char const *tport, char const *host, char const *port,
+	     double weight);
+
+void print_addr_results(struct transport const *tports,
+			char const *tport, char const *tport2,
+			sres_record_t **answers, int type, int af,
+			char const *port,
+			double weight, int preference);
+
+void print_result(char const *addr, char const *port, char const *tport,
+		  double weight,
+		  unsigned preference);
+
+int prepare_transport(struct dig *dig, char const *tport);
+
+int count_transports(struct dig *dig,
+		     char const *tp1, 
+		     char const *tp2);
+
+void usage(int exitcode)
+{
+  fprintf(stderr, "usage: %s [OPTIONS] [@dnsserver] uri\n", name);
+  exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+  int exitcode = 0;
+  int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1;
+  int family = 0, multiple = 0;
+  char const *dnsserver = NULL;
+  char const *string;
+  url_t *uri = NULL;
+
+  char const *host;
+  char const *port;
+  char *transport = NULL, tport[32];
+
+  struct dig dig[1] = {{ NULL }};
+
+  if (su_init() != 0) 
+    return -1;
+
+  while (argv[1] && argv[1][0] == '-') {
+    if (strcmp(argv[1], "-v") == 0)
+      o_verbatim++;
+    else if (strcmp(argv[1], "-6") == 0)
+      dig->ip6 = ++family;
+    else if (strcmp(argv[1], "-4") == 0)
+      dig->ip4 = ++family;
+    else if (strncmp(argv[1], "-p", 2) == 0) {
+      char const *proto;
+
+      if (argv[1][2] == '=')
+	proto = argv[1] + 3;
+      else if (argv[1][2])
+	proto = argv[1] + 2;
+      else
+	proto = argv++[2];
+
+      if (proto == NULL)
+	usage(2);
+
+      if (prepare_transport(dig, proto) < 0)
+	exit(2);
+    }
+    else if (strcmp(argv[1], "--udp") == 0)
+      prepare_transport(dig, "udp");
+    else if (strcmp(argv[1], "--tcp") == 0)
+      prepare_transport(dig, "tcp");
+    else if (strcmp(argv[1], "--tls") == 0)
+      prepare_transport(dig, "tls");
+    else if (strcmp(argv[1], "--sctp") == 0)
+      prepare_transport(dig, "sctp");
+    else if (strcmp(argv[1], "--tls-sctp") == 0)
+      prepare_transport(dig, "tls-sctp");
+    else if (strcmp(argv[1], "--tls-udp") == 0)
+      prepare_transport(dig, "tls-udp");
+    else if (strcmp(argv[1], "--no-sctp") == 0)
+      o_sctp = 0, o_tls_sctp = 0;
+    else if (strcmp(argv[1], "--help") == 0)
+      usage(0);
+    else if (strcmp(argv[1], "-h") == 0)
+      usage(0);
+    else if (strcmp(argv[1], "-?") == 0)
+      usage(0);
+    else if (strcmp(argv++[1], "-") == 0)
+      break;
+    else
+      usage(2);
+    argv++;
+  }
+
+  if (!family)
+    dig->ip4 = 1, dig->ip6 = 2;
+
+  if (argv[1] && argv[1][0] == '@')
+    dnsserver = argv++[1] + 1;
+
+  if (!argv[1])
+    usage(2);
+
+  multiple = argv[1] && argv[2];
+
+  if (!count_transports(dig, NULL, NULL)) {
+    prepare_transport(dig, "udp");
+    prepare_transport(dig, "tcp");
+    if (o_sctp)
+      prepare_transport(dig, "sctp");
+    prepare_transport(dig, "tls");
+    if (o_tls_sctp)
+      prepare_transport(dig, "tls-sctp");
+  }
+
+  dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
+  if (!dig->sres)
+    perror("sres_resolver_new"), exit(1);
+
+  for (; (string = argv[1]); argv++) {
+    if (multiple)
+      puts(string);
+
+    uri = url_hdup(NULL, (void *)string);
+
+    if (uri && uri->url_type == url_unknown)
+      url_sanitize(uri);
+
+    if (uri->url_type == url_any)
+      continue;
+
+    if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) {
+      fprintf(stderr, "%s: invalid uri\n", string);
+      exitcode = 1;
+      continue;
+    }
+
+    port = url_port(uri);
+    if (port && !port[0]) port = NULL;
+    if (url_param(uri->url_params, "transport=", tport, sizeof tport) > 0)
+      transport = tport;
+
+    host = uri->url_host;
+
+    if (host_is_ip_address(host)) {
+      if (transport) {
+	print_result(host, port, transport, 1.0, 1);
+      }
+      else if (uri->url_type == url_sips) {
+	print_result(host, port, "tls", 1.0, 1);
+      }
+      else {
+	print_result(host, port, "udp", 1.0, 1);
+	print_result(host, port, "tcp", 1.0, 2);
+      }
+      continue;
+    }
+
+    if (!host_is_domain(host)) {
+      fprintf(stderr, "%s: invalid host\n", string);
+      exitcode = 1;
+      continue;
+    }
+
+    dig->sips = uri->url_type == url_sips;
+    dig->preference = 1;
+
+    if (!port && !transport && dig_naptr(dig, host, 1.0))
+      continue /* resolved naptr */;
+    else if (!port && dig_all_srvs(dig, transport, host, 1.0))
+      continue /* resolved srv */;
+    else if (dig_addr(dig, transport, host, port, 1.0))
+      continue /* resolved a/aaaa */;
+
+    fprintf(stderr, "%s: not found\n", string);
+    exitcode = 1;
+  }
+
+  sres_resolver_unref(dig->sres);
+
+  return exitcode;
+}
+
+
+int transport_is_secure(char const *tportname)
+{
+  return tportname && strncasecmp(tportname, "tls", 3) == 0;
+}
+
+int prepare_transport(struct dig *dig, char const *tport)
+{
+  struct transport *tports = dig->tports;
+  int j;
+
+  for (j = 0; j < N_TPORT - 1; j++) {
+    if (!tports[j].name)
+      break;
+    if (strcasecmp(tports[j].name, tport) == 0)
+      return 1;
+  }
+
+  if (j == N_TPORT)
+    return 0;
+
+  if (strchr(tport, '/')) {
+    char *service = strchr(tport, '/');
+    char *srv = strchr(service + 1, '/');
+
+    if (!srv || srv[strlen(srv) - 1] != '.') {
+      fprintf(stderr, "%s: invalid transport specifier \"%s\"\n", name, tport);
+      fputs(
+"\tspecifier should have name/service/srv-id\n"
+"\twhere name is protocol name (e.g, \"tls-udp\")\n"
+"\t      service specifies service as per RFC 2915 (e.g., \"SIPS+D2U\")\n"
+"\t      srv-id is prefix for SRV lookup (e.g., \"_sips._udp.\")\n",
+         stderr);
+      if (srv)
+	fputs("\t      and it should end with a dot \".\"\n", stderr);
+      return -1;
+    }
+
+    *service++ = '\0', *srv++ = '\0';
+
+    tports[j].name = tport,
+    tports[j].service = service;
+    tports[j].srv = srv;
+  }
+  else if (strcasecmp(tport, "udp") == 0) {
+    tports[j].name = "udp";
+    tports[j].service = "SIP+D2U";
+    tports[j].srv = "_sip._udp.";
+  }
+  else if (strcasecmp(tport, "tcp") == 0) {
+    tports[j].name = "tcp";
+    tports[j].service = "SIP+D2T";
+    tports[j].srv = "_sip._tcp.";
+  }
+  else if (strcasecmp(tport, "tls") == 0) {
+    tports[j].name = "tls";
+    tports[j].service = "SIPS+D2T";
+    tports[j].srv = "_sips._tcp.";
+  }
+  else if (strcasecmp(tport, "sctp") == 0) {
+    tports[j].name = "sctp";
+    tports[j].service = "SIP+D2S";
+    tports[j].srv = "_sip._sctp.";
+  }
+  else if (strcasecmp(tport, "tls-sctp") == 0) {
+    tports[j].name = "tls-sctp";
+    tports[j].service = "SIPS+D2S";
+    tports[j].srv = "_sips._sctp.";
+  }
+  else {
+    fprintf(stderr, "%s: unknown transport \"%s\"\n", name, tport);
+    return -1;
+  }
+
+  j++;
+
+  tports[j].service = tports[j].srv = tports[j].name = NULL;
+
+  return 1;
+}
+
+int
+count_transports(struct dig *dig,
+		 char const *tport,
+		 char const *tport2)
+{
+  
+  int i, tcount = 0;
+  struct transport const *tports = dig->tports;
+
+  for (i = 0; tports[i].name; i++) {
+    if (dig->sips && !transport_is_secure(tports[i].name))
+      continue;
+    if (!tport || strcasecmp(tport, tports[i].name) == 0)
+      tcount++;
+    if (tport2 && strcasecmp(tport2, tports[i].name) == 0)
+      tcount++;
+  }
+
+  return tcount;
+}
+
+struct transport const *
+transport_by_service(struct transport const *tports, char const *s)
+{
+  int i;
+
+  for (i = 0; tports[i].name; i++) {
+    if (strcasecmp(tports[i].service, s) == 0)
+      return tports + i;
+  }
+
+  return NULL;
+}
+
+int dig_naptr(struct dig *dig,
+	      char const *host,
+	      double weight)
+{
+  sres_record_t **answers = NULL;
+  struct transport const *tp;
+  int i, error;
+  int order = 0, count = 0, nacount = 0, scount = 0;
+
+  error = sres_blocking_query(dig->sres, sres_type_naptr, host, 0, &answers);
+  if (error < 0)
+    return 0;
+
+  /* Sort by priority */
+  sres_sort_answers(dig->sres, answers);
+
+  /* Count number of matching naptrs */
+  for (i = 0; answers[i]; i++) {
+    sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+    if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
+      continue;
+
+    if (dig->print)
+      printf("%s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
+	     na->na_record->r_name, na->na_record->r_ttl,
+	     na->na_order, na->na_prefer,
+	     na->na_flags, na->na_services,
+	     na->na_regexp, na->na_replace);
+
+    if (strcasecmp(na->na_flags, "s") && strcasecmp(na->na_flags, "a"))
+      continue;
+
+    if (nacount && order != na->na_order)
+      continue;
+
+    if (dig->sips && strncasecmp(na->na_services, "SIPS+", 5))
+      continue;
+
+    if (!transport_by_service(dig->tports, na->na_services))
+      continue;
+
+    order = na->na_order, nacount++;
+  }
+
+  if (nacount == 0) {
+    sres_free_answers(dig->sres, answers);
+    return 0;
+  }
+
+  for (i = 0; answers[i]; i++) {
+    sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+    if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
+      continue;
+    if (order != na->na_order)
+      continue;
+    if (strcasecmp(na->na_flags, "s") && strcasecmp(na->na_flags, "a"))
+      continue;
+    if (dig->sips && strncasecmp(na->na_services, "SIPS+", 5))
+      continue;
+
+    tp = transport_by_service(dig->tports, na->na_services);
+    if (!tp)
+      continue;
+
+    if (strcasecmp(na->na_flags, "s") == 0) {
+      scount = dig_srv(dig, tp->name, na->na_replace, weight / nacount);
+    }
+    else if (strcasecmp(na->na_flags, "a") == 0) {
+      scount = dig_addr(dig, tp->name, na->na_replace, NULL, weight / nacount);
+    }
+    else 
+      scount = 0;
+
+    count += scount;
+  }
+
+  return count;
+}
+
+int dig_all_srvs(struct dig *dig,
+		 char const *tport,
+		 char const *host,
+		 double weight)
+{
+  int i, j, n;
+  int tcount, count = 0, scount;
+  char *domain;
+
+  struct {
+    char const *proto; sres_record_t **answers;
+  } srvs[N_TPORT + 1] = {{ NULL }};
+
+  tcount = count_transports(dig, tport, NULL);
+  if (!tcount)
+    return 0;
+
+  for (i = 0, n = 0; dig->tports[i].name; i++) {
+    if (tport && strcasecmp(dig->tports[i].name, tport))
+      continue;
+
+    if (dig->sips && !transport_is_secure(dig->tports[i].name))
+      continue;
+
+    domain = su_strcat(NULL, dig->tports[i].srv, host);
+
+    if (domain) {
+      if (sres_blocking_query(dig->sres, sres_type_srv, domain, 0,
+			      &srvs[n].answers) >= 0) {
+	srvs[n++].proto = dig->tports[i].name;
+      }
+      free(domain);
+    }
+  }
+
+  if (n == 0)
+    return 0;
+
+  for (i = 0; i < n; i++) {
+    unsigned priority = 0, pweight = 0, m = 0;
+    sres_record_t **answers = srvs[i].answers;
+    char const *tport = srvs[i].proto;
+
+    for (j = 0; answers[j]; j++) {
+      sres_srv_record_t const *srv = answers[j]->sr_srv;
+
+      if (srv->srv_record->r_type != sres_type_srv)
+	continue;
+      if (srv->srv_record->r_status != 0)
+	continue;
+      
+      if (srv->srv_priority != priority && pweight != 0) {
+	scount = dig_srv_at(dig, tport, answers, weight / n, pweight,
+			    priority);
+	if (scount) dig->preference++;
+	count += scount;
+	pweight = 0, m = 0;
+      }
+
+      priority = srv->srv_priority, pweight += srv->srv_weight, m++;
+    }
+
+    if (m) {
+      scount = dig_srv_at(dig, tport, answers, weight / n, pweight, priority);
+      if (scount)
+	dig->preference++;
+      count += scount;
+    }
+  }
+
+  return count;
+}
+
+int dig_srv(struct dig *dig,
+	    char const *tport,
+	    char const *domain,
+	    double weight)
+{
+  sres_record_t **answers = NULL;
+  int j, n, error;
+  int count = 0, scount = 0;
+
+  uint32_t priority, pweight;
+
+  assert(tport && domain);
+
+  error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
+  if (error < 0)
+    return 0;
+
+  /* Sort by priority */
+  sres_sort_answers(dig->sres, answers);
+
+  priority = 0; pweight = 0; n = 0;
+
+  for (j = 0; answers[j]; j++) {
+    sres_srv_record_t const *srv = answers[j]->sr_srv;
+
+    if (srv->srv_record->r_type != sres_type_srv)
+      continue;
+    if (srv->srv_record->r_status != 0)
+      continue;
+
+    if (srv->srv_priority != priority && pweight != 0) {
+      scount = dig_srv_at(dig, tport, answers, weight, pweight,
+			  priority);
+      if (scount) dig->preference++;
+      count += scount;
+      pweight = 0, n = 0;
+    }
+
+    priority = srv->srv_priority, pweight += srv->srv_weight, n++;
+  }
+
+  if (n) {
+    scount = dig_srv_at(dig, tport, answers, weight, pweight, priority);
+    if (scount) dig->preference++;
+    count += scount;
+  }
+
+  sres_free_answers(dig->sres, answers);
+
+  return count;
+}
+
+int dig_srv_at(struct dig *dig,
+	       char const *tport,
+	       sres_record_t **answers,
+	       double weight, int pweight,
+	       int priority)
+{
+  int count = 0;
+  int i;
+  char port[8];
+
+  if (pweight == 0)
+    pweight = 1;
+
+  for (i = 0; answers[i]; i++) {
+    sres_srv_record_t const *srv = answers[i]->sr_srv;
+    if (srv->srv_record->r_type != sres_type_srv)
+      continue;
+    if (srv->srv_record->r_status != 0)
+      continue;
+    if (srv->srv_priority != priority)
+      continue;
+    snprintf(port, sizeof port, "%u", srv->srv_port);
+
+    count += dig_addr(dig, tport, srv->srv_target, port,
+		      weight * srv->srv_weight / pweight);
+  }
+
+  return count;
+}
+
+int dig_addr(struct dig *dig,
+	     char const *tport,
+	     char const *host,
+	     char const *port,
+	     double weight)
+{
+  int error, i;
+  char const *tport2 = NULL;
+  sres_record_t **answers1 = NULL, **answers2 = NULL;
+  unsigned count1 = 0, count2 = 0, tcount = 0;
+  int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
+
+  if (dig->ip6 > dig->ip4) {
+    type1 = sres_type_aaaa, family1 = AF_INET6;
+    if (dig->ip4)
+      type2 = sres_type_a, family2 = AF_INET;
+  }
+  else {
+    type1 = sres_type_a, family1 = AF_INET;
+    if (dig->ip6)
+      type2 = sres_type_aaaa, family2 = AF_INET6;
+  }
+
+  if (tport == NULL) {
+    if (dig->sips)
+      tport = "tls";
+    else
+      tport = "udp", tport2 = "tcp";
+  }
+
+  tcount = count_transports(dig, tport, tport2);
+  if (!tcount)
+    return 0;
+
+  if (type1) {
+    error = sres_blocking_query(dig->sres, type1, host, 0, &answers1);
+    if (error >= 0)
+      for (i = 0; answers1[i]; i++) {
+	sres_common_t *r = answers1[i]->sr_record;
+	count1 += r->r_type == type1 &&	r->r_status == 0;
+      }
+  }
+
+  if (type2) {
+    error = sres_blocking_query(dig->sres, type2, host, 0, &answers2);
+    if (error >= 0)
+      for (i = 0; answers2[i]; i++) {
+	sres_common_t *r = answers2[i]->sr_record;
+	count2 += r->r_type == type2 &&	r->r_status == 0;
+      }
+  }
+
+  if (count1 + count2) {
+    double w = weight / (count1 + count2) / tcount;
+
+    if (count1)
+      print_addr_results(dig->tports, tport, tport2,
+			 answers1, type1, family1, port,
+			 w, dig->preference);
+    if (count2)
+      print_addr_results(dig->tports, tport, tport2,
+			 answers2, type2, family2, port,
+			 w, dig->preference);
+  }
+
+  sres_free_answers(dig->sres, answers1);
+  sres_free_answers(dig->sres, answers2);
+
+  return count1 + count2;
+}
+
+void
+print_addr_results(struct transport const *tports,
+		   char const *tport, char const *tport2,
+		   sres_record_t **answers, int type, int af,
+		   char const *port,
+		   double weight, int preference)
+{
+  int i, j;
+  char addr[64];
+
+  for (i = 0; answers[i]; i++) {
+    if (answers[i]->sr_record->r_type != type)
+      continue;
+    if (answers[i]->sr_record->r_status != 0)
+      continue;
+
+    inet_ntop(af, &answers[i]->sr_a->a_addr, addr, sizeof addr);
+
+    for (j = 0; tports[j].name; j++) {
+      if (strcasecmp(tport, tports[j].name) == 0)
+	print_result(addr, port, tport, weight, preference);
+      if (tport2 && strcasecmp(tport2, tports[j].name) == 0)
+	print_result(addr, port, tport2, weight, preference);
+    }
+  }
+}
+
+void print_result(char const *addr,
+		  char const *port,
+		  char const *tport,
+		  double weight,
+		  unsigned preference)
+{
+  if (!port || !port[0])
+    port = transport_is_secure(tport) ? "5061" : "5060";
+
+  printf("\t%u %.3f %s %s %s\n", preference, weight, tport, port, addr);
+}

Added: freeswitch/trunk/libs/sofia-sip/utils/sip-options.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-options.c	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,396 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page sip-options Query SIP OPTIONS
+ * 
+ * @section synopsis Synopsis
+ * <tt>sip-options [--bind=url] [--from=url] [-a|--all] to </tt>
+ *
+ * @section description Description
+ * The @em sip-options utility sends a SIP OPTIONS request (or any other SIP
+ * request) to a SIP server.
+ *
+ * The @em sip-options tool will print out status line and interesting headers
+ * from the response, excluding From, Via, Call-ID, and CSeq. The message
+ * body is also printed.
+ *
+ * @section options Command Line Options
+ * The @e options utility accepts following command line options:
+ * <dl>
+ * <dt>-m url | --contact=url | --bind=url</dt>
+ * <dd>Specifies the SIP URL to which the @em options utility binds.
+ * </dd>
+ * <dt>--1XX | -1</dt>
+ * <dd>Print also preliminary responses. If this option is not present,
+ *     preliminary responses are silently discarded.
+ * </dd>
+ * <dt>--all | -a</dt>
+ * <dd>All SIP headers will be printed. If the --all option is given, 
+ *     the @em options utility also prints @b From, @b Via, @b Call-ID or
+ *     @b CSeq headers.
+ * </dd>
+ * <dt>--from=url</dt>
+ * <dd>Specifies the @b From header. Unless this option is used or the
+ *     environment variable @c SIPADDRESS is set, local Contact URL is used
+ *     as @b From header as well.
+ * </dd>
+ * <dt>--mf=n</dt>
+ * <dd>Specify the initial Max-Forwards count (defaults to 70, stack default).
+ * </dd>
+ * <dt>--method=s</dt>
+ * <dd>Specify the request method (defaults to OPTIONS).
+ * </dd>
+ * </dl>
+ *
+ * @section return Return Codes
+ * <table>
+ * <tr><td>0<td>when successful (a 2XX-series response is received)
+ * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
+ * <tr><td>2<td>initialization failure
+ * </table>
+ *
+ * @section examples Examples
+ * You want to query supported features of sip:essip00net.nokia.com:
+ * @code
+ * $ options sip:essip00net.nokia.com
+ * @endcode
+ *
+ * @section environment Environment
+ * #SIPADDRESS, #sip_proxy, #NTA_DEBUG, #TPORT_DEBUG, #TPORT_LOG.
+ * 
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct context_s context_t;
+#define NTA_OUTGOING_MAGIC_T context_t
+
+#include <sofia-sip/nta.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sl_utils.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/auth_client.h>
+#include <sofia-sip/tport_tag.h>
+
+struct context_s {
+  su_home_t   	  c_home[1];
+  su_root_t   	 *c_root;
+  nta_agent_t 	 *c_agent;
+  url_t          *c_proxy;
+  char const     *c_username;
+  char const     *c_password;
+  nta_leg_t   	 *c_leg;
+  nta_outgoing_t *c_orq;
+  auth_client_t  *c_proxy_auth;
+  auth_client_t  *c_auth;
+  unsigned        c_proxy_auth_retries;
+  unsigned        c_auth_retries;
+  int             c_all;
+  int             c_pre;
+  int             c_retval;
+};
+
+char const name[] = "sip-options";
+
+static
+void usage(int rc)
+{
+  fprintf(rc ? stderr : stdout, 
+	  "usage: %s OPTIONS url [extra-file]\n"
+	  "where OPTIONS are\n"
+	  "    --mf=count | --max-forwards=count\n"
+	  "    --contact=url | --bind=url | -m=url\n"
+	  "    --from=url\n"
+	  "    --ua=user-agent\n"
+	  "    --all | -a\n"
+	  "    --1XX | -1\n"
+	  "    --x | --extra \n",
+	  name);
+  exit(rc);
+}
+
+#include "apps_utils.h"
+
+static int response_to_options(context_t *context,
+			       nta_outgoing_t *oreq,
+			       sip_t const *sip);
+static char *readfile(FILE *f);
+
+int main(int argc, char *argv[])
+{
+  su_home_t *home;
+  context_t context[1] = {{{SU_HOME_INIT(context)}}};
+  char 
+    *extra = NULL,
+    *o_bind = "sip:*:*", 
+    *o_from = getenv("SIPADDRESS"),
+    *o_http_proxy = NULL,
+    *o_max_forwards = NULL,
+    *o_method = NULL,
+    *o_to = NULL;
+   
+  char *s, *v;
+
+  sip_method_t method = sip_method_options;
+
+#define MATCH(s, o) \
+      ((strncmp(s, o, strlen(o)) == 0))
+#define MATCH1(s, o) \
+      ((strncmp(s, o, strlen(o)) == 0) && \
+       (v = (s[strlen(o)] ? s + strlen(o) : argv++[1])))
+#define MATCH2(s, o) \
+      ((strncmp(s, o, strlen(o)) == 0) && \
+       (s[strlen(o)] == '=' || s[strlen(o)] == '\0') && \
+       (v = s[strlen(o)] ? s + strlen(o) + 1 : argv++[1]))
+
+  while ((s = argv++[1])) {
+    if (!MATCH(s, "-"))             { o_to = s;           break; }
+    else if (strcmp(s, "") == 0)    { o_to = argv++[1];   break; }
+    else if (MATCH(s, "-a") || MATCH(s, "--all")) 
+                                    { context->c_all = 1; }
+    else if (MATCH(s, "-x") || MATCH(s, "--extra")) 
+                                    { extra = "-"; }
+    else if (MATCH(s, "-1") || MATCH(s, "--1XX")) 
+                                    { context->c_pre = 1; }
+    else if (MATCH2(s, "--mf"))     { o_max_forwards = v; }
+    else if (MATCH2(s, "--http-proxy"))     { o_http_proxy = v; }
+    else if (MATCH2(s, "--max-forwards"))     { o_max_forwards = v; }
+    else if (MATCH2(s, "--bind"))   { o_bind = v; }
+    else if (MATCH1(s, "-m"))       { o_bind = v; }
+    else if (MATCH2(s, "--contact")){ o_bind = v; }
+    else if (MATCH2(s, "--from"))   { o_from = v; }
+    else if (MATCH2(s, "--method")) { o_method = v; }
+    else if (MATCH(s, "--help"))    { usage(0); }
+    else 
+      usage(2);
+  }
+
+  if (!o_to)
+    usage(2);
+
+  if (argv[1])
+    extra = argv++[1];
+
+  su_init();
+  
+  su_home_init(home = context->c_home);
+
+  context->c_root = su_root_create(context);
+  context->c_retval = 2;
+
+  if (context->c_root) {
+    url_string_t *r_uri;
+
+    context->c_agent = 
+      nta_agent_create(context->c_root,
+		       URL_STRING_MAKE(o_bind),
+		       NULL, NULL, /* Ignore incoming messages */
+		       TPTAG_HTTP_CONNECT(o_http_proxy),
+		       TAG_END());
+
+    if (context->c_agent) {
+      sip_addr_t *from, *to;
+      sip_contact_t const *m = nta_agent_contact(context->c_agent);
+
+      to = sip_to_create(home, (url_string_t *)o_to);
+
+      if (o_from)
+	from = sip_from_make(home, o_from);
+      else
+	from = sip_from_create(home, (url_string_t const *)m->m_url);
+
+      if (!from) {
+	fprintf(stderr, "%s: no valid From address\n", name);
+	exit(2);
+      }
+
+      tag_from_header(context->c_agent, context->c_home, from);
+
+      if (o_method) {
+	method = sip_method_code(o_method); 
+      } else {
+	isize_t len;
+	char const *params = to->a_url->url_params;
+
+	len = url_param(params, "method", NULL, 0);
+
+	if (len > 0) {
+	  o_method = su_alloc(home, len + 1);
+	  if (o_method == 0 ||
+	      url_param(params, "method", o_method, len + 1) != len) {
+	    fprintf(stderr, "%s: %s\n", name, 
+		    o_method ? "internal error" : strerror(errno));
+	    exit(2);
+	  }
+	  method = sip_method_code(o_method);
+	}
+      }
+
+      r_uri = (url_string_t *)url_hdup(home, to->a_url);
+
+      sip_aor_strip(to->a_url);
+      sip_aor_strip(from->a_url);
+
+      context->c_username = from->a_url->url_user;
+      context->c_password = from->a_url->url_password;
+      from->a_url->url_password = NULL;
+
+      if (extra) {
+	FILE *hf;
+	
+	if (strcmp(extra, "-"))
+	  hf = fopen(extra, "rb");
+	else
+	  hf = stdin;
+
+	extra = readfile(hf);
+      }
+
+      context->c_proxy = url_hdup(context->c_home, 
+				  (url_t *)getenv("sip_proxy"));
+
+      nta_agent_set_params(context->c_agent,
+			   NTATAG_SIPFLAGS(MSG_FLG_EXTRACT_COPY),
+			   NTATAG_DEFAULT_PROXY(context->c_proxy),
+			   TAG_END());
+
+      context->c_leg = 
+	nta_leg_tcreate(context->c_agent,
+			NULL, NULL,      /* ignore incoming requests */
+			SIPTAG_FROM(from), /* who is sending OPTIONS? */
+			SIPTAG_TO(to), /* whom we are sending OPTIONS? */
+			TAG_END());
+				      
+      if (context->c_leg) {
+	context->c_orq = 
+	  nta_outgoing_tcreate(context->c_leg,
+			       response_to_options, context, 
+			       NULL,
+			       method, o_method, r_uri,
+			       SIPTAG_USER_AGENT_STR("options"),
+			       SIPTAG_MAX_FORWARDS_STR(o_max_forwards),
+			       SIPTAG_HEADER_STR(extra),
+			       TAG_END());
+
+	if (context->c_orq) {
+	  su_root_run(context->c_root); 
+	  nta_outgoing_destroy(context->c_orq), context->c_orq = NULL;
+	}
+
+	nta_leg_destroy(context->c_leg), context->c_leg = NULL;
+      }
+
+      nta_agent_destroy(context->c_agent), context->c_agent = NULL;
+    }
+    
+    su_root_destroy(context->c_root);
+  }
+
+  su_deinit();
+
+  return context->c_retval;
+}
+
+/** Handle responses to registration request */
+static
+int response_to_options(context_t *context,
+			nta_outgoing_t *oreq,
+			sip_t const *sip)
+{
+  if (proxy_authenticate(context, oreq, sip, response_to_options))
+    return 0;
+  if (server_authenticate(context, oreq, sip, response_to_options))
+    return 0;
+				   
+  if (sip->sip_status->st_status >= 200 || context->c_pre) {
+    sip_header_t *h = (sip_header_t *)sip->sip_status;
+    char hname[64];
+
+    for (; h; h = (sip_header_t *)h->sh_succ) {
+      if (!context->c_all) {
+	if (sip_is_from(h) ||
+	    sip_is_via(h) ||
+	    sip_is_call_id(h) ||
+	    sip_is_cseq(h) ||
+	    sip_is_content_length(h))
+	  continue;
+      }
+      if (h->sh_class->hc_name) {
+	snprintf(hname, sizeof hname, "%s: %%s\n", h->sh_class->hc_name);
+	sl_header_print(stdout, hname, h); 
+      }
+      else {
+	sl_header_print(stdout, NULL, h); 
+      }
+    }
+  }
+  
+  if (sip->sip_status->st_status >= 200) {
+    context->c_retval = sip->sip_status->st_status >= 300;
+    su_root_break(context->c_root);
+  }
+
+  return 0;
+}
+
+/* Read in whole (binary!) file */
+char *readfile(FILE *f)
+{
+  char *buffer = NULL;
+  long size;
+  size_t len;
+
+  if (f == NULL)
+    return NULL;
+
+  for (size = 8192, buffer = NULL, len = 0; !feof(f); size += 8192) {
+    buffer = realloc(buffer, size + 1);
+    if (!buffer)
+      exit(2);
+    len += fread(buffer + len, 1, 8192, f);
+  }
+
+  buffer[len] = '\0';
+
+  return buffer;
+}

Added: freeswitch/trunk/libs/sofia-sip/win32/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/ChangeLog	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,44 @@
+2006-05-11  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  	* Now building libsofia_sip_ua.dll on win32.
+  
+  	We define both IN_LIBSOFIA_SIP_UA and IN_LIBSOFIA_SRES in
+  	libsofia_sip_ua.dsp.
+  
+  	Because of DLL linkage, we compile tags typedefs as C++
+  	(see win32/tests/test_nua/test_nat_tags.cpp).
+  
+  	Removed LIBSOFIA_SIP_UA_STATIC from win32/sofia-sip/su_configure.h.
+  
+  	Added libsofia_sip_ua_static.lib, too. If you want to compile against
+  	that, you need define LIBSOFIA_SIP_UA_STATIC by yourself. 
+  
+  	Added libsofia-sip-ua-static/libsofia_sip_ua_static.dsp.
+  
+  	Using multithreaded DLL runtime for all projects.
+
+2006-05-03  Kai Vehmanen  <kai.vehmanen at nokia.com>
+
+	* Added utils/sip_options example application to SofiaSIP.dsw.
+
+2006-04-17  Pekka Pessi  <Pekka.Pessi at nokia.com>
+
+  * Added test_tport.dsp to SofiaSIP.dsw
+
+  * Added source files:
+  
+  sres.c sres_blocking.c sres_cache.c stun.c stun_common.c stun_dns.c
+  stun_internal.h stun_mini.c nua_params.c nua_params.h tport_internal.h
+  tport_logging.c tport_stub_sigcomp.c tport_stub_stun.c
+  tport_threadpool.c tport_type_connect.c tport_type_tcp.c
+  tport_type_udp.c
+  
+  and
+  
+  sofia-resolv/sres.h sofia-resolv/sres_async.h
+  sofia-resolv/sres_cache.h sofia-resolv/sres_record.h
+  sofia-sip/tport_plugins.h
+  
+  to libsofia_sip_ua.dsp.
+
+  * Added stat() as well as struct stat to compatibity win32/unistd.h.

Added: freeswitch/trunk/libs/sofia-sip/win32/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/Makefile.am	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+#
+# Makefile.am for sofia-sip/win32
+#
+# This is used for including win32 files in dist
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+
+noinst_HEADERS = sofia-sip/su_configure.h unistd.h config.h
+
+EXTRA_DIST = SofiaSIP.dsw \
+	libsofia-sip-ua/libsofia_sip_ua.dsp \
+	libsofia-sip-ua/sofia-sip-ua.def \
+	libsofia-sip-ua-static/libsofia_sip_ua_static.dsp \
+	tests/test_nua/test_nua.dsp \
+	tests/test_nua/test_nat_tags.cpp \
+	tests/test_nta/test_nta.dsp \
+	tests/test_tport/test_tport.dsp \
+	tests/test_tport/test_class.cpp \
+	tests/test_tport/test_table.cpp \
+	tests/torture_su_alloc/torture_su_alloc.dsp \
+	tests/torture_su_root/torture_su_root.dsp \
+	tests/torture_su_tag/torture_su_tag.dsp \
+	tests/test_su/test_su.dsp \
+	tests/torture_su_time/torture_su_time.dsp \
+	tests/torture_su_timer/torture_su_timer.dsp \
+	tests/torture_su/torture_su.dsp \
+	tests/test_memmem/test_memmem.dsp \
+	tests/test_htable/test_htable.dsp \
+	tests/torture_rbtree/torture_rbtree.dsp \
+	tests/torture_su_bm/torture_su_bm.dsp \
+	tests/torture_su_port/torture_su_port.dsp \
+	utils/localinfo/localinfo.dsp \
+	utils/sip_options/sip_options.dsp \
+	utils/sip_dig/sip_dig.dsp \
+	utils/stunc/stunc.dsp \
+	$(PTHREAD_DIST) \
+	README.txt \
+	autogen.cmd build_sources.cmd version_files.cmd version.awk \
+	install.cmd check.cmd
+
+PTHREAD_DIST = \
+	pthread/ChangeLog \
+	pthread/md5.sum.txt \
+	pthread/pthreadVC2.dll \
+	pthread/pthreadVC2.lib \
+	pthread/semaphore.h \
+	pthread/sched.h \
+	pthread/pthread.h
+
+mostlyclean-local:
+	test "$(top_builddir)" = "$(top_srcdir)" || rm -f config.h

Added: freeswitch/trunk/libs/sofia-sip/win32/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/Makefile.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,474 @@
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/win32
+#
+# This is used for including win32 files in dist
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = win32
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in $(srcdir)/config.h.in ChangeLog
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
+	$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
+	$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h \
+	$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES = config.h
+SOURCES =
+DIST_SOURCES =
+HEADERS = $(noinst_HEADERS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
+COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWFLAG = @CWFLAG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
+ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
+EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_VERSION = @GLIB_VERSION@
+HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
+HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
+HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
+HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
+HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
+HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
+HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
+HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
+HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
+HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
+LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
+LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
+LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
+LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
+MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
+NDEBUG_FALSE = @NDEBUG_FALSE@
+NDEBUG_TRUE = @NDEBUG_TRUE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REPLACE_LIBADD = @REPLACE_LIBADD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOFIA_CFLAGS = @SOFIA_CFLAGS@
+SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
+STRIP = @STRIP@
+TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
+VERSION = @VERSION@
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_LD = @ac_ct_LD@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+include_sofiadir = @include_sofiadir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+noinst_HEADERS = sofia-sip/su_configure.h unistd.h config.h
+EXTRA_DIST = SofiaSIP.dsw \
+	libsofia-sip-ua/libsofia_sip_ua.dsp \
+	libsofia-sip-ua/sofia-sip-ua.def \
+	libsofia-sip-ua-static/libsofia_sip_ua_static.dsp \
+	tests/test_nua/test_nua.dsp \
+	tests/test_nua/test_nat_tags.cpp \
+	tests/test_nta/test_nta.dsp \
+	tests/test_tport/test_tport.dsp \
+	tests/test_tport/test_class.cpp \
+	tests/test_tport/test_table.cpp \
+	tests/torture_su_alloc/torture_su_alloc.dsp \
+	tests/torture_su_root/torture_su_root.dsp \
+	tests/torture_su_tag/torture_su_tag.dsp \
+	tests/test_su/test_su.dsp \
+	tests/torture_su_time/torture_su_time.dsp \
+	tests/torture_su_timer/torture_su_timer.dsp \
+	tests/torture_su/torture_su.dsp \
+	tests/test_memmem/test_memmem.dsp \
+	tests/test_htable/test_htable.dsp \
+	tests/torture_rbtree/torture_rbtree.dsp \
+	tests/torture_su_bm/torture_su_bm.dsp \
+	tests/torture_su_port/torture_su_port.dsp \
+	utils/localinfo/localinfo.dsp \
+	utils/sip_options/sip_options.dsp \
+	utils/sip_dig/sip_dig.dsp \
+	utils/stunc/stunc.dsp \
+	$(PTHREAD_DIST) \
+	README.txt \
+	autogen.cmd build_sources.cmd version_files.cmd version.awk \
+	install.cmd check.cmd
+
+PTHREAD_DIST = \
+	pthread/ChangeLog \
+	pthread/md5.sum.txt \
+	pthread/pthreadVC2.dll \
+	pthread/pthreadVC2.lib \
+	pthread/semaphore.h \
+	pthread/sched.h \
+	pthread/pthread.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  win32/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  win32/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+config.h: $(top_builddir)/config.status $(srcdir)/config.h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/libsofia-sip-ua $(distdir)/libsofia-sip-ua-static $(distdir)/pthread $(distdir)/sofia-sip $(distdir)/tests/test_htable $(distdir)/tests/test_memmem $(distdir)/tests/test_nta $(distdir)/tests/test_nua $(distdir)/tests/test_su $(distdir)/tests/test_tport $(distdir)/tests/torture_rbtree $(distdir)/tests/torture_su $(distdir)/tests/torture_su_alloc $(distdir)/tests/torture_su_bm $(distdir)/tests/torture_su_port $(distdir)/tests/torture_su_root $(distdir)/tests/torture_su_tag $(distdir)/tests/torture_su_time $(distdir)/tests/torture_su_timer $(distdir)/utils/localinfo $(distdir)/utils/sip_dig $(distdir)/utils/sip_options $(distdir)/utils/stunc
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+	-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool \
+	mostlyclean-local
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool ctags distclean distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool mostlyclean-local pdf pdf-am ps ps-am tags \
+	uninstall uninstall-am uninstall-info-am
+
+
+mostlyclean-local:
+	test "$(top_builddir)" = "$(top_srcdir)" || rm -f config.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: freeswitch/trunk/libs/sofia-sip/win32/README.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/README.txt	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+======================================
+win32/README.txt / Sofia-SIP for win32
+======================================
+
+The win32 subdirectory contains the build environment for Win32 environment
+using MSVC. In order to compile the code with Windows 2000 SDK you have to
+install so called "IPv6 Technology Preview for Windows 2000". The preview
+contains updated IPv6 API in <tpipv6.h> and <wspiapi.h> header files.
+
+http://msdn.microsoft.com/downloads/sdks/platform/tpipv6.asp
+
+There is a pthread implementation for Visual C on Win32 included.
+Source code and documentation for the pthread library can also be
+downloaded from http://sources.redhat.com/pthreads-win32/.
+
+The script autogen.cmd should be used to prepare source tree before
+compiling Sofia SIP. Note that it uses the gawk utility - see
+http://unxutils.sourceforge.net.
+
+Currently, the SofiaSIP.dsw workspace creates a shared library for
+sofia-sip-ua and a few test programs. The tests programs can be run 
+with the script check.cmd.

Added: freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,341 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libsofia_sip_ua"=".\libsofia-sip-ua\libsofia_sip_ua.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libsofia_sip_ua_static"=".\libsofia-sip-ua-static\libsofia_sip_ua_static.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "localinfo"=".\utils\localinfo\localinfo.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_dig"=".\utils\sip_dig\sip_dig.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_options"=".\utils\sip_options\sip_options.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_options_static"=".\utils\sip_options_static\sip_options_static.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "stunc"=".\utils\stunc\stunc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_htable"=".\tests\test_htable\test_htable.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_memmem"=".\tests\test_memmem\test_memmem.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_nta"=".\tests\test_nta\test_nta.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_nua"=".\tests\test_nua\test_nua.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_su"=".\tests\test_su\test_su.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_tport"=".\tests\test_tport\test_tport.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_rbtree"=".\tests\torture_rbtree\torture_rbtree.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su"=".\tests\torture_su\torture_su.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_alloc"=".\tests\torture_su_alloc\torture_su_alloc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_bm"=".\tests\torture_su_bm\torture_su_bm.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_port"=".\tests\torture_su_port\torture_su_port.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_root"=".\tests\torture_su_root\torture_su_root.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_tag"=".\tests\torture_su_tag\torture_su_tag.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_time"=".\tests\torture_su_time\torture_su_time.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_timer"=".\tests\torture_su_timer\torture_su_timer.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libsofia_sip_ua
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+

Added: freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+::
+:: Prepare pristine Sofia SIP source tree for Visual C
+::
+:: NOTE: this script requires gawk - see http://unxutils.sourceforge.net
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library 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
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+
+ at call version_files.cmd
+
+ at call build_sources.cmd
+
+ at echo.
+ at echo NOTE:
+ at echo NOTE: Remember to install pthreadVC2.dll to your path, too!
+ at echo NOTE:
+ at endlocal
\ No newline at end of file

Added: freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,115 @@
+::
+:: Build sources on win32
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+ at set CHECK=@IF errorlevel 1 GOTO failed
+
+:: Check that we really have awk
+@%AWK% "{ exit(0); }" < NUL >NUL
+ at if not errorlevel 9009 goto have_awk
+ at echo *** install %AWK% (GNU awk) into your PATH ***
+ at goto failed
+:have_awk
+
+ at set MSG_AWK=gawk -v BINMODE=rw -f ../libsofia-sip-ua/msg/msg_parser.awk
+:: in Win32 exit 0; from gawk 3.1.3 gets converted to errorlevel 1
+:: If you have gawk 3.1.3 uncomment the following line
+:: @set MSG_AWK=gawk -v BINMODE=rw -f ../libsofia-sip-ua/msg/msg_parser.awk success=-1
+ at set TAG_AWK=gawk -f ../libsofia-sip-ua/su/tag_dll.awk BINMODE=rw
+
+ at set IN=../libsofia-sip-ua/msg/test_class.h
+ at set PR=../libsofia-sip-ua/msg/test_protos.h
+ at set PT=../libsofia-sip-ua/msg/test_table.c
+
+%MSG_AWK% module=msg_test NO_MIDDLE=1 NO_LAST=1 ^
+  PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg_test prefix=msg MC_HASH_SIZE=127 multipart=msg_multipart ^
+  PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/msg/sofia-sip/msg_mime.h
+ at set PR=../libsofia-sip-ua/msg/sofia-sip/msg_protos.h
+ at set PR2=../libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h
+ at set PT=../libsofia-sip-ua/msg/msg_mime_table.c
+
+%MSG_AWK% module=msg NO_FIRST=1 NO_MIDDLE=1 PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg NO_FIRST=1 NO_LAST=1 PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg_multipart tprefix=msg prefix=mp MC_HASH_SIZE=127 ^
+  PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/sip/sofia-sip/sip.h
+ at set PR=../libsofia-sip-ua/sip/sip_tag.c
+ at set PR2=../libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h
+ at set PR3=../libsofia-sip-ua/sip/sofia-sip/sip_protos.h
+ at set PR4=../libsofia-sip-ua/sip/sofia-sip/sip_tag.h
+ at set PT=../libsofia-sip-ua/sip/sip_parser_table.c
+
+%MSG_AWK% module=sip PR=%PR% %IN%  < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR3% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR4% %IN% < NUL
+%CHECK%
+
+%MSG_AWK% module=sip MC_HASH_SIZE=127 MC_SHORT_SIZE=26 ^
+  FLAGFILE=../libsofia-sip-ua/sip/sip_bad_mask ^
+  PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/http/sofia-sip/http.h
+ at set PR=../libsofia-sip-ua/http/http_tag.c
+ at set PR2=../libsofia-sip-ua/http/sofia-sip/http_protos.h
+ at set PR3=../libsofia-sip-ua/http/sofia-sip/http_tag.h
+ at set PT=../libsofia-sip-ua/http/http_parser_table.c
+
+%MSG_AWK% module=http PR=%PR% %IN%  < NUL
+%CHECK%
+%MSG_AWK% module=http PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=http PR=%PR3% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=http MC_HASH_SIZE=127 PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set P=../libsofia-sip-ua
+
+%TAG_AWK% NO_DLL=1 %P%/http/http_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/iptsec/auth_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/msg/msg_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/nea/nea_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=nta_tag_list %P%/nta/nta_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/nth/nth_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=nua_tag_list %P%/nua/nua_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/sdp/sdp_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/sip/sip_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=soa_tag_list %P%/soa/soa_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=stun_tag_list %P%/stun/stun_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/tport/tport_tag.c  < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/url/url_tag.c  < NUL
+%CHECK%
+
+ at GOTO end
+:failed
+ at ECHO *** FAILED ***
+:end
+ at endlocal

Added: freeswitch/trunk/libs/sofia-sip/win32/check.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/check.cmd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+:: Run test programs
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library 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
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+tests\torture_su_alloc\Debug\torture_su_alloc.exe
+ at if errorlevel 1 ( echo torture_su_alloc: FAIL ) else echo torture_su_alloc: PASS
+
+tests\torture_su_root\Debug\torture_su_root.exe
+ at if errorlevel 1 ( echo torture_su_root: FAIL ) else echo torture_su_root: PASS
+
+tests\torture_su_tag\Debug\torture_su_tag.exe
+ at if errorlevel 1 ( echo torture_su_tag: FAIL ) else echo torture_su_tag: PASS
+
+tests\test_su\Debug\test_su.exe
+ at if errorlevel 1 ( echo test_su: FAIL ) else echo test_su: PASS
+
+tests\torture_su_time\Debug\torture_su_time.exe
+ at if errorlevel 1 ( echo torture_su_time: FAIL ) else echo torture_su_time: PASS
+
+tests\torture_su_timer\Debug\torture_su_timer.exe
+ at if errorlevel 1 ( echo torture_su_timer: FAIL ) else echo torture_su_timer: PASS
+
+tests\torture_su\Debug\torture_su.exe
+ at if errorlevel 1 ( echo torture_su: FAIL ) else echo torture_su: PASS
+
+tests\test_memmem\Debug\test_memmem.exe
+ at if errorlevel 1 ( echo test_memmem: FAIL ) else echo test_memmem: PASS
+
+tests\test_tport\Debug\test_tport.exe
+ at if errorlevel 1 ( echo test_tport: FAIL ) else echo test_tport: PASS
+
+tests\test_nta\Debug\test_nta.exe
+ at if errorlevel 1 ( echo test_nta: FAIL ) else echo test_nta: PASS
+
+tests\test_nua\Debug\test_nua.exe
+ at if errorlevel 1 ( echo test_nua: FAIL ) else echo test_nua: PASS
+
+tests\test_htable\Debug\test_htable.exe
+ at if errorlevel 1 ( echo test_htable: FAIL ) else echo test_htable: PASS
+
+tests\torture_rbtree\Debug\torture_rbtree.exe
+ at if errorlevel 1 ( echo torture_rbtree: FAIL ) else echo torture_rbtree: PASS
+
+tests\torture_su_bm\Debug\torture_su_bm.exe
+ at if errorlevel 1 ( echo torture_su_bm: FAIL ) else echo torture_su_bm: PASS
+
+tests\torture_su_port\Debug\torture_su_port.exe
+ at if errorlevel 1 ( echo torture_su_port: FAIL ) else echo torture_su_port: PASS

Added: freeswitch/trunk/libs/sofia-sip/win32/config.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/config.h.in	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,467 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file win32/config.h.in
+ * @brief <config.h> used by Windows.
+ *
+ * Use this on WIN32. 
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 12 19:22:54 2000 ppessi
+ */
+
+/* Define this as the random number source name. */
+#undef DEV_URANDOM
+
+/* Define this as 1 if you have addrinfo structure. */
+#define HAVE_ADDRINFO 1
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_getcpuclockid' function. */
+#undef HAVE_CLOCK_GETCPUCLOCKID
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define this as 1 if you have /dev/urandom. */
+#undef HAVE_DEV_URANDOM
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `epoll' function. */
+#undef HAVE_EPOLL
+
+/* Define this as 1 if you have WIN32 FILETIME type and
+   GetSystemTimeAsFileTime(). */
+#define HAVE_FILETIME 1
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define as 1 if the C compiler supports __func__ */
+#undef HAVE_FUNC
+
+/* Define as 1 if the C compiler supports __FUNCTION__ */
+#undef HAVE_FUNCTION
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#define HAVE_GAI_STRERROR 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getipnodebyname' function. */
+#undef HAVE_GETIPNODEBYNAME
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddr.h> header file. */
+#undef HAVE_IFADDR_H
+
+/* Define this as 1 if you have SIOCGIFCONF */
+#undef HAVE_IFCONF
+
+/* Define this as 1 if you have SIOCGIFNUM ioctl */
+#undef HAVE_IFNUM
+
+/* Define this as 1 if you have ifr_ifindex in <net/if.h> */
+#undef HAVE_IFR_IFINDEX
+
+/* Define this as 1 if you have ifr_index in <net/if.h> */
+#undef HAVE_IFR_INDEX
+
+/* Define to 1 if you have the `if_nameindex' function. */
+#undef HAVE_IF_NAMEINDEX
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initstate' function. */
+#undef HAVE_INITSTATE
+
+/* Define this as 1 if you have inlining compiler */
+#define HAVE_INLINE 1
+
+/* Define this as 1 if you have WIN32 INTERFACE_INFO_EX type. */
+#undef HAVE_INTERFACE_INFO_EX
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define as 1 you have WIN32 <iphlpapi.h> */
+// XXX: vehmanek-win32-fix:
+#undef HAVE_IPHLPAPI_H
+
+/* Define this as 1 if you have IPV6_RECVERR in <netinet/in6.h> */
+#undef HAVE_IPV6_RECVERR
+
+/* Define this as 1 if you have IP_RECVERR in <netinet/in.h> */
+#undef HAVE_IP_RECVERR
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `memccpy' function. */
+#undef HAVE_MEMCCPY
+
+/* Define to 1 if you have the `memcspn' function. */
+#undef HAVE_MEMCSPN
+
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memspn' function. */
+#undef HAVE_MEMSPN
+
+/* Define this as 1 if you are compiling in MinGW environment */
+#undef HAVE_MINGW
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+#undef HAVE_NETINET_SCTP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define this as 1 if you have OpenSSL */
+#undef HAVE_OPENSSL
+
+/* Define to 1 if you have the <openssl/tls1.h> header file. */
+#undef HAVE_OPENSSL_TLS1_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define this as 1 if you have /proc/net/if_inet6 control file */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the `random' function. */
+/* See later */
+#define HAVE_RANDOM 1
+
+/* Define this as 1 if you have sa_len in struct sockaddr */
+#undef HAVE_SA_LEN
+
+/* Define this a 1 if you have SCTP */
+#undef HAVE_SCTP
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define this as 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SIGCOMP
+
+/* Define to 1 if you have the <sigcomp.h> header file. */
+#undef HAVE_SIGCOMP_H
+
+/* Define as 1 if you have SIGPIPE */
+#undef HAVE_SIGPIPE
+
+/* Define this as 1 if you have IPv6 structures and constants */
+#define HAVE_SIN6 1
+
+/* Define this as 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY. */
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define this as 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SOFIA_SIGCOMP
+
+/* Define as 1 always */
+#define HAVE_SOFIA_SIP 1
+
+/* Define as 1 if we use S/MIME library */
+#undef HAVE_SOFIA_SMIME
+
+/* Define as 1 if we use DNS library */
+#define HAVE_SOFIA_SRESOLV 1
+
+/* Define as 1 if we use STUN library */
+#undef HAVE_SOFIA_STUN
+
+/* Define as 1 always */
+#define HAVE_SOFIA_SU 1
+
+/* Define as 1 if we use SRTP */
+#undef HAVE_SRTP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define this as 1 if your CC supports C99 struct initialization */
+#undef HAVE_STRUCT_KEYWORDS
+
+/* Define to 1 if you have the <sofia-sip/su_wait.h> header file. */
+#define HAVE_SU_WAIT_H 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define this as 1 if you have TLS */
+#undef HAVE_TLS
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define as 1 if we use UPnP */
+#undef HAVE_UPNP
+
+/* Define as 1 you have WIN32 */
+#define HAVE_WIN32 1
+
+/* Define to 1 if you have the <windef.h> header file. */
+#define HAVE_WINDEF_H 1
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#define HAVE_WINSOCK2_H 1
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#define HAVE_WS2TCPIP_H 1
+
+/* Define as format (%lli) for long long */
+#define LLI "%I64i"
+
+/* Define as format (%llu) for unsigned long long */
+#define LLU "%I64u"
+
+/* Define as format (%llx) for long long hex */
+#define LLX "%I64x"
+
+/* Name of package */
+#define PACKAGE "@PACKAGE@"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PACKAGE_NAME@"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "@PACKAGE_STRING@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PACKAGE_TARNAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PACKAGE_VERSION@"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#define VERSION "@PACKAGE_VERSION@"
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define as at least 64-bit int type */
+#define longlong __int64
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* PPe: defined in stddef.h */
+#undef size_t
+
+#define HOSTTYPE "pc-xp-win32"
+/* #define HOSTTYPE "pc-98-win32" */
+/* #define HOSTTYPE "pc-nt-win32" */
+
+/* Define this as locale-independent strcmp().  */
+#define strcasecmp  _stricmp
+
+/* Define this as locale-independent strncmp().  */
+#define strncasecmp _strnicmp
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+#define srandom(x)    srand((x))
+#define random()      rand()
+
+/* This is GCC magic  */
+#define __attribute__(x)
+
+/* Define this as 1 if you have TimeGetTime() */
+#define HAVE_TIMEGETTIME     1
+
+#define PATH_MAX _MAX_PATH
+
+#define HAVE_WINMM 1
+
+/* Define this as 1 if you have FILETIME */
+#define HAVE_FILETIME 1
+
+/* Define this as 1 if you have WinSock2 ioctl SIO_ADDRESS_LIST_QUERY */
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+
+/* Define this as 1 if you have INTERFACE_INFO ioctl */
+#define HAVE_INTERFACE_INFO 	   (1) 
+
+/* Ignore certain warnings */
+#ifdef _MSC_VER
+#pragma warning( disable : 4090 4204 4244 4018 4514 4706 4761)
+/* VC does not grok const */
+#pragma warning( disable : 4022 4028 )
+/* Temporarily disable high frequency, low value warnings.  
+   We may still want to re-enable and fix these */
+#pragma warning( disable : 4132 4100 4127 4152)
+#if (_MSC_VER >= 1400) // VC8+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif // VC8+
+#endif
+
+/* size_t/ssize_t modifiers 
+ * ref: http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx */
+#define MOD_ZD "%ld"
+#define MOD_ZU "%lu"

Added: freeswitch/trunk/libs/sofia-sip/win32/install.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/install.cmd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+::
+:: Collect files to be installed to install directory
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library 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
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+set name=sofia-sip
+set major=1.11
+set config=debug
+
+:: Uncomment this if you want release
+:: set config=release
+
+set destdir=..\..\%name%-%major%-%config%
+set includedir=%destdir%\include
+set sofiadir=%includedir%\sofia-sip
+set libdir=%destdir%\lib
+mkdir %destdir% %includedir% %sofiadir% %libdir%
+
+::
+:: Copy docs
+::
+set docs=README AUTHORS COPYING COPYRIGHTS README.developers RELEASE TODO ChangeLog
+for %%f in (%docs%) do xcopy /Y ..\%%f %destdir%
+
+::
+:: Copy headers
+::
+set SUBDIRS=su features bnf sresolv sdp url msg sip stun ipt soa tport http nta nea iptsec nth nua
+
+xcopy /Y sofia-sip\*.h %sofiadir%
+for %%s in (%SUBDIRS%) do xcopy /Y ..\libsofia-sip-ua\%%s\sofia-sip\*.h %sofiadir%
+
+xcopy /Y pthread\.*.h %includedir%
+
+::
+:: Copy libraries
+::
+
+::xcopy /Y libsofia-sip-ua\%config%\libsofia_sip_ua.dll %libdir%
+xcopy /Y libsofia-sip-ua\%config%\libsofia_sip_ua.lib %libdir%
+xcopy /Y Pthread\*.dll %libdir%
+xcopy /Y Pthread\*.lib %libdir%

Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1373 @@
+# Microsoft Developer Studio Project File - Name="libsofia_sip_ua_static" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libsofia_sip_ua_static - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libsofia_sip_ua_static.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libsofia_sip_ua_static.mak" CFG="libsofia_sip_ua_static - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libsofia_sip_ua_static - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libsofia_sip_ua_static - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libsofia_sip_ua_static - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "IN_LIBSOFIA_SIP_UA_STATIC" /D "LIBSOFIA_SIP_UA_STATIC" /D "LIBSRES_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "libsofia_sip_ua_static - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "IN_LIBSOFIA_SIP_UA_STATIC" /D "LIBSOFIA_SIP_UA_STATIC" /D "LIBSRES_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libsofia_sip_ua_static - Win32 Release"
+# Name "libsofia_sip_ua_static - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "su"
+
+# PROP Default_Filter "su*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_ntop.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_pton.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_addrinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc_lock.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_default_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_errno.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_global_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_localinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_md5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_os_nw.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_sprintf.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strdup.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strlst.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag_io.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_taglist.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_uniqueid.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_vector.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_wait.c"
+# End Source File
+# End Group
+# Begin Group "ipt"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\base64.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\rc4.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\string0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\token64.c"
+# End Source File
+# End Group
+# Begin Group "url"
+
+# PROP Default_Filter "url*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "features"
+
+# PROP Default_Filter "features*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\features.c"
+# End Source File
+# End Group
+# Begin Group "bnf"
+
+# PROP Default_Filter "bnf*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\bnf.c"
+# End Source File
+# End Group
+# Begin Group "msg"
+
+# PROP Default_Filter "msg*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_auth.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_date.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_generic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_copy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_make.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mclass.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_tag.c"
+# End Source File
+# End Group
+# Begin Group "clib replacement"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memcspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strcasestr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strtoull.c"
+# End Source File
+# End Group
+# Begin Group "sip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_caller_prefs.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_feature.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_prack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_pref_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_reason.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_security.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_util.c"
+# End Source File
+# End Group
+# Begin Group "http"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nth"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "sresolv"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_blocking.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_cache.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sresolv.c"
+# End Source File
+# End Group
+# Begin Group "nea"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "iptsec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_digest.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_http.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_sip.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin_delayed.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.c"
+# End Source File
+# End Group
+# Begin Group "stun"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_dns.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_mini.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nua"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_event_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_message.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_notifier.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_options.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_publish.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_registrar.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_subnotref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.h"
+# End Source File
+# End Group
+# Begin Group "nta"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_check.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_read_payload.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_print.c"
+# End Source File
+# End Group
+# Begin Group "tport"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_logging.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_sigcomp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_connect.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_tcp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_udp.c"
+# End Source File
+# End Group
+# Begin Group "sdp"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_parse.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_print.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "soa"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_session.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_static.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag_ref.c"
+# End Source File
+# End Group
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "su headers"
+
+# PROP Default_Filter "su*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable2.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\rbtree.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_addrinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc_stat.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_bm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_errno.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_localinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_log.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_md5.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_module_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_os_nw.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_source.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_strlst.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_inline.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_io.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tagarg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_time.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_types.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_uniqueid.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_vector.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_wait.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\tstdef.h"
+# End Source File
+# End Group
+# Begin Group "win32 headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\sofia-sip\su_configure.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\unistd.h
+# End Source File
+# End Group
+# Begin Group "ipt headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\base64.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\rc4.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\string0.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\token64.h"
+# End Source File
+# End Group
+# Begin Group "url headers"
+
+# PROP Default_Filter "url*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "features headers"
+
+# PROP Default_Filter "features*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\sofia-sip\sofia_features.h"
+# End Source File
+# End Group
+# Begin Group "bnf headers"
+
+# PROP Default_Filter "bnf*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\hostdomain.h"
+# End Source File
+# End Group
+# Begin Group "msg headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_addr.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_date.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass_hash.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_types.h"
+# End Source File
+# End Group
+# Begin Group "sip headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extensions.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_util.h"
+# End Source File
+# End Group
+# Begin Group "http headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "nth headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth_tag.h"
+# End Source File
+# End Group
+# Begin Group "sresolv headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_async.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_cache.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_record.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-sip\sresolv.h"
+# End Source File
+# End Group
+# Begin Group "nea headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea_tag.h"
+# End Source File
+# End Group
+# Begin Group "iptsec headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_digest.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_module.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_ntlm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.h"
+# End Source File
+# End Group
+# Begin Group "stun headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_tag.h"
+# End Source File
+# End Group
+# Begin Group "nua headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua_tag.h"
+# End Source File
+# End Group
+# Begin Group "nta headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_stateless.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\sl_utils.h"
+# End Source File
+# End Group
+# Begin Group "tport headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_plugins.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tls.h"
+# End Source File
+# End Group
+# Begin Group "sdp headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp_tag.h"
+# End Source File
+# End Group
+# Begin Group "soa headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_add.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_tag.h"
+# End Source File
+# End Group
+# End Group
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1389 @@
+# Microsoft Developer Studio Project File - Name="libsofia_sip_ua" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libsofia_sip_ua - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libsofia_sip_ua.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libsofia_sip_ua.mak" CFG="libsofia_sip_ua - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libsofia_sip_ua - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libsofia_sip_ua - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libsofia_sip_ua - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /D IN_LIBSOFIA_SIP_UA=1 /D IN_LIBSOFIA_SRES=1 /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /dll /machine:I386
+
+!ELSEIF  "$(CFG)" == "libsofia_sip_ua - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /D IN_LIBSOFIA_SIP_UA=1 /D IN_LIBSOFIA_SRES=1 /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Copy dll to win32 directory
+PostBuild_Cmds=copy Debug\libsofia_sip_ua.dll ..
+# End Special Build Tool
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libsofia_sip_ua - Win32 Release"
+# Name "libsofia_sip_ua - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "su"
+
+# PROP Default_Filter "su*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_ntop.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_pton.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_addrinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc_lock.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_default_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_errno.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_global_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_localinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_md5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_os_nw.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_sprintf.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strdup.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strlst.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag_io.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_taglist.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_uniqueid.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_vector.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_wait.c"
+# End Source File
+# End Group
+# Begin Group "ipt"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\base64.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\rc4.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\string0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\token64.c"
+# End Source File
+# End Group
+# Begin Group "url"
+
+# PROP Default_Filter "url*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "features"
+
+# PROP Default_Filter "features*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\features.c"
+# End Source File
+# End Group
+# Begin Group "bnf"
+
+# PROP Default_Filter "bnf*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\bnf.c"
+# End Source File
+# End Group
+# Begin Group "msg"
+
+# PROP Default_Filter "msg*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_auth.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_date.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_generic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_copy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_make.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mclass.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_tag.c"
+# End Source File
+# End Group
+# Begin Group "clib replacement"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memcspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strcasestr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strtoull.c"
+# End Source File
+# End Group
+# Begin Group "sip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_caller_prefs.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_feature.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_prack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_pref_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_reason.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_security.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_util.c"
+# End Source File
+# End Group
+# Begin Group "http"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nth"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "sresolv"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_blocking.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_cache.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sresolv.c"
+# End Source File
+# End Group
+# Begin Group "nea"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "iptsec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_digest.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_http.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_sip.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin_delayed.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.c"
+# End Source File
+# End Group
+# Begin Group "stun"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_dns.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_mini.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nua"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_event_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_message.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_notifier.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_options.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_publish.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_registrar.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_subnotref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.h"
+# End Source File
+# End Group
+# Begin Group "nta"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_check.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_read_payload.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_print.c"
+# End Source File
+# End Group
+# Begin Group "tport"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_logging.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_sigcomp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_connect.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_tcp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_udp.c"
+# End Source File
+# End Group
+# Begin Group "sdp"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_parse.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_print.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "soa"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_session.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_static.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag_ref.c"
+# End Source File
+# End Group
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "su headers"
+
+# PROP Default_Filter "su*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable2.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\rbtree.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_addrinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc_stat.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_bm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_errno.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_localinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_log.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_md5.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_module_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_os_nw.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_source.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_strlst.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_inline.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_io.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tagarg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_time.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_types.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_uniqueid.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_vector.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_wait.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\tstdef.h"
+# End Source File
+# End Group
+# Begin Group "win32 headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\sofia-sip\su_configure.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\unistd.h
+# End Source File
+# End Group
+# Begin Group "ipt headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\base64.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\rc4.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\string0.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\token64.h"
+# End Source File
+# End Group
+# Begin Group "url headers"
+
+# PROP Default_Filter "url*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "features headers"
+
+# PROP Default_Filter "features*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\sofia-sip\sofia_features.h"
+# End Source File
+# End Group
+# Begin Group "bnf headers"
+
+# PROP Default_Filter "bnf*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\hostdomain.h"
+# End Source File
+# End Group
+# Begin Group "msg headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_addr.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_date.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass_hash.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_types.h"
+# End Source File
+# End Group
+# Begin Group "sip headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extensions.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_util.h"
+# End Source File
+# End Group
+# Begin Group "http headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "nth headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth_tag.h"
+# End Source File
+# End Group
+# Begin Group "sresolv headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_async.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_cache.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_record.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-sip\sresolv.h"
+# End Source File
+# End Group
+# Begin Group "nea headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea_tag.h"
+# End Source File
+# End Group
+# Begin Group "iptsec headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_digest.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_module.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_ntlm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.h"
+# End Source File
+# End Group
+# Begin Group "stun headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_tag.h"
+# End Source File
+# End Group
+# Begin Group "nua headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua_tag.h"
+# End Source File
+# End Group
+# Begin Group "nta headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_stateless.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\sl_utils.h"
+# End Source File
+# End Group
+# Begin Group "tport headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_plugins.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tls.h"
+# End Source File
+# End Group
+# Begin Group "sdp headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp_tag.h"
+# End Source File
+# End Group
+# Begin Group "soa headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_add.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_tag.h"
+# End Source File
+# End Group
+# End Group
+# Begin Source File
+
+SOURCE=..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,573 @@
+LIBRARY "libsofia_sip_ua"
+DESCRIPTION  'Sofia-SIP-UA WIN32 DLL'
+EXPORTS
+auc_authorize
+auc_challenge
+auc_credentials
+auth_digest_challenge_get
+auth_digest_response
+auth_digest_response_get
+auth_digest_sessionkey
+auth_mod_challenge
+auth_mod_check
+auth_mod_check_ireq
+auth_mod_check_ireq2
+auth_mod_check_msg
+auth_mod_create
+auth_mod_destroy
+base64_d
+base64_e
+;inet_pton
+msg_addr
+msg_addr_copy
+msg_addr_zero
+msg_addrinfo
+msg_addrlen
+msg_auth_d
+msg_auth_dup_one
+msg_auth_dup_xtra
+msg_auth_e
+msg_buf_alloc
+msg_buf_commit
+msg_buf_committed
+msg_buf_move
+msg_buf_set
+msg_buf_size
+msg_clone
+msg_comment_d
+msg_copy_all
+msg_create
+msg_date_d
+msg_date_delta_d
+msg_date_e
+msg_default_dup_one
+msg_default_dup_xtra
+msg_delta_d
+msg_delta_e
+msg_destroy
+msg_dup
+msg_extract
+msg_extract_payload
+msg_extract_separator
+msg_find_hclass
+msg_firstline_d
+msg_generic_d
+msg_generic_dup_one
+msg_generic_dup_xtra
+msg_generic_e
+msg_hash_string
+msg_hclass_offset
+msg_header_add_dup
+msg_header_add_dup_as
+msg_header_add_str
+msg_header_alloc
+msg_header_alloc
+msg_header_alloc
+msg_header_copy
+msg_header_copy_as
+msg_header_d
+msg_header_dup
+msg_header_dup_as
+msg_header_e
+msg_header_insert
+msg_header_make
+msg_header_offset
+msg_header_remove
+msg_header_remove
+msg_header_vformat
+msg_hostport_d
+msg_iovec
+msg_list_d
+msg_list_dup_one
+msg_list_dup_one
+msg_list_dup_xtra
+msg_list_dup_xtra
+msg_list_e
+msg_list_e
+msg_mclass_clone
+msg_name_addr_d
+msg_name_addr_e
+msg_next
+msg_now
+msg_numeric_d
+msg_numeric_e
+msg_object
+msg_object_e
+msg_params_add
+msg_params_cmp
+msg_params_cmp
+msg_params_d
+msg_params_dup
+msg_params_e
+msg_params_find
+msg_params_find
+msg_params_find
+msg_params_find
+msg_params_replace
+msg_params_replace
+msg_payload_d
+msg_payload_dup_one
+msg_payload_dup_xtra
+msg_payload_e
+msg_prepare
+msg_public
+msg_quoted_d
+msg_recv_commit
+msg_recv_iovec
+msg_separator_d
+msg_separator_e
+msg_serialize
+msg_set_flags
+msg_token_d
+msg_unquote_dup
+msghdrtag_dup
+msghdrtag_snprintf 
+msghdrtag_xtra
+msgobjtag_dup
+msgobjtag_snprintf
+msgobjtag_xtra
+nea_create
+nea_destroy
+nea_server_create
+nea_server_destroy
+nea_server_notify
+nea_server_update
+nta_agent_add_tport
+nta_agent_contact
+nta_agent_create
+nta_agent_destroy
+nta_agent_get_params
+nta_agent_get_stats
+nta_agent_magic
+nta_agent_newtag
+nta_agent_set_params
+nta_agent_version
+nta_agent_via
+nta_compartment_decref
+nta_incoming_bind
+nta_incoming_destroy
+nta_incoming_getrequest
+nta_incoming_getresponse
+nta_incoming_mreply
+nta_incoming_tag
+nta_incoming_treply
+nta_is_internal_msg
+nta_leg_bind
+nta_leg_by_dialog
+nta_leg_by_uri
+nta_leg_client_route
+nta_leg_destroy
+nta_leg_get_tag
+nta_leg_magic
+nta_leg_rtag
+nta_leg_server_route
+nta_leg_stateful
+nta_leg_tag
+nta_leg_tcreate
+nta_msg_ackbye
+nta_msg_complete
+nta_msg_create
+nta_msg_discard
+nta_msg_request_complete
+nta_msg_response_complete
+nta_msg_send
+nta_msg_treply
+nta_msg_tsend
+nta_outgoing_cancel
+nta_outgoing_compartment
+nta_outgoing_cseq
+nta_outgoing_delay
+nta_outgoing_destroy
+nta_outgoing_getrequest
+nta_outgoing_getrequest_ref
+nta_outgoing_getresponse
+nta_outgoing_getresponse_ref
+nta_outgoing_mcreate
+nta_outgoing_method
+nta_outgoing_method_name
+nta_outgoing_prack
+nta_outgoing_request_uri
+nta_outgoing_route_uri
+nta_outgoing_status
+nta_outgoing_tagged
+nta_outgoing_tcancel
+nta_outgoing_tcreate
+nta_outgoing_tmcreate
+nta_reliable_treply
+nua_authenticate
+nua_bye
+nua_cancel
+nua_create
+nua_destroy
+nua_get_params
+nua_handle
+nua_handle_bind
+nua_handle_destroy
+nua_invite
+nua_message
+nua_notify
+nua_options
+nua_redirect
+nua_refer
+nua_register
+nua_respond
+nua_set_params
+nua_shutdown
+nua_subscribe
+nua_unregister
+nua_unsubscribe
+nua_unsubscribe
+nutag_address
+nutag_allow
+nutag_auth
+nutag_authtime
+nutag_autoAlert
+nutag_autoAnswer
+nutag_enableInvite
+nutag_enableMessage
+nutag_event
+nutag_handle
+nutag_hold
+nutag_invite_timer
+nutag_notify_refer
+nutag_phrase
+nutag_registrar
+nutag_session_timer
+nutag_sip_parser
+nutag_status
+nutag_url
+nutag_use_dialog
+sdp_attribute_by_mode
+sdp_attribute_dup
+sdp_attribute_find
+sdp_attribute_find2
+sdp_attribute_mapped_find
+sdp_attribute_mode
+sdp_bandwidth_dup
+sdp_connection_dup
+sdp_key_dup
+sdp_list_dup
+sdp_media_dup
+sdp_message
+sdp_message
+sdp_message_size
+sdp_message_size
+sdp_origin_dup
+sdp_parse
+sdp_parser_free
+sdp_parsing_error
+sdp_print
+sdp_print
+sdp_printer_free
+sdp_printer_free
+sdp_printing_error
+sdp_repeat_dup
+sdp_repeat_dup
+sdp_rtpmap_dup
+sdp_session
+sdp_session_dup
+sdp_time_dup
+sdp_zone_dup
+sip_add_dup
+sip_add_headers
+sip_add_make
+sip_add_tl
+sip_allow_events_add
+sip_call_id_create
+sip_complete_message
+sip_complete_response
+sip_contact_add_param
+sip_contact_expires
+sip_content_length_create
+sip_copy_all
+sip_cseq_create
+sip_default_mclass
+sip_expires_create
+sip_from_create
+sip_from_tag
+sip_has_feature
+sip_header_as_string
+sip_header_d
+sip_header_dup
+sip_header_e
+sip_header_field_d
+sip_header_field_e
+sip_header_format
+sip_header_size
+sip_method_name
+sip_now
+sip_params_add
+sip_params_cmp
+sip_params_find
+sip_params_replace
+sip_payload_create
+sip_record_route_create
+sip_request_create
+sip_route_create
+sip_route_follow
+sip_route_remove
+sip_sanity_check
+sip_separator_create
+sip_serialize
+sip_status_create
+sip_status_phrase
+sip_to_add_param   
+sip_to_create
+sip_to_tag
+sip_version_d
+sip_via_add_param
+sip_via_create
+sip_via_remove
+siptag_sip
+sl_allow_print
+sl_contact_print
+sl_contact_print
+sl_from_print
+sl_from_print
+sl_message_log
+sl_message_log
+sl_payload_print
+sl_to_print
+sl_to_print
+soa_activate
+soa_clone
+soa_create
+soa_deactivate
+soa_destroy
+soa_error_as_sip_reason
+soa_error_as_sip_response
+soa_generate_answer
+soa_generate_offer
+soa_get_capability_sdp
+soa_get_local_sdp
+soa_get_paramlist
+soa_get_params
+soa_get_remote_sdp
+soa_get_user_sdp
+soa_init_offer_answer
+soa_is_audio_active
+soa_is_chat_active
+soa_is_complete
+soa_is_image_active
+soa_is_remote_audio_active
+soa_is_remote_chat_active
+soa_is_remote_image_active
+soa_is_remote_video_active
+soa_is_video_active
+soa_media_features
+soa_process_answer
+soa_process_reject
+soa_remote_sip_features
+soa_set_capability_sdp
+soa_set_params
+soa_set_remote_sdp
+soa_set_user_sdp
+soa_sip_require
+soa_sip_supported
+soa_terminate
+soatag_active_audio
+soatag_active_audio_ref
+soatag_active_chat
+soatag_active_chat_ref
+soatag_active_image
+soatag_active_image_ref
+soatag_active_video
+soatag_active_video_ref
+soatag_address
+soatag_address_ref
+soatag_af
+soatag_af_ref
+soatag_caps_sdp
+soatag_caps_sdp_ref
+soatag_caps_sdp_str
+soatag_caps_sdp_str_ref
+soatag_hold
+soatag_hold_ref
+soatag_local_sdp
+soatag_local_sdp_ref
+soatag_local_sdp_str
+soatag_local_sdp_str_ref
+soatag_remote_sdp
+soatag_remote_sdp_ref
+soatag_remote_sdp_str
+soatag_remote_sdp_str_ref
+soatag_srtp_confidentiality
+soatag_srtp_confidentiality_ref
+soatag_srtp_enable
+soatag_srtp_enable_ref
+soatag_srtp_integrity
+soatag_srtp_integrity_ref
+soatag_user_sdp
+soatag_user_sdp_ref
+soatag_user_sdp_str
+soatag_user_sdp_str_ref
+srestag_resolv_conf
+strncspn
+strnspn
+su_alloc
+su_clone_forget
+su_clone_start
+su_clone_stop
+su_clone_task
+su_clone_wait
+su_close
+su_cmp_sockaddr
+su_counter
+su_deinit
+su_duration
+su_errno
+su_free
+su_freeaddrinfo
+su_freelocalinfo
+su_gai_strerror
+su_getaddrinfo
+su_getlocalinfo
+su_getlocalip
+su_getmsgsize
+su_gli_strerror
+su_guid_generate
+su_guid_sprintf
+su_home_check
+su_home_clone
+su_home_create
+su_home_deinit
+su_home_destroy
+su_home_init
+su_home_threadsafe
+su_init
+su_ioctl
+su_llog
+su_log
+su_log_default
+su_log_global
+su_log_init
+su_log_redirect
+su_log_set_level
+su_log_soft_set_level
+su_match_sockaddr
+su_md5_digest
+su_md5_init
+su_md5_iupdate
+su_md5_str0update
+su_md5_stri0update
+su_md5_striupdate
+su_md5_strupdate
+su_md5_update
+su_msg_create
+su_msg_data
+su_msg_destroy
+su_msg_from
+su_msg_reply
+su_msg_send
+su_msg_to
+su_now
+su_ntp_hi
+su_ntp_lo
+su_ntp_mw
+su_ntp_now
+su_ntp_sec
+su_perror
+su_perror2
+su_randint
+su_random
+su_realloc
+su_root_break
+su_root_create
+su_root_deregister
+su_root_destroy
+su_root_eventmask
+su_root_magic
+su_root_parent
+su_root_register
+su_root_run
+su_root_set_magic
+su_root_sleep
+su_root_step
+su_root_task
+su_root_threading
+su_root_unregister
+su_salloc
+su_setblocking
+su_seterrno
+su_setreuseaddr
+su_socket
+su_soerror
+su_sprintf
+su_strdup
+su_strerror
+su_strndup
+su_task_cmp
+su_task_copy
+su_task_deinit
+su_task_init
+su_task_is_running
+su_task_move
+su_task_null
+su_task_root
+su_time
+su_time_cmp
+su_time_diff
+su_time_print
+su_timer_create
+su_timer_destroy
+su_timer_reset
+su_timer_root
+su_timer_run
+su_timer_set
+su_timer_set_at
+su_vllog
+su_vsend
+su_wait
+su_wait_create
+su_wait_destroy
+su_wait_events
+su_wait_init
+su_wait_mask
+su_zalloc
+t_bool_snprintf
+t_int_snprintf
+t_ptr_snprintf
+t_str_dup
+t_str_snprintf
+t_str_xtra
+tag_any
+tag_next
+tag_null
+tag_skip
+tl_adup
+tl_afilter
+tl_dup
+tl_filter
+tl_find
+tl_gets
+tl_len
+tl_list
+tl_move
+tl_next
+tl_print
+tl_tfilter
+tl_tgets
+tl_tlist
+tl_tmove
+tl_tremove
+tl_vfree
+tl_vlen
+tl_vlist
+tl_vlist2
+tl_xtra
+token64_e
+tport_bind
+tport_by_name
+tport_create
+tport_destroy
+tport_hostport
+tport_is_reliable
+tport_magic
+tport_name
+tport_name_by_url
+tport_name_dup
+tport_next
+tport_send
+tport_set_magic
+tport_tbind
+tport_tsend

Added: freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file su_configure_win32.h
+ *
+ * @b su library configuration for WIN32 (VC6/VC98)
+ *
+ * The file <su_configure_win32.h> contains configuration information needed
+ * by WIN32 programs using @b su library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jan 18 15:30:55 2001 ppessi
+ */
+
+#define WIN32_LEAN_AND_MEAN
+/* Remove this when building DLL */
+/* #define LIBSOFIA_SIP_UA_STATIC */
+
+#define SU_HAVE_WIN32		1
+#define SU_HAVE_WINSOCK         1
+#define SU_HAVE_WINSOCK2        1
+#define SU_HAVE_POLL            0
+#define SU_HAVE_BSDSOCK         0
+#define SU_HAVE_STDINT          (0)
+#define SU_HAVE_NT              0
+#define SU_HAVE_IN6             1
+
+#define SU_HAVE_PTHREADS        (1)
+
+/** Define as 1 if you have sa_len field in struct sockaddr */
+#undef SU_HAVE_SOCKADDR_SA_LEN
+
+/** Define as 1 if you have struct sockaddr_storage */
+#define SU_HAVE_SOCKADDR_STORAGE 1
+
+/* Define this as 1 if you have if_nameindex() */
+#undef SU_HAVE_IF_NAMEINDEX
+
+/* Define as 1 if you have struct getaddrinfo. */
+#define SU_HAVE_ADDRINFO     1
+
+#define SU_INLINE                  __inline
+#define su_inline                  static __inline
+#define SU_HAVE_INLINE             (1)
+
+/** Define this as 1 if we can use tags directly from stack. */
+#define SU_HAVE_TAGSTACK (1)
+
+#define SU_S64_T __int64
+#define SU_U64_T unsigned __int64
+#define SU_S32_T __int32
+#define SU_U32_T unsigned __int32
+#define SU_S16_T __int16
+#define SU_U16_T unsigned __int16
+#define SU_S8_T  __int8
+#define SU_U8_T  unsigned __int8
+
+#define SU_LEAST64_T __int64
+#define SU_LEAST32_T __int32
+#define SU_LEAST16_T __int16
+#define SU_LEAST8_T  __int8
+
+#define SU_S64_C(i) (SU_S64_T)(i ## L)
+#define SU_U64_C(i) (SU_U64_T)(i ## UL)
+#define SU_S32_C(i) (SU_S32_T)(i ## L)
+#define SU_U32_C(i) (SU_U32_T)(i ## UL)
+#define SU_S16_C(i) (SU_S16_T)(i)
+#define SU_U16_C(i) (SU_U16_T)(i ## U)
+#define SU_S8_C(i)  (SU_S8_T)(i)
+#define SU_U8_C(i)  (SU_U8_T)(i ## U)
+
+#ifndef strcasecmp
+#define strcasecmp  _stricmp
+#endif
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+#ifndef snprintf
+#define snprintf    _snprintf
+#endif
+#ifndef vsnprintf
+#define vsnprintf   _vsnprintf
+#endif
+
+#define srandom(x)    srand((x))
+#define random()      rand()
+
+#include <basetsd.h>
+
+#define SOFIA_ISIZE_T size_t
+#define SOFIA_USIZE_T size_t
+
+#ifdef _WIN64
+#define SOFIA_SSIZE_T __in64
+#define SOFIA_ISSIZE_T __int64
+#define SU_INTPTR_T __int64
+#elif _MSC_VER >= 1400
+#define SOFIA_SSIZE_T __int32 __w64
+#define SOFIA_ISSIZE_T __int32 __w64
+#define SU_INTPTR_T __int32 __w64
+#else
+#define SOFIA_SSIZE_T __int32
+#define SOFIA_ISSIZE_T __int32
+#define SU_INTPTR_T __int32
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX MAXINT_PTR
+#endif
+#ifndef SSIZE_MAX
+#define SSIZE_MAX MAXUINT_PTR
+#endif
+
+#define ISIZE_MAX SIZE_MAX
+#define ISSIZE_MAX SSIZE_MAX
+#define USIZE_MAX SIZE_MAX

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_htable" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_htable - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_htable.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_htable.mak" CFG="test_htable - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_htable - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_htable - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_htable - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_htable - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_htable - Win32 Release"
+# Name "test_htable - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_htable.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_memmem" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_memmem - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_memmem.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_memmem.mak" CFG="test_memmem - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_memmem - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_memmem - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_memmem - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\pthread" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_memmem - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_memmem - Win32 Release"
+# Name "test_memmem - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,94 @@
+# Microsoft Developer Studio Project File - Name="test_nta" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_nta - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_nta.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_nta.mak" CFG="test_nta - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_nta - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_nta - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_nta - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_nta - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_nta - Win32 Release"
+# Name "test_nta - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nta\test_nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_nat_tags.c"

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,183 @@
+# Microsoft Developer Studio Project File - Name="test_nua" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_nua - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_nua.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_nua.mak" CFG="test_nua - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_nua - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_nua - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_nua - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_nua - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_nua - Win32 Release"
+# Name "test_nua - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_100rel.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_basic_call.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_call_hold.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_call_reject.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_cancel_bye.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_init.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nat.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\test_nat_tags.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua_api.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_ops.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_proxy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_proxy.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_session_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_simple.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_sip_events.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_su" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_su - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_su.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_su.mak" CFG="test_su - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_su - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_su - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_su - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_su - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_su - Win32 Release"
+# Name "test_su - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_su.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_class.c"

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_table.c"

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="test_tport" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_tport - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "test_tport.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "test_tport.mak" CFG="test_tport - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "test_tport - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_tport - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "test_tport - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "test_tport - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "test_tport - Win32 Release"
+# Name "test_tport - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\test_class.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\msg\test_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\msg\test_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\test_table.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\tport\test_tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_rbtree" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_rbtree - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_rbtree.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_rbtree.mak" CFG="torture_rbtree - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_rbtree - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_rbtree - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_rbtree - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_rbtree - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_rbtree - Win32 Release"
+# Name "torture_rbtree - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_rbtree.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su.mak" CFG="torture_su - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su - Win32 Release"
+# Name "torture_su - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_alloc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_alloc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_alloc.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_alloc.mak" CFG="torture_su_alloc - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_alloc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_alloc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_alloc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_alloc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_alloc - Win32 Release"
+# Name "torture_su_alloc - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_bm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_bm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_bm.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_bm.mak" CFG="torture_su_bm - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_bm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_bm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_bm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_bm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_bm - Win32 Release"
+# Name "torture_su_bm - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_port" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_port - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_port.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_port.mak" CFG="torture_su_port - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_port - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_port - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_port - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_port - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_port - Win32 Release"
+# Name "torture_su_port - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_root" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_root - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_root.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_root.mak" CFG="torture_su_root - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_root - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_root - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_root - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_root - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_root - Win32 Release"
+# Name "torture_su_root - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_tag" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_tag - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_tag.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_tag.mak" CFG="torture_su_tag - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_tag - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_tag - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_tag - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_tag - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_tag - Win32 Release"
+# Name "torture_su_tag - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_time" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_time - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_time.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_time.mak" CFG="torture_su_time - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_time - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_time - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_time - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_time - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_time - Win32 Release"
+# Name "torture_su_time - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_timer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_timer - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_timer.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "torture_su_timer.mak" CFG="torture_su_timer - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "torture_su_timer - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_timer - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "torture_su_timer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "torture_su_timer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "torture_su_timer - Win32 Release"
+# Name "torture_su_timer - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/unistd.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/unistd.h	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* Dummy unistd.h for win32 */
+
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define write(fd, buf, len) _write((fd), (buf), (unsigned int)(len))
+#define read(fd, buf, len)  _read((fd), (buf), (len))
+#define close(fd)           _close((fd))
+#define mktemp(template)    _mktemp((template))
+#define mkstemp(template)   _open(_mktemp(template), _O_RDWR|_O_CREAT, 0600)
+#define unlink(name)        _unlink((name))
+#define stat _stat
+
+#define O_RDONLY        _O_RDONLY
+#define O_WRONLY        _O_WRONLY
+#define O_RDWR          _O_RDWR
+#define O_APPEND        _O_APPEND
+#define O_CREAT         _O_CREAT
+#define O_TRUNC         _O_TRUNC
+#define O_EXCL          _O_EXCL
+
+#include <process.h>
+
+#define getpid() _getpid()

Added: freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,118 @@
+# Microsoft Developer Studio Project File - Name="localinfo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=localinfo - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "localinfo.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "localinfo.mak" CFG="localinfo - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "localinfo - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "localinfo - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "localinfo - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "localinfo - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "localinfo - Win32 Release"
+# Name "localinfo - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\getopt.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\localinfo.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_dig" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_dig - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_dig.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_dig.mak" CFG="sip_dig - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "sip_dig - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_dig - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "sip_dig - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "sip_dig - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "sip_dig - Win32 Release"
+# Name "sip_dig - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-dig.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_options" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_options - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_options.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_options.mak" CFG="sip_options - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "sip_options - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_options - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "sip_options - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "sip_options - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "sip_options - Win32 Release"
+# Name "sip_options - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-options.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_options_static" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_options_static - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_options_static.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "sip_options_static.mak" CFG="sip_options_static - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "sip_options_static - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_options_static - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "sip_options_static - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "sip_options_static - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "sip_options_static - Win32 Release"
+# Name "sip_options_static - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-options.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="stunc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=stunc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "stunc.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "stunc.mak" CFG="stunc - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "stunc - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "stunc - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "stunc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\features" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "stunc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\features" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "stunc - Win32 Release"
+# Name "stunc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\stun\stunc.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project

Added: freeswitch/trunk/libs/sofia-sip/win32/version.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/version.awk	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,51 @@
+#! /bin/gawk
+#
+# This script extracts the version information from configure.ac
+# and re-generates win32/config.h and 
+# libsofia-sip-ua/features/sofia_sip_features.h
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Contributor(s): Pekka.Pessi at nokia.com.
+#
+# Created: Wed Jan 25 15:57:10 2006 ppessi
+#
+
+BEGIN { IN=1; OUT=0; }
+
+IN && /^AC_INIT/ { version=$2; gsub(/[\]\[)]/, "", version); }
+
+OUT && /@[A-Z_]+@/ { 
+  gsub(/@PACKAGE_VERSION@/, version);
+  gsub(/@PACKAGE_BUGREPORT@/, "sofia-sip-devel at lists.sourceforge.net");
+  gsub(/@PACKAGE_NAME@/, "sofia-sip");
+  gsub(/@PACKAGE@/, "sofia-sip");
+  gsub(/@PACKAGE_STRING@/, "sofia-sip");
+  gsub(/@PACKAGE_TARNAME@/, "sofia-sip");
+}
+
+OUT { print; }
+

Added: freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd	Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+::
+:: Generate files usually generated by autoconf
+::
+:: NOTE: this script requires gawk - see http://unxutils.sourceforge.net
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2005 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library 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
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+ at set VERSION=%AWK% -v BINMODE="rw" -f version.awk
+ at set AC=..\configure.ac
+
+:: Check that we really have awk
+@%AWK% "{ exit(0); }" < NUL >NUL
+ at if not errorlevel 9009 goto have_awk
+ at echo *** install %AWK% (GNU awk) into your PATH ***
+ at goto end
+:have_awk
+
+for %%f in (config.h ..\libsofia-sip-ua\features\sofia-sip\sofia_features.h) ^
+do %VERSION% %AC% OUT=1 %%f.in > %%f
+ at if errorlevel 1 goto echo *** version_files failed ***
+
+:end
+ at endlocal

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile	Thu Dec 21 01:30:28 2006
@@ -1,6 +1,5 @@
 OS_ARCH         := $(subst /,_,$(shell uname -s | sed /\ /s//_/))
 VERSION = sofia-sip-1.12
-TARBALL = sofia-sip-1.12.4.tar.gz
 CFLAGS += -I. -I$(PREFIX)/include/$(VERSION)
 LDFLAGS += -lsofia-sip-ua
 LINKER=$(CC)
@@ -10,7 +9,7 @@
 all:	depends $(MODNAME).$(DYNAMIC_LIB_EXTEN)
 
 depends:
-	MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install $(TARBALL) --prefix=$(PREFIX) --with-pic --with-glib=no
+	MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install sofia-sip --prefix=$(PREFIX) --with-pic --with-glib=no
 
 %.o:  %.c
 	$(CC) -fPIC $(CFLAGS) -c -o $@ $<



More information about the Freeswitch-svn mailing list